summaryrefslogtreecommitdiffstats
path: root/lcpubsh/bin
diff options
context:
space:
mode:
authorGeorg2021-08-14 10:02:44 +0200
committerGeorg2021-08-14 10:10:42 +0200
commitc27753da863b3c44ceb81b2fe6ac689550704f89 (patch)
tree40e31d653640e43188ce5b45e08136297210a63f /lcpubsh/bin
downloadpublic-shell-c27753da863b3c44ceb81b2fe6ac689550704f89.tar.gz
public-shell-c27753da863b3c44ceb81b2fe6ac689550704f89.tar.bz2
public-shell-c27753da863b3c44ceb81b2fe6ac689550704f89.zip
Init
Signed-off-by: Georg <georg@lysergic.dev>
Diffstat (limited to 'lcpubsh/bin')
-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
4 files changed, 338 insertions, 0 deletions
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()