Headless remote sessions in GNOME, Part 3

Share
Share

From login session to user session

It’s been explained how when an RDP client connects the system-daemon handles creating a headless login session with a handover-daemon, and then hands over the RDP client from the system-daemon to the handover-daemon using the ServerRedirection method and the Handover dbus interface (see Part 2).

Then the user authenticates through GDM to open its session but… With Xorg, the GDM login session and the opened user session would run on the same Xorg server, so there wasn’t required any transition. This doesn’t happen due to the more secure design of Wayland. A new session uses a new Wayland compositor (mutter) and a new handover-daemon. This adds more complexity to using a headless user session. The decided solution was to do again a ServerRedirection but now instead of from the system-daemon to the handover-daemon on the login session, it would be from the handover-daemon on the login session to the handover-daemon on the user session.

The RDP client is at the handover-daemon connected at the login session, and that handover-daemon communicates with the system-daemon through the Handover interface, let’s call it destination interface because it was the last destination of the RDP client. 

After authentication, GDM creates a new headless user session and exports again a new RemoteDisplay interface with the same remote_id and its session_id. The system-daemon finds out this new RemoteDisplay is created, so it creates a Handover interface with the session_id of that RemoteDisplay. It finds out that for that remote_id there was already a Handover interface, the destination interface; but now a new Handover interface has appeared, the new Handover interface will be the destination interface, and the old Handover interface will be the source interface.

The next diagram shows how a handover is done between two handover-daemons. How GDM has the two RemoteDisplay interfaces and how the system-daemon exports two Handover interfaces, src and dst, to communicate with the handover-daemons at login and user sessions.

The system-daemon has to communicate with the two handover-daemons connected to the source and destination interfaces to handle the handover. The steps are: the handover-daemon at the user session tells the system-daemon to start the handover and sends its one-time credentials; the system-daemon tells the handover-daemon at the login session to start the redirection and sends those one-time credentials and the remote_id; that handover-daemon sends to its RDP client the ServerRedirection PDU with those one-time credentials, the remote_id as the routing token, and its certificate; the RDP client disconnects and reconnects sending that routing token on its first bytes; the system-daemon peeks those bytes, finds the routing token and finds that it has for that remote_id a Handover dbus interface as destination, so on that dbus interface informs that there is an RDP client; the handover-daemon at the user session receives that and gets the RDP client; the RDP client verifies the identity, authenticates and displays the user session. One missing detail: all handover-daemons get the certificate and key from the system-daemon on the first call to start the handover.

Below there’s a diagram showing the steps the RDP client does from connecting for the first time to the system-daemon until displaying the user session. In step 1 the client connects for the first time to the system-daemon. Steps 2 and 3 are the first ServerRedirection, from system-daemon to login session. Steps 4 and 5 are the second ServerRedirection, from login session to user session. Between 1 and 2 the system-daemon requests GDM to create a headless login session. Between 3 and 4 the user authenticates and GDM creates a headless user session.

Making Windows client work

Testing this with the official Microsoft RDP client, mstsc, is interesting because on one side, it allows to use Linux on Windows, and on the other side, the RDP protocol is developed by Microsoft so the client mstsc should be the best candidate for test if the approach fits with the protocol.

Spoiler: mstsc didn’t work well. 

The ServerRedirection is sent, and the mstsc client disconnects and reconnects again. Then it uses the first credentials used to authenticate against the system-daemon, the ones the user inserted, instead of the one-time credentials sent from the ServerRedirection. That made the client fail authentication and drop the connection.

The RDP protocol has different authentication methods. The default authentication and the one FreeRDP supported was called NLA (Network Level Authentication). However, when a server redirection happens, a new security method can be used called RDSTLS. This security method uses some properties from the ServerRedirection to authenticate the client and then continues establishing a TLS connection.

It was thought that maybe mstsc used the old credentials when using NLA, and it would use the credentials from the ServerRedirection if RDSTLS is used. So more contributions were made to FreeRDP to support the RDSTLS security method. After having that implemented, testing again with mstsc telling it to use RDSTLS was a success and the one-time credentials were used. Now, you can have a secure connection using ServerRedirection and FreeRDP (through gnome-remote-desktop).

One important detail is that by default mstsc won’t use RDSTLS, and you have to manually save an .rdp file configuration and add to it the line: use redirection server name:i:1.

Some work was done on gnome-remote-desktop to make mstsc work ‘out of the box’. The RDP server detects when the client is mstsc. In that case, when NLA security is used, the RDP server will use the first credentials, and when RDSTLS security is used, the one-time credentials will be used. 

TL;DR, it is always recommended to have use redirection server name:i:1 on the .rdp file configuration to have a more secure connection.

 

Next steps

This first solution landed in GNOME 46, it didn’t support persistent sessions, so when the RDP client disconnects, the session is automatically logged out. With GNOME 47, persistent sessions are supported and you can disconnect and reconnect as much as you like without automatically logging out. 

However, if the session was already opened on a physical display, meaning it’s headful, then you won’t be able to access it remotely. You will get a dialog telling you that accessing it remotely is incompatible and allowing you to force kill it to start the session again, losing the previous state. The same goes for the opposite way, from headless to headful.

In the future, it is intended to have hybrid sessions. That means that you could log in remotely to a headful session and it would transform transparently to headless returning the physical display to the login screen. And the opposite way, from headless to headful too, closing the remote connection.

 

That’s the summary of the work done to make GNOME provide the first remote headless session support for Wayland. I hope you can find it useful. If you want to use it, you can configure this system service with the tool grdctl –system rdp <set-credentials, set-tls-cert, set-tls-key, enable>, or directly accessing the GNOME settings -> System -> Remote Desktop -> Remote Login. The latter is easier because it automatically generates the cert/key.

Share
(Visited 1 times, 1 visits today)