Supposez que vous vouliez faire tourner un outil graphique de configuration qui nécessite d'avoir les privilèges du compte root alors que la session X actuelle se déroule sous votre compte. Cela peut sembler étrange au premier abord, mais le serveur X ne permettra pas à cet outil d'accéder à votre unité d'affichage. Comment cela est-il possible alors que root peut normalement tout faire ? Et comment contourner ce problème ?
Élargissons le propos au cas où l'on veut faire tourner une application X,
sous un identificateur d'utilisateur clientuser
, alors que la session
X a été lancée par serveruser
. Si vous avez lu le paragraphe sur les
cookies, il est évident que clientuser
ne peut pas accéder à
votre unité d'affichage :
~clientuser/.Xauthority
ne contient le cookie magique qui permet
d'accéder à l'unité d'affichage. Le cookie correct se trouve dans
~serveruser/.Xauthority
.
Naturellement, tout ce qui marche pour un X distant marchera aussi pour
un X à partir d'un identificateur d'utilisateur différent (particulièrement
slogin localhost -l clientuser
). Et ici l'hôte client et l'hôte
serveur sont précisément les mêmes. Cependant, quand les deux hôtes
sont les mêmes, il y a quelques raccourcis pour transférer le
cookie magique.
On supposera que l'on utilise su
pour passer d'un identificateur
utilisateur à l'autre. Essentiellement, il faut écrire un script qui
appelle su
, mais enveloppe la commande que su
exécute d'un
peu de code qui effectue les tâches nécessaires pour le X distant.
Ces tâches nécessaires sont l'initialisation de la variable DISPLAY
et le transfert du cookie magique.
L'initialisation de DISPLAY
est relativement facile ; il faut
simplement définir
DISPLAY="$DISPLAY"
avant d'exécuter l'argument de la commande su. Donc,
il faut simplement faire :
su - clientuser -c "env DISPLAY="$DISPLAY" clientprogram &"
Ce n'est pas tout, il faut encore transférer le cookie. On peut le retrouver
en utilisant xauth list "$DISPLAY"
. Cette commande renvoie le
cookie dans un format qui convient pour l'utiliser dans la commande
xauth add
; ce dont
nous avons justement besoin !
On pourrait imaginer le passer le cookie par l'intermédiaire d'un canal de
transmission.
Manque de chance, ce n'est pas si facile de passer quelque chose à la
commande su
par l'intermédiaire d'un canal de transmission car su
attends le mot de passe de l'entrée standard. Cependant, dans un script shell
on peut jongler avec quelques descripteurs de fichiers et arriver à le faire.
Donc, on écrit un script de ce style en le paramétrant avec clientuser
et
clientprogram
. Pendant que nous y sommes, améliorons un peu ce
script, ça va le rendre un peu moins compréhensible mais un
peu plus robuste. Le tout ressemble à cela :
#!/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>&-"
}
Je pense que c'est portable et que cela fonctionne suffisamment correctement
dans la plupart des circonstances. Le seul défaut auquel je pense en ce
moment est dû à l'utilisation de '$*'
, les guillemets simples dans
command
vont perturber les guillemets de l'argument('$*'
)
de la commande su
. Si cela entraîne quelque chose de vraiment gênant,
envoyez-moi un courrier électronique.
Nommez le script /usr/local/bin/xsu
, et vous pouvez faire :
xsu clientuser 'command &'
Cela ne peut pas être plus facile, à moins que vous ne vous débarrassiez du
mot de passe. Oui, il existe des moyens pour y arriver (sudo
), mais
ce n'est pas l'endroit pour en parler.
Évidemment, tout ce qui marche pour un client non root doit fonctionner
pour root. Cependant, avec root vous pouvez faire cela encore plus
facilement, car celui-ci peut lire le fichier ~/.Xauthority
de
tout le monde. Il n'y a pas besoin de transférer le cookie. Tout ce
qu'il y a à faire consiste à initialiser DISPLAY
, et à faire pointer
XAUTHORITY
sur ~serveruser/.Xauthority
. Donc, vous
pouvez écrire :
su - -c "exec env DISPLAY='$DISPLAY' \
XAUTHORITY='${XAUTHORITY-$HOME/.Xauthority}' \
command"
Et, en mettant cela dans un script, cela donne quelque chose comme
#!/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 '$*'"
Nommez le script /usr/local/bin/xroot
, et vous pouvez faire :
xroot 'control-panel &'
Cependant, si vous avez déjà initialisé xsu
, il n'y a pas de vrai
raison de faire cela.