170 lines
6.0 KiB
HTML
170 lines
6.0 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
|
<HTML>
|
|
<HEAD>
|
|
<META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
|
|
<TITLE>Remote X Apps mini-HOWTO: X Applications from Another User-id</TITLE>
|
|
<LINK HREF="Remote-X-Apps-8.html" REL=next>
|
|
<LINK HREF="Remote-X-Apps-6.html" REL=previous>
|
|
<LINK HREF="Remote-X-Apps.html#toc7" REL=contents>
|
|
</HEAD>
|
|
<BODY>
|
|
<A HREF="Remote-X-Apps-8.html">Next</A>
|
|
<A HREF="Remote-X-Apps-6.html">Previous</A>
|
|
<A HREF="Remote-X-Apps.html#toc7">Contents</A>
|
|
<HR>
|
|
<H2><A NAME="s7">7. X Applications from Another User-id</A></H2>
|
|
|
|
<P>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 <EM>not</EM>
|
|
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?
|
|
<P>
|
|
<P>Let's generalise to the situation where you want to an X appliation
|
|
under a user-id <CODE>clientuser</CODE>, but the X session was started
|
|
by <CODE>serveruser</CODE>. If you have read the section on cookies,
|
|
it is clear why <CODE>clientuser</CODE> cannot access your display:
|
|
<CODE>~clientuser/.Xauthority</CODE> does not contain the right magic
|
|
cookie for accessing the display. The right cookie is found in
|
|
<CODE>~serveruser/.Xauthority</CODE>.
|
|
<P>
|
|
<H2><A NAME="ss7.1">7.1 Different Users on the Same Host</A>
|
|
</H2>
|
|
|
|
<P>Of course, anything that works for remote X also works for X from
|
|
a different user-id as well (particularly <CODE>slogin localhost -l
|
|
clientuser</CODE>). 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.
|
|
<P>
|
|
<P>We'll assume that you use <CODE>su</CODE> to switch user-ids. Basically, what
|
|
you have to do is write a script that will call <CODE>su</CODE>, but wraps the
|
|
command that <CODE>su</CODE> executes with some code that does the necessary
|
|
things for remote X. These necessary things are setting the <CODE>DISPLAY</CODE>
|
|
variable and transferring the magic cookie.
|
|
<P>
|
|
<P>Setting <CODE>DISPLAY</CODE> is relatively easy; it just means defining
|
|
<CODE>DISPLAY="$DISPLAY"</CODE> before running the su command argument. So you
|
|
could just do:
|
|
<P>
|
|
<BLOCKQUOTE><CODE>
|
|
<PRE>
|
|
su - clientuser -c "env DISPLAY=$DISPLAY clientprogram &"
|
|
</PRE>
|
|
</CODE></BLOCKQUOTE>
|
|
<P>
|
|
<P>This doesn't work yet, because we still have to transfer the cookie.
|
|
We can retrieve the cookie using <CODE>xauth list "$DISPLAY"</CODE>. This command
|
|
happens to list the cookie in a format that's suitable for feeding back
|
|
to the <CODE>xauth add</CODE> command; just what we need!
|
|
<P>We shall want to pass the cookie through a pipe. Unfortunately, it
|
|
isn't easy to pass something through a pipe to the <CODE>su</CODE> command,
|
|
because <CODE>su</CODE> 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.
|
|
<P>So we write a script around this, parameterizing by <CODE>clientuser</CODE>
|
|
and <CODE>clientprogram</CODE>. Let's improve the script a little while we're
|
|
at it, making it less readable but more robust. It looks like this:
|
|
<P>
|
|
<BLOCKQUOTE><CODE>
|
|
<PRE>
|
|
#!/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>&-"
|
|
|
|
}
|
|
</PRE>
|
|
</CODE></BLOCKQUOTE>
|
|
<P>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
|
|
<CODE>'$*'</CODE>, single quotes in <CODE>command</CODE> will mess up quoting in the
|
|
<CODE>su</CODE> command argument (<CODE>'$*'</CODE>). If there's anything else seriously
|
|
wrong with it, please drop me an email.
|
|
<P>
|
|
<P>Call the script <CODE>/usr/local/bin/xsu</CODE>, and you can do:
|
|
<P>
|
|
<BLOCKQUOTE><CODE>
|
|
<PRE>
|
|
xsu clientuser 'command &'
|
|
</PRE>
|
|
</CODE></BLOCKQUOTE>
|
|
<P>
|
|
<P>Can't be much easier, unless you get rid of the password. Yes, there
|
|
are ways for that too (<CODE>sudo</CODE>), but this is not the place for that.
|
|
<P>
|
|
<P>The tiny <CODE>xsu</CODE> script just mentioned has served as the basis for a
|
|
more extended script called <CODE>sux</CODE> which apparently has found its way
|
|
as a package into the
|
|
<A HREF="http://www.debian.org/">Debian</A>
|
|
distribution.
|
|
<P>
|
|
<H2><A NAME="ss7.2">7.2 Client User Is Root</A>
|
|
</H2>
|
|
|
|
<P>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 <CODE>~/.Xauthority</CODE> file. There's no
|
|
need to transfer the cookie. All you have to do is set <CODE>DISPLAY</CODE>, and
|
|
point <CODE>XAUTHORITY</CODE> to <CODE>~serveruser/.Xauthority</CODE>. So you can do:
|
|
<P>
|
|
<BLOCKQUOTE><CODE>
|
|
<PRE>
|
|
su - -c "exec env DISPLAY='$DISPLAY' \
|
|
XAUTHORITY='${XAUTHORITY-$HOME/.Xauthority}' \
|
|
command"
|
|
</PRE>
|
|
</CODE></BLOCKQUOTE>
|
|
<P>
|
|
<P>Putting it into a script would give something like:
|
|
<P>
|
|
<BLOCKQUOTE><CODE>
|
|
<PRE>
|
|
#!/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 '$*'"
|
|
</PRE>
|
|
</CODE></BLOCKQUOTE>
|
|
<P>
|
|
<P>Call the script <CODE>/usr/local/bin/xroot</CODE>, and you can do:
|
|
<P>
|
|
<BLOCKQUOTE><CODE>
|
|
<PRE>
|
|
xroot 'control-panel &'
|
|
</PRE>
|
|
</CODE></BLOCKQUOTE>
|
|
<P>
|
|
<P>Although, if you've set up <CODE>xsu</CODE> already, there's no real reason to
|
|
do this.
|
|
<P>
|
|
<HR>
|
|
<A HREF="Remote-X-Apps-8.html">Next</A>
|
|
<A HREF="Remote-X-Apps-6.html">Previous</A>
|
|
<A HREF="Remote-X-Apps.html#toc7">Contents</A>
|
|
</BODY>
|
|
</HTML>
|