Запуск приложения от другого пользователя

Предположим, что вам нужно запустить графическую утилиту конфигурации, которая требует привилегий root. Тем не менее, ваш сеанс под X запущен от обычного пользователя. Это может показаться странным, но X-сервер не даст утилите доступа к вашему экрану. Как это может быть возможным, если обычно root может делать все что угодно? И как мне решить эту проблему?

Давайте обобщим ситуацию. Итак, вы хотите запустить X-клиент от другого пользователя clientuser, а X-сервер запущен пользователем serveruser. Если вы внимательно читали раздел, посвященный авторизационным записям, вам ясно, почему clientuser не имеет доступа к дисплею: ˜clientuser/.Xauthority не содержит правильной авторизационной записи для доступа к вашему дисплею. Правильная авторизационная запись находится в ˜clientuser/.Xauthority.

Разные пользователи на одной машине

Конечно, все что работает на удаленной машине, аналогично работает для другого пользователя на той же машине. Просто клиент и сервер это одна и та же машина. Тем не менее, в данном случае существует несколько кратчайших путей передать авторизационную запись.

Допустим, что вы используете su для переключения между пользователями. То есть все, что вы должны сделать, это написать скрипт, запускающий su с командами, необходимыми для запуска X-клиента: установить переменную DISPLAY и передать авторизационную запись.

Установить переменную DISPLAY сравнительно просто; надо определить DISPLAY="$DISPLAY" перед запуском команды su. Итак, вы можете просто сделать:

su - clientuser -c "env DISPLAY=$DISPLAY clientprogram &"

Это пока не сработает, потому что мы все еще не передали авторизационную запись. Мы можем извлечь запись при помощи команды xauth list "$DISPLAY". Эта команда выдает список авторизационных записей в формате, в котором их можно загрузить обратно в xauth; то что нам нужно! Так что нам осталось передать авторизационную запись в xauth и установить переменную DISPLAY в команде su.

su - clientuser -c "xauth add `xauth list $DISPLAY`; \
                    exec env DISPLAY=$DISPLAY clientprogram"

Вы можете написать скрипт, похожий на этот, указав правильные clientuser и clientprogram. Но давайте улучшим скрипт, сделав его менее удобочитаемым, но более универсальным:

#!/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 '$*'"

Я думаю, он достаточно универсален и работает для большинства случаев. Единственный недостаток, который я могу найти прямо сейчас, это использование одинарных кавычек вместе с двойными кавычками в аргументах команды su ('$*'). Если это считается совершенно неправильным, напишите мне.

Назовите скрипт /usr/local/bin/xsu и попробуйте запустить его:

xsu clientuser 'command &'

Просто, не правда ли?

Root-клиент

Очевидно, все, что работает для обычных пользователей, будет работать и для root. Тем не менее, в случае с root вы можете сделать это даже проще, т.к. root может прочитать чей угодно ˜/.Xauthority. Так что нет необходимости передавать записи авторизации. Все, что вам нужно сделать, это установить переменную 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 &'

Еще проще, не правда ли?