Blog
VNC + Ubuntu 22.04
Date: 3/5/2024
Tags: linux remote-desktop
My local Linux server is Intel Nuc running Ubuntu. A few months ago I upgraded from 18.04 to 22.04, seemed like a reasonable thing to do. In the process I lost the ability to vnc into the server and use the desktop graphically. Originally I was using this command to run the vnc server:

tigervncserver -geometry 2400x1350 -depth 24 -localhost no :1

Worked wonderfully on 18.04. Not so much on 22.04, something to do with the gnome session not starting up after the VNC connection was established. I spent hours and hours over the course of the last few months trying to debug that. But got nowhere. The logs didn't give me anything useful, and my google searches for various errors were all dead ends. Then I had some success with using the built in gnome-remote-desktop features (accessed from the main settings app's sharing -> remote desktop -> ...) on my 22.04 machine at work. So I thought today... "I'll try that!".

It did not go well.

Firstly after enabling it and attempting to connect all I got was a hung connection. No window appeared on the client end (Windows 10). I knew it was running because I checked it was listening on the right port:

matthew@nuc:~$ sudo lsof -i -P -n | grep 5900
gnome-rem 22207         matthew   10u  IPv6 249744      0t0  TCP *:5900 (LISTEN)

Nice, good to know. But what is 'gnome-rem'?

matthew@nuc:~$ ps -A | grep gnome-rem
  22207 ?        00:01:11 gnome-remote-de

Ha, slightly more info.

matthew@nuc:~$ ps -fp 22207
UID          PID    PPID  C STIME TTY          TIME CMD
matthew    22207    1075  6 11:11 ?        00:01:11 /usr/libexec/gnome-remote-desktop-daemon

Ah, so what is 'gnome-remote-desktop-daemon' anyway?

matthew@nuc:~$ dpkg -S /usr/libexec/gnome-remote-desktop-daemon
gnome-remote-desktop: /usr/libexec/gnome-remote-desktop-daemon

Ok so the 'gnome-remote-desktop' package is what's providing the actual functionality. So what else is in that package?

matthew@nuc:~$ dpkg -L gnome-remote-desktop
/.
/usr
/usr/bin
/usr/bin/grdctl
/usr/lib
/usr/lib/systemd
/usr/lib/systemd/user
/usr/lib/systemd/user/gnome-remote-desktop.service
/usr/libexec
/usr/libexec/gnome-remote-desktop-daemon
/usr/share
/usr/share/doc
/usr/share/doc/gnome-remote-desktop
/usr/share/doc/gnome-remote-desktop/changelog.Debian.gz
/usr/share/doc/gnome-remote-desktop/copyright
/usr/share/glib-2.0
/usr/share/glib-2.0/schemas
/usr/share/glib-2.0/schemas/org.gnome.desktop.remote-desktop.enums.xml
/usr/share/glib-2.0/schemas/org.gnome.desktop.remote-desktop.gschema.xml
/usr/share/gnome-remote-desktop
/usr/share/gnome-remote-desktop/grd-cuda-avc-utils_30.ptx
/usr/share/gnome-remote-desktop/grd-cuda-damage-utils_30.ptx

Alright... hmmm, grdctl? What is that?

matthew@nuc:~$ grdctl --help
Usage: grdctl [OPTIONS...] COMMAND [SUBCOMMAND]...
Commands:
  rdp                                        - RDP subcommands:
    enable                                   - Enable the RDP backend
    disable                                  - Disable the RDP backend
    set-tls-cert               - Set path to TLS certificate
    set-tls-key                 - Set path to TLS key
    set-credentials      - Set username and password
                                               credentials
    clear-credentials                        - Clear username and password
                                               credentials
    enable-view-only                         - Disable remote control of input
                                               devices
    disable-view-only                        - Enable remote control of input
                                               devices

  vnc                                        - VNC subcommands:
    enable                                   - Enable the VNC backend
    disable                                  - Disable the VNC backend
    set-password                   - Set the VNC password
    clear-password                           - Clear the VNC password
    set-auth-method password|prompt          - Set the authorization method
    enable-view-only                         - Disable remote control of input
                                               devices
    disable-view-only                        - Enable remote control of input
                                               devices

  status [--show-credentials]                - Show current status

Options:
  --help                                     - Print this help text

At this point I played around with the vnc settings, setting a password... trying the set-auth-method options etc. Not much changed. So I thought well... it's "Open Source" right? I could like... GET the source and have a look right?

matthew@nuc:~$ /usr/libexec/gnome-remote-desktop-daemon --version
GNOME Remote Desktop 42.9

Ok, googled the source archive for that and got this. Download and unpacked that onto the nuc server and had a look. Fairly standard meson package... nice.

So I mkdir'd a build folder and installed meson. It complained there were many missing libraries. So I worked my way through them all, using apt-cache to find the -dev lib and apt install'ed each of them. Finally I could build gnome-remote-desktop locally.

From the build folder I found an x64 binary: ./src/gnome-remote-desktop-daemon

Perfect. Ok, lets stop the system one:

systemctl --user stop gnome-remote-desktop

And to make seeing the logging easy I decided to co-opt the logging to just printf to the screen. So in src/grd-daemon.c, the main function, I added:

g_log_set_default_handler(printf_log, NULL);

Where 'printf_log' is defined as:

void printf_log(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
{
  printf("%s:%i:%s\n", log_domain?log_domain:"-none-", log_level, message);
}

Super simple, but makes all the logging way easier to see. Now that that works. I ran ./src/gnome-remote-desktop-daemon and tried to connect.

Still no joy. But I was getting a 'New VNC client' in the logging. So kinda hopeful right? Well I greped the code and found the 'handle_new_client' function. Nice, it seems to get the auth method and handle it. First things first, lets log the auth method so I know what we're dealing with. It was GRD_VNC_AUTH_METHOD_PROMPT. Ok. Well what if we tried GRD_VNC_AUTH_METHOD_PASSWORD? How do I change that? Well... remember that grdctl tool?

grdctl vnc set-auth-method password

Run it again... and this time the client asks for a password! Hurrah... seems like I'm making progress. However once the password is entered the client says "unexpected error". So where are the credentials checked? check_rfb_password seems like it does that. And reading through that found:

memcmp (challenge_encrypted, response_encrypted, len)

I added some logging and checked the result... and? It's ok! The password checks out as correct. But yet... the client complains. Interesting. Something in the logging caught my attention:

-none-:16:Failed to record monitor: GDBus.Error:org.freedesktop.DBus.Error.Failed: Unknown monitor

A little googling of that error resulted in finding some forum posts about how the backend doesn't want to function on a headless machine. Which is not great, but at least I could try plugging a monitor in. So I grabbed a long HDMI cable and plugged it into my PC monitor's second port... just so it's attached to _something_ rather than nothing.

Tried to reconnect and .... SUCCESS! A remote desktop!



I have bought a little HDMI display emulator to trick it into thinking there is a monitor. And maybe someday it'll run headless properly... but I think for the moment I'm just happy it works at all. Open source is great... and a pain all at the same time. I doubt I'd even have this trouble with Windows or Mac. It does just seem to work out of the box a little better.
(0) Comments | Add Comment