Run X program in another user's GUI
System administrators (sysadmins, from now on) may occasionally need to display messages to the user who is currently running a GUI: let his username be targetuser
; let sysadm’s username be admguy
; let local system’s hostname be guihost
.
In Linux and other *nix OSs, graphical interfaces are usually handled by X Window System. In this example, sysadm needs:
- to belong to the local system group
sudo
; - to be connected to the local system through a text interface;
- to properly set up some environment variables.
Sysadmin does not need to know (he is also not allowed to know) targetuser
’s password.
admguy@guihost:~$ who
targetuser tty7 2018-12-16 12:02 (:0)
admguy pts/8 2018-12-16 14:53 (192.168.1.2)
This is an example output of who
in the local system. Sysadm admguy
is logged in through a remote SSH connection; targetuser
has instead performed a graphic login and his GUI runs on local display :0
.
Sysadmin may choose to act:
- as himself;
- as
targetuser
.
If acting by himself, sysadm must first set up his environment variable DISPLAY
to match targetuser
’s one: :0
.
admguy@guihost:~$ export DISPLAY=:0
Note that this variable was originally not defined in sysadm’s env
, because he is using a text-only connection. X Window System grants access to a display only if some credentials are provided. When targetuser
loaded GUI for the first time, a hidden file .Xauthority
in his home directory /home/targetuser
or equivalently ~targetuser
was created. Its contents can be shown as:
targetuser@guihost:~$ xauth list
guihost/unix:0 MIT-MAGIC-COOKIE-1 bd2b204d7d9b2328e4bfc3b2b7a237f0
X applications run by targetuser
can connect to display :0
through a Unix socket on host guihost
only if they provide the correct MIT-MAGIC-COOKIE-1
value, which is used for authentication. File .Xauthority
for targetuser
lists: hostname, socket type, display, cookie type and cookie value. GUI applications run by targetuser
must read information on this file to be allowed to run on display :0
, with targetuser
as owner. Note that access to .Xauthority
is very restrictive:
targetuser@guihost:~$ ls -la | grep Xauthority
-rw------- 1 targetuser targetuser 277 dic 16 12:02 .Xauthority
If sysadm wants to run a GUI application on targetuser
’s display, this application must follow the same procedure, but – being launched by sysadm – it is only able to read sysadm’s .Xauthority
file, not targetuser
’s one. However, sysadm can acquire the ~targetuser/.Xauthority
information into his own .Xauthority
file: the canonical way is through X command xauth
.
Information can be extracted from a specific .Xauthority
file from its owner (which, in this case, is targetuser
) as:
targetuser@guihost:~$ xauth extract - $DISPLAY
See man xauth
for more information (this is referred to the current most recent X11R7 release; see also the manpage on your Operating System). This will print some illegible characters on screen (because stdout
has been chosen with -
for output of xauth extract
): they are suitable, though, to be read with xauth merge -
. Note that only targetuser
can perform xauth extract
, because he is the only one who is able to read ~targetuser/.Xauthority
file; on the other hand, if sysadm must acquire this information, xauth merge -
must be run by admguy
.
Sysadm must then act as targetuser
when performing xauth extract - $DISPLAY
(and sudo
lets him to do this); then, he must act as himself to acquire that ~targetuser/.Xauthority
output information and merge it into ~admguy/.Xauthority
:
admguy@guihost:~$ sudo -u targetuser -i xauth extract - $DISPLAY | xauth merge -
Acting as targetuser
through sudo
, information on ~targetuser/.Xauthority
is extracted to admguy
’s stdout
; then, with xauth merge -
(which reads stdout
) normally run as admguy
, it is gathered into sysadms’s .Xauthority
file.
Sysadm admguy
is now able to act on targetuser
’s display as well as targetuser
, because the environment variable DISPLAY
is already set to :0
and he owns the required authentication credentials. Then, for example,
admguy@guihost:~$ xclock
displays a clock in targetuser
’s GUI. Note that the process is owned by admguy
, the sysadm user:
admguy@guihost:~$ ps -aux | grep xclock
admguy 23102 0.0 0.0 71048 6580 pts/8 S+ 17:03 0:00 xclock
A non-canonical, alternative way is to copy ~targetuser/.Xauthority
through sudo
to an appropriate location, change its owner from the default root
(which is the owner after the sudo
copy operation) to admguy
, and set the value of the environmental variable XAUTHORITY
to the full path of the copied .Xautority
file:
admguy@guihost:~$ export DISPLAY=:0
admguy@guihost:~$ sudo cp ~targetuser/.Xauthority /custom_directory/custom_name
admguy@guihost:~$ sudo chown admguy /custom_directory/custom_name
admguy@guihost:~$ export XAUTHORITY=/custom_directory/custom_name
admguy@guihost:~$ xclock
This procedure would have the same effect as before, but it is not recommended.
Any other GUI program can be run on targetuser
’s display as a process owned by admguy
: for example, xcalc
. To display a message, X Window System provides:
admguy@guihost:~$ xmessage -buttons Yes,No,Maybe -nearmouse "Do you enjoy pineapple on pizza?"
Buttons names are customizable, as well as their exit values, which can be displayed through $?
once the window has been closed by targetuser
through some of the buttons. Default exit values are:
101
if buttonYes
is pressed;102
if buttonNo
is pressed;103
if buttonMaybe
is pressed;1
if window is closed through upper-rightx
.
See man xmessage
for more information. Please, be careful that character encodings other than ASCII may not be correctly displayed or may need dedicated settings.
Sysadm can also act as targetuser
through sudo
. This way, he does not need to acquire .Xauthority
information into his own .Xauthority
file, because he will represent targetuser
to all intents and purposes and will have a direct access to ~targetuser/.Xauthority
. Sysadm needs only to reproduce the correct environment targetuser
would have: this implies, in this case, just to set the DISPLAY
variable.
admguy@guihost:~$ sudo -u targetuser DISPLAY=:0 xmessage -buttons Yes,No,Maybe -nearmouse "Do you enjoy pineapple on pizza?"
Note that DISPLAY
can be here set just for the scope of the line. This has been tested on Ubuntu 16.04, 18.04, KDE Neon 5.14. This way, process is owned not by sysadm, but by targetuser
:
admguy@guihost:~$ ps -aux | grep xmessage
targetuser 24928 0.0 0.0 50548 5604 pts/8 S+ 18:01 0:00 xmessage -buttons Yes,No,Maybe -nearmouse "Do you enjoy pineapple on pizza?"
Alternatively, quick notifications can be sent:
admguy@guihost:~$ sudo -u targetuser DISPLAY=:0 notify-send -u critical "Order pineapple pizza"
While xmessage
is made available by X Window System, notify-send
availability depends on the Desktop Environment. GNOME, Xfce and KDE Neon offer it, but other may not. Urgency level critical
lets the notification never disappear; choosing other levels may cause it to be automatically closed after some time. See man nofity-send
for more information.
This has been tested on Ubuntu 16.04. As regards Ubuntu 18.04 and KDE Neon 5.14, also the environment variable XDG_RUNTIME_DIR
must be specified, which is usually /run/user/<user_ID>
.
In such cases, if possible, run
targetuser@guihost:~$ notify-send -u critical "Order pineapple pizza"
for test purposes from a targetuser
GUI terminal emulator. If targetuser
is able to correctly display the message, while admguy
with sudo -u targetuser
is apparently not, as anticipated the only difference may be represented by the environment variable values in these two contexts.
Run env
in the targetuser
GUI terminal emulator to get a full list of all the environment variables; then, compare their names and their values to the ones in the shell obtained, from admguy
prompt, after typing sudo -u targetuser bash
, assuming bash
as shell. If a variable VARIABLE
with value value
is defined in the first environment but not in the second one, type export VARIABLE=name
in the sudo -u targetuser bash
shell. Run notify-send -u critical "Order pineapple pizza"
again. If it fails, try to export
another VARIABLE
, value
pair. Not all the variables in targetuser
’s environment are always needed.
While for Ubuntu 16.04 variable DISPLAY
was sufficient, Ubuntu 18.04 and KDE Neon 5.14 required also XDG_RUNTIME_DIR
in order to provide the same result.
User ID can be obtained through getent passwd
. Assume that targetuser
’s user ID is 1000
:
admguy@guihost:~$ sudo -u targetuser bash
admguy@guihost:~$ export DISPLAY=:0
admguy@guihost:~$ export XDG_RUNTIME_DIR=/run/user/1000
admguy@guihost:~$ notify-send -u critical "Order pineapple pizza"
This way, sysadm will be able through the graphical interface to poll targetuser
with xmessage
, or to simply notify him some messages with notify-send
. Note that xmessage
can be used to send notifications, too: moreover, it always lets sysadm to know if they have been read, because its process exits only when targetuser
presses a button; a default button okay
is included also when no -buttons
are specified.