Display managers and graphical sessions

Trace login handoff and graphical session startup boundaries.

14 min readChapter 135 of 168Intermediate → advanced
In this chapter

Before you start#

Read userspace, systemd, and containers and compositors. This chapter examines GDM 46.2 and surveys SDDM 0.21.0 as a separately pinned comparison. No exercise authenticates a user, starts a display manager, switches virtual terminals, or changes a session.

Learning goals#

Separate the authority and lifetimes of a display-manager daemon, greeter, authentication worker and user session. Trace GDM's authentication and session-open failures and describe how logind, a seat, device descriptors and the user manager fit into a conditional graphical login.

Source walkthrough#

From greeter to user session
  1. Greeter

    Collects interaction under its own identity

  2. Session worker

    Runs configured authentication and opens session

  3. Session manager

    Tracks seat, authority and user session

  4. User session

    Starts selected session and later cleans up

Conceptual model. A conditional session lifecycle, not a captured authentication or login.

A display manager coordinates a graphical login and session selection. Its daemon, greeter, authentication helper and user session are distinct roles; an implementation may combine roles in processes, and their UIDs and authority vary by display manager and configuration. The greeter presents a login interface and sends interaction to the manager's authentication machinery. It does not become the user's session merely because the user entered a name. User-session execution follows the configured authentication, account, credential and session setup steps, but its later startup can still fail.

Greeter, daemon, worker and PAM
Greeter, daemon, worker and PAM1. Greeter to Daemon: username and password entered. 2. Daemon to Session worker: start worker for this conversation. 3. Session worker to PAM stack: pam_authenticate with conversation callback. 4. PAM stack to Session worker (return): module result or failure. 5. Session worker to Daemon (return): pending invocation completes or errors. 6. Daemon to Greeter (return): generic failure or next step shown.GreeterDaemonSession workerPAM stackusername andpassword enteredstart worker forthis conversationpam_authenticatewith conversationcallbackmodule result orfailurepending invocationcompletes or errorsgeneric failure ornext step shown
  1. GreeterDaemon

    username and password entered

  2. DaemonSession worker

    start worker for this conversation

  3. Session workerPAM stack

    pam_authenticate with conversation callback

  4. PAM stackSession worker

    Return. module result or failure

  5. Session workerDaemon

    Return. pending invocation completes or errors

  6. DaemonGreeter

    Return. generic failure or next step shown

Time runs downward. Dashed arrows show returns.

Read the text version
  1. Greeter → Daemon: username and password entered
  2. Daemon → Session worker: start worker for this conversation
  3. Session worker → PAM stack: pam_authenticate with conversation callback
  4. PAM stack → Session worker (return): module result or failure
  5. Session worker → Daemon (return): pending invocation completes or errors
  6. Daemon → Greeter (return): generic failure or next step shown
Conceptual model. Conceptual model of the GDM 46.2 roles described in this chapter, not a captured login; the worker is a separate process in the source model.

GDM's session worker implements a stateful conversation with PAM. PAM is a framework for configured authentication and account modules, not a single password-checking algorithm. Its conversation callback can request information from the user through the greeter, and modules can fail for many reasons. A username, authentication success, account authorization, credential establishment and an opened session are different facts. A worker must not proceed to a user session after an earlier required stage failed. See GDM 46.2 daemon/gdm-session-worker.c and session coordination.

From gdm_session_worker_authenticate_user in GDM 46.2 daemon/gdm-session-worker.c, GPL-2.0-or-later as stated in the file; setup and later error branches are omitted:

c
        error_code = pam_authenticate (worker->pam_handle, authentication_flags);

        if (error_code == PAM_AUTHINFO_UNAVAIL) {

The first statement calls PAM using the worker's current handle and selected flags. It can block while the PAM conversation runs. The second begins a specific error branch for unavailable authentication information; surrounding code turns that condition into a GDM error and unwinds. The function's caller do_authenticate completes the pending D-Bus invocation on success or transfers the error on failure, then clears its pending invocation pointer. A successful local message dispatch is therefore not evidence of successful authentication. PAM modules and policy determine the real outcome, and this source example does not authenticate anyone.

The caller is do_authenticate in the same file, daemon/gdm-session-worker.c, GDM 46.2, GPL-2.0-or-later as stated in the file (surrounding code omitted):

c
do_authenticate (GdmSessionWorker *worker)
{
        g_autoptr(GError) error = NULL;
        gboolean res;

        /* find out who the user is and ensure they are who they say they are
         */
        res = gdm_session_worker_authenticate_user (worker,
                                                    worker->password_is_required,
                                                    &error);
        if (res) {
                /* we're authenticated.  Let's make sure we've been given
                 * a valid username for the system
                 */
                if (!worker->is_program_session) {
                        g_debug ("GdmSessionWorker: trying to get updated username");
                        gdm_session_worker_update_username (worker);
                }

                gdm_dbus_worker_complete_authenticate (GDM_DBUS_WORKER (worker), worker->pending_invocation);
        } else {
                g_debug ("GdmSessionWorker: Unable to verify user");
                g_dbus_method_invocation_take_error (worker->pending_invocation,
                                                     g_steal_pointer (&error));
        }
        worker->pending_invocation = NULL;
}

Both branches clear worker->pending_invocation after completing or erroring it. The excerpt does not show the PAM calls inside gdm_session_worker_authenticate_user, so it does not show which module failed.

Session setup and cleanup

After authentication, account checks can reject a login even when credentials were accepted. Credential establishment and PAM session opening can perform additional policy and environment setup. Some PAM operations need particular privilege or identity transitions; the worker source explicitly discusses the distinction between credential setup and opening the session. A session can also fail because its virtual terminal, executable, environment, home directory, service or display backend is unavailable. Failure must be associated with the stage that failed; a generic claim that the user typed a wrong password can be misleading.

From GDM 46.2 daemon/gdm-session-worker.c, the session-opening path, GPL-2.0-or-later; the error construction after the final line is omitted:

c
        error_code = pam_open_session (worker->pam_handle, flags);

        if (error_code != PAM_SUCCESS) {

The call asks the configured PAM stack to open a session. The condition catches a non-success result; surrounding code constructs an error and goes to cleanup instead of marking the session opened. On success the worker advances its state and can record session information. pam_open_session is not equivalent to executing the desktop session. The worker's gdm_session_worker_uninitialize_pam conditionally closes an opened session, deletes established credentials as appropriate, and calls pam_end. Those steps depend on which stages were reached; cleanup must not pretend that every resource was acquired.

The cleanup function is in the same file, daemon/gdm-session-worker.c, GDM 46.2, GPL-2.0-or-later as stated in the file (surrounding code omitted):

c
static void
gdm_session_worker_uninitialize_pam (GdmSessionWorker *worker,
                                     int               status)
{
        g_debug ("GdmSessionWorker: uninitializing PAM");

        if (worker->pam_handle == NULL)
                return;

        gdm_session_worker_get_username (worker, NULL);

        if (worker->state >= GDM_SESSION_WORKER_STATE_SESSION_OPENED) {
                pam_close_session (worker->pam_handle, 0);
                gdm_session_auditor_report_logout (worker->auditor);
        } else {
                gdm_session_auditor_report_login_failure (worker->auditor,
                                                          status,
                                                          pam_strerror (worker->pam_handle, status));
        }

        if (worker->state >= GDM_SESSION_WORKER_STATE_ACCREDITED) {
                pam_setcred (worker->pam_handle, PAM_DELETE_CRED);
        }

        pam_end (worker->pam_handle, status);
        worker->pam_handle = NULL;

        gdm_session_worker_stop_auditor (worker);

        g_debug ("GdmSessionWorker: state NONE");
        gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_NONE);
}

The branches depend on the state the worker reached: pam_close_session runs only at SESSION_OPENED or later, and pam_setcred with PAM_DELETE_CRED only at ACCREDITED or later. pam_end runs whenever a handle exists. The excerpt does not show the status values passed in, so it does not show which error reached the greeter.

Stages of one GDM session worker
  1. Authenticate

    gdm_session_worker_authenticate_user calls pam_authenticate and sets AUTHENTICATED; an error stops here.

  2. Authorize

    gdm_session_worker_authorize_user calls pam_acct_mgmt for account policy.

  3. Accredit

    gdm_session_worker_accredit_user calls pam_setcred and sets ACCREDITED.

  4. Open session

    gdm_session_worker_open_session calls pam_open_session and sets SESSION_OPENED on success.

  5. Uninitialize

    Closes the PAM session only at SESSION_OPENED or later, deletes credentials at ACCREDITED or later, then pam_end.

Source map. Source map of stage order in GDM 46.2 gdm-session-worker.c, simplified to the calls and states named here; not a captured PAM run.

A PAM handle has a lifecycle, and each transition belongs to the worker that owns it. Its conversation data, environment and module state must remain valid while PAM uses them. On failure, the worker sends the appropriate result to its caller, releases pending invocation state, and uninitializes PAM according to its state. If a worker exits or the greeter disconnects while a conversation is active, the manager needs to terminate the operation and release resources. An application should not log passwords or blindly copy PAM environment values into unrelated processes. This chapter does not inspect PAM configuration, credentials or authentication logs.

Seat, session, and device handoff

A seat groups devices intended for one local interaction context, such as a display and input devices. A session is a login instance associated with a user and potentially a seat and virtual terminal. logind tracks sessions and applies configured policy; a graphical compositor or display server may obtain device access through a session-management mechanism. TakeDevice is an interface for an authorized session controller to obtain a device fd, with pause and resume notifications when ownership changes. The fd is a capability to an already opened device under the applicable rules, not a permanent promise that the device will remain usable after a session switch or device removal. See the systemd v256 logind D-Bus interface.

A compositor that receives a pause must stop or quiesce use according to the session and device API, acknowledge where required, and cope with resume or revocation. It must not assume that keeping the integer fd alone grants perpetual active-seat authority. A new fd may refer to a replacement open file description, and an old numeric fd can be reused after close. The precise behavior differs across device types, backends, logind versions and seat-management alternatives. A user session may use a nested or remote backend rather than direct DRM; not every session uses seat0, a particular VT or a physical GPU.

A virtual terminal is a kernel console abstraction, not a user identity or a compositor. Switching active VTs can trigger session and device transitions. A display manager can arrange a new VT or use another configured display mode. The source's failure path for VT setup returns an opening-session error before pam_open_session; it does not imply that all graphical sessions need the same VT path. We do not switch terminals or inspect other users' sessions.

User manager and session lifetime

A per-user systemd manager can manage user services and a user bus in configurations that use them. A graphical login session is not identical to that manager. The user manager can serve multiple sessions and can remain alive with lingering enabled after a particular graphical session ends. Conversely, user-manager startup can fail or be absent in other environments. Session targets and environment import are distribution- and desktop-specific; an environment variable in a greeter process should not be assumed to describe a later user compositor. The systemd v256 user manager documentation describes the manager and lingering relationship.

A session executable or desktop file identifies what to start after the display manager has completed required setup. A Wayland session can start a user compositor; an X11 session can start or connect to an X server and then a window manager and clients. Greeters themselves can use different display protocols from the selected session. The identity and privilege of an X server or compositor depends on the configuration, device access and platform; neither X11 nor Wayland implies one universal rootless arrangement. A session startup failure after authentication is a different problem from a failed PAM authentication.

Worked success and failure states

The following table is a synthetic state model, not a record of a login:

StageExample actorState and resource
Greeterunprivileged greeter accountPresents UI; no user desktop process yet
Authenticationsession worker under its configured authorityPAM handle and pending conversation
Session openworkerPAM session and possible session environment if successful
User executionprocess under selected user identitySession executable and inherited permitted descriptors
Teardownmanager and workerStop session, close resources, close PAM session if opened

Suppose authentication returns an unavailable-service error. The worker reports that error to the pending invocation and does not advance to account authorization or session execution. It releases the PAM handle under the worker's error path. There is no user session executable to terminate because it was never started. The greeter can display a generic failure without exposing a secret; exact wording and retry policy are implementation-specific.

In a second example, authentication and authorization succeed, but opening the requested virtual terminal fails before the PAM session opens. The worker reports a session-opening error. Any descriptor acquired before the failure must be closed by its owning path, and PAM cleanup must reflect the stages actually reached. There is no justification for calling a close operation on a resource that was never successfully opened merely to make the state table symmetrical. In a third example, the session starts and later exits; its processes, device grants and PAM session need coordinated teardown. A child process inheriting a descriptor can keep a resource alive beyond the parent's close, so close-on-exec and explicit ownership matter.

The table separates the greeter's identity from the selected user's identity. A greeter account may have limited authority to present a login screen, while the worker or daemon performs privileged setup. Their exact credentials are installation-specific. A UI message saying “starting session” is not proof that the user's session process reached a usable desktop. Process execution can succeed while a compositor later fails to connect to its backend or while user services are still starting.

A manager may also receive notification that the session child exited while teardown is already in progress. Handling the exit twice can close a descriptor that has since been reused or send a second reply to an already completed invocation. A sound design marks each owned resource as released and associates notifications with the correct session instance. A later login for the same account is a new session with its own process and lifecycle; the username alone is insufficient to identify which pending cleanup belongs to it.

Comparing GDM and SDDM

SDDM has its own daemon, greeter and helper design and commonly uses Qt in its implementation. Its 0.21.0 PAM backend provides a separate source point for comparing authentication responsibilities. This chapter surveys that file; it does not assert that SDDM has GDM's internal worker state machine or trace its full session lifecycle. Both can use PAM in an appropriate configuration, but their display-server choices, helper protocols and policy details differ.

Different systems can use other display managers, a text login followed by a manually started compositor, or remote sessions without a local greeter. A curriculum trace should identify which process owns the connection to logind, which process opens a device, who receives each fd, and which component owns a child process. The name of the desktop environment alone is not enough to reconstruct those lifetimes. Likewise, a session being registered does not prove an application has rendered or that every configured user service has started.

Failure, cleanup, and investigation boundaries

When diagnosing a failure, start with the earliest state transition for which evidence exists. A PAM authentication error belongs to a different layer than a missing compositor binary, a denied DRM device, or a failed user service. Record the stage and relevant nonsecret error without collecting passwords or another user's session data. If a device grant fails after a compositor starts, the application should release any other acquired resources and present or log an appropriate failure under its policy; it should not repeatedly change host device permissions to force the experiment.

A process can exit while another component still holds its D-Bus proxy, pid reference or device fd. Those references describe separate resources with separate release conditions. A disconnected D-Bus peer can invalidate future method calls even if a client still holds a proxy object. Conversely, a device fd can remain open while the session is inactive, but the session-management protocol may forbid using it until resume. Robust cleanup relies on state and ownership, not on a single “logged out” Boolean assumed to close every resource instantly.

Practice#

This read-only command reports only whether this process has a session-type variable; it does not query logind or enumerate users:

sh
python3 - <<'PY'
import os
value = os.environ.get('XDG_SESSION_TYPE')
print('own process session type:', value if value else '(unset)')
PY

A value such as wayland, x11, or an unset value describes this process's inherited environment, not proof of the active display server or login manager. SSH and headless environments commonly have no useful value. The source-only alternative is the state table above: in the unavailable-authentication case, identify the PAM handle and pending invocation, then explain why there is no session executable to terminate. For the VT-failure case, identify whether PAM session-open was reached. Deliver both paths and their cleanup owners. No real authentication attempt is required.

Knowledge check#

  1. Why is a successful PAM authentication not the same as a running desktop?
  2. What happens in the shown GDM path when pam_open_session fails?
  3. Does a greeter necessarily run as the selected user?
  4. What does a logind device fd fail to guarantee after a pause?
  5. Can a user manager outlive one graphical session?

Answers#

  1. Authorization, credential setup, session opening, process execution and compositor startup are separate stages with their own errors.
  2. The worker constructs an opening-session error and enters cleanup instead of setting the opened state. Cleanup depends on resources actually acquired.
  3. No. The greeter and selected user's session are separate roles and commonly have distinct identities; exact credentials depend on configuration.
  4. It does not guarantee the session remains authorized to use the device while inactive or that the device still exists. The controller must follow pause and resume rules.
  5. Yes. Multiple sessions or lingering can keep a user manager running; this depends on the system's configuration.

Checkpoint#

Submit the authentication-failure and VT-failure state tables, including owners of the PAM handle, invocation and acquired fds. Pass when neither case claims that a user desktop started and cleanup is conditional on acquisition. If not, reread the worker's authentication, open and uninitialize paths. This is practice, not certification.

Sources#

Read GDM session worker, GDM session coordination, SDDM PAM backend, and systemd logind interface. These separate versions are not a tested login stack.

A little further beneath the surface.

Check your understanding with the checkpoint. Marking a chapter as read saves a bookmark, not a proficiency assessment.