diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c index 1318211105..782e428ba3 100644 --- a/src/login/pam_systemd.c +++ b/src/login/pam_systemd.c @@ -370,48 +370,6 @@ static int get_seat_from_display(const char *display, const char **seat, uint32_ return 0; } -static int export_legacy_dbus_address( - pam_handle_t *handle, - const char *runtime) { - - int r; - - assert(handle); - - /* We need to export $DBUS_SESSION_BUS_ADDRESS because various applications will not connect - * correctly to the bus without it. This setting matches what dbus.socket does for the user session - * using 'systemctl --user set-environment'. We want to have the same configuration in processes - * started from the PAM session. - * - * The setting of the address is guarded by the access() check because it is also possible to compile - * dbus without --enable-user-session, in which case this socket is not used, and - * $DBUS_SESSION_BUS_ADDRESS should not be set. An alternative approach would to not do the access() - * check here, and let applications try on their own, by using "unix:path=%s/bus;autolaunch:". But we - * expect the socket to be present by the time we do this check, so we can just as well check once - * here. */ - - if (!runtime) - return PAM_SUCCESS; - - const char *s = strjoina(runtime, "/bus"); - if (access(s, F_OK) < 0) { - if (errno != ENOENT) - pam_syslog_errno(handle, LOG_WARNING, errno, "Failed to check if %s/bus exists, ignoring: %m", runtime); - - return PAM_SUCCESS; - } - - _cleanup_free_ char *t = NULL; - if (asprintf(&t, DEFAULT_USER_BUS_ADDRESS_FMT, runtime) < 0) - return pam_log_oom(handle); - - r = pam_misc_setenv(handle, "DBUS_SESSION_BUS_ADDRESS", t, /* readonly= */ false); - if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to set bus variable: @PAMERR@"); - - return PAM_SUCCESS; -} - static int append_session_memory_max(pam_handle_t *handle, sd_bus_message *m, const char *limit) { int r; @@ -1497,6 +1455,80 @@ static int make_area_runtime_directory( return 0; } +static int export_legacy_dbus_address( + pam_handle_t *handle, + const char *runtime) { + + assert(handle); + assert(runtime); + + /* We need to export $DBUS_SESSION_BUS_ADDRESS because various applications will not connect + * correctly to the bus without it. This setting matches what dbus.socket does for the user session + * using 'systemctl --user set-environment'. We want to have the same configuration in processes + * started from the PAM session. + * + * The setting of the address is guarded by the access() check because it is also possible to compile + * dbus without --enable-user-session, in which case this socket is not used, and + * $DBUS_SESSION_BUS_ADDRESS should not be set. An alternative approach would to not do the access() + * check here, and let applications try on their own, by using "unix:path=%s/bus;autolaunch:". But we + * expect the socket to be present by the time we do this check, so we can just as well check once + * here. */ + + const char *s = strjoina(runtime, "/bus"); + if (access(s, F_OK) < 0) { + if (errno != ENOENT) + pam_syslog_errno(handle, LOG_WARNING, errno, "Failed to check if %s/bus exists, ignoring: %m", runtime); + + return PAM_SUCCESS; + } + + _cleanup_free_ char *t = NULL; + if (asprintf(&t, DEFAULT_USER_BUS_ADDRESS_FMT, runtime) < 0) + return pam_log_oom(handle); + + return update_environment(handle, "DBUS_SESSION_BUS_ADDRESS", t); +} + +static int setup_runtime_directory( + pam_handle_t *handle, + UserRecord *ur, + const char *runtime_directory, + const char *area) { + + int r; + + assert(handle); + assert(ur); + + if (!runtime_directory) { + /* If this is an area switch request, always reset $XDG_RUNTIME_DIR if we got nothing + * to ensure the main runtime dir won't be clobbered. */ + if (area) + return update_environment(handle, "XDG_RUNTIME_DIR", NULL); + + return PAM_SUCCESS; + } + + /* Also create a per-area subdirectory for $XDG_RUNTIME_DIR, so that each area has their own + * set of runtime services. We follow the same directory structure as for $HOME. Note that we + * do not define any form of automatic clean-up for the per-aera subdirs beyond the regular + * clean-up of the whole $XDG_RUNTIME_DIR hierarchy when the user finally logs out. */ + _cleanup_free_ char *per_area_runtime_directory = NULL; + if (area) { + r = make_area_runtime_directory(handle, ur, runtime_directory, area, &per_area_runtime_directory); + if (r != PAM_SUCCESS) + return r; + + runtime_directory = per_area_runtime_directory; + } + + r = update_environment(handle, "XDG_RUNTIME_DIR", runtime_directory); + if (r != PAM_SUCCESS) + return r; + + return export_legacy_dbus_address(handle, runtime_directory); +} + static int setup_environment( pam_handle_t *handle, UserRecord *ur, @@ -1564,25 +1596,7 @@ static int setup_environment( if (r != PAM_SUCCESS) return r; - _cleanup_free_ char *per_area_runtime_directory = NULL; - if (runtime_directory && area) { - /* Also create a per-area subdirectory for $XDG_RUNTIME_DIR, so that each area has their own - * set of runtime services. We follow the same directory structure as for $HOME. Note that we - * do not define any form of automatic clean-up for the per-aera subdirs beyond the regular - * clean-up of the whole $XDG_RUNTIME_DIR hierarchy when the user finally logs out. */ - - r = make_area_runtime_directory(handle, ur, runtime_directory, area, &per_area_runtime_directory); - if (r != PAM_SUCCESS) - return r; - - runtime_directory = per_area_runtime_directory; - } - - r = update_environment(handle, "XDG_RUNTIME_DIR", runtime_directory); - if (r != PAM_SUCCESS) - return r; - - return export_legacy_dbus_address(handle, runtime_directory); + return setup_runtime_directory(handle, ur, runtime_directory, area); } static int open_osc_context(pam_handle_t *handle, const char *session_type, UserRecord *ur) {