summaryrefslogtreecommitdiff
path: root/sux
diff options
context:
space:
mode:
Diffstat (limited to 'sux')
-rwxr-xr-xsux312
1 files changed, 312 insertions, 0 deletions
diff --git a/sux b/sux
new file mode 100755
index 0000000..75c7449
--- /dev/null
+++ b/sux
@@ -0,0 +1,312 @@
+#!/bin/sh
+
+# Written by Francois Gouget, fgouget@free.fr
+# With many thanks to Daniel Martin and Falk Hueffner for their help
+
+# How to transfer cookies for root. See the sux_cookie_transfer variable
+# for options. Note that use-xauthority may not work if home directories
+# are on NFS. In such a case, change the default to copy-cookies.
+sux_root_cookie_transfer="c"
+
+
+usage()
+{
+ echo "usage: `basename $0` [-m|-p|--preserve-environment]" >&2
+ echo " [--display display]" >&2
+ echo " [--no-cookies|--copy-cookies|--use-xauthority]" >&2
+ echo " [--untrusted] [--timeout x]" >&2
+ echo " [-] [username [command]]" >&2
+ exit 2
+}
+
+
+##
+# Process the sux options
+sux_su_opts=""
+sux_preserve=""
+sux_got_minus=0
+# "" -> default, n -> no-cookies, c -> copy-cookies, x -> use-xauthority
+sux_cookie_transfer=""
+sux_username=""
+sux_untrusted=""
+sux_timeout=""
+while [ $# -gt 0 ]
+do
+ if [ "$sux_got_minus" = "1" ]
+ then
+ # Username follows "-"
+ sux_username="$1"
+ sux_su_opts="$sux_su_opts $1"
+ shift
+ # The remainder is the command to be executed
+ break
+ elif [ "$1" = "-" ]
+ then
+ # Last option before the username
+ sux_su_opts="$sux_su_opts $1"
+ sux_got_minus=1
+ shift
+ elif [ "$1" = "-m" -o "$1" = "-p" -o "$1" = "--preserve-environment" ]
+ then
+ sux_preserve="1"
+ sux_su_opts="$sux_su_opts $1"
+ shift
+ elif [ "$1" = "--display" ]
+ then
+ if [ $# -lt 2 ]
+ then
+ echo "--display takes a display name as an argument" >&2
+ usage # exits
+ fi
+ export DISPLAY="$2"
+ shift 2
+ elif [ "$1" = "--no-cookies" ]
+ then
+ if [ -n "$sux_cookie_transfer" -a "$sux_cookie_transfer" != "n" ]
+ then
+ echo "--no-cookies is incompatible with --copy-cookies and --use-xauthority" >&2
+ usage # exits
+ fi
+ sux_cookie_transfer="n"
+ shift
+ elif [ "$1" = "--copy-cookies" ]
+ then
+ if [ -n "$sux_cookie_transfer" -a "$sux_cookie_transfer" != "c" ]
+ then
+ echo "--copy-cookies is incompatible with --no-cookies and --use-xauthority" >&2
+ usage # exits
+ fi
+ sux_cookie_transfer="c"
+ shift
+ elif [ "$1" = "--use-xauthority" ]
+ then
+ if [ -n "$sux_cookie_transfer" -a "$sux_cookie_transfer" != "x" ]
+ then
+ echo "--use-xauthority is incompatible with --no-cookies and --copy-cookies" >&2
+ usage # exits
+ fi
+ sux_cookie_transfer="x"
+ shift
+ elif [ "$1" = "--untrusted" ]
+ then
+ sux_untrusted="untrusted"
+ shift
+ elif [ "$1" = "--timeout" ]
+ then
+ if [ $# -lt 2 ]
+ then
+ echo "--timeout takes a timeout in seconds" >&2
+ usage # exits
+ fi
+ sux_timeout="timeout $2"
+ shift 2
+ elif [ "$1" = "-?" ]
+ then
+ usage # exits
+ else
+ # First non-option is the username
+ sux_username="$1"
+ sux_su_opts="$sux_su_opts $1"
+ shift
+ # The remainder is the command to be executed
+ break
+ fi
+done
+
+
+##
+# Get rid of the simple case
+if [ -z "$DISPLAY" ]
+then
+ # If DISPLAY is not set we can take a shortcut...
+ if [ -n "$sux_untrusted" -o -n "$sux_timeout" ]
+ then
+ echo "--untrusted and --timeout are only supported if DISPLAY is set" >&2
+ usage #exits
+ fi
+ exec su $sux_su_opts "$@"
+fi
+
+
+##
+# Do some option checking
+if [ -z "$sux_username" ]
+then
+ sux_username="root"
+fi
+if [ -z "$sux_cookie_transfer" ]
+then
+ if [ "$sux_username" = "root" ]
+ then
+ sux_cookie_transfer="$sux_root_cookie_transfer"
+ else
+ sux_cookie_transfer="c"
+ fi
+fi
+if [ "$sux_cookie_transfer" = "x" -a "$sux_username" != "root" ]
+then
+ echo "Only root can use --use-xauthority" >&2
+ usage # exits
+fi
+
+
+##
+# Create new cookies / retrieve the existing ones if necessary
+if [ -n "$sux_untrusted" -o -n "$sux_timeout" ]
+then
+ if [ "$sux_cookie_transfer" != "c" ]
+ then
+ echo "--no-cookies/--use-xauthority are incompatible with --untrusted/--timeout" >&2
+ usage #exits
+ fi
+
+ # Yeah, tempfile is a debian-specific command. Workarounds exist for
+ # other machines. If you do use a workaround, be certain that said
+ # workaround actually creates the new file, (via touch or similar) or
+ # xauth (below) will produce a pointless warning message.
+ sux_tmpfile=`tempfile -p sux`
+ xauth -q -f $sux_tmpfile generate $DISPLAY . $sux_untrusted $sux_timeout
+ sux_xauth_data=`xauth -f $sux_tmpfile nlist $DISPLAY`
+ rm -f $sux_tmpfile
+fi
+
+
+##
+# Build the command to restore the cookies in the su
+if [ "$sux_cookie_transfer" = "c" ]
+then
+ # --copy-cookies case. We copy the cookie(s) using the xauth command.
+
+ # If display is of the form "host:x.y" we may also need to get the
+ # cookies for "host/unix:x.y".
+ sux_unix_display=`echo $DISPLAY | sed -e 's#^\([a-zA-Z_.][a-zA-Z_.]*\):#\1/unix:#'`
+ if [ "$DISPLAY" = "$sux_unix_display" ]
+ then
+ sux_unix_display=""
+ fi
+
+ # Get the cookies if we don't have them already
+ if [ -z "$sux_xauth_data" ]
+ then
+ # Get the cookies. Note that we may need to
+ sux_xauth_data=`xauth -q nlist $DISPLAY`
+ if [ -n "$sux_unix_display" ]
+ then
+ sux_xauth_data="$sux_xauth_data `xauth -q nlist $sux_unix_display`"
+ fi
+ fi
+
+ # We highjack the TERM environment variable to transfer the cookies to the
+ # other user. We do this so that they never appear on any command line, and
+ # because TERM appears to be the only environment variable that is not
+ # reset by su. Then, as long as 'echo' is a shell builtin, these cookies
+ # will never appear as command line arguments which means noone will be
+ # able to intercept them (assuming they were safe in the first place).
+ sux_term="TERM='$TERM'"
+ # now we can store the script that will restore the cookies on the other
+ # side of the su, in TERM!
+
+ # Remove the old cookies. They may cause trouble if we transfer only one
+ # cookie, e.g. an MIT cookie, and there's still a stale XDM cookie hanging
+ # around.
+ export TERM="xauth -q remove $DISPLAY 2>/dev/null;"
+ if [ -n "$sux_unix_display" ]
+ then
+ TERM="$TERM xauth -q remove $sux_unix_display;"
+ fi
+
+ # Note that there may be more than one cookie to transfer, hence
+ # this loop
+ sux_i=0
+ for sux_str in $sux_xauth_data
+ do
+ if [ $sux_i -eq 0 ]
+ then
+ TERM="$TERM echo $sux_str"
+ else
+ TERM="$TERM $sux_str"
+ fi
+ sux_i=`expr $sux_i + 1`
+ if [ $sux_i -eq 9 ]
+ then
+ TERM="$TERM | xauth nmerge - ;"
+ sux_i=0
+ fi
+ done
+ sux_xauth_cmd="eval \$TERM;"
+ sux_xauthority=""
+elif [ "$sux_cookie_transfer" = "x" ]
+then
+ # --use-xauthority case. For root we can simplify things and simply
+ # access the original user's .Xauthority file.
+ sux_term=""
+ sux_xauth_cmd=""
+ if [ -n "$XAUTHORITY" ]
+ then
+ sux_xauthority="XAUTHORITY='$XAUTHORITY'"
+ else
+ sux_xauthority="XAUTHORITY='$HOME/.Xauthority'"
+ fi
+else
+ # --no-cookies case. We just transfer $DISPLAY and assume the
+ # target user already has the necessary cookies
+ sux_term=""
+ sux_xauth_cmd=""
+ sux_xauthority=""
+fi
+
+
+##
+# Marshall the specified command in an effort to support parameters that
+# contain spaces. This should be enough to get commands like
+# 'xterm -title "My XTerm"' to work.
+sux_cmd=""
+if [ $# -gt 0 ]
+then
+ while [ $# -gt 0 ]
+ do
+ sux_cmd="$sux_cmd \"$1\""
+ shift
+ done
+elif [ "`basename $0`" = "suxterm" ]
+then
+ # Start an xterm, useful for temporary cookies
+ sux_cmd="xterm"
+else
+ # If no command is specified, start a shell
+ if [ $# -eq 0 ]
+ then
+ if [ "$sux_got_minus" = "1" ]
+ then
+ sux_cmd="sh -c \"exec -l \$SHELL\""
+ else
+ sux_cmd="\$SHELL"
+ fi
+ fi
+fi
+
+
+##
+# We would not want the other user to try and use our XAUTHORITY file. He
+# wouldn't have the proper access rights anyway...
+unset XAUTHORITY
+
+
+##
+# --preserve-environment special case
+if [ -n "$sux_preserve" -a -n "$sux_xauth_cmd" ]
+then
+ sux_home=`egrep "^$sux_username:" /etc/passwd | cut -d: -f6`
+ if [ -z "$sux_home" ]
+ then
+ echo "WARNING: --preserve-environment has been set, but no good value was found for XAUTHORITY, expect trouble" >&2
+ else
+ export XAUTHORITY="$sux_home/.Xauthority"
+ fi
+fi
+
+
+##
+# Execute su
+exec su $sux_su_opts -c "$sux_xauth_cmd \
+ exec env $sux_xauthority $sux_term DISPLAY='$DISPLAY' $sux_cmd;"