]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
pam_systemd: split pam_sm_open_session() into more digestable blocks
authorLennart Poettering <lennart@poettering.net>
Fri, 15 Nov 2024 13:25:59 +0000 (14:25 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 17 Dec 2024 16:52:18 +0000 (17:52 +0100)
Let's separate four different parts of pam_sm_open_session():

1. Acquiring of our various parameters from pam env, pam data, pam items
2. Mangling of that data to clean it up
3. Registering of the service with logind
4. Importing shell credentials into environment variables
5. Enforcement of user record data

This makes the code a lot more readable, and gets rid of an ugly goto
label.

It also corrects things: if step 3 doesnt work because logind is not
around, we'll now still do step 4, which we previously erroneously
skipped.

Besides that no real code changes.

src/login/pam_systemd.c

index b9b257df00ec23f4b92d2008a2786443390d36c3..247167a573bb88bdf935156c0084bd0c9028d0da 100644 (file)
@@ -851,10 +851,10 @@ typedef struct SessionContext {
         const char *class;
         const char *desktop;
         const char *seat;
-        const uint32_t vtnr;
+        uint32_t vtnr;
         const char *tty;
         const char *display;
-        const bool remote;
+        bool remote;
         const char *remote_user;
         const char *remote_host;
         const char *memory_max;
@@ -862,6 +862,7 @@ typedef struct SessionContext {
         const char *cpu_weight;
         const char *io_weight;
         const char *runtime_max_sec;
+        bool incomplete;
 } SessionContext;
 
 static int create_session_message(
@@ -948,180 +949,111 @@ static int create_session_message(
         return 0;
 }
 
-static int import_shell_credentials(pam_handle_t *handle) {
-
-        static const char *const propagate[] = {
-                "shell.prompt.prefix", "SHELL_PROMPT_PREFIX",
-                "shell.prompt.suffix", "SHELL_PROMPT_SUFFIX",
-                "shell.welcome",       "SHELL_WELCOME",
-                NULL
-        };
-        int r;
-
-        assert(handle);
-
-        STRV_FOREACH_PAIR(k, v, propagate) {
-                r = propagate_credential_to_environment(handle, *k, *v);
-                if (r != PAM_SUCCESS)
-                        return r;
-        }
-
-        return PAM_SUCCESS;
-}
-
-_public_ PAM_EXTERN int pam_sm_open_session(
+static void session_context_mangle(
                 pam_handle_t *handle,
-                int flags,
-                int argc, const char **argv) {
-
-        /* Let's release the D-Bus connection once this function exits, after all the session might live
-         * quite a long time, and we are not going to process the bus connection in that time, so let's
-         * better close before the daemon kicks us off because we are not processing anything. */
-        _cleanup_(pam_bus_data_disconnectp) PamBusData *d = NULL;
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
-        const char
-                *id, *object_path, *runtime_path,
-                *service = NULL,
-                *tty = NULL, *display = NULL,
-                *remote_user = NULL, *remote_host = NULL,
-                *seat = NULL,
-                *type = NULL, *class = NULL,
-                *class_pam = NULL, *type_pam = NULL, *desktop = NULL, *desktop_pam = NULL,
-                *memory_max = NULL, *tasks_max = NULL, *cpu_weight = NULL, *io_weight = NULL, *runtime_max_sec = NULL;
-        uint64_t default_capability_bounding_set = UINT64_MAX, default_capability_ambient_set = UINT64_MAX;
-        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
-        _cleanup_(user_record_unrefp) UserRecord *ur = NULL;
-        int session_fd = -EBADF, existing, r;
-        bool debug = false, remote, incomplete;
-        uint32_t vtnr = 0;
-        uid_t original_uid;
+                SessionContext *c,
+                UserRecord *ur,
+                bool debug) {
 
         assert(handle);
+        assert(c);
+        assert(ur);
 
-        pam_log_setup();
-
-        if (parse_argv(handle,
-                       argc, argv,
-                       &class_pam,
-                       &type_pam,
-                       &desktop_pam,
-                       &debug,
-                       &default_capability_bounding_set,
-                       &default_capability_ambient_set) < 0)
-                return PAM_SESSION_ERR;
-
-        pam_debug_syslog(handle, debug, "pam-systemd initializing");
-
-        r = acquire_user_record(handle, &ur);
-        if (r != PAM_SUCCESS)
-                return r;
-
-        /* Make most of this a NOP on non-logind systems */
-        if (!logind_running())
-                goto success;
-
-        r = pam_get_item_many(
-                        handle,
-                        PAM_SERVICE, &service,
-                        PAM_XDISPLAY, &display,
-                        PAM_TTY, &tty,
-                        PAM_RUSER, &remote_user,
-                        PAM_RHOST, &remote_host);
-        if (r != PAM_SUCCESS)
-                return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM items: @PAMERR@");
-
-        seat = getenv_harder(handle, "XDG_SEAT", NULL);
-        vtnr = getenv_harder_uint32(handle, "XDG_VTNR", 0);
-        type = getenv_harder(handle, "XDG_SESSION_TYPE", type_pam);
-        class = getenv_harder(handle, "XDG_SESSION_CLASS", class_pam);
-        desktop = getenv_harder(handle, "XDG_SESSION_DESKTOP", desktop_pam);
-        incomplete = getenv_harder_bool(handle, "XDG_SESSION_INCOMPLETE", false);
-
-        if (streq_ptr(service, "systemd-user")) {
+        if (streq_ptr(c->service, "systemd-user")) {
                 /* If we detect that we are running in the "systemd-user" PAM stack, then let's patch the class to
                  * 'manager' if not set, simply for robustness reasons. */
-                type = "unspecified";
-                class = IN_SET(user_record_disposition(ur), USER_INTRINSIC, USER_SYSTEM, USER_DYNAMIC) ?
+                c->type = "unspecified";
+                c->class = IN_SET(user_record_disposition(ur), USER_INTRINSIC, USER_SYSTEM, USER_DYNAMIC) ?
                         "manager-early" : "manager";
-                tty = NULL;
+                c->tty = NULL;
 
-        } else if (tty && strchr(tty, ':')) {
+        } else if (c->tty && strchr(c->tty, ':')) {
                 /* A tty with a colon is usually an X11 display, placed there to show up in utmp. We rearrange things
                  * and don't pretend that an X display was a tty. */
-                if (isempty(display))
-                        display = tty;
-                tty = NULL;
+                if (isempty(c->display))
+                        c->display = c->tty;
+                c->tty = NULL;
 
-        } else if (streq_ptr(tty, "cron")) {
+        } else if (streq_ptr(c->tty, "cron")) {
                 /* cron is setting PAM_TTY to "cron" for some reason (the commit carries no information why, but
                  * probably because it wants to set it to something as pam_time/pam_access/… require PAM_TTY to be set
                  * (as they otherwise even try to update it!) — but cron doesn't actually allocate a TTY for its forked
                  * off processes.) */
-                type = "unspecified";
-                class = "background";
-                tty = NULL;
+                c->type = "unspecified";
+                c->class = "background";
+                c->tty = NULL;
 
-        } else if (streq_ptr(tty, "ssh")) {
+        } else if (streq_ptr(c->tty, "ssh")) {
                 /* ssh has been setting PAM_TTY to "ssh" (for the same reason as cron does this, see above. For further
                  * details look for "PAM_TTY_KLUDGE" in the openssh sources). */
-                type = "tty";
-                class = "user";
-                tty = NULL; /* This one is particularly sad, as this means that ssh sessions — even though usually
-                             * associated with a pty — won't be tracked by their tty in logind. This is because ssh
-                             * does the PAM session registration early for new connections, and registers a pty only
-                             * much later (this is because it doesn't know yet if it needs one at all, as whether to
-                             * register a pty or not is negotiated much later in the protocol). */
-
-        } else if (tty)
+                c->type = "tty";
+                c->class = "user";
+                c->tty = NULL; /* This one is particularly sad, as this means that ssh sessions — even though
+                               * usually associated with a pty — won't be tracked by their tty in
+                               * logind. This is because ssh does the PAM session registration early for new
+                               * connections, and registers a pty only much later (this is because it doesn't
+                               * know yet if it needs one at all, as whether to register a pty or not is
+                               * negotiated much later in the protocol). */
+
+        } else if (c->tty)
                 /* Chop off leading /dev prefix that some clients specify, but others do not. */
-                tty = skip_dev_prefix(tty);
+                c->tty = skip_dev_prefix(c->tty);
 
-        if (!isempty(display) && !vtnr) {
-                if (isempty(seat))
-                        (void) get_seat_from_display(display, &seat, &vtnr);
-                else if (streq(seat, "seat0"))
-                        (void) get_seat_from_display(display, NULL, &vtnr);
+        if (!isempty(c->display) && !c->vtnr) {
+                if (isempty(c->seat))
+                        (void) get_seat_from_display(c->display, &c->seat, &c->vtnr);
+                else if (streq(c->seat, "seat0"))
+                        (void) get_seat_from_display(c->display, /* seat= */ NULL, &c->vtnr);
         }
 
-        if (seat && !streq(seat, "seat0") && vtnr != 0) {
-                pam_debug_syslog(handle, debug, "Ignoring vtnr %"PRIu32" for %s which is not seat0", vtnr, seat);
-                vtnr = 0;
+        if (c->seat && !streq(c->seat, "seat0") && c->vtnr != 0) {
+                pam_debug_syslog(handle, debug, "Ignoring vtnr %"PRIu32" for %s which is not seat0", c->vtnr, c->seat);
+                c->vtnr = 0;
         }
 
-        if (isempty(type))
-                type = !isempty(display) ? "x11" :
-                           !isempty(tty) ? "tty" : "unspecified";
+        if (isempty(c->type))
+                c->type = !isempty(c->display) ? "x11" :
+                              !isempty(c->tty) ? "tty" : "unspecified";
 
-        if (isempty(class))
-                class = streq(type, "unspecified") ? "background" :
+        if (isempty(c->class))
+                c->class = streq(c->type, "unspecified") ? "background" :
                         ((IN_SET(user_record_disposition(ur), USER_INTRINSIC, USER_SYSTEM, USER_DYNAMIC) &&
-                         streq(type, "tty")) ? "user-early" : "user");
+                         streq(c->type, "tty")) ? "user-early" : "user");
 
-        if (incomplete) {
-                if (streq(class, "user"))
-                        class = "user-incomplete";
+        if (c->incomplete) {
+                if (streq(c->class, "user"))
+                        c->class = "user-incomplete";
                 else
-                        pam_syslog_pam_error(handle, LOG_WARNING, 0, "PAM session of class '%s' is incomplete, which is not supported, ignoring.", class);
+                        pam_syslog_pam_error(handle, LOG_WARNING, 0, "PAM session of class '%s' is incomplete, which is not supported, ignoring.", c->class);
         }
 
-        remote = !isempty(remote_host) && !is_localhost(remote_host);
+        c->remote = !isempty(c->remote_host) && !is_localhost(c->remote_host);
+}
 
-        r = pam_get_data(handle, "systemd.memory_max", (const void **)&memory_max);
-        if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
-                return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM systemd.memory_max data: @PAMERR@");
-        r = pam_get_data(handle, "systemd.tasks_max",  (const void **)&tasks_max);
-        if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
-                return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM systemd.tasks_max data: @PAMERR@");
-        r = pam_get_data(handle, "systemd.cpu_weight", (const void **)&cpu_weight);
-        if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
-                return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM systemd.cpu_weight data: @PAMERR@");
-        r = pam_get_data(handle, "systemd.io_weight",  (const void **)&io_weight);
-        if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
-                return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM systemd.io_weight data: @PAMERR@");
-        r = pam_get_data(handle, "systemd.runtime_max_sec", (const void **)&runtime_max_sec);
-        if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
-                return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM systemd.runtime_max_sec data: @PAMERR@");
+static int register_session(
+                pam_handle_t *handle,
+                SessionContext *c,
+                UserRecord *ur,
+                bool debug,
+                char **ret_seat) {
+
+        /* Let's release the D-Bus connection once this function exits, after all the session might live
+         * quite a long time, and we are not going to process the bus connection in that time, so let's
+         * better close before the daemon kicks us off because we are not processing anything. */
+        _cleanup_(pam_bus_data_disconnectp) PamBusData *d = NULL;
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+        int r;
+
+        assert(handle);
+        assert(c);
+        assert(ur);
+        assert(ret_seat);
+
+        /* Make most of this a NOP on non-logind systems */
+        if (!logind_running())
+                goto skip;
 
         /* Talk to logind over the message bus */
         r = pam_acquire_bus_connection(handle, "pam-systemd", debug, &bus, &d);
@@ -1132,40 +1064,22 @@ _public_ PAM_EXTERN int pam_sm_open_session(
                          "Asking logind to create session: "
                          "uid="UID_FMT" pid="PID_FMT" service=%s type=%s class=%s desktop=%s seat=%s vtnr=%"PRIu32" tty=%s display=%s remote=%s remote_user=%s remote_host=%s",
                          ur->uid, getpid_cached(),
-                         strempty(service),
-                         type, class, strempty(desktop),
-                         strempty(seat), vtnr, strempty(tty), strempty(display),
-                         yes_no(remote), strempty(remote_user), strempty(remote_host));
+                         strempty(c->service),
+                         c->type, c->class, strempty(c->desktop),
+                         strempty(c->seat), c->vtnr, strempty(c->tty), strempty(c->display),
+                         yes_no(c->remote), strempty(c->remote_user), strempty(c->remote_host));
         pam_debug_syslog(handle, debug,
                          "Session limits: "
                          "memory_max=%s tasks_max=%s cpu_weight=%s io_weight=%s runtime_max_sec=%s",
-                         strna(memory_max), strna(tasks_max), strna(cpu_weight), strna(io_weight), strna(runtime_max_sec));
-
-        const SessionContext context = {
-                .service = service,
-                .type = type,
-                .class = class,
-                .desktop = desktop,
-                .seat = seat,
-                .vtnr = vtnr,
-                .tty = tty,
-                .display = display,
-                .remote = remote,
-                .remote_user = remote_user,
-                .remote_host = remote_host,
-                .memory_max = memory_max,
-                .tasks_max = tasks_max,
-                .cpu_weight = cpu_weight,
-                .io_weight = io_weight,
-                .runtime_max_sec = runtime_max_sec,
-        };
+                         strna(c->memory_max), strna(c->tasks_max), strna(c->cpu_weight), strna(c->io_weight), strna(c->runtime_max_sec));
 
-        r = create_session_message(bus,
-                                   handle,
-                                   ur,
-                                   &context,
-                                   /* avoid_pidfd = */ false,
-                                   &m);
+        r = create_session_message(
+                        bus,
+                        handle,
+                        ur,
+                        c,
+                        /* avoid_pidfd = */ false,
+                        &m);
         if (r < 0)
                 return pam_bus_log_create_error(handle, r);
 
@@ -1179,7 +1093,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
                 r = create_session_message(bus,
                                            handle,
                                            ur,
-                                           &context,
+                                           c,
                                            /* avoid_pidfd = */ true,
                                            &m);
                 if (r < 0)
@@ -1192,7 +1106,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
                         /* We are already in a session, don't do anything */
                         pam_debug_syslog(handle, debug,
                                          "Not creating session: %s", bus_error_message(&error, r));
-                        goto success;
+                        goto skip;
                 }
 
                 pam_syslog(handle, LOG_ERR,
@@ -1200,23 +1114,27 @@ _public_ PAM_EXTERN int pam_sm_open_session(
                 return PAM_SESSION_ERR;
         }
 
-        r = sd_bus_message_read(reply,
-                                "soshusub",
-                                &id,
-                                &object_path,
-                                &runtime_path,
-                                &session_fd,
-                                &original_uid,
-                                &seat,
-                                &vtnr,
-                                &existing);
+        const char *id, *object_path, *runtime_path, *real_seat;
+        int session_fd = -EBADF, existing;
+        uint32_t original_uid, real_vtnr;
+        r = sd_bus_message_read(
+                        reply,
+                        "soshusub",
+                        &id,
+                        &object_path,
+                        &runtime_path,
+                        &session_fd,
+                        &original_uid,
+                        &real_seat,
+                        &real_vtnr,
+                        &existing);
         if (r < 0)
                 return pam_bus_log_parse_error(handle, r);
 
         pam_debug_syslog(handle, debug,
                          "Reply from logind: "
                          "id=%s object_path=%s runtime_path=%s session_fd=%d seat=%s vtnr=%u original_uid=%u",
-                         id, object_path, runtime_path, session_fd, seat, vtnr, original_uid);
+                         id, object_path, runtime_path, session_fd, real_seat, real_vtnr, original_uid);
 
         /* Please update manager_default_environment() in core/manager.c accordingly if more session envvars
          * shall be added. */
@@ -1239,25 +1157,25 @@ _public_ PAM_EXTERN int pam_sm_open_session(
          * somewhere else (for example PAM module parameters). Let's now update the environment variables, so that this
          * data is inherited into the session processes, and programs can rely on them to be initialized. */
 
-        r = update_environment(handle, "XDG_SESSION_TYPE", type);
+        r = update_environment(handle, "XDG_SESSION_TYPE", c->type);
         if (r != PAM_SUCCESS)
                 return r;
 
-        r = update_environment(handle, "XDG_SESSION_CLASS", class);
+        r = update_environment(handle, "XDG_SESSION_CLASS", c->class);
         if (r != PAM_SUCCESS)
                 return r;
 
-        r = update_environment(handle, "XDG_SESSION_DESKTOP", desktop);
+        r = update_environment(handle, "XDG_SESSION_DESKTOP", c->desktop);
         if (r != PAM_SUCCESS)
                 return r;
 
-        r = update_environment(handle, "XDG_SEAT", seat);
+        r = update_environment(handle, "XDG_SEAT", real_seat);
         if (r != PAM_SUCCESS)
                 return r;
 
-        if (vtnr > 0) {
-                char buf[DECIMAL_STR_MAX(vtnr)];
-                sprintf(buf, "%u", vtnr);
+        if (real_vtnr > 0) {
+                char buf[DECIMAL_STR_MAX(real_vtnr)];
+                xsprintf(buf, "%u", real_vtnr);
 
                 r = update_environment(handle, "XDG_VTNR", buf);
                 if (r != PAM_SUCCESS)
@@ -1279,13 +1197,121 @@ _public_ PAM_EXTERN int pam_sm_open_session(
                 TAKE_FD(fd);
         }
 
-success:
+        /* Everything worked, hence let's patch in the data we learned. Since 'real_set' points into the
+         * D-Bus message, let's copy it and return it as a buffer */
+        char *rs = strdup(real_seat);
+        if (!rs)
+                return pam_log_oom(handle);
+
+        c->seat = *ret_seat = rs;
+        c->vtnr = real_vtnr;
+
+        return PAM_SUCCESS;
+
+skip:
+        *ret_seat = NULL;
+        return PAM_SUCCESS;
+}
+
+static int import_shell_credentials(pam_handle_t *handle) {
+
+        static const char *const propagate[] = {
+                "shell.prompt.prefix", "SHELL_PROMPT_PREFIX",
+                "shell.prompt.suffix", "SHELL_PROMPT_SUFFIX",
+                "shell.welcome",       "SHELL_WELCOME",
+                NULL
+        };
+        int r;
+
+        assert(handle);
+
+        STRV_FOREACH_PAIR(k, v, propagate) {
+                r = propagate_credential_to_environment(handle, *k, *v);
+                if (r != PAM_SUCCESS)
+                        return r;
+        }
+
+        return PAM_SUCCESS;
+}
+
+_public_ PAM_EXTERN int pam_sm_open_session(
+                pam_handle_t *handle,
+                int flags,
+                int argc, const char **argv) {
+
+        int r;
+
+        assert(handle);
+
+        pam_log_setup();
+
+        uint64_t default_capability_bounding_set = UINT64_MAX, default_capability_ambient_set = UINT64_MAX;
+        const char *class_pam = NULL, *type_pam = NULL, *desktop_pam = NULL;
+        bool debug = false;
+        if (parse_argv(handle,
+                       argc, argv,
+                       &class_pam,
+                       &type_pam,
+                       &desktop_pam,
+                       &debug,
+                       &default_capability_bounding_set,
+                       &default_capability_ambient_set) < 0)
+                return PAM_SESSION_ERR;
+
+        pam_debug_syslog(handle, debug, "pam-systemd initializing");
+
+        _cleanup_(user_record_unrefp) UserRecord *ur = NULL;
+        r = acquire_user_record(handle, &ur);
+        if (r != PAM_SUCCESS)
+                return r;
+
+        SessionContext c = {};
+        r = pam_get_item_many(
+                        handle,
+                        PAM_SERVICE, &c.service,
+                        PAM_XDISPLAY, &c.display,
+                        PAM_TTY, &c.tty,
+                        PAM_RUSER, &c.remote_user,
+                        PAM_RHOST, &c.remote_host);
+        if (r != PAM_SUCCESS)
+                return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM items: @PAMERR@");
+
+        c.seat = getenv_harder(handle, "XDG_SEAT", NULL);
+        c.vtnr = getenv_harder_uint32(handle, "XDG_VTNR", 0);
+        c.type = getenv_harder(handle, "XDG_SESSION_TYPE", type_pam);
+        c.class = getenv_harder(handle, "XDG_SESSION_CLASS", class_pam);
+        c.desktop = getenv_harder(handle, "XDG_SESSION_DESKTOP", desktop_pam);
+        c.incomplete = getenv_harder_bool(handle, "XDG_SESSION_INCOMPLETE", false);
+
+        r = pam_get_data(handle, "systemd.memory_max", (const void **)&c.memory_max);
+        if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
+                return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM systemd.memory_max data: @PAMERR@");
+        r = pam_get_data(handle, "systemd.tasks_max",  (const void **)&c.tasks_max);
+        if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
+                return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM systemd.tasks_max data: @PAMERR@");
+        r = pam_get_data(handle, "systemd.cpu_weight", (const void **)&c.cpu_weight);
+        if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
+                return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM systemd.cpu_weight data: @PAMERR@");
+        r = pam_get_data(handle, "systemd.io_weight",  (const void **)&c.io_weight);
+        if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
+                return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM systemd.io_weight data: @PAMERR@");
+        r = pam_get_data(handle, "systemd.runtime_max_sec", (const void **)&c.runtime_max_sec);
+        if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
+                return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM systemd.runtime_max_sec data: @PAMERR@");
+
+        session_context_mangle(handle, &c, ur, debug);
+
+        _cleanup_free_ char *seat_buffer = NULL;
+        r = register_session(handle, &c, ur, debug, &seat_buffer);
+        if (r != PAM_SUCCESS)
+                return r;
+
         r = import_shell_credentials(handle);
         if (r != PAM_SUCCESS)
                 return r;
 
         if (default_capability_ambient_set == UINT64_MAX)
-                default_capability_ambient_set = pick_default_capability_ambient_set(ur, service, seat);
+                default_capability_ambient_set = pick_default_capability_ambient_set(ur, c.service, c.seat);
 
         return apply_user_record_settings(handle, ur, debug, default_capability_bounding_set, default_capability_ambient_set);
 }