diff --git a/README b/README
index 6801d0dc2d..c0b264abf4 100644
--- a/README
+++ b/README
@@ -169,7 +169,7 @@ REQUIREMENTS:
dependencies:
util-linux >= v2.27.1 required
- dbus >= 1.4.0 (strictly speaking optional, but recommended)
+ dbus >= 1.9.14 (strictly speaking optional, but recommended)
NOTE: If using dbus < 1.9.18, you should override the default
policy directory (--with-dbuspolicydir=/etc/dbus-1/system.d).
dracut (optional)
diff --git a/man/pam_systemd.xml b/man/pam_systemd.xml
index 5eab995a52..3ce3b282bd 100644
--- a/man/pam_systemd.xml
+++ b/man/pam_systemd.xml
@@ -84,40 +84,43 @@
- Takes a string argument which sets the session
- class. The XDG_SESSION_CLASS environmental variable takes
- precedence. One of
- user,
- greeter,
- lock-screen or
- background. See
- sd_session_get_class3
- for details about the session class.
+ Takes a string argument which sets the session class. The XDG_SESSION_CLASS
+ environment variable (see below) takes precedence. One of user, greeter,
+ lock-screen or background. See
+ sd_session_get_class3 for
+ details about the session class.
- Takes a string argument which sets the session
- type. The XDG_SESSION_TYPE environmental variable takes
- precedence. One of
- unspecified,
- tty,
- x11,
- wayland or
- mir. See
- sd_session_get_type3
- for details about the session type.
+ Takes a string argument which sets the session type. The XDG_SESSION_TYPE
+ environment variable (see below) takes precedence. One of unspecified,
+ tty, x11, wayland or mir. See
+ sd_session_get_type3 for
+ details about the session type.
+
+
+
+
+
+ Takes a single, short identifier string for the desktop environment. The
+ XDG_SESSION_DESKTOP environment variable (see below) takes precedence. This may be used to
+ indicate the session desktop used, where this applies and if this information is available. For example:
+ GNOME, or KDE. It is recommended to use the same identifiers and
+ capitalization as for $XDG_CURRENT_DESKTOP, as defined by the Desktop Entry
+ Specification. (However, note that the option only takes a single item, and not a colon-separated list
+ like $XDG_CURRENT_DESKTOP.) See
+ sd_session_get_desktop3 for
+ further details.
- Takes an optional
- boolean argument. If yes or without
- the argument, the module will log
- debugging information as it
- operates.
+ Takes an optional boolean argument. If yes or without the argument, the module will log
+ debugging information as it operates.
@@ -131,20 +134,20 @@
Environment
- The following environment variables are set for the
- processes of the user's session:
+ The following environment variables are initialized by the module and available to the processes of the
+ user's session:$XDG_SESSION_ID
- A session identifier, suitable to be used in
- filenames. The string itself should be considered opaque,
- although often it is just the audit session ID as reported by
- /proc/self/sessionid. Each ID will be
- assigned only once during machine uptime. It may hence be used
- to uniquely label files or other resources of this
- session.
+ A short session identifier, suitable to be used in filenames. The string itself should be
+ considered opaque, although often it is just the audit session ID as reported by
+ /proc/self/sessionid. Each ID will be assigned only once during machine uptime. It may
+ hence be used to uniquely label files or other resources of this session. Combine this ID with the boot
+ identifier, as returned by
+ sd_id128_get_boot3, for a
+ globally unique identifier for the current session.
@@ -174,45 +177,31 @@
- The following environment variables are read by the module
- and may be used by the PAM service to pass metadata to the
- module:
+ The following environment variables are read by the module and may be used by the PAM service to pass
+ metadata to the module. If these variables are not set when the PAM module is invoked but can be determined
+ otherwise they are set by the module, so that these variables are initialized for the session and applications if
+ known at all.$XDG_SESSION_TYPE
- The session type. This may be used instead of
- on the module parameter line, and is
- usually preferred.
+ The session type. This may be used instead of on the module parameter
+ line, and is usually preferred.$XDG_SESSION_CLASS
- The session class. This may be used instead of
- on the module parameter line, and is
- usually preferred.
+ The session class. This may be used instead of on the module parameter
+ line, and is usually preferred.$XDG_SESSION_DESKTOP
- A single, short identifier string for the
- desktop environment. This may be used to indicate the session
- desktop used, where this applies and if this information is
- available. For example: GNOME, or
- KDE. It is recommended to use the same
- identifiers and capitalization as for
- $XDG_CURRENT_DESKTOP, as defined by the
- Desktop
- Entry Specification. (However, note that
- $XDG_SESSION_DESKTOP only takes a single
- item, and not a colon-separated list like
- $XDG_CURRENT_DESKTOP.) See
- sd_session_get_desktop3
- for more details.
+ The desktop identifier. This may be used instead of on the module
+ parameter line, and is usually preferred.
@@ -231,9 +220,9 @@
- If not set, pam_systemd will determine the
- values for $XDG_SEAT and $XDG_VTNR
- based on the $DISPLAY variable.
+ If not set, pam_systemd will initialize
+ $XDG_SEAT and $XDG_VTNR
+ based on the $DISPLAY variable (if the latter is set).
diff --git a/src/basic/util.c b/src/basic/util.c
index 8f2d6061da..2206c1b4ad 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -77,31 +77,6 @@ bool display_is_local(const char *display) {
display[1] <= '9';
}
-int socket_from_display(const char *display, char **path) {
- size_t k;
- char *f, *c;
-
- assert(display);
- assert(path);
-
- if (!display_is_local(display))
- return -EINVAL;
-
- k = strspn(display+1, "0123456789");
-
- f = new(char, STRLEN("/tmp/.X11-unix/X") + k + 1);
- if (!f)
- return -ENOMEM;
-
- c = stpcpy(f, "/tmp/.X11-unix/X");
- memcpy(c, display+1, k);
- c[k] = 0;
-
- *path = f;
-
- return 0;
-}
-
bool kexec_loaded(void) {
_cleanup_free_ char *s = NULL;
diff --git a/src/basic/util.h b/src/basic/util.h
index 9699d228f9..42c262f598 100644
--- a/src/basic/util.h
+++ b/src/basic/util.h
@@ -50,7 +50,6 @@ static inline const char* enable_disable(bool b) {
bool plymouth_running(void);
bool display_is_local(const char *display) _pure_;
-int socket_from_display(const char *display, char **path);
#define NULSTR_FOREACH(i, l) \
for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)
diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c
index 7037c13cd8..4d0e7fd5e6 100644
--- a/src/login/pam_systemd.c
+++ b/src/login/pam_systemd.c
@@ -16,6 +16,7 @@
#include "bus-common-errors.h"
#include "bus-error.h"
#include "bus-util.h"
+#include "cgroup-util.h"
#include "def.h"
#include "fd-util.h"
#include "fileio.h"
@@ -24,19 +25,19 @@
#include "login-util.h"
#include "macro.h"
#include "parse-util.h"
+#include "path-util.h"
#include "process-util.h"
#include "socket-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "util.h"
-#include "path-util.h"
-#include "cgroup-util.h"
static int parse_argv(
pam_handle_t *handle,
int argc, const char **argv,
const char **class,
const char **type,
+ const char **desktop,
bool *debug) {
unsigned i;
@@ -53,6 +54,10 @@ static int parse_argv(
if (type)
*type = argv[i] + 5;
+ } else if (startswith(argv[i], "desktop=")) {
+ if (desktop)
+ *desktop = argv[i] + 8;
+
} else if (streq(argv[i], "debug")) {
if (debug)
*debug = true;
@@ -109,6 +114,31 @@ static int get_user_data(
return PAM_SUCCESS;
}
+static int socket_from_display(const char *display, char **path) {
+ size_t k;
+ char *f, *c;
+
+ assert(display);
+ assert(path);
+
+ if (!display_is_local(display))
+ return -EINVAL;
+
+ k = strspn(display+1, "0123456789");
+
+ f = new(char, STRLEN("/tmp/.X11-unix/X") + k + 1);
+ if (!f)
+ return -ENOMEM;
+
+ c = stpcpy(f, "/tmp/.X11-unix/X");
+ memcpy(c, display+1, k);
+ c[k] = 0;
+
+ *path = f;
+
+ return 0;
+}
+
static int get_seat_from_display(const char *display, const char **seat, uint32_t *vtnr) {
union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
@@ -160,40 +190,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,
- uid_t uid,
- const char *runtime) {
-
- _cleanup_free_ char *s = NULL;
- int r = PAM_BUF_ERR;
-
- /* FIXME: We *really* should move the access() check into the
- * daemons that spawn dbus-daemon, instead of forcing
- * DBUS_SESSION_BUS_ADDRESS= here. */
-
- s = strjoin(runtime, "/bus");
- if (!s)
- goto error;
-
- if (access(s, F_OK) < 0)
- return PAM_SUCCESS;
-
- s = mfree(s);
- if (asprintf(&s, DEFAULT_USER_BUS_ADDRESS_FMT, runtime) < 0)
- goto error;
-
- r = pam_misc_setenv(handle, "DBUS_SESSION_BUS_ADDRESS", s, 0);
- if (r != PAM_SUCCESS)
- goto error;
-
- return PAM_SUCCESS;
-
-error:
- pam_syslog(handle, LOG_ERR, "Failed to set bus variable.");
- return r;
-}
-
static int append_session_memory_max(pam_handle_t *handle, sd_bus_message *m, const char *limit) {
uint64_t val;
int r;
@@ -231,8 +227,7 @@ static int append_session_memory_max(pam_handle_t *handle, sd_bus_message *m, co
return 0;
}
-static int append_session_tasks_max(pam_handle_t *handle, sd_bus_message *m, const char *limit)
-{
+static int append_session_tasks_max(pam_handle_t *handle, sd_bus_message *m, const char *limit) {
uint64_t val;
int r;
@@ -257,23 +252,62 @@ static int append_session_cg_weight(pam_handle_t *handle, sd_bus_message *m, con
uint64_t val;
int r;
- if (!isempty(limit)) {
- r = cg_weight_parse(limit, &val);
- if (r >= 0) {
- r = sd_bus_message_append(m, "(sv)", field, "t", val);
- if (r < 0) {
- pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
- return r;
- }
- } else if (streq(field, "CPUWeight"))
- pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.cpu_weight: %s, ignoring.", limit);
- else
- pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.io_weight: %s, ignoring.", limit);
- }
+ if (isempty(limit))
+ return 0;
+
+ r = cg_weight_parse(limit, &val);
+ if (r >= 0) {
+ r = sd_bus_message_append(m, "(sv)", field, "t", val);
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
+ return r;
+ }
+ } else if (streq(field, "CPUWeight"))
+ pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.cpu_weight: %s, ignoring.", limit);
+ else
+ pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.io_weight: %s, ignoring.", limit);
return 0;
}
+static const char* getenv_harder(pam_handle_t *handle, const char *key, const char *fallback) {
+ const char *v;
+
+ assert(handle);
+ assert(key);
+
+ /* Looks for an environment variable, preferrably in the environment block associated with the specified PAM
+ * handle, falling back to the process' block instead. */
+
+ v = pam_getenv(handle, key);
+ if (!isempty(v))
+ return v;
+
+ v = getenv(key);
+ if (!isempty(v))
+ return v;
+
+ return fallback;
+}
+
+static int update_environment(pam_handle_t *handle, const char *key, const char *value) {
+ int r;
+
+ assert(handle);
+ assert(key);
+
+ /* Updates the environment, but only if there's actually a value set. Also, log about errors */
+
+ if (isempty(value))
+ return PAM_SUCCESS;
+
+ r = pam_misc_setenv(handle, key, value, 0);
+ if (r != PAM_SUCCESS)
+ pam_syslog(handle, LOG_ERR, "Failed to set environment variable %s.", key);
+
+ return r;
+}
+
_public_ PAM_EXTERN int pam_sm_open_session(
pam_handle_t *handle,
int flags,
@@ -288,7 +322,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
*remote_user = NULL, *remote_host = NULL,
*seat = NULL,
*type = NULL, *class = NULL,
- *class_pam = NULL, *type_pam = NULL, *cvtnr = NULL, *desktop = NULL,
+ *class_pam = NULL, *type_pam = NULL, *cvtnr = NULL, *desktop = NULL, *desktop_pam = NULL,
*memory_max = NULL, *tasks_max = NULL, *cpu_weight = NULL, *io_weight = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int session_fd = -1, existing, r;
@@ -307,6 +341,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
argc, argv,
&class_pam,
&type_pam,
+ &desktop_pam,
&debug) < 0)
return PAM_SESSION_ERR;
@@ -338,10 +373,6 @@ _public_ PAM_EXTERN int pam_sm_open_session(
return r;
}
- r = export_legacy_dbus_address(handle, pw->pw_uid, rt);
- if (r != PAM_SUCCESS)
- return r;
-
return PAM_SUCCESS;
}
@@ -352,29 +383,11 @@ _public_ PAM_EXTERN int pam_sm_open_session(
pam_get_item(handle, PAM_RUSER, (const void**) &remote_user);
pam_get_item(handle, PAM_RHOST, (const void**) &remote_host);
- seat = pam_getenv(handle, "XDG_SEAT");
- if (isempty(seat))
- seat = getenv("XDG_SEAT");
-
- cvtnr = pam_getenv(handle, "XDG_VTNR");
- if (isempty(cvtnr))
- cvtnr = getenv("XDG_VTNR");
-
- type = pam_getenv(handle, "XDG_SESSION_TYPE");
- if (isempty(type))
- type = getenv("XDG_SESSION_TYPE");
- if (isempty(type))
- type = type_pam;
-
- class = pam_getenv(handle, "XDG_SESSION_CLASS");
- if (isempty(class))
- class = getenv("XDG_SESSION_CLASS");
- if (isempty(class))
- class = class_pam;
-
- desktop = pam_getenv(handle, "XDG_SESSION_DESKTOP");
- if (isempty(desktop))
- desktop = getenv("XDG_SESSION_DESKTOP");
+ seat = getenv_harder(handle, "XDG_SEAT", NULL);
+ cvtnr = getenv_harder(handle, "XDG_VTNR", NULL);
+ 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);
tty = strempty(tty);
@@ -415,9 +428,9 @@ _public_ PAM_EXTERN int pam_sm_open_session(
if (!isempty(display) && !vtnr) {
if (isempty(seat))
- get_seat_from_display(display, &seat, &vtnr);
+ (void) get_seat_from_display(display, &seat, &vtnr);
else if (streq(seat, "seat0"))
- get_seat_from_display(display, NULL, &vtnr);
+ (void) get_seat_from_display(display, NULL, &vtnr);
}
if (seat && !streq(seat, "seat0") && vtnr != 0) {
@@ -550,11 +563,9 @@ _public_ PAM_EXTERN int pam_sm_open_session(
"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);
- r = pam_misc_setenv(handle, "XDG_SESSION_ID", id, 0);
- if (r != PAM_SUCCESS) {
- pam_syslog(handle, LOG_ERR, "Failed to set session id.");
+ r = update_environment(handle, "XDG_SESSION_ID", id);
+ if (r != PAM_SUCCESS)
return r;
- }
if (original_uid == pw->pw_uid) {
/* Don't set $XDG_RUNTIME_DIR if the user we now
@@ -563,34 +574,38 @@ _public_ PAM_EXTERN int pam_sm_open_session(
* in privileged apps clobbering the runtime directory
* unnecessarily. */
- r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", runtime_path, 0);
- if (r != PAM_SUCCESS) {
- pam_syslog(handle, LOG_ERR, "Failed to set runtime dir.");
- return r;
- }
-
- r = export_legacy_dbus_address(handle, pw->pw_uid, runtime_path);
+ r = update_environment(handle, "XDG_RUNTIME_DIR", runtime_path);
if (r != PAM_SUCCESS)
return r;
}
- if (!isempty(seat)) {
- r = pam_misc_setenv(handle, "XDG_SEAT", seat, 0);
- if (r != PAM_SUCCESS) {
- pam_syslog(handle, LOG_ERR, "Failed to set seat.");
- return r;
- }
- }
+ /* Most likely we got the session/type/class from environment variables, but might have gotten the data
+ * 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);
+ if (r != PAM_SUCCESS)
+ return r;
+
+ r = update_environment(handle, "XDG_SESSION_CLASS", class);
+ if (r != PAM_SUCCESS)
+ return r;
+
+ r = update_environment(handle, "XDG_SESSION_DESKTOP", desktop);
+ if (r != PAM_SUCCESS)
+ return r;
+
+ r = update_environment(handle, "XDG_SEAT", seat);
+ if (r != PAM_SUCCESS)
+ return r;
if (vtnr > 0) {
char buf[DECIMAL_STR_MAX(vtnr)];
sprintf(buf, "%u", vtnr);
- r = pam_misc_setenv(handle, "XDG_VTNR", buf, 0);
- if (r != PAM_SUCCESS) {
- pam_syslog(handle, LOG_ERR, "Failed to set virtual terminal number.");
+ r = update_environment(handle, "XDG_VTNR", buf);
+ if (r != PAM_SUCCESS)
return r;
- }
}
r = pam_set_data(handle, "systemd.existing", INT_TO_PTR(!!existing), NULL);
@@ -632,7 +647,7 @@ _public_ PAM_EXTERN int pam_sm_close_session(
/* Only release session if it wasn't pre-existing when we
* tried to create it */
- pam_get_data(handle, "systemd.existing", &existing);
+ (void) pam_get_data(handle, "systemd.existing", &existing);
id = pam_getenv(handle, "XDG_SESSION_ID");
if (id && !existing) {