sddm y x11vnc tiene truco

25 Oct

Porque con otros accesos gráficos al sistema como el de Gnome es engorroso y no merece la pena. La idea es integrar el acceso en Guacamole y para eso lo mejor es el VNC de toda la vida. En mi opinión, claro.

A raíz de los problemas de los que hablé en la entrada anterior he visto que necesito acceso a la sesión gráfica de los diferentes clientes Linux que tengo ahora funcionando. Acceso vía SSH siempre tengo pero es más difícil depurar los problemas que padecen si no tengo acceso a su pantalla.

Algunas aclaraciones previas:

  1. Estoy empleando el programa x11vnc para crear el acceso remoto así que lo mencionaré como si fuese la única opción aunque existen otras.
  2. Todo esto sólo funciona en sesiones X11 y no en Wayland. Debian usa ahora mismo este sistema como valor predeterminado así que hay que asegurarse de cambiar a X11 antes de probar nada que se sufre mucho hasta que te percatas.

Como organizar las cosas

Lo primero es echarle un vistazo a las opciones. Los usuarios arrancan la sesión gráfica identificándose primero en el gestor de sesiones y aquí ya tenemos un buen puñado para elegir, pero la mayor parte de ellos funcionan como sigue:

  1. Arrancan un servidor xorg.
  2. Dibujan la pantalla con mayor o menor complejidad.
  3. Solicitan un nombre de cuenta y una contraseña.
  4. Arrancan una sesión gráfica con el mismo servidor del punto 1 pero con el ID del usuario que se ha identificado en el punto 3.

Si añades un servicio x11vnc contra ese servidor gráfico (con la pertinente autorización) tras el punto 1, éste se pone en marcha y da acceso por el puerto correspondiente (5900 como valor predeterminado) al servidor gráfico en cualquiera de los puntos. Esto es importante porque eso significa que tienes acceso a la entrada al sistema y al sesión de usuario que origina. Si el usuario entrase por consola y arrancase allí la sesión gráfica (empleando startx) no tendrías acceso VNC a menos que en ella se pusiese en marcha el servicio x11vnc. Como mis homínidos acceden siempre al servicio desde el mismo punto tengo todas las ventajas con esta disposición.

De los gestores de sesión gráficos que he mirado en Debian gdm3 de Gnome se lleva la palma en cuanto a rarezas. Resulta que abre una sesión en miniatura, limitada, con la que solicita el usuario y su contraseña y luego, con esos datos, abre otra para el usuario en sí. Para emplear en este caso x11vnc tendría que hacer dos conexiones: la primera al servidor gráfico del gestor gráfico y la segunda, en otro puerto porque tiene que ser distinta, para acceder a la sesión de usuario. Vamos, que para una emergencia donde no funcione otra cosa y tengas paciencia puede valer. Para mis homínidos mejor que no.

El gestor gráfico sddm

Así que entre los otros el que menos problemas me ha dado por lo sencillo y monolítico de su diseño ha sido sddm, un gestor que emplea Qt y que se utiliza en el entorno KDE y LXqT. Bueno, problemas en la puesta en marcha porque con lo que he tenido que pelearme de verdad de la buena, y varias horas además, ha sido con la integración con x11vnc.

La primera dificultad ha sido determinar el archivo de autorización del servidor gráfico. sddm no usa una ruta fija ni determinística si no que crea archivos empleando UUID como nombre en un directorio en concreto (eso al menos no cambia) y lo hace por motivos de seguridad por una parte y por facilitar la creación de accesos múltiples en una máquina.

Si sólo vas a tener una sesión gráfica la manera recomendada de acceder al archivo es empleando el siguiente truco:

AUTHORITY=$(find /var/run/sddm -type f)

Tiene el problema de que te la juegas si hay más de uno pero existe otra solución según el autor. A sddm se le puede indicar que ejecute un programa tras la creación del servidor X11 en la ruta indicada en la variable DisplayCommand cuyo valor predeterminado es /usr/share/sddm/scripts/Xsetup y que en Debian es mejor ignorar porque modificar cualquier cosa bajo el directorio /usr implica perderlo en la siguiente actualización. Debian sólo contempla mecanismo de protección en los archivos de configuración que suelen estar bajo /etc.

Así que lo primero es cambiar la ruta en el archivo de configuración hacia un script bajo nuestro contol de la siguiente forma:

[X11]
DisplayCommand=/etc/sddm/Xsetup

Y en el script Xsetup, que podemos copiar del original del paquete, debemos poner en marcha el servicio VNC de la varias formas pero la que he encontrado que funciona es la siguiente:

!/bin/bash
# Xsetup - run as root before the login dialog appears

if [ -z "$AUTHORITY" ]; then
        AUTHORITY=$(find /var/run/sddm -type f)
fi 

/usr/bin/x11vnc -rfbauth /etc/x11vnc.passwd -rfbport 5900 -reopen -loop -noxdamage -repeat -auth $AUTHORITY &

sleep 3

Según el autor de sddm, cuando el programa llama a este script crea un valor concreto para el archivo de autorización en la variable XAUTHORITY por lo que se puede emplear directamente en el script. En mi caso, y sólo por precaución, he incluido una comprobación previa al uso. La instrucción sleep 3 es la clave de todo el asunto. La mayor parte de las soluciones que he encontrado en la red no la incluyen y es el punto determinante para todo el montaje.

Estuve varias horas probando y probando sin conseguir nada. sddm registraba que había lanzado el script pero no había huella alguna de él en el sistema, ni con errores ni sin ellos. Tuve que mirar el código fuente del programa para ver qué demonios pasaba:

Podemos observar la siguiente secuencia:

  1. Se obtiene la ruta del script en la configuración
  2. Se prepara para ejecutarlo
  3. Se lanza y se dispone que al finalizar la ejecución se acabe con el proceso
  4. Se espera durante 30 segundos a que termine y lo haga o no el proceso se elimina

Si lanzamos el script sin pasarlo a segundo plano con el carácter & al final, x11vnc se ejecuta alegremente pero no pasa a segundo plano a menos que se lo indiquemos (y en la mayoría de la soluciones este parámetro –bg– se omite) por lo que pasados los treinta segundos -en los cuales no hemos continuado con el proceso de arranque de sddm- matamos el proceso y la cosa acaba ahí.

Pero incluso si lo pasamos a segundo plano, al dejar la existencia de manera inmediata y no soltarse del grupo de procesos (x11vnc es más bien lento en el arranque), sddm recibe el valor correspondiente del método WaitForFinished de Qt y mata al proceso directamente.

Así que la única solución que he encontrado que funciona es lanzarlo en segundo plano y esperar unos segundos para darle tiempo a que forme su propio grupo de procesos y dejar de depender del proceso sddm que lo crea.

Así funciona bien. Sólo he tenido que retocar a veces el valor en segundos y elevarlo a 5 porque en algunas máquinas 3 no era suficiente. Y como sddm no crea otro servidor X11 para la sesión de usuario la autorización que ha creado y pasado como variable al script sigue siendo válida.

Y la solución definitiva es …

Pues otra, porque la anterior funciona hasta determinado punto tal y como he descubierto. El problema se da cuando se cierra la sesión VNC, bien mediante cierre de sesión de usuario, bien mediante cierre de visor VNC. En este caso sddm mata el servidor X11 y crea otro desde el principio, incluyendo los programas de arranque y parada que hemos comentado: DisplayCommand y DisplapStopCommand. No habría más problemas si no fuese porque la primera vez que lo ejecuta deja a x11vnc como un proceso independiente que de repente se encuentra con que la autorización inicial no vale y no se puede conectar y está en bucle. El segundo proceso que se lanza lo hace con errores similares siendo el mayor el que el puerto 5900 está ocupado así que tampoco.

De resultas de ello un usuario llamado dpellegr publicó la solución como servicio de systemd. Copio aquí a continuación el código y mantengo abajo en las referencias su dirección exacta:

[Unit]
Description=x11vnc VNC Server for X11
Requires=display-manager.service
After=display-manager.service

[Service]
Type=forking
ExecStartPre=/usr/bin/bash -c "/usr/bin/systemctl set-environment SDDMXAUTH=$(/usr/bin/find /var/run/sddm/ -type f)"
ExecStart=/usr/bin/x11vnc -display :0 -auth ${SDDMXAUTH} -ncache 10 -forever -shared -bg -o /var/log/x11vnc.log -rfbauth /etc/x11vnc.passwd -xkb -norc -noxrecord -noxdamage -nomodtweak -multiptr
ExecStop=/usr/bin/killall x11vnc
Restart=on-failure
RestartSec=2

[Install]
WantedBy=graphical.target

En ella hay dos aspectos fundamentales: el primero es que antes de arrancar el servicio obtiene el valor de la autorización para conectarse con el servidor X11 y la guarda en una variable para emplearla dentro del servicio (realmente desconocía esta opción y la verdad es que resulta muy útil). El segundo es que el servicio se reinicia sólo cuando falla esperando dos segundos antes de hacerlo. Eso significa que si x11vnc encuentra las dificultades de las que he hablado se muere y el proceso se reinicia volviendo a leer la nueva autentificación.

Y, quitando que he tenido que ajustar algunas opciones del propio x11vnc para que funcionase a mi gusto el montaje es excelente y soporta todas las condiciones de fin de sesión VNC que he podido probar.

El servicio x11vnc

Esta parte está llena de misticismos y cosas que no he llegado a entender del todo. He creado un contraseña de acceso en cada máquina, por supuesto, pero el resto de las opciones se me hace muy cuesta arriba. En general y teniendo fibra en ambas conexiones se puede decir que va bien. Carga demasiados gráficos y no he visto forma de hacer que el fondo, por ejemplo, no se transfiera como con las conexiones RDP pero no desespero de conseguir una combinación óptima.

Aún así he tenido que eliminar varias opciones que se muestran en el servicio systemd y ha quedado de la siguiente manera:

ExecStart=/usr/bin/x11vnc -display :0 -auth ${SDDMXAUTH} -forever -shared -bg -o /var/log/x11vnc.log -rfbauth /etc/x11vnc.passwd -noxdamage 

De momento usando Guacamole hay conexiones que me funcionan bien y otras que no y aún no sé por qué. Con remmina, por ejemplo, no he tenido problemas en conectar con ninguno empleando un túnel SSH dado que son máquinas internas. No es que tenga la mejor pantalla porque hay cosas que no hace bien si no es en pantalla completa pero no tengo queja tampoco.

Una muestra de lo que se ve funcionando:

Mi escritorio del trabajo desde mi escritorio de casa

Referencias