Re: X authentication and su (Re: changing framebuffer device owner during login)
Here's a much improved version of sux. The code should be relatively
self-explanatory but don't be afraid to ask if something looks strange.
The only big issue that remains, is that the cookies will sit on the su
command line while you type your password. That's bad. The only solution
I see, is to transfer them via an environment variable. The only one
that I know of which is not reset by su is TERM.
With many thanks to Daniel Martin for his tip on how to use xauth
generate.
--- cut here ---
#!/bin/sh
# TODO:
# - behave just like su if DISPLAY is not set... as long as no special
# option is used
# - don't pass the cookies on su's command line, highjack TERM?
# - clean up environment variables as much as possible, in case '-' is not
# used
# - modify environment variable names to minimize the chances of conflict
# with existing environment variables...
# - Is it really needed to transfer the TCP/IP cookie or just the unix one?
usage()
{
echo "usage: `basename $0` [-m] [-p] [--preserve-environment]" >&2
echo " [--untrusted] [--timeout x]" >&2
echo " [-] [username [command]]" >&2
exit 2
}
if [ -z "$DISPLAY" ]
then
echo "DISPLAY is not set, just use su" >&2
usage
fi
##
# Process the sux options
su_opts=""
got_minus=0
username=""
untrusted=""
timeout=""
while [ $# -gt 0 ]
do
if [ "$got_minus" = "1" ]
then
# Username follows "-"
username="$1"
su_opts="$su_opts $1"
shift
break
elif [ "$1" = "-" ]
then
# Last option before the username
su_opts="$su_opts $1"
got_minus=1
shift
elif [ "$1" = "-m" -o "$1" = "-p" -o "$1" = "--preserve-environment" ]
then
su_opts="$su_opts $1"
shift
elif [ "$1" = "--untrusted" ]
then
untrusted="untrusted"
shift
elif [ "$1" = "--timeout" ]
then
if [ $# -lt 2 ]
then
# Complain and exit
usage
fi
timeout="timeout $2"
shift 2
elif [ "$1" = "-?" ]
then
# Complain and exit
usage
else
# First non-option is the username
username="$1"
su_opts="$su_opts $1"
shift
break
fi
done
##
# Create new cookies / retrieve the existing ones if necessary
if [ -n "$untrusted" -o -n "$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.
tmpfile=`tempfile -p sux`
xauth -q -f $tmpfile generate $DISPLAY . $untrusted $timeout
xauth_data=`xauth -f $tmpfile list $DISPLAY`
rm -f $tmpfile
fi
##
# Build the command to restore the cookies in the su
if [ -n "$xauth_data" -o \( -n "$username" -a "$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".
unix_display=`echo $DISPLAY | sed -e 's#^\([a-zA-Z_.][a-zA-Z_.]*\):#\1/unix:#'`
if [ "$DISPLAY" = "$unix_display" ]
then
unix_display=""
fi
# Get the cookies if we don't have them already
if [ -z "$xauth_data" ]
then
# Get the cookies. Note that we may need to
xauth_data=`xauth -q list $DISPLAY`
if [ -n "$unix_display" ]
then
xauth_data="$xauth_data `xauth -q list $unix_display`"
fi
fi
# 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.
xauth_cmd="xauth -q remove $DISPLAY;"
if [ -n "$unix_display" ]
then
xauth_cmd="$xauth_cmd xauth -q remove $unix_display;"
fi
# Note that there may be more than one cookie to transfer, hence
# this loop
i=0
for str in $xauth_data
do
if [ $i -eq 0 ]
then
xauth_cmd="$xauth_cmd echo add $str"
else
xauth_cmd="$xauth_cmd $str"
fi
i=`expr $i + 1`
if [ $i -eq 3 ]
then
xauth_cmd="$xauth_cmd | xauth source - 2>/dev/null;"
i=0
fi
done
xauthority=""
else
# For root we can simplify things and simply access the original user's
# .Xauthority file. Also this way the cookies won't end up on su's
# command line
xauth_cmd=""
if [ -n "$XAUTHORITY" ]
then
xauthority="XAUTHORITY='$XAUTHORITY'"
else
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.
cmd=""
if [ $# -gt 0 ]
then
while [ $# -gt 0 ]
do
cmd="$cmd \"$1\""
shift
done
elif [ "`basename $0`" = "suxterm" ]
then
# Start an xterm, useful for temporary cookies
cmd="xterm"
else
# If no command is specified, start a shell
if [ $# -eq 0 ]
then
if [ "$got_minus" = "1" ]
then
cmd="sh -c \"exec -l \$SHELL\""
else
cmd="\$SHELL"
fi
fi
fi
##
# We would not want the other user to try and use our XAUTHORITY file
unset XAUTHORITY
##
# Execute su
exec su $su_opts -c "eval \"$xauth_cmd\"; \
exec env $xauthority DISPLAY='$DISPLAY' $cmd;"
--- cut here ---
--
Francois Gouget fgouget@free.fr http://fgouget.free.fr/
"Lotto: A tax on people who are bad at math." -- unknown
"Windows: Microsoft's tax on computer illiterates." -- WE7U
Reply to: