[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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: