call_end

    • chevron_right

      Joan Torres López: Remote Login Design

      news.movim.eu / PlanetGnome • 23 December 2025 • 3 minutes

    GNOME 46 introduced remote login. This post explores the architecture primarily through diagrams and tables for a clearer understanding.

    Components overview


    There are 4 components involved: the remote client, the GRD dispatcher daemon, the GRD handover daemon and the GDM daemon:

    Component Type Responsibility
    Remote Client Remote User Connects remotely via RDP. Supports RDP Server Redirection method.
    Dispatcher GRD System-level daemon Handles initial connections, peeks routing token and orchestrates handovers.
    Handover GRD User-level daemon Runs inside sessions (Greeter or User). Provides remote access of the session to the remote client.
    GDM GDM System-level daemon Manages Displays and Sessions (Greeter or User).

    API Overview


    The components communicate with each other through dbus interfaces:

    Exposed by GDM

    org.gnome.DisplayManager.RemoteDisplayFactory

        • Method CreateRemoteDisplay
          Requests GDM to start a headless greeter. Accepts a RemoteId argument.

    org.gnome.DisplayManager.RemoteDisplay

      • Property RemoteId
        The unique ID generated by the Dispatcher.
      • Property SessionId
        The session ID of the created session wrapped by this display.

    Exposed by GRD Dispatcher

    org.gnome.RemoteDesktop.Dispatcher

      • Method RequestHandover
        Returns the object path of the Handover interface matching the caller’s session ID.

    org.gnome.RemoteDesktop.Handover

    Dynamically created. One for each remote session.

      • Method StartHandover
        Initiates the handover process. Receives one-time username/password, returns certificate and key used by dispatcher.
      • Method TakeClient
        Gives the file descriptor of the remote client’s connection to the caller.
      • Signal TakeClientReady
        Informs that a file descriptor is ready to be taken.
      • Signal RedirectClient
        Instructs the source session to redirect the remote client to the destination session.

    Flow Overview


    Flow phase 1: Initial connection to greeter session

    1. Connection:

      • Dispatcher receives a new connection from a Remote Client . Peeks the first bytes and doesn’t find a routing token. This means this is a new connection.

    2. Authentication:

      • Dispatcher authenticates the Remote Client using system level credentials.

    3. Session Request:

      • Dispatcher generates a unique remote_id (also known as routing token), and calls CreateRemoteDisplay() on GDM with this remote_id .

    4. Registration:

      • GDM starts a headless greeter session.
      • GDM exposes RemoteDisplay object with RemoteId and SessionId .
      • Dispatcher detects new object. Matches RemoteId . Creates Handover D-Bus interface for this SessionId .

    5. Handover Setup:

      • Handover is started in the headless greeter session.
      • Handover calls RequestHandover() to get its D-Bus object path with the Handover interface.
      • Handover calls StartHandover() with autogenerated one-time credentials. Gets from that call the certificate and key (to be used when Remote Client connects).

    6. Redirection (The “Handover”):

      • Dispatcher performs RDP Server Redirection sending the one-time credentials, routing token ( remote_id ) and certificate.
      • Remote Client disconnects and reconnects.
      • Dispatcher peeks bytes; finds valid routing token.
      • Dispatcher emits TakeClientReady on the Handover interface.

    7. Finalization:

      • Handover calls TakeClient() and gets the file descriptor of the Remote Client ‘s connection.
      • Remote Client is connected to the headless greeter session.

    Flow phase 2: Session transition (from greeter to user)

    1. Session Creation:

      • User authenticates.
      • GDM starts a headless user session.

    2. Registration:

      • GDM exposes a new RemoteDisplay with the same RemoteId and a new SessionId .
      • Dispatcher detects a RemoteId collision.
      • State Update: Dispatcher creates a new Handover D-Bus interface ( dst ) to be used by the New Handover in the headless user session.
      • The Existing Handover remains connected to its original Handover interface ( src ).

    3. Handover Setup:

      • New Handover is started in the headless user session.
      • New Handover calls RequestHandover() to obtain its D-Bus object path with the Handover interface.
      • New Handover calls StartHandover() with new one-time credentials and receives the certificate and key.

    4. Redirection Chain:

      • Dispatcher receives StartHandover() from dst .
      • Dispatcher emits RedirectClient on src (headless greeter session) with the new one-time credentials.
      • Existing Handover receives the signal and performs RDP Server Redirection.

    5. Reconnection:

      • Remote Client disconnects and reconnects.
      • Dispatcher peeks bytes and finds a valid routing token ( remote_id ).
      • Dispatcher resolves the remote_id to the destination Handover ( dst ).
      • Dispatcher emits TakeClientReady on dst .

    6. Finalization:

      • New Handover calls TakeClient() and receives the file descriptor of the Remote Client ‘s connection.
      • Remote Client is connected to the headless user session.

    Disclaimer

    Please note that while this post outlines the basic architectural structure and logic, it may not guarantee a 100% match with the actual implementation at any given time. The codebase is subject to ongoing refactoring and potential improvements.