Remote X Apps mini-HOWTO

Vincent Zweije

     [email protected]
   

Перевод: Павел Гашев, SWSoft Pte Ltd.

19 Ноября 1999

В этот документе описываются способы запуска удаленных приложений под X. То есть представлена информация о том, как заставить программу выводить результат на дисплей другого компьютера, а не того, на котором она запущена. Или наоборот: как заставить программу работать на другом компьютере так, как будто вы сидите за ним. И как запустить приложение от другого пользователя на этом же компьютере. Основное внимание здесь уделяется безопасности.


1. Введение

В этом документе описываются способы запуска удаленных приложений под X. Он был написан по нескольким причинам.

  1. В конференциях Usenet появилось много вопросов о том, как запускать удаленные приложения под X.

  2. Я вижу многие, многие ответы типа ``используйте xhost +hostname'' или даже ``xhost +'', чтобы разрешить доступ к X-серверу. Это очень небезопасно, есть лучшие методы.

  3. Я не знаю о существовании простого документа, описывающего эти возможности. Если вы знаете, то напишите мне по адресу [email protected].

Описание в этом документе рассчитано на системы Unix. Если ваша локальная или удаленная операционная система из другой серии, то, по крайней мере, вы ,поймете как это работает в принципе, или же сами переведете примеры на свою систему.

Наиболее свежую версию этого документа можно всегда найти на WWW по адресу http://www.xs4all.nl/~zweije/xauth.html. На сайте http://sunsite.unc.edu/LDP/HOWTO/mini/Remote-X-Apps этот документ называется Remote X Apps mini-HOWTO.

Это версия 0.6.1. Без гарантий, но с хорошими намерениями. Всегда рад вашим предложениям, идеям, дополнениям, полезным указаниям, исправлениям опечаток, и т.п. Я хочу оставить этот документ в простой форме, но и в лучшем стиле HOWTO. Все негодования буду препровождать в /dev/null.

Содержание обновлено 19 ноября 1999 Vincent Zweije


2. Аналогичные решения

Другой WWW документ на эту тему - это ``What to do when Tk says that your display is insecure'', http://ce-toolkit.crd.ge.com/tkxauth/. Его написал Kevin Kenny. Он предлагает аналогичное решение аутентификации X (xauth). Kevin дает решение, более подходящее для xdm.

X System Window System Vol. 8 X ``Window System Administrator's Guide'' от O'Reilly and Associates также привлек мое внимание в качестве хорошего источника информации. К сожалению, я не смог проверить его.

Еще один документ, похожий на этот называется ``Securing X Windows'' и находится по адресу http://ciac.llnl.gov/ciac/documents/ciac2316.html.

Можно также почитать конференции Usenet (такие как comp.windows.x, comp.os.linux.x, и comp.os.linux.networking).


3. Постановка задачи

Вы используете два компьютера. Первый, с графической оболочкой X, используется в качестве графического терминала. Второй - для некоторых важных работ с графикой. Вы хотите работать на втором компьютере, находясь за первым. X-windows предоставляет эту возможность.

Конечно для этого вам нужно соединить их в сеть. И желательно быструю; X-протокол сильно загружает сеть. Но при небольшом терпении и соответствующем протоколе сжатия, вы можете запускать приложения через модем. Для сжатия X-протокола, можно использовать dxpc http://ccwf.cc.utexas.edu/~zvonler/dxpc/ или LBX http://www.ultranet.com/~pauld/faqs/LBX-HOWTO.html также известного как LBX mini-HOWTO.

Чтобы достигнуть этого, необходимо две вещи:

  1. Скомандовать X-серверу, чтобы он работал с удаленным компьютером.

  2. Скомандовать удаленному компьютеру (клиенту), чтобы он посылал информацию на ваш дисплей.


4. Немного теории

Волшебное слово это DISPLAY (ДИСПЛЕЙ). В X-windows под дисплеем понимается (упрощенно) клавиатура, мышь и экран. Дисплей управляется программой-сервером, известной как X-сервер. Сервер обслуживает вывод программ, подключенных к нему.

Дисплей указывается именем, например:

  • DISPLAY=light.uni.verse:0

  • DISPLAY=localhost:4

  • DISPLAY=:0

Название дисплея содержит имя компьютера (напр. light.uni.verse или localhost), двоеточие и номер (напр. 0 или 4). Имя компьютера в названии дисплея - это имя машины, на которой запущен X-сервер. Неуказанное имя компьютера подразумевает localhost. Номер дисплея обычно ``0'', и может варьироваться, если к компьютеру подключено несколько дисплеев.

Если вы когда-либо сталкивались в названии дисплея с дополнительным .n в конце, это номер экрана. Хотя обычно есть только один экран с номером n=0 по умолчанию.

Существуют другие формы описания дисплея, но для наших целей достаточно вышесказанного.

Для любопытных:

  • hostname:D.S означает экран S на дисплее D машины hostname; X-сервер для этого дисплея находится на TCP порту 6000+D.

  • host/unix:D.S означает экран S на дисплее D машины host; X-сервер для этого дисплея находится на UNIX domain socket /tmp/.X11-unix/XD (т.е. доступном только с машины host).

  • :D.S эквивалент host/unix:D.S, где host это имя локальной машины.


5. Говорим клиенту:

Клиентская программ (например, ваше графическое приложение) знает, какой дисплей использовать из переменной окружения DISPLAY. Ее можно переопределить, либо использовать аргумент -display hostname:0 во время запуска вашей программы. Рассмотрим это на примере.

Наш компьютер известен в сети как light, в домене uni.verse. Если мы запустим обычный X-сервер, переменная DISPLAY будет равна light.uni.verse:0. Но мы хотим запустить программу для рисования xfig на удаленном компьютере dark.matt.er, а в качестве дисплея использовать машину light.

Полагаю, что вы уже вошли на удаленный компьютер dark.matt.er.

Если вы используете csh в качестве оболочки на нем:

dark% setenv DISPLAY light.uni.verse:0
dark% xfig &

или же:

dark% xfig -display light.uni.verse:0 &

Если вы используете sh в качестве оболочки:

dark$ DISPLAY=light.uni.verse:0
dark$ export DISPLAY
dark$ xfig &

или же:

dark$ DISPLAY=light.uni.verse:0 xfig &

или, конечно же:

dark$ xfig -display light.uni.verse:0 &

Кажется, некоторые версии telnet автоматически передают переменную DISPLAY на удаленный компьютер. Если у вас как раз такая, считайте, что вам повезло, и не надо указывать ее вручную. В противном случае, большинство версий telnet передают переменную окружения TERM; можно установить переменную DISPLAY, основываясь на переменной TERM.

Основная идея состоит в том, чтобы при помощи скрипта сделать следующее: перед запуском telnet, добавляем значение переменной DISPLAY к переменной TERM. На другом конце в скрипте .*shrc устанавливаем значение DISPLAY из переменной TERM.


6. Говорим серверу:

Сервер не принимает соединения просто так, откуда угодно. Да вам и не нужно, чтобы кто-нибудь выводил окна на экране. Или читал, что вы набираете (помните! клавиатура это часть дисплея).

Слишком мало людей, кажется, понимают, что подобный доступ к вашему дисплею снижает степень безопасности. Кто-нибудь, кто имеет доступ к вашему дисплею, может, что угодно посмотреть и написать на ваш экран , считывать нажатия клавиш и действий мыши.

Большинство серверов знают два пути аутентификации: механизм, основанный на списке машин (xhost), и механизм, основанный на magic cookie (xauth). Кроме того, есть ssh, оболочка с шифрованием, которая может обслуживать X-соединения.


6.1. Xhost

Xhost открывает доступ, основанный на названиях машин. Сервер поддерживает список машин, которым позволено подключаться к нему. Он же может отключить проверку имен полностью. Осторожно: это значит, что не будет выполняться никаких проверок, так что может подключиться любая машина!

Вы можете изменять список машин при помощи программы xhost. Чтобы использовать этот механизм для предыдущего примера, сделайте:

light$ xhost +dark.matt.er

Это открывает доступ ко всем соединениям с машины dark.matt.er. Как только ваш X-клиент подключится к X-серверу (появятся окна), закройте доступ при помощи:

light$ xhost -dark.matt.er

Вы можете отключить проверку вообще:

light$ xhost +

Это отключает проверку и позволяет подключиться кому угодно. Вы никогда не должны этого делать в сети, в которой вы доверяете не всем пользователям (напр. Internet). Вы можете снова включить проверку:

light$ xhost -

"xhost -" не удаляет все машины из списка доступа (это было бы бесполезно - вы не смогли бы подсоединиться ниоткуда, даже со своей же машины).

Xhost - очень небезопасный механизм. Он не различает пользователей на удаленной машине между собой. Кроме того, имена машин (а тем более адреса) можно подделать. А это плохо, если вы находитесь в сети, которой не доверяете (например, уже при PPP доступе к Internet).


6.2. Xauth

Xauth открывает доступ всем, кто знает "секрет". Этот секрет называется "авторизационная запись" или "magic cookie" (волшебная печенька). Эта схема авторизации формально названа MIT-MAGIC-COOKIE-1.

Эти записи для разных дисплеев хранятся вместе в файле ˜/.Xauthority. Ваш ˜/.Xauthority должен быть недоступен для других пользователей. Программа xauth управляет этими записями, т.е. xauth - псевдонимная система аутентификации.

В начале сеанса сервер считывает запись из файла, указанного в аргументе -auth. После этого сервер позволяет соединения только тем клиентам, которые имеют ту же запись. Если запись в ˜/.Xauthority меняется, сервер не считает изменение.

Новые сервера могут генерировать такие записи на лету для клиентов, которые запрашивают их. Хотя записи содержатся внутри сервера, они не запишутся в ˜/.Xauthority, если только клиент это не сделает сам. Согласно David Wiggins:

"Одна штучка была добавлена в X11R6.3, которой вы можете заинтересоваться. Через новую систему безопасности, сам X-сервер может сгенерировать и передать новые авторизационные записи на лету. Кроме того, запись может быть определена как ``ненадежная'', ограничивая функционирование приложений. Например, они не могут узнать содержимое окна или ввод с клавиатуры/мыши от других "надежных" клиентов. В xauth введена новая подкоманда ``generate'', чтобы сделать это средство, по крайней мере, возможным (если не легким) в использовании."

Xauth имеет большое преимущество в безопасности перед xhost. Вы можете ограничить доступ специфических пользователей на специфических компьютерах. В отличии от xhost, его невозможно обмануть, подделав адрес компьютера. И если хотите, вы можете по прежнему пользоваться xhost.


6.2.1. Создание авторизационной записи

Если вы хотите использовать xauth, запустите X-сервер с аргументом -auth authfile. Если вы пользуетесь скриптом startx, лучше это сделать в нем. Создайте авторизационную запись, как показано ниже в вашем скрипте startx.

Отрывок из /usr/X11R6/bin/startx:

mcookie|sed -e 's/^/add :0 . /'|xauth -q
xinit -- -auth "$HOME/.Xauthority"

Mcookie - это простая программа в пакете util-linux (ftp://ftp.math.uio.no/pub/linux/). Кроме того, вы можете использовать md5sum для преобразования случайных данных (например, из /dev/urandom или ps -axl) в формат авторизационной записи:

dd if=/dev/urandom count=1|md5sum|sed -e 's/^/add :0 . /'|xauth -q
xinit -- -auth "$HOME/.Xauthority"

Если вы не можете отредактировать скрипт startx (если вы не root), скажите своему системному администратору, чтобы он настроил startx правильно, или пусть установит xdm. Если он не хочет или не может, вы можете создать скрипт ˜/.xserverrc. Если он у вас есть, он запускается через xinit, а не через X-сервер. Затем вы можете запустить X-сервер из этого скрипта с правильными аргументами:

#!/bin/sh
mcookie|sed -e 's/^/add :0 . /'|xauth -q
exec /usr/X11R6/bin/X "$@" -auth "$HOME/.Xauthority"

Если для управления сеансами вы используете xdm, то можно легко использовать xauth. Определите ресурс DisplayManager.authDir в /etc/X11/xdm/xdm-config. Во время запуска X-сервера xdm сам укажет аргумент -auth, а когда вы войдете в систему, xdm положит авторизационную запись в ваш ˜/.Xauthority. Для дополнительной информации читайте xdm(1). Например, мой /etc/X11/xdm/xdm-config содержит следующую строчку:

DisplayManager.authDir: /var/lib/xdm


6.2.2. Передача авторизационных записей

Теперь, когда вы запустили X-сервер на машине light.uni.verse и у вас есть файл ˜/.Xauthority, нужно передать авторизационную запись на машину клиента dark.matt.er.

Самое простое, если у вас один и тот же сетевой домашний каталог на машинах light и dark. Файл ˜/.Xauthority один и тот же и авторизационная запись передается моментально. Тем не менее, здесь есть одна проблема: когда вы кладете авторизационную запись для :0 в ˜/.Xauthority, машина dark думает, что эта запись для нее, а не для light. Поэтому вам нужно явно указывать имя компьютера во время создания записи. Можно установить одинаковую запись для :0 и light:0 при помощи:

#!/bin/sh
cookie=`mcookie`
xauth add :0 . $cookie
xauth add "$HOST:0" . $cookie
exec /usr/X11R6/bin/X "$@" -auth "$HOME/.Xauthority"

Если домашний каталог не разделяется между машинами, вы можете передать авторизационную запись при помощи rsh:

light$ xauth nlist "${HOST}:0" | rsh dark.matt.er xauth nmerge -

  1. Извлечь запись из ˜/.Xauthority (xauth nlist :0).

  2. Передать на dark.matt.er (| rsh dark.matt.er).

  3. Поместить ее в ˜/.Xauthority there (xauth nmerge -).

Замечу насчет ${HOST}. Вам нужно передать авторизационную запись, явно ассоциированную с локальной машиной. Удаленное приложение может интерпретировать :0 как ссылку на удаленную машину, а это не то, что вы хотите!

Возможно, что rsh не разрешен для вас. Кроме того, rsh имеет недостаток с точки зрения безопасности (можно подделать имя машины, если я правильно помню). Если вы не можете или не хотите использовать rsh, передайте авторизационную запись вручную. Примерно так:

light$ echo $DISPLAY
:0
light$ xauth list $DISPLAY
light/unix:0 MIT-MAGIC-COOKIE-1 076aaecfd370fd2af6bb9f5550b26926
light$ rlogin dark.matt.er
Password:
dark% setenv DISPLAY light.uni.verse:0
dark% xauth add $DISPLAY . 076aaecfd370fd2af6bb9f5550b26926
dark% xfig &
[15332]
dark% logout
light$

Для дополнительной информации см. rsh(1) и xauth(1x).

Есть возможность передать авторизационную запись в переменных окружения TERM или DISPLAY. Это делается таким же образом, как и передача переменной DISPLAY. См. раздел "Говорим клиенту:". Это моя точка зрения, но я заинтересован в том, чтобы кто-нибудь подтвердил или опроверг ее.


6.2.3. Использование авторизационной записи

X-приложение на машине dark.matt.er, такое как xfig, автоматически заглядывает в файл ˜/.Xauthority и ищет нужную запись для авторизации.

Есть небольшая проблема во время использования localhost:D. X-клиент во время поиска записи может перевести localhost:D как host/unix:D. На самом деле это означает, что авторизационная запись для localhost:D в ˜/.Xauthority не имеет эффекта.


6.3. Ssh

Авторизационные записи передаются по сети без шифрования. Если вы боитесь, что кто-нибудь будет подглядывать за вашим соединением, используете ssh, безопасную оболочку. Она обеспечит зашифрованное соединение сервера и клиента. И кроме того, она полезна и для других случаев. Это хорошее структурное улучшение вашей системы. Просто сходите на http://www.cs.hut.fi/ssh/

Кто знает еще какие-нибудь методы аутентификации или шифрования X-соединений? Может быть kerberos?


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

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

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


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

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

Допустим, что вы используете 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 &'

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


7.2. 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 &'

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


8. Запуск удаленного менеджера окон

Менеджер окон (такой как twm, wmaker, или fvwm95) это такое же приложение, как другие. Должна сработать та же процедура.

Хорошо, почти. В одно и тоже время на дисплее может работать только один менеджер окон. Если у вас уже запущен локальный менеджер окон, вы не можете запустить еще и удаленный (он поругается и закончит работу). Необходимо сначала снять (используя kill или просто выйти) локальный менеджер.

К сожалению, большинство X-сессий заканчиваются командой

exec менеджер-окон-на-ваш-выбор

а это значит, что когда (локальный) менеджер окон заканчивает работу, сеанс заканчивается, и X-сервер завершает работу.

По ходу вам придется решить еще парочку не очень сложных проблем. Просто поиграйтесь со скриптом X-сеанса (обычно это ˜/.xsession или ˜/.xinitrc), чтобы настроить его так, как вы хотите.

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


9. Распространенные ошибки

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

xterm Xt error: Can't open display(Не могу открыть дисплей):

Нет переменной DISPLAY в окружении, и вы не указали программе параметр -display. Приложение принимает по умолчанию пустую строку, а это синтаксически не правильно. Установите переменную DISPLAY (при помощи setenv или export в зависимости от оболочки).

_X11TransSocketINETConnect: Can't connect(Не могу соединиться) : errno = 101
xterm Xt error: Can't open display(Не могу открыть дисплей):  love.dial.xs4all.nl:0

Errno = 101 это ``Сеть не доступна''. Приложение не может выполнить сетевое соединение с сервером. Проверьте, правильно ли установлена переменная DISPLAY, и доступен ли сервер с вашего клиента (сеть должна работать, в конце концов, вы только что вошли на удаленную машину через сеть).

_X11TransSocketINETConnect: Can't connect(Не могу соединиться):  errno = 111
xterm Xt error: Can't open display(Не могу открыть дисплей):  love.dial.xs4all.nl:0

Errno = 111 это ``В соединении отказано (Connection refused)''. Машина сервера, к которой вы хотите подсоединиться доступна, но указанный сервер на ней не запущен. Проверьте, правильное ли имя машины и номер дисплея вы используете.

Xlib: connection to ":0.0" refused by server (в соединении с ":0.0" отказано сервером)
Xlib: Client is not authorized to connect to Server (Клиент не имеет авторизован для подключения к Серверу)
xterm Xt error: Can't open display (Не могу открыть дисплей): love.dial.xs4all.nl:0.0

Клиент подключился к серверу, но сервер не позволяет клиенту пользоваться им (не авторизован). Убедитесь, что передана правильная авторизационная запись, и она не устарела (сервер использует новую запись каждый раз во время запуска).


10. Авторские права

Авторские права на русский перевод этого текста принадлежат © 2000 SWSoft Pte Ltd. Все права зарезервированы.

Этот документ является частью проекта Linux HOWTO.

Авторские права на документы Linux HOWTO принадлежат их авторам, если явно не указано иное. Документы Linux HOWTO, а также их переводы, могут быть воспроизведены и распространены полностью или частично на любом носителе, физическом или электронном, при условии сохранения этой заметки об авторских правах на всех копиях. Коммерческое распространение разрешается и поощряется; но, так или иначе, автор текста и автор перевода желали бы знать о таких дистрибутивах.

Все переводы и производные работы, выполненные по документам Linux HOWTO, должны сопровождаться этой заметкой об авторских правах. Это делается в целях предотвращения случаев наложения дополнительных ограничений на распространение документов HOWTO. Исключения могут составить случаи получения специального разрешения у координатора Linux HOWTO, с которым можно связаться по адресу приведенному ниже.

Мы бы хотели распространить эту информацию по всем возможным каналам. Но при этом сохранить авторские права и быть уведомленными о всех планах распространения HOWTO. Если у вас возникли вопросы, пожалуйста, обратитесь к координатору проекта Linux HOWTO по электронной почте: или к координатору русского перевода Linux HOWTO компании SWSoft Pte Ltd. по адресу