Suppose you want to run a graphical configuration tool that requires root privileges. However, your X session is running under your usual account. It may seem strange at first, but the X server will not allow the tool to access your display. How is this possible when root can normally do anything? And how do you work around this problem?
Let's generalise to the situation where you want to an X
appliation under a user-id clientuser, but the X
session was started by serveruser. If you have read
the section on cookies, it is clear why clientuser
cannot access your display: ~clientuser/.Xauthority
does not contain the right magic cookie for accessing the
display. The right cookie is found in
~serveruser/.Xauthority.
Of course, anything that works for remote X also works for X from
a different user-id as well (particularly slogin localhost
-l clientuser). It's just that the client host and the
server host happen to be the same. However, when both hosts are
the same, there are some shortcuts for transferring the magic
cookie.
We'll assume that you use su to switch user-ids.
Basically, what you have to do is write a script that will call
su, but wraps the command that su
executes with some code that does the necessary things for remote
X. These necessary things are setting the DISPLAY
variable and transferring the magic cookie.
Setting DISPLAY is relatively easy; it just means
defining DISPLAY="$DISPLAY" before running the su
command argument. So you could just do:
su - clientuser -c "env DISPLAY=$DISPLAY clientprogram &"
This doesn't work yet, because we still have to transfer the
cookie. We can retrieve the cookie using xauth list
"$DISPLAY". This command happens to list the cookie in a
format that's suitable for feeding back to the xauth
add command; just what we need!
We shall want to pass the cookie through a pipe. Unfortunately,
it isn't easy to pass something through a pipe to the
su command, because su wants to read
the password from its standard input. Fortunately again, in a
shell script we can joggle some file descriptors around, and get
it done.
So we write a script around this, parameterizing by
clientuser and clientprogram. Let's
improve the script a little while we're at it, making it less
readable but more robust. It looks like this:
#!/bin/sh if [ $# -lt 2 ] then echo "usage: `basename $0` clientuser command" >&2 exit 2 fi CLIENTUSER="$1" shift # FD 4 becomes stdin too exec 4>&0 xauth list "$DISPLAY" | sed -e 's/^/add /' | { # FD 3 becomes xauth output # FD 0 becomes stdin again # FD 4 is closed exec 3>&0 0>&4 4>&- exec su - "$CLIENTUSER" -c \ "xauth -q <&3 exec env DISPLAY='$DISPLAY' "'"$SHELL"'" -c '$*' 3>&-" }
I think this is portable and works well enough in most
circumstances. The only shortcoming I can think of right now is
that, due to using '$*', single quotes in
command will mess up quoting in the su
command argument ('$*'). If there's anything else
seriously wrong with it, please drop me an email.
Call the script /usr/local/bin/xsu, and you can do:
xsu clientuser 'command &'
Can't be much easier, unless you get rid of the password. Yes,
there are ways for that too (sudo), but this is not
the place for that.
The tiny xsu script just mentioned has served as the
basis for a more extended script called sux which
apparently has found its way as a package into the Debian distribution.
Obviously, anything that works for non-root client users is going
to work for root as well. However, with root you can make it even
easier, because root can read anyone's ~/.Xauthority
file. There's no need to transfer the cookie. All you have to do
is set DISPLAY, and point XAUTHORITY to
~serveruser/.Xauthority. So you can do:
su - -c "exec env DISPLAY='$DISPLAY' \ XAUTHORITY='${XAUTHORITY-$HOME/.Xauthority}' \ command"
Putting it into a script would give something like:
#!/bin/sh if [ $# -lt 1 ] then echo "usage: `basename $0` command" >&2 exit 2 fi su - -c "exec env DISPLAY='$DISPLAY' \ XAUTHORITY='${XAUTHORITY-$HOME/.Xauthority}' \ "'"$SHELL"'" -c '$*'"
Call the script /usr/local/bin/xroot, and you can
do:
xroot 'control-panel &'
Although, if you've set up xsu already, there's no
real reason to do this.