root 特権の必要な、グラフィカルな設定ツールを実行したいとしましょう。しかし、 X セッションは普通のアカウントで実行しています。始めは奇妙に思うかも しれませんが、X サーバはツールがディスプレイにアクセスすることを許しません。 root で普通に何かしたい時に、どうすれば可能ですか? そしてどうすればこの問題を回避できますか?
ユーザ ID clientuser
で X アプリケーションを起動したいが X セッションは
serveruser
で起動されているという、一般的な状況にしましょう。クッキーの
セクションを読んでいれば、なぜ clientuser
がディスプレイに
アクセスできないのか分かるはずです。
~clientuser/.Xauthority
はディスプレイにアクセスするための 正しいマジッククッキーを含んでいません。正しいクッキーは~serveruser/.Xauthority
にあります。
もちろん、リモート X で動作するものは、異なるユーザ ID の X でも同じように
動作します (端的には slogin localhost -l clientuser
)。
クライアントホストとサーバホストがたまたま同じだというだけです。しかし、
両方のホストが同じ時、マジッククッキーの転送には近道があります。
ユーザ ID の切り替えに su
を使うと仮定します。
基本的に、行わなければならないことは、su
を呼ぶスクリプトを書き、
そこで su
の行うコマンドを、リモート X に必要な処理を行う
適切なコードでラップすることです。
必要な処理とは
DISPLAY
変数の設定とマジッククッキーの転送です。
DISPLAY
の設定は比較的簡単です――su コマンドを実行する前に、
その引数として DISPLAY="$DISPLAY"
を定義するだけです。
以下のようにします。
su - clientuser -c "env DISPLAY=$DISPLAY clientprogram &"
これだけでは動作しません。さらにクッキーの転送を行う必要があります。
クッキーの取得は xauth list "$DISPLAY"
を使えば可能です。
このコマンドがクッキーのリストに用いる書式は、たまたま
xauth add
コマンドに与える際の書式に合致しています
――ちょうど必要としていたものです。
当然パイプでクッキーを渡したいところです。残念ながら、su
は
その標準入力からパスワードを読もうとするので、su
コマンドにパイプで渡す
ことは簡単ではありません。ここでも都合のいいことには、
シェルスクリプトの内部では
ファイル記述子をいじり回すことができますので、これが可能になります。
clientuser
と clientprogram
をパラメータ化し汎用化したスクリプトを
書きます。読みやすさは少し犠牲にして頑強になるように、スクリプトを改善
しましょう。以下のようになります。
#!/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>&-"
}
ほとんどの状況で、移植性と動作に十分だと考えます。
現在著者が考えうる欠点は、'$*'
を使っているため、
command
内部でシングルクォートを用いると
su
コマンドの引数 ('$*'
) が壊れてしまうことです。
もし他にもなにか深刻な間違いがあったら、著者に email を書き送って
ください。
スクリプトを /usr/local/bin/xsu
とすれば
xsu clientuser 'command &'
とできます。
パスワードを使う限り、これ以上そう簡単にはできません。
ええ、(sudo
) を使う方法もありますね。でもここでは扱いません。
当然、root ではないクライアントユーザが root で動作することも同様にできます。
しかし、root はすべての人の ~/.Xauthority
ファイルを読むことが
できるので、root の場合はより簡単です。クッキーを送る必要がありません。
DISPLAY
環境変数を設定し、XAUTHORITY
が
~serveruser/.Xauthority
を見るように設定するだけです。つまり:
su - -c "exec env DISPLAY='$DISPLAY' \
XAUTHORITY='${XAUTHORITY-$HOME/.Xauthority}' \
command"
これをスクリプト中に書くと以下のようになるでしょう。
#!/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 '$*'"
スクリプトを /usr/local/bin/xroot
とすれば
xroot 'control-panel &'
とできます。
でも、もし xsu
をすでに設定してあれば、
このようにしなければならない理由はありません。