logo rsync

El objetivo es que las aplicaciones X11 (X-Window) funcionen “también” desde root. Que funcionen desde un usuario es inmediato, pero entrar luego a root con su/sudo y que X11 funcione no está permitido en Linux. La conexión X11 solo pertenece al usuario con el que entraste por SSH.


Sin embargo siempre hay un truco 🤗, aunque me adelanto un poco, la solución pasa por reutilizar las credenciales X11 del usuario original con el que te conectaste, su lista de cookies, se las prestaremos a root usando diferentes métodos, lo vemos más adelante.


Configuración SSH

He documentado en otro apunte una introducción a SSH por si estás interesado. Aquí vamos a ver de nuevo la configuración de SSH en ambos, servidor y cliente, centrándome en la parte de X11. Si quieres saber mucho más sobre SSH consulta la documentación oficial de openssh


Servidor SSH y X11

Para situarnos, las pruebas las hago con ssh como luis (desde un Mac), conectando a un servidor linux con sshd llamado cortafuegix (gentoo). Esta es la configuración SSH del servidor:

  • Configuración del servidor sshd:
cortafuegix ~ # cat /etc/ssh/sshd_config
# Config LuisPa
PubkeyAuthentication yes
PasswordAuthentication no
AuthenticationMethods publickey
UsePAM no
X11Forwarding yes     # !! X11 !!
X11DisplayOffset 10   # !! X11 !!
X11UseLocalhost yes   # !! X11 !!
AddressFamily inet
PrintMotd no
PrintLastLog no
Subsystem	sftp	/usr/lib64/misc/sftp-server
AcceptEnv LANG LC_*


Cliente SSH y X11

El cliente SSH que utilizo es el que viene con MacOS (idefix). Este es el fichero de configuración que uso en mi usuario luis.

  • Configuración del cliente ssh:
➜  ~ > confcat /Users/luis/.ssh/config 
PubkeyAuthentication yes
Host *
    ForwardAgent yes                    # 
    ForwardX11 yes                      # !! X11 !!
    ForwardX11Trusted yes               # !! X11 !!
    XAuthLocation /opt/X11/bin/xauth    # !! X11 !!
    ControlPath ~/.ssh/sockets/%r@%h-%p
    ControlPersist 600
    AddKeysToAgent yes
    UseKeychain yes
    IdentityFile ~/.ssh/id_rsa


Apuntes relacionados con X11:


  • En el SERVIDOR:
    • X11Forwarding yes: Permito reenvío de X11 con mis clientes
    • X11DisplayOffset 10: Primer número de pantalla (Variable DISPLAY)
    • X11UseLocalhost yes: Asociar el reenvío de X11 a la dirección loopback


  • En el CLIENTE:
    • ForwardX11 yes: Permito reenvío de X11
    • ForwardX11Trusted yes: Conectar con -X o -Y tendrá el mismo efecto
    • XAuthLocation /opt/X11/bin/xauth: Para evitar el error “No xauth data…”


En terminología X-Window se llama Servidor a lo que vemos, en el mac XQuartz es el servidor y muestra en pantalla lo le piden los clientes remotos. Se llama Cliente a las Aplicaciones, en este caso un ejemplo sería xclock ejecutándose en el linux.

Nota: Si xclock te da el error “Warning: Missing charsets in String to FontSet conversion” la solución es sencilla, modifica tu /etc/profile añade lo siguiente: alias xclock='LC_ALL=C /usr/bin/xclock'

Al poner ForwardX11Trusted yes en el Mac lo que estoy diciendo es que ignore la extensión “X11 SECURITY” que provoca que cualquier Aplicación del linux podrá acceder a mi Servidor XQuartz.

Preferencias XQuartz en cliente Mac.

Para que funcione X11 desde el cliente usaremos ssh -X o ssh -Y. La primera (-X) consulta ForwardX11Trusted mientras que la segunda (-Y) la ignora. Al poner su valor a yesestoy diciendo que da igual conectar con una o la otra, en ambos casos se ignora la extensión de seguridad “X11 SECURITY”, es decir que da igual si conecto con -X o -Y que el efecto será el mismo.


Prueba de concepto

Para empezar desde cero, borro el fichero $HOME/.Xauthority en mi servidor (además de cualquier fichero $HOME/.xauth*), tanto en mi usuario luis como en root.

La autenticación X se basa en cookies, un chorro de datos que solo el servidor y tu usuario conocen. Al conectar se crea una magic-cookie y se archiva en el fichero de luis: /home/luis/.Xauthority. En el siguiente ejemplo vemos que, al conectar no existía, se crea (lo hace el servidor sshd), insertando la magic cookie y establece la variable DISPLAY.

➜  ~ > ssh -X luis@cortafuegix.parchis.org 
/usr/bin/xauth:  file /home/luis/.Xauthority does not exist

luis@cortafuegix ~ $ ls -al .Xauthority 
-rw------- 1 luis luis 57 may  3 11:48 .Xauthority

luis@cortafuegix ~ $ xauth list
cortafuegix/unix:11  MIT-MAGIC-COOKIE-1  afd3b06294cd3963efade050a69c7c4b

luis@cortafuegix ~ $ echo $DISPLAY
localhost:11.0

luis@cortafuegix ~ $ xclock
SSH y xclock como usuario 'luis'

Me convierto en root para ver cómo aparece el problema, da igual el método que utilice, aún teniendo bien la variable DISPLAY nunca consigo que funcione:

➜  ~ > ssh -X luis@cortafuegix.parchis.org

luis@cortafuegix ~ $ su  (Da igual el comando: "su -", "sudo -i", "sudo su -")
:
cortafuegix ~ # echo $DISPLAY
localhost:10.0

cortafuegix /home/luis # xclock
X11 connection rejected because of wrong authentication.
Error: Can't open display: localhost:10.0
Por defecto no será posible conectar


La solución

Como decía, la autenticación X se basa en cookies, un chorro de datos que solo el servidor y tu usuario conocen. En el ejemplo anterior luis conecta vía ssh con el servidor y X11 funciona, la primera vez se crea dicha cookie en (~/.Xauthority).  Para que también nos funcione al convertirnos en root necesito esa magic cookie, así que voy ver qué opciones tenemos para prestársela a root.

Método 1: Copiar/Pegar

Este método funciona muy bien si soy el único que entra en rooten mis servidores. Lo que hago es leer la cookie de luis y la añado en el .Xauthority de root. Para conseguirlo voy a añadir una serie de comandos en el .profile de root para que hagan precisamente eso:

cortafuegix ~ # cat .profile 
:
su - luis -c 'xauth list' |\
              grep -E "localhost|`hostname`" |\
              xargs -n 3 xauth add

Ten en cuenta que se tiene que ejecutar el .profile o no funcionará, por lo tanto:

  • Funcionan: su -, sudo -i, sudo su - o sudo -i xclock
  • No funcionan (la primera vez): su o sudo xclock. No ejecutan el .profile de root. Ahora bien, si ya he entrado alguna vez con los anteriores, entonces estos empezarán a funcionar.
Empieza a funcionar

OJO! funcionar, funciona, pero es un poco chapuza porque solo le funcionará a un usuario (imagina un linux con múltiples usuario entrando como root) y porque te puede despistar que a veces no funcione… dependiendo de qué comando uses y si está o no creado el .Xauthority…


Método 2: XAUTHORITY

Esta opción es otra pequeña chapuzilla… consiste en usar la variable de entorno XAUTHORITY apuntando al fichero .Xauthority del usuario (en mi ejemplo luis). Añado una línea al .profile de root y ya está. No necesitas ejecutar el comando xauth y no necesitas el fichero /root/.Xauthority.

/root/.profile
export XAUTHORITY=/home/luis/.Xauthority

Tampoco me gusta demasiado, así que no la he activado. Veamos la tercera opción.


Método 3: usar pam_xauth.so

Existe la posibilidad de activar el módulo pam_xauth.so en la última línea del fichero /etc/pam.d/su. Añado lo siguiente

session optional pam_xauth.so

Al convertirte en root se creará automáticamente en el HOME de root un fichero del tipo ./xauthXXXXXX (siendo XXXXXX valores aleatorios) con la cookie del usuario original (luis), y al salir de la sesión se eliminará este fichero temporal. Se puede encontrar más información en man pam_xauth

Vamos a probarlo. Elimino la opción 1 del .profile y activo esta nueva opción en /etc/pam.d/su:

cortafuegix ~ # cat .profile 
:
# LAS SIGUIENTES 3 LINEAS QUEDAN INHABILITADAS
#su - luis -c 'xauth list' |\
#              grep -E "localhost|`hostname`" |\
#              xargs -n 3 xauth add


cortafuegix ~ # cat /etc/pam.d/su
:
session		optional	pam_xauth.so

Esta opción es un poco más pura linux, aunque como verás en la tabla siguiente tampoco cubre todos los casos.


Resumen

Opciones disponibles.

Dependiendo de cual de las tres elijas conseguirás que X11 en root funcione o falle.

  (1) .profile (2) XAUTHORITY (3) pam_xauth.so
su SEMIFALLA FALLA OK
su - OK OK OK
sudo su - OK OK FALLA
sudo -i OK OK FALLA
sudo xclock SEMIFALLA FALLA FALLA
sudo -i xclock OK OK FALLA


Mi propuesta

En mi caso combino las opciones (1), (3) y un alias 🤗:

Archivo Código
.profile (root) su - luis -c 'xauth list' | grep -E "localhost|`hostname`" | xargs -n 3 xauth add
/etc/pam.d/su session optional pam_xauth.so
.profile (Luis) alias sudo='sudo -i'