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 le mettre dans xauth
; ce dont
nous avons justement besoin ! Donc, on met le cookie obtenu dans
xauth
dans le commande su
, on initialise DISPLAY ici
, et on
lance la commande désirée
su - clientuser -c "xauth add `xauth list $DISPLAY`; \
exec env DISPLAY=$DISPLAY clientprogram"
On peut écrire un script pour réaliser tout cela, en le paramètrant avec
clientuser
et clientprogram
. Améliorons un peu le script pendant
que nous y sommes, ç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
exec su - "$CLIENTUSER" -c "xauth add `xauth list \"$DISPLAY\"`; \
exec env DISPLAY='$DISPLAY' "'"$SHELL"'" -c '$*'"
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 &'
Facile, non ?
É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 &'
Encore plus facile, non ??