Created
January 26, 2022 12:31
systemd-sudo.sh: a non-setuid sudo-alike using systemd-run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
set -euo pipefail | |
MYNAME=$(basename "${0}") | |
opts=$(getopt --name "$MYNAME" --options 'hVsEnu:g:D:' \ | |
--longoptions 'help,version,shell,preserve-env,non-interactive,user:,group:,chdir:' -- "${@}") | |
eval set -- "${opts}" | |
U=0 | |
G=0 | |
SHELLARGS=() | |
NOINTERACTIVEARGS=() | |
ENVARGS=() | |
WDIR="$PWD" | |
while true; do | |
case "$1" in | |
-h|--help) | |
echo "$MYNAME - execute a command as another user through systemd-run (no SUID binary involved except /usr/lib/polkit-1/polkit-agent-helper-1), recognizes set PATH in contrast to sudo" | |
echo "usage: $MYNAME -h" | |
echo "usage: $MYNAME [-En] [-D directory] [-g group] [-u user] [-s] [<command>]" | |
echo | |
echo "Options:" | |
echo "-D, --chdir=directory change the working directory before running command" | |
echo "-E, --preserve-env preserve user environment when running command (includes PATH in constrast to sudo)" | |
echo "-g, --group=group run command as the specified group name or ID" | |
echo "-h, --help display help message and exit" | |
echo "-n, --non-interactive non-interactive mode, no prompts are used" | |
echo "-s, --shell run shell as the target user; a command may also be specified" | |
echo "-u, --user=user run command (or edit file) as specified user name or ID" | |
echo "-V, --version display version information and exit" | |
echo "-- stop processing command line arguments" | |
echo "The following sudo options will not be supported: -A -B -C -e -h -i -K -k -l -p -r -S -t -U -v" | |
echo "TODO: implement setting env vars by specifying VAR=VALUE" | |
echo "TODO: implement --preserve-env=list" | |
echo "TODO: implement -P -S -b -H -R -T" | |
exit 1 | |
;; | |
-V|--version) | |
echo "systemd-sudo version 0.1" | |
exit 0 | |
;; | |
-s|--shell) | |
# runs "$SHELL" | |
SHELLARGS=("-S" "--pty") | |
;; | |
-E|--preserve-env) | |
ENVARGS=() | |
# Extra "sh -c" is needed to only export the exported variables | |
for VARNAME in $(sh -c 'compgen -v'); do | |
set +u | |
VAL="${!VARNAME}" | |
set -u | |
ENVARGS+=("--setenv" "${VARNAME}=${VAL}") | |
done | |
;; | |
-n|--non-interactive) | |
NOINTERACTIVEARGS=("--no-ask-password") | |
;; | |
-D|--chdir) | |
WDIR="$1" | |
shift | |
;; | |
-u|--user) | |
UNAME="$1" | |
shift | |
U=$(id -u "$UNAME") | |
;; | |
-g|--group) | |
GNAME="$1" | |
G=$(id -g "$GNAME") | |
shift | |
;; | |
--) | |
shift | |
break;; | |
esac | |
shift | |
done | |
exec systemd-run --system --quiet --wait --collect --pipe --working-directory "$WDIR" --uid "$U" --gid "$G" "${SHELLARGS[@]}" "${NOINTERACTIVEARGS[@]}" "${ENVARGS[@]}" -- "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Known issue: Ctrl-C doesn't stop the process with --pipe, one could use --pty (but it leads to processes expecting stdin when there is none) or better let the wrapper script handle the INT trap and stop the service (or add a watchdog to the service that checks if the wrapper script process is still alive and stops the service if not).