diff --git a/man/pam_systemd_home.xml b/man/pam_systemd_home.xml index e0e24e5888..ab02f98337 100644 --- a/man/pam_systemd_home.xml +++ b/man/pam_systemd_home.xml @@ -73,7 +73,12 @@ the re-authentication must take place from a component running outside of the user's context, so that it does not require access to the user's home directory for operation. Traditionally, most desktop environments do not implement screen locking this way, and need to be updated - accordingly. + accordingly. + + This setting may also be controlled via the $SYSTEMD_HOME_SUSPEND + environment variable (see below), which pam_systemd_home reads during initialization and sets + for sessions. If both the environment variable is set and the module parameter specified the latter + takes precedence. @@ -105,6 +110,15 @@ Indicates that the user's home directory is managed by systemd-homed.service. + + $SYSTEMD_HOME_SUSPEND= + + Indicates whether the session has been registered with the suspend mechanism enabled + or disabled (see above). The variable's value is either 0 or + 1. Note that the module both reads the variable when initializing, and sets it for + sessions. + + diff --git a/src/home/pam_systemd_home.c b/src/home/pam_systemd_home.c index 72ce062f54..baa3586bf7 100644 --- a/src/home/pam_systemd_home.c +++ b/src/home/pam_systemd_home.c @@ -60,6 +60,35 @@ static int parse_argv( return 0; } +static int parse_env( + pam_handle_t *handle, + bool *please_suspend) { + + const char *v; + int r; + + /* Let's read the suspend setting from an env var in addition to the PAM command line. That makes it + * easy to declare the features of a display manager in code rather than configuration, and this is + * really a feature of code */ + + v = pam_getenv(handle, "SYSTEMD_HOME_SUSPEND"); + if (!v) { + /* Also check the process env block, so that people can control this via an env var from the + * outside of our process. */ + v = secure_getenv("SYSTEMD_HOME_SUSPEND"); + if (!v) + return 0; + } + + r = parse_boolean(v); + if (r < 0) + pam_syslog(handle, LOG_WARNING, "Failed to parse $SYSTEMD_HOME_SUSPEND argument, ignoring: %s", v); + else if (please_suspend) + *please_suspend = r; + + return 0; +} + static int acquire_user_record( pam_handle_t *handle, const char *username, @@ -636,6 +665,9 @@ _public_ PAM_EXTERN int pam_sm_authenticate( bool debug = false, suspend_please = false; + if (parse_env(handle, &suspend_please) < 0) + return PAM_AUTH_ERR; + if (parse_argv(handle, argc, argv, &suspend_please, @@ -660,6 +692,9 @@ _public_ PAM_EXTERN int pam_sm_open_session( bool debug = false, suspend_please = false; int r; + if (parse_env(handle, &suspend_please) < 0) + return PAM_SESSION_ERR; + if (parse_argv(handle, argc, argv, &suspend_please, @@ -681,6 +716,12 @@ _public_ PAM_EXTERN int pam_sm_open_session( return r; } + r = pam_putenv(handle, suspend_please ? "SYSTEMD_HOME_SUSPEND=1" : "SYSTEMD_HOME_SUSPEND=0"); + if (r != PAM_SUCCESS) { + pam_syslog(handle, LOG_ERR, "Failed to set PAM environment variable $SYSTEMD_HOME_SUSPEND: %s", pam_strerror(handle, r)); + return r; + } + /* Let's release the D-Bus connection, 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. */ @@ -764,6 +805,9 @@ _public_ PAM_EXTERN int pam_sm_acct_mgmt( usec_t t; int r; + if (parse_env(handle, &please_suspend) < 0) + return PAM_AUTH_ERR; + if (parse_argv(handle, argc, argv, &please_suspend, diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c index 96ce4742f0..64771153cd 100644 --- a/src/login/pam_systemd.c +++ b/src/login/pam_systemd.c @@ -647,10 +647,6 @@ _public_ PAM_EXTERN int pam_sm_open_session( assert(handle); - /* Make this a NOP on non-logind systems */ - if (!logind_running()) - return PAM_SUCCESS; - if (parse_argv(handle, argc, argv, &class_pam, @@ -666,6 +662,10 @@ _public_ PAM_EXTERN int pam_sm_open_session( if (r != PAM_SUCCESS) return r; + /* Make most of this a NOP on non-logind systems */ + if (!logind_running()) + goto success; + /* Make sure we don't enter a loop by talking to * systemd-logind when it is actually waiting for the * background to finish start-up. If the service is @@ -689,11 +689,7 @@ _public_ PAM_EXTERN int pam_sm_open_session( if (r != PAM_SUCCESS) return r; - r = apply_user_record_settings(handle, ur, debug); - if (r != PAM_SUCCESS) - return r; - - return PAM_SUCCESS; + goto success; } /* Otherwise, we ask logind to create a session for us */ @@ -847,7 +843,9 @@ _public_ PAM_EXTERN int pam_sm_open_session( if (sd_bus_error_has_name(&error, BUS_ERROR_SESSION_BUSY)) { if (debug) pam_syslog(handle, LOG_DEBUG, "Not creating session: %s", bus_error_message(&error, r)); - return PAM_SUCCESS; + + /* We are already in a session, don't do anything */ + goto success; } else { pam_syslog(handle, LOG_ERR, "Failed to create session: %s", bus_error_message(&error, r)); return PAM_SESSION_ERR; @@ -944,6 +942,7 @@ _public_ PAM_EXTERN int pam_sm_open_session( } } +success: r = apply_user_record_settings(handle, ur, debug); if (r != PAM_SUCCESS) return r;