summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorg2021-08-14 10:02:44 +0200
committerGeorg2021-08-14 10:10:42 +0200
commitc27753da863b3c44ceb81b2fe6ac689550704f89 (patch)
tree40e31d653640e43188ce5b45e08136297210a63f
downloadpublic-shell-c27753da863b3c44ceb81b2fe6ac689550704f89.tar.gz
public-shell-c27753da863b3c44ceb81b2fe6ac689550704f89.tar.bz2
public-shell-c27753da863b3c44ceb81b2fe6ac689550704f89.zip
Init
Signed-off-by: Georg <georg@lysergic.dev>
-rw-r--r--README.md1
-rw-r--r--dockersh/install-custom.sh13
-rw-r--r--etc/dockersh.ini29
-rw-r--r--etc/motd23
-rw-r--r--etc/sshd/sshd-banner2
-rw-r--r--lcpubsh/bin/adduser.sh4
-rw-r--r--lcpubsh/bin/generate.sh48
-rw-r--r--lcpubsh/bin/make_lc_user_image.sh12
-rwxr-xr-xlcpubsh/bin/pubsh274
-rw-r--r--lcpubsh/image_template/Dockerfile9
-rw-r--r--lcpubsh/image_template/user-mapping.sh21
11 files changed, 436 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c151c16
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+Hosts configurations related to our POC shell service.
diff --git a/dockersh/install-custom.sh b/dockersh/install-custom.sh
new file mode 100644
index 0000000..aed138e
--- /dev/null
+++ b/dockersh/install-custom.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+# Original by https://github.com/sleeepyjack/dockersh
+# Modified by georg@lysergic.dev
+
+pip3 install --upgrade -r requirements.txt
+if [ -z "$1" ]; then
+ activate-global-python-argcomplete
+else
+ activate-global-python-argcomplete --dest=$1
+fi
+cp dockersh /opt/dockersh/bin/
+chmod +x /opt/dockersh/bin/dockersh
+cp -n dockersh.ini /opt/dockersh/etc/
diff --git a/etc/dockersh.ini b/etc/dockersh.ini
new file mode 100644
index 0000000..90b5a81
--- /dev/null
+++ b/etc/dockersh.ini
@@ -0,0 +1,29 @@
+[ADMIN]
+command = admin
+shell = /bin/bash
+names =
+ cranberry-adm
+ mogad0n-adm
+maintenance = off
+maintenance_scp = on
+maintenance_text = This Maschine is in Maintanence Mode. However, you can copy files with `scp`, `rsync`, `sftp` or list files with `ls` without connecting to the maschine. I.e.
+ ssh ${HOSTNAME} ls -la
+
+[DEFAULT]
+image = ubuntu_user
+suffix = _${USER}
+homedir = /home/${USER}
+shell = /bin/bash
+greeting = Ready.
+
+[test01]
+image = test01
+
+[test02]
+image = test02
+
+[test03]
+image = test03
+
+[cranberry-test]
+image = cranberry-test
diff --git a/etc/motd b/etc/motd
new file mode 100644
index 0000000..4430e44
--- /dev/null
+++ b/etc/motd
@@ -0,0 +1,23 @@
+#################################################################
+## ##
+## --- https://liberta.casa --- ##
+## ##
+## - This is an EXPERIMENTAL, Proof Of Concept, environment. ##
+## - You are being offered an isolated container which ##
+## you are free to experiment in. ##
+## - Sudo is not configured by default, but you may ##
+## use root password ` freedom `. ##
+## - Containers stay running/online for a while ##
+## after `exit`ing. ##
+## - The memory shown in common CLI tools is NOT accurate - ##
+## if you exceed 512MB, processes may get killed. ##
+## - At this stage, shells may be reset at any time. ##
+## - If you encounter issues, please let us know. ##
+## ##
+## For your sanity: ##
+## - Do NOT consider this a secure environment. ##
+## - Do NOT consider this a reliable environment. ##
+## - Be considerate, don't waste other users resources. ##
+## - Help: Type ` help.sh ` or join #help on irc.liberta.casa ##
+## ##
+#################################################################
diff --git a/etc/sshd/sshd-banner b/etc/sshd/sshd-banner
new file mode 100644
index 0000000..ac788a5
--- /dev/null
+++ b/etc/sshd/sshd-banner
@@ -0,0 +1,2 @@
+You are connecting to the LibertaCasa public shell infrastructure.
+If you do not have an account yet, please request one in #libcasa.info on irc.liberta.casa (Webchat: https://liberta.casa/gamja).
diff --git a/lcpubsh/bin/adduser.sh b/lcpubsh/bin/adduser.sh
new file mode 100644
index 0000000..53e018d
--- /dev/null
+++ b/lcpubsh/bin/adduser.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+# georg@lysergic.dev
+# The filename is flawed, however changing it would likely break scripts in three other places.
+echo "$1:$2" | chpasswd
diff --git a/lcpubsh/bin/generate.sh b/lcpubsh/bin/generate.sh
new file mode 100644
index 0000000..299cab6
--- /dev/null
+++ b/lcpubsh/bin/generate.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+# georg@lysergic.dev
+set -e
+echo "Shell generation invoked." | nc -N 127.0.0.2 2424
+if [ ! "$#" -eq 0 ]; then
+user="$(echo "$1" |tr '[:upper:]' '[:lower:]')"
+case "$2" in
+ "archlinux")
+ os="archlinux"
+ image="lc-archlinux-userbase-v2:sh0"
+ ;;
+ "ubuntu")
+ os="ubuntu"
+ image="lcbase_ubuntu_14082021_2:sh0"
+ ;;
+ *)
+ echo "Choose between archlinux or ubuntu"
+ exit 1
+ ;;
+esac
+fingerprint_ecdsa="$(ssh-keygen -lf /etc/ssh/ssh_host_ecdsa_key.pub)"
+if id "$1" &>/dev/null; then
+ echo "Aborted. Username is already taken."
+ echo "Aborted: $user is already taken." | nc -N 127.0.0.2 2424
+else
+ echo "Hang on ..."
+ echo "Creating $user locally." | nc -N 127.0.0.2 2424
+ sudo useradd -mUs /opt/lcpubsh/bin/pubsh -G docker $user
+ pass=$(shuf -n2 /usr/share/dict/words | tr -d '\n')
+ echo "Appending to config." | nc -N 127.0.0.2 2424
+ echo "" >> /etc/dockersh.ini
+ echo "[$user]" >> /etc/dockersh.ini
+ echo "image = $user" >> /etc/dockersh.ini
+ echo "Forking Docker base image ($image)." | nc -N 127.0.0.2 2424
+ /opt/lcpubsh/bin/make_lc_user_image.sh $user $image | nc -N 127.0.0.2 2424
+ echo "Setting password." | nc -N 127.0.0.2 2424
+ sudo /opt/adduser.sh $user $pass
+ echo "@$user ssh -p 2222 $user@sh.lib.casa" | nc -N 127.0.0.2 2424
+ echo "@$user $fingerprint_ecdsa" | nc -N 127.0.0.2 2424
+ echo "@$user $pass" | nc -N 127.0.0.2 2424
+ echo "#universe $pass" | nc -N 127.0.0.2 2424
+ echo "Done." | nc -N 127.0.0.2 2424
+ echo "OK. Details sent to user and/or admins."
+fi
+else
+ echo "No argument supplied."
+fi
+
diff --git a/lcpubsh/bin/make_lc_user_image.sh b/lcpubsh/bin/make_lc_user_image.sh
new file mode 100644
index 0000000..fb0aa8a
--- /dev/null
+++ b/lcpubsh/bin/make_lc_user_image.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+# Original by https://github.com/sleeepyjack/dockersh
+# Modified by georg@lysergic.dev
+
+if [ -z "$1" -o -z "$2" ]; then
+ echo "./make_user_image.sh [name] [source-image]"; exit 100
+fi
+
+sed -i "1s/.*/FROM $2/" /opt/dockersh/dockersh-git/image_template/Dockerfile
+cd /opt/dockersh/dockersh-git/image_template
+docker build -t $1:sh0 .
+
diff --git a/lcpubsh/bin/pubsh b/lcpubsh/bin/pubsh
new file mode 100755
index 0000000..b40f143
--- /dev/null
+++ b/lcpubsh/bin/pubsh
@@ -0,0 +1,274 @@
+#!/usr/bin/env python3
+# PYTHON_ARGCOMPLETE_OK
+# Original by https://github.com/sleeepyjack/dockersh
+# Modified by georg@lysergic.dev
+# POC / IN DEVELOPMENT
+# Do NOT use this in insecure environments
+import os
+os.environ['TERM'] = 'xterm' # removes warning on non-tty commands
+
+import argparse
+#import argcomplete
+#from argcomplete.completers import ChoicesCompleter
+from configparser import ConfigParser, ExtendedInterpolation
+import docker
+import random
+import string
+import sys
+from pwd import getpwnam
+import socket
+import os
+import getpass
+
+prog = 'dockersh'
+version = prog + " v1.0"
+config_file = "/etc/dockersh.ini"
+
+user = getpass.getuser()
+hostname = socket.gethostname()
+
+cli = docker.APIClient()
+
+def containers(image_filter='', container_filter='', sort_by='Created', all=True):
+ cs = cli.containers(all=all, filters={'label': "user="+user})
+ cs.sort(key=lambda c: c[sort_by])
+ cs = [c for c in cs if str(c['Image']+':sh0').startswith(image_filter)]
+ cs = [c for c in cs if c['Names'][0][1:].startswith(container_filter)]
+ return cs
+
+def random_string(length):
+ def random_char():
+ return random.choice(string.ascii_uppercase + string.digits)
+ return ''.join(random_char() for _ in range(length))
+
+def strip(s, suffix=''):
+ for c in ['/', ':', '.', ' ']: #QUESTION does this suffice?
+ s = s.replace(c, '')
+ if s.endswith(suffix):
+ s = s[:len(s)-len(suffix)]
+ return s
+
+def pull(image):
+ if not image in image_names:
+ s = image.split(':')
+ if len(s) > 1:
+ cli.pull(s[0], s[1])
+ else:
+ cli.pull(s[0])
+
+def image_split(s):
+ sp = s.split(':')
+ if len(sp) == 1:
+ return sp[0], 'sh0'
+ else:
+ return sp[0], sp[1]
+
+def selection_menu(choices):
+ if len(choices) == 1:
+ return 0
+ print("There are multiple matching containers running:")
+ for j, c in enumerate(choices):
+ print("[" + str(j+1) + "]\t" + c)
+ inp = input("select [1]: ")
+ if inp == "":
+ i = 0
+ else:
+ i = int(inp) - 1
+ assert(0 <= i < len(choices))
+ return i
+
+#if __name__ == "__main__":
+def parse_args():
+
+
+
+ parser = argparse.ArgumentParser(prog=prog)
+ parser.add_argument('--version',
+ action='version',
+ version=version)
+ parser.add_argument('-i', '--image',
+ dest='image',
+ help="base image to be used",
+ default="") #.completer = ChoicesCompleter(tuple(images))
+ parser.add_argument('-n', '--name',
+ dest='name',
+ help="container name",
+ default="") #.completer = ChoicesCompleter(tuple(containers))
+ parser.add_argument('-t', '--temporary',
+ dest='temp',
+ action='store_true',
+ help="execute in temporary container",
+ default=False)
+ parser.add_argument('-c', '--command',
+ dest='cmd',
+ help="pass command to bash in container",
+ default="")
+ parser.add_argument('--home',
+ dest='home',
+ help="user home directory",
+ default=ini['homedir'])
+ #argcomplete.autocomplete(parser) #TODO make autocompletion work
+ args = parser.parse_args()
+
+ args.suffix = ini['suffix']
+ args.greeting = ini['greeting']
+ args.ini = ini
+ return args
+
+
+
+
+# load ini
+cfg = ConfigParser({"USER": user, "HOSTNAME": hostname}, interpolation=ExtendedInterpolation())
+cfg.read(config_file, encoding="utf-8")
+
+if os.getenv("USER") and user != os.getenv('USER') and user in cfg["ADMIN"]["names"].splitlines():
+ user = os.getenv('USER')
+
+ # reread config
+ cfg = ConfigParser({"USER": user, "HOSTNAME": hostname}, interpolation=ExtendedInterpolation())
+ cfg.read(config_file, encoding="utf-8")
+
+
+admin_cmd = "admin"
+admin_shell = "/bin/bash"
+if cfg.has_section("ADMIN") and "command" in cfg["ADMIN"]:
+ admin_cmd = cfg["ADMIN"]["command"]
+ if "admin_shell" in cfg["ADMIN"]:
+ admin_shell = cfg["ADMIN"]["admin_shell"]
+ini = cfg[user] if cfg.has_section(user) else cfg['DEFAULT']
+
+#if __name__ == "__main__":
+args = parse_args()
+
+if args.cmd == admin_cmd:
+ print("Trying to login into host: "+user)
+ if not sys.stdout.isatty():
+ print()
+ print("admin mode is only possible using pseudo tty-allocation.")
+ print("Try login using:")
+ print("ssh -t ...")
+ sys.exit(0)
+ os.system("sudo -u "+user+" sudo "+admin_shell)
+ sys.exit(0)
+
+
+if cfg.has_section("ADMIN") and "maintenance" in cfg["ADMIN"] and cfg["ADMIN"]["maintenance"] == "on" and (not "maintenance_scp" in cfg["ADMIN"] or cfg["ADMIN"]["maintenance_scp"] != "on"):
+ if "maintenance_text" in cfg["ADMIN"]:
+ print(cfg["ADMIN"]["maintenance_text"])
+ else:
+ print("This Maschine is in Maintanence Mode.")
+ sys.exit(0)
+
+is_scp_cmd = False
+if args.cmd:
+ if os.path.basename(args.cmd).startswith(("scp","rsync --server","sftp-server","ls","*")):
+ is_scp_cmd = True
+ if args.cmd == "envir":
+ print(os.environ)
+name_passed = (args.name != "")
+image_passed = (args.image != "")
+
+if not is_scp_cmd and cfg.has_section("ADMIN") and "maintenance" in cfg["ADMIN"] and cfg["ADMIN"]["maintenance"] == "on":
+ if "maintenance_text" in cfg["ADMIN"]:
+ print(cfg["ADMIN"]["maintenance_text"])
+ else:
+ print("This Maschine is in Maintanence Mode. However, you can copy files with scp, rsync, sftp or list files with ls without connecting to the maschine.")
+ sys.exit(0)
+
+if args.temp:
+ if not image_passed:
+ args.image = args.ini['image']
+ args.image_base, args.image_tag = image_split(args.image)
+ args.image = args.image_base + ':' + args.image_tag
+ args.name = strip(args.image) + '_tmp' + random_string(4)
+else:
+ if name_passed:
+ args.name = strip(args.name, args.suffix)
+
+ filtered_con = containers(image_filter=args.image, container_filter=args.name)
+
+ if len(filtered_con) > 0:
+ con_names = [c['Names'][0][1:] for c in filtered_con]
+ i = selection_menu(con_names)
+ args.name = strip(con_names[i], args.suffix)
+ else:
+ if not image_passed:
+ args.image = args.ini['image']
+ args.image_base, args.image_tag = image_split(args.image)
+ args.image = args.image_base + ':' + args.image_tag
+
+ if not name_passed:
+ args.name = strip(args.image)
+
+ if len(containers(container_filter=args.name)) != 0:
+ print("WARNING: container name already exists (ignoring --image)")
+
+args.full_name = args.name + args.suffix
+
+initing = False
+if len(containers(container_filter=args.name)) == 0:
+ volumes = []
+ if "volumes" in args.ini:
+ volumes = volumes + args.ini["volumes"].split(",")
+ volumes = [v.split(":") for v in volumes]
+ binds = {v[0].strip():{"bind":v[1].strip(),"mode":v[2].strip()} for v in volumes}
+ volumes = [v[1] for v in volumes]
+
+ host_config = cli.create_host_config(
+ binds=binds,
+ restart_policy={'Name' : 'unless-stopped'})
+
+ #cli.pull(args.image)
+ userpwd = getpwnam(user)
+ cli.create_container(args.image,
+ stdin_open=True,
+ tty=True,
+ name=args.full_name,
+ hostname=args.name,
+ labels={'group': prog, 'user': user},
+ volumes=volumes,
+ working_dir=args.home,
+ environment={
+ "HOST_USER_ID": userpwd.pw_uid,
+ "HOST_USER_GID": userpwd.pw_gid,
+ "HOST_USER_NAME": user
+ },
+ host_config=host_config
+ )
+ initing=True
+
+cli.start(args.full_name)
+if initing:
+ print("")
+ print("Initializing...")
+ #os.popen('docker exec '+args.full_name + ' /bin/bash -c "if [ -e /init-user ]; then /init-user; else echo \"No Initialization skript found for container\"; fi; echo Initialization finished."').read().split(":")[-1]
+ init_cmd = 'docker exec '+args.full_name + ' /bin/bash -c "if [ -e /init-user ]; then /init-user; else echo \\\"Script...\\\"; fi; echo Initialization finished."'
+ print(os.popen(init_cmd).read())
+ #print("Please login again.")
+ #sys.exit(0)
+if len(args.cmd) == 0:
+ try:
+ print(args.greeting.replace("```",""))
+ except UnicodeEncodeError:
+ print(hostname)
+user_bash = os.popen('docker exec -u root '+args.full_name + ' getent passwd '+user+'').read().split(":")[-1]
+if user_bash == "":
+ user_bash = "/bin/bash"
+cmd = args.cmd if args.cmd else user_bash
+#custom
+#user_bash = "/bin/sh"
+#cmd = user_bash
+cmd = "/bin/bash -c \"" + cmd + "\""
+
+#custom
+#os.system('docker exec -u '+user+' '+ args.full_name + ' ' + 'useradd -s /bin/bash user')
+
+# a tty needs -it, scp needs -i
+docker_arg = "-i" if not sys.stdout.isatty() or is_scp_cmd else "-it"
+os.system('docker exec -u '+user+" " + docker_arg +' '+ args.full_name + ' ' + cmd+"")
+
+if args.temp:
+ cli.remove_container(args.full_name, v=True, force=True)
+
+cli.close()
diff --git a/lcpubsh/image_template/Dockerfile b/lcpubsh/image_template/Dockerfile
new file mode 100644
index 0000000..85b1008
--- /dev/null
+++ b/lcpubsh/image_template/Dockerfile
@@ -0,0 +1,9 @@
+# Original by https://github.com/sleeepyjack/dockersh
+# Modified by georg@lysergic.dev
+# Note! This is a skeleton, it is being altered by the spawn process.
+FROM lc-archlinux-userbase-v2:sh0
+
+COPY user-mapping.sh /
+RUN chmod u+x /user-mapping.sh
+
+ENTRYPOINT ["/user-mapping.sh"]
diff --git a/lcpubsh/image_template/user-mapping.sh b/lcpubsh/image_template/user-mapping.sh
new file mode 100644
index 0000000..f2aa456
--- /dev/null
+++ b/lcpubsh/image_template/user-mapping.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+# Original by https://github.com/sleeepyjack/dockersh
+# Modified by georg@lysergic.dev
+if [ -z "${HOST_USER_NAME}" -o -z "${HOST_USER_ID}" -o -z "${HOST_USER_GID}" ]; then
+ echo "HOST_USER_NAME, HOST_USER_ID & HOST_USER_GID needs to be set!"; exit 100
+fi
+
+useradd \
+ --uid ${HOST_USER_ID} \
+ --gid ${HOST_USER_GID} \
+ --create-home \
+ --shell /bin/bash \
+ ${HOST_USER_NAME}
+groupadd --gid "${HOST_USER_GID}" "${HOST_USER_NAME}"
+usermod -aG sudo ${HOST_USER_NAME}
+sleep 5s
+
+echo ${HOST_USER_NAME}:${HOST_USER_NAME} | chpasswd
+
+exec su - "${HOST_USER_NAME}"
+