commit fb0670d41fc9e72c119698a5fd5ae5d45f655e69
parent e9cac0551b174f25d4a2c9fb50d9ac4b142b7c67
Author: Jan Pobrislo <ccx@webprojekty.cz>
Date: Tue, 15 Dec 2020 04:47:32 +0100
Remove uid-changing code from su-term.py, rely on chained commands instead.
Diffstat:
3 files changed, 50 insertions(+), 48 deletions(-)
diff --git a/bin/zshaskpass_lock b/bin/zshaskpass_lock
@@ -120,14 +120,20 @@ cmd() {
logincap b;;
(root)
# logincap "terminal rxvt-unicode importas -i PTY_FD PTY_FD s6-envdir /run/user/ccx/X$[ ${TTY#/dev/tty} + 4 ]/env urxvt -pty-fd \$PTY_FD" ;;
- logincap "terminal $terminal_env $terminal_el" ;;
+ logincap "terminal $terminal_env $terminal_el"
+ logincap chvt X
+ ;;
(t *)
- logincap "terminal-${1#t } $terminal_env $terminal_el" ;;
+ logincap "terminal-${1#t } $terminal_env $terminal_el"
+ logincap chvt X
+ ;;
(lock)
- lock;;
+ lock
+ ;;
(exit)
true >/run/user/ccx/X$[ ${TTY#/dev/tty} + 4 ]/fifo
- keep_running=0;;
+ keep_running=0
+ ;;
(shell)
zsh -i; printf "shell exited with %d\n" $?;;
(*) printf '%s: unknown command\n' ${(qqq)REPLY};;
@@ -149,6 +155,7 @@ read-plumber-message() {
case $plumb_data in
(poweroff) logincap o;;
(reboot) logincap b;;
+ (terminal-*) logincap "${plumb_data%% *} $terminal_env $terminal_el";;
(lock)
logincap chvt tty
lock
diff --git a/sbin/logincaps b/sbin/logincaps
@@ -73,38 +73,44 @@ cap_cmd() {
}
typeset -f -t cap_cmd
+terminal_spawn_wrapper() {
+ local term_cmd term_env
+ term_cmd="${2#* }"
+ term_env=${term_cmd%% *}
+ if ! [[ $term_env =~ [-.0-9a-zA-Z]* ]]; then
+ printf 'ERR: invalid TERM'
+ return 1
+ fi
+ term_cmd="${term_cmd#* }"
+ cap_cmd execlineb -c "$1 -- ${(qqq)term_env} cd / s6-setuidgid ${(qqq)USER} $term_cmd"
+}
+
+terminal_spawn_password() {
+ terminal_spawn_wrapper /command/su-term.py "$@"
+}
+
+terminal_spawn() {
+ terminal_spawn_wrapper /command/spawn-pty.py "$@"
+}
+
main() {
local line term_cmd term_env REPLY
while read line; do
case $line in
- (o) printf >&2 "%s\n" "Would power-off."
+ (o)
cap_cmd s6-poweroff
;;
- (b) printf >&2 "%s\n" "Would reboot."
+ (b)
cap_cmd s6-reboot
;;
(terminal *)
- term_cmd=( "${(Q@)${(z)${line#terminal }}}" )
- printf >&2 "%s\n" "Would launch root terminal."
- pretendrun /command/su-term.py -d 1 -u $USER -g $USER -- "$term_cmd[@]" <&2
- #{ /command/su-term.py -d 1 -u $USER -- "$term_cmd[@]" <&2 &!
- #} | read
- printf 'OK\n'
+ terminal_spawn_password "$line"
;;
(terminal-wpa_cli *)
- 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 } cd / 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'
+ terminal_spawn "$line"
;;
(chvt tty)
diff --git a/sbin/su-term.py b/sbin/su-term.py
@@ -13,18 +13,25 @@ import getpass
import argparse
import re
-parser = argparse.ArgumentParser(description="Check root password and run terminal as given user with root shell")
-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 = argparse.ArgumentParser(description="Check root password and run terminal with root shell")
parser.add_argument('-d', '--notify-fd', type=int, help="Write newline to this filedescriptor after reading password")
parser.add_argument('term_env', help='The TERM variable used by the shell')
parser.add_argument('exe', nargs='+', help='Terminal application to execute')
-def exec_terminal(uid, gid, home, terminal, term_env, shell, shell_workdir):
- assert isinstance(uid, int)
- assert isinstance(gid, int)
- assert isinstance(home, str)
+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):
+ try:
+ os.execve(os.path.join(p, argv[0]), argv, env)
+ except OSError:
+ continue
+ raise SystemExit(1)
+
+
+def exec_terminal(terminal, term_env, shell, shell_workdir):
assert isinstance(terminal, (list, tuple))
assert all(isinstance(s, str) for s in terminal)
assert len(terminal)
@@ -35,17 +42,9 @@ def exec_terminal(uid, gid, home, terminal, term_env, shell, shell_workdir):
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('/bin/exec', ['exec'] + terminal, env)
+ execve(terminal, env)
else:
# child
os.close(master)
@@ -84,13 +83,6 @@ def constant_time_compare(val1, val2):
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)
root_hash = spwd.getspnam('root').sp_pwd
root_pwent = pwd.getpwnam('root')
p = getpass.getpass()
@@ -99,9 +91,6 @@ def main():
if args.notify_fd is not None:
os.write(args.notify_fd, '\n')
exec_terminal(
- uid=uid,
- gid=gid,
- home=pwent.pw_dir,
terminal=args.exe,
term_env=args.term_env,
shell=root_pwent.pw_shell,