Headless remote sessions in GNOME, Part 2

Share
Share

With that basic proof of concept established, see Part 1, the focus shifted to developing a more robust and user-friendly solution, leading to architectural changes and two new daemons.

 

Two new gnome-remote-desktop daemons

The overview idea of the approach would be: an RDP client connects to the remote system and gets a GDM login screen; authenticates; and gets its GNOME session; everything happens headlessly.

Originally the gnome-remote-desktop was a daemon running at the same user session as mutter; it communicates with mutter through dbus and provides remote desktop access through RDP. With the new approach, two new daemons with different responsibilities were needed. The first one will be running as a system service and won’t communicate with any mutter, it won’t display any desktop. It will just listen on the RDP port and when a new RDP connection appears, it will hand over the RDP connection to a different gnome-remote-desktop daemon which will be running on a headless GDM login screen. This different daemon is the other new daemon, this one communicates with a headless mutter but the RDP connection is obtained from the system-daemon, not from the RDP port. The first one is called system-daemon and the latter handover-daemon.

The communication between the system-daemon and the different handover-daemons (multiple headless sessions can coexist) happens through the system dbus. The system-daemon exposes one interface org.gnome.RemoteDesktop.Rdp.Dispatcher, which will be used by all the handover-daemons to request if they have an RDP client waiting to be handed over. That request, if it’s positive, returns the dbus object path of the other dbus interface: org.gnome.RemoteDesktop.Rdp.Handover, this one has the methods and signals to sync and send the RDP client from one gnome-remote-desktop daemon to another.

To manage all RDP clients the system-daemon stores the clients’ info in a list. Each client is identified with a unique remote_id. This remote_id is important because it will be used in the RDP protocol to hand over the client between two daemons.

 

Connecting gnome-remote-desktop with GDM

When a new RDP client connects to the system-daemon, the system-daemon communicates with GDM to request the creation of a headless login screen. This is done by GDM exposing a new dbus interface org.gnome.DisplayManager.RemoteDisplayFactory with only one method: CreateRemoteDisplay. The system-daemon calls this method and sets the remote_id as a parameter to identify the RDP client which should go to that remote display. When the new headless login session is created, GDM will expose a new dbus interface org.gnome.DisplayManager.RemoteDisplay with the remote_id and session_id as properties. The system-daemon is watching GDM dbus looking for a new RemoteDisplay dbus interface with that remote_id that identifies the waiting RDP client. When that is found, the system-daemon exports a handover dbus interface using an object path generated with the session_id. That handover interface will be used by the handover-daemon running on the headless login session to get the RDP client.

The headless sessions created by GDM are started with a handover-daemon automatically. This is done thanks to a change at gnome-settings-daemon which will start the handover-daemon when two conditions are met: the session is remote and the system-daemon is running. In the future, it is desired to add to systemd a feature that allows a user service to depend on a system service, i.e. when the system service is started, the user service will be started too. That would cover this kind of “automatic start” instead of relying on a specific GNOME solution.

 

The ServerRedirection method

All this solution is based on RDP because it is the new default on gnome-remote-desktop, but more importantly because the RDP protocol has the ServerRedirection method. This method allows an RDP client to be redirected to a different RDP server. This fits perfectly in the design of GNOME to support headless remote sessions because the RDP client must be “redirected” to different RDP servers (gnome-remote-desktop daemons): from the system-daemon to the daemon at the login session.

This special method starts at the server sending the ServerRedirection message to the client. This message has some data the client needs for the redirection. The most important data and the one gnome-remote-desktop uses on the handover are: a routing token, a certificate, a username and a password.

The routing token is a unique identifier of the RDP client connection, the previously mentioned remote_id is used as this routing token. The username and password are randomly generated to be different each time a redirection happens, so security is increased, these are the credentials the RDP client will use to authenticate against the destination server. The certificate is an X.509 certificate which adds another layer of security; it will be used by the RDP client to verify the destination server identity.

When the server sends the ServerRedirection message to the client, the client disconnects and reconnects. The system-daemon gets this new connection from the client. This time the first bytes sent by the client hold the routing token. The system-daemon always peeks those bytes to see if the client is new or if it has a routing token. As mentioned earlier, the routing token is the remote_id. The way a remote_id is related to a handover-daemon is from the RemoteDisplay dbus interface exported by GDM which has that remote_id and the session_id. For that RemoteDisplay, the system-daemon has a Handover dbus interface exported to communicate with the handover-daemon of that session. So the system-daemon uses that Handover interface to inform the handover-daemon of the new RDP client. The handover-daemon gets that connection through this dbus interface. Then the RDP client authenticates using those one-time credentials and verifies the server with the certificate; when everything succeeds the RDP client will be displaying that session.

The diagram below shows how the RDP client, GDM, the headless session and the daemons are connected through dbus.

 

FreeRDP supported the ServerRedirection on the client side, however, some contributions were required to make it support the ServerRedirection on the server side to allow the gnome-remote-desktop daemon to send it.

The next part will focus on what happens after authentication. How the system-daemon communicates using dbus with different handover-daemons to pass the RDP client from one daemon to another.

Share
(Visited 1 times, 1 visits today)