mrrl-logincaps

MRRL version of logincaps
git clone https://ccx.te2000.cz/git/mrrl-logincaps
Log | Files | Refs

commit 407159e0afba5294cb855b6db771452e9e351a39
parent dbe0ab77f9cac03173d03ec8ab94a25e3935ab2f
Author: Jan Pobrislo <ccx@webprojekty.cz>
Date:   Tue, 15 Dec 2020 03:38:41 +0100

Replace user-terminal.py with more generic spawn-pty.py; use execlineb for interpreting terminal command.
Diffstat:
Abin/spawn-pty.py | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mbin/zshaskpass_lock | 2+-
Msbin/logincaps | 15++++++++++-----
Dsbin/user-term.py | 96-------------------------------------------------------------------------------
4 files changed, 101 insertions(+), 102 deletions(-)

diff --git a/bin/spawn-pty.py b/bin/spawn-pty.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python + +from __future__ import ( + generators, division, absolute_import, with_statement, print_function +) +import sys +import os +import os.path +import pwd +import argparse +import re + +parser = argparse.ArgumentParser(description="Runs one program inside pty and another with changed privileges with master pty as fd 0") +parser.add_argument('term_env', help='The TERM variable used by the slave') +parser.add_argument('exe', nargs='+', help='Execline block defining program ran on slave end, then terminal program') + + +def execve(argv, env): + if '/' in argv[0]: + os.execve(argv[0], argv, env) + else: + for p in os.environ['PATH'].split(os.path.pathsep): + os.execve(os.path.join(p, argv[0]), argv, env) + raise SystemExit(1) + + +def exec_terminal(uid, gid, home, terminal, term_env, slave_exe): + assert isinstance(uid, int) + assert isinstance(gid, int) + assert isinstance(home, str) + assert isinstance(terminal, (list, tuple)) + assert all(isinstance(s, str) for s in terminal) + assert len(terminal) + assert isinstance(slave_exe, list) + assert all(isinstance(s, str) for s in slave_exe) + master, slave = os.openpty() + if os.fork(): + # parent + os.close(slave) + os.dup2(master, 0) + os.close(master) + env = dict(os.environ) + env['PTY_FD'] = "0" + env['HOME'] = home + execve(terminal, env) + else: + # child + os.close(master) + os.dup2(slave, 0) + os.dup2(slave, 1) + os.dup2(slave, 2) + os.close(slave) + os.setsid() + env = dict(os.environ) + env['TERM'] = term_env + env.pop('LOGNAME', None) + execve(slave_exe, env) + + +def main(): + args = parser.parse_args() + + argv = list(args.exe) + slave_argv = [] + + while argv: + a = argv.pop(0) + if a == '': + break + elif a[0] == ' ': + slave_argv.append(a[1:]) + else: + sys.stderr.write("Improperly terminated block!\n") + return 1 + if not argv: + sys.stderr.write("Terminal executable not specified.\n") + return 1 + + exec_terminal( + uid=uid, + gid=gid, + home=pwent.pw_dir, + terminal=argv, + slave_exe=slave_argv, + term_env=args.term_env, + ) + + +if __name__ == '__main__': + main() diff --git a/bin/zshaskpass_lock b/bin/zshaskpass_lock @@ -46,7 +46,7 @@ if [[ -n $X ]]; then typeset -g plumber_fifo plumber_fifo=/run/containers/xsession.$X.ccx/run/plumber_fifo exec_socket=$HOME/chome/xsession.$[ ${TTY#/dev/tty} + 4 ]/exec/socket - terminal_args=( s6-sudo $exec_socket:A urxvt -pty-fd 0 ) + terminal_args=( s6-sudo $exec_socket:A background urxvt -pty-fd 0 ) terminal_env=rxvt-unicode # the TERM variable used else coproc_args+=( tail -F /run/user/ccx.logs/current ) diff --git a/sbin/logincaps b/sbin/logincaps @@ -73,7 +73,7 @@ cap_cmd() { } main() { - local line term_cmd REPLY + local line term_cmd term_env REPLY while read line; do case $line in (o) printf >&2 "%s\n" "Would power-off." @@ -94,10 +94,15 @@ main() { ;; (terminal-wpa_cli *) - term_cmd=( "${(Q@)${(z)${line#* }}}" ) - printf >&2 "%s\n" "Would launch terminal with wpa_cli." - pretendrun /command/user-term.py -u $USER -g $USER -- "$term_cmd[1]" ' wpa_cli' '' "${(@)term_cmd[2,-1]}" - /command/user-term.py -u $USER -g $USER -- "$term_cmd[1]" ' wpa_cli' '' "${(@)term_cmd[2,-1]}" </dev/null >&2 &! + term_cmd="${line#* }" + term_env=${term_cmd$$ *} + if ! [[ $term_env =~ [-.0-9a-zA-Z]* ]]; then + printf 'ERR: invalid TERM' + continue + fi + term_cmd="${term_cmd#* }" + cap_cmd execlineb -c "/command/spawn-pty.py -- ${(qqq)term_env} { wpa_cli } s6-setuidgid ${(qqq)USER} $term_cmd" + #/command/user-term.py -u $USER -g $USER -- "$term_cmd[1]" ' wpa_cli' '' "${(@)term_cmd[2,-1]}" </dev/null >&2 &! printf 'OK\n' ;; diff --git a/sbin/user-term.py b/sbin/user-term.py @@ -1,96 +0,0 @@ -#!/usr/bin/env python - -from __future__ import ( - generators, division, absolute_import, with_statement, print_function -) -import sys -import os -import os.path -import pwd -import argparse -import re - -parser = argparse.ArgumentParser(description="Runs one program as current user in pty and another with changed privileges with master pty fd") -parser.add_argument('-u', '--user', required=True, help="User name or ID to run terminal as") -parser.add_argument('-g', '--group', type=int, help="Group ID to run terminal as") -parser.add_argument('term_env', help='The TERM variable used by the slave') -parser.add_argument('exe', nargs='+', help='Execline block defining program ran on slave end, then terminal program') - - -def exec_terminal(uid, gid, home, terminal, term_env, slave_exe): - assert isinstance(uid, int) - assert isinstance(gid, int) - assert isinstance(home, str) - assert isinstance(terminal, (list, tuple)) - assert all(isinstance(s, str) for s in terminal) - assert len(terminal) - assert isinstance(slave_exe, list) - assert all(isinstance(s, str) for s in slave_exe) - master, slave = os.openpty() - if os.fork(): - # parent - os.close(slave) - os.dup2(master, 0) - os.close(master) - os.setgid(gid) - os.setuid(uid) - os.chdir(home) - env = dict(os.environ) - env['PTY_FD'] = "0" - env['HOME'] = home - if '/' in terminal[0]: - os.execve(terminal[0], terminal, env) - else: - # TODO: proper search path - os.execve('/command/exec', ['exec'] + terminal, env) - else: - # child - os.close(master) - os.dup2(slave, 0) - os.dup2(slave, 1) - os.dup2(slave, 2) - os.close(slave) - os.setsid() - env = dict(os.environ) - env['TERM'] = term_env - env.pop('LOGNAME', None) - os.execve('/command/exec', ['exec'] + slave_exe, env) - - -def main(): - args = parser.parse_args() - if re.match('[0-9]+', args.user): - uid = int(args.user) - pwent = pwd.getpwuid(uid) - else: - pwent = pwd.getpwnam(args.user) - uid = pwent.pw_uid - gid = pwent.pw_gid if args.group is None else int(args.group) - - argv = list(args.exe) - slave_argv = [] - while argv: - a = argv.pop(0) - if a == '': - break - elif a[0] == ' ': - slave_argv.append(a[1:]) - else: - sys.stderr.write("Improperly terminated block!\n") - return 1 - if not argv: - sys.stderr.write("Terminal executable not specified.\n") - return 1 - - exec_terminal( - uid=uid, - gid=gid, - home=pwent.pw_dir, - terminal=argv, - slave_exe=slave_argv, - term_env=args.term_env, - ) - - -if __name__ == '__main__': - main()