Re: X authentication and su (Re: changing framebuffer device owner during login)
Here's another improved version of sux.
I believe that all the previous issues have been solved. Most notably
the cookies should not appear on any command line anywhere at
anytime, anymore.
So I believe that this version should be really secure now. Or does
someone see a way for a third party to snarf the cookies while sux is
running?
Features:
* 'sux user' and 'sux - user' behave just like su but transfer
$DISPLAY and the X cookies.
* You can specify a command on the command line, even if it contains
spaces. This is likely to be buggy (double-quotes...) but should be
enough to let you type: sux - xterm -title "Root's XTerm"
* you can generate untrusted / temporary cookies for that user using
'--untrusted' and/or '--timeout xxx' (see xauth generate)
* if you symlink suxterm to sux, then 'suxterm - foo' will create a
new xterm for user foo. This makes '--timeout' more usable: the
cookie will remain valid as long as this xterm is open. So you could
type 'suxterm --timeout 20 - foo' and the cookie will expire 20
seconds after the xterm has been closed. (It also means you have 20
seconds to type your password. Also it's equivalent to 'sux --timeout
20 - foo xterm', but the script could be modified to have a timeout
by default... (Inspired by Daniel Martin)
* 'sux -' will use the standard XAUTHORITY trick. It's the simplest
way to do it for root, hence the better way. Of course the
exception is if you use '--untrusted' or '--timeout', then sux will
do it as usual.
* You can use the su '--preserve-environment' option. In that case sux
will override XAUTHORITY to the so that xauth does not try to use the
original user's .Xauthority file (which it obviously could not
do anyway due to access rights).
* sux should work even for those using csh. But I'm not using it myself
so I could not check. Let me know if there's a problem.
--- cut here ---
#!/bin/sh
usage()
{
echo "usage: `basename $0` [-m] [-p] [--preserve-environment]" >&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
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
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" = "--untrusted" ]
then
sux_untrusted="untrusted"
shift
elif [ "$1" = "--timeout" ]
then
if [ $# -lt 2 ]
then
# Complain and exit
usage
fi
sux_timeout="timeout $2"
shift 2
elif [ "$1" = "-?" ]
then
# Complain and exit
usage
else
# First non-option is the username
sux_username="$1"
sux_su_opts="$sux_su_opts $1"
shift
break
fi
done
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
fi
exec su $sux_su_opts "$@"
fi
##
# Create new cookies / retrieve the existing ones if necessary
if [ -n "$sux_untrusted" -o -n "$sux_timeout" ]
then
# 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 list $DISPLAY`
rm -f $sux_tmpfile
fi
##
# Build the command to restore the cookies in the su
if [ -n "$sux_xauth_data" -o \( -n "$sux_username" -a "$sux_username" != "root" \) ]
then
# 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 list $DISPLAY`
if [ -n "$sux_unix_display" ]
then
sux_xauth_data="$sux_xauth_data `xauth -q list $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.
# Now, as long as 'echo' is a shell builtin, these cookies will never
# appear as command line arguments.
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 add $sux_str"
else
TERM="$TERM $sux_str"
fi
sux_i=`expr $sux_i + 1`
if [ $sux_i -eq 3 ]
then
TERM="$TERM | xauth source - ;"
sux_i=0
fi
done
sux_xauth_cmd="eval \$TERM;"
sux_xauthority=""
else
# 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
fi
##
# And execute the specified command. We marshall the parameters a little
# bit in an effort to support spaces in parameters. 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
##
# Adapt the environment for the new user
if [ -n "$sux_preserve" -a -n "sux_xauth_cmd" ]
then
XAUTHORITY=`egrep "^$sux_username:" /etc/passwd | cut -d: -f6`
if [ -z "$XAUTHORITY" ]
then
echo "WARNING: --preserve-environment has been set, but no good value was found for XAUTHORITY, expect trouble" >&2
unset XAUTHORITY
else
export XAUTHORITY="$XAUTHORITY/.Xauthority"
fi
fi
##
# Execute su
exec su $sux_su_opts -c "$sux_xauth_cmd \
exec env $sux_xauthority $sux_term DISPLAY='$DISPLAY' $sux_cmd;"
--- cut here ---
--
Francois Gouget fgouget@free.fr http://fgouget.free.fr/
La terre est une bêta...
Reply to: