From ce31ec116f9bf4ad45952b6a200f4181fac311a3 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Tue, 13 Sep 2016 21:24:07 -0400 Subject: ./tools/notsd-move --- src/grp-login/pam_systemd/Makefile | 57 +++ src/grp-login/pam_systemd/pam_systemd.c | 553 ++++++++++++++++++++++++++++++ src/grp-login/pam_systemd/pam_systemd.sym | 15 + src/grp-login/pam_systemd/pam_systemd.xml | 296 ++++++++++++++++ 4 files changed, 921 insertions(+) create mode 100644 src/grp-login/pam_systemd/Makefile create mode 100644 src/grp-login/pam_systemd/pam_systemd.c create mode 100644 src/grp-login/pam_systemd/pam_systemd.sym create mode 100644 src/grp-login/pam_systemd/pam_systemd.xml (limited to 'src/grp-login/pam_systemd') diff --git a/src/grp-login/pam_systemd/Makefile b/src/grp-login/pam_systemd/Makefile new file mode 100644 index 0000000000..9bb3af70b0 --- /dev/null +++ b/src/grp-login/pam_systemd/Makefile @@ -0,0 +1,57 @@ +# -*- Mode: makefile; indent-tabs-mode: t -*- +# +# This file is part of systemd. +# +# Copyright 2010-2012 Lennart Poettering +# Copyright 2010-2012 Kay Sievers +# Copyright 2013 Zbigniew Jędrzejewski-Szmek +# Copyright 2013 David Strauss +# Copyright 2016 Luke Shumaker +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with systemd; If not, see . +include $(dir $(lastword $(MAKEFILE_LIST)))/../../../config.mk +include $(topsrcdir)/build-aux/Makefile.head.mk + +ifneq ($(HAVE_PAM),) +pam_systemd_la_SOURCES = \ + src/login/pam_systemd.sym \ + src/login/pam_systemd.c + +pam_systemd_la_CFLAGS = \ + $(AM_CFLAGS) \ + $(PAM_CFLAGS) + +pam_systemd_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + -module \ + -export-dynamic \ + -avoid-version \ + -shared \ + -Wl,--version-script=$(srcdir)/pam_systemd.sym + +pam_systemd_la_LIBADD = \ + libshared.la \ + $(PAM_LIBS) + +pamlib_LTLIBRARIES = \ + pam_systemd.la + +dist_pamconf_DATA = \ + src/login/systemd-user + +EXTRA_DIST += \ + src/login/systemd-user.m4 +endif # HAVE_PAM + +include $(topsrcdir)/build-aux/Makefile.tail.mk diff --git a/src/grp-login/pam_systemd/pam_systemd.c b/src/grp-login/pam_systemd/pam_systemd.c new file mode 100644 index 0000000000..11f527cda0 --- /dev/null +++ b/src/grp-login/pam_systemd/pam_systemd.c @@ -0,0 +1,553 @@ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "basic/alloc-util.h" +#include "basic/audit-util.h" +#include "basic/def.h" +#include "basic/fd-util.h" +#include "basic/fileio.h" +#include "basic/formats-util.h" +#include "basic/hostname-util.h" +#include "basic/login-util.h" +#include "basic/macro.h" +#include "basic/parse-util.h" +#include "basic/socket-util.h" +#include "basic/strv.h" +#include "basic/terminal-util.h" +#include "basic/util.h" +#include "sd-bus/bus-common-errors.h" +#include "sd-bus/bus-error.h" +#include "shared/bus-util.h" + +static int parse_argv( + pam_handle_t *handle, + int argc, const char **argv, + const char **class, + const char **type, + bool *debug) { + + unsigned i; + + assert(argc >= 0); + assert(argc == 0 || argv); + + for (i = 0; i < (unsigned) argc; i++) { + if (startswith(argv[i], "class=")) { + if (class) + *class = argv[i] + 6; + + } else if (startswith(argv[i], "type=")) { + if (type) + *type = argv[i] + 5; + + } else if (streq(argv[i], "debug")) { + if (debug) + *debug = true; + + } else if (startswith(argv[i], "debug=")) { + int k; + + k = parse_boolean(argv[i] + 6); + if (k < 0) + pam_syslog(handle, LOG_WARNING, "Failed to parse debug= argument, ignoring."); + else if (debug) + *debug = k; + + } else + pam_syslog(handle, LOG_WARNING, "Unknown parameter '%s', ignoring", argv[i]); + } + + return 0; +} + +static int get_user_data( + pam_handle_t *handle, + const char **ret_username, + struct passwd **ret_pw) { + + const char *username = NULL; + struct passwd *pw = NULL; + int r; + + assert(handle); + assert(ret_username); + assert(ret_pw); + + r = pam_get_user(handle, &username, NULL); + if (r != PAM_SUCCESS) { + pam_syslog(handle, LOG_ERR, "Failed to get user name."); + return r; + } + + if (isempty(username)) { + pam_syslog(handle, LOG_ERR, "User name not valid."); + return PAM_AUTH_ERR; + } + + pw = pam_modutil_getpwnam(handle, username); + if (!pw) { + pam_syslog(handle, LOG_ERR, "Failed to get user data."); + return PAM_USER_UNKNOWN; + } + + *ret_pw = pw; + *ret_username = username; + + return PAM_SUCCESS; +} + +static int get_seat_from_display(const char *display, const char **seat, uint32_t *vtnr) { + union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + }; + _cleanup_free_ char *p = NULL, *tty = NULL; + _cleanup_close_ int fd = -1; + struct ucred ucred; + int v, r; + + assert(display); + assert(vtnr); + + /* We deduce the X11 socket from the display name, then use + * SO_PEERCRED to determine the X11 server process, ask for + * the controlling tty of that and if it's a VC then we know + * the seat and the virtual terminal. Sounds ugly, is only + * semi-ugly. */ + + r = socket_from_display(display, &p); + if (r < 0) + return r; + strncpy(sa.un.sun_path, p, sizeof(sa.un.sun_path)-1); + + fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); + if (fd < 0) + return -errno; + + if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) + return -errno; + + r = getpeercred(fd, &ucred); + if (r < 0) + return r; + + r = get_ctty(ucred.pid, NULL, &tty); + if (r < 0) + return r; + + v = vtnr_from_tty(tty); + if (v < 0) + return v; + else if (v == 0) + return -ENOENT; + + if (seat) + *seat = "seat0"; + *vtnr = (uint32_t) v; + + 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", NULL); + if (!s) + goto error; + + if (access(s, F_OK) < 0) + return PAM_SUCCESS; + + s = mfree(s); + if (asprintf(&s, UNIX_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; +} + +_public_ PAM_EXTERN int pam_sm_open_session( + pam_handle_t *handle, + int flags, + int argc, const char **argv) { + + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + const char + *username, *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, *cvtnr = NULL, *desktop = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + int session_fd = -1, existing, r; + bool debug = false, remote; + struct passwd *pw; + uint32_t vtnr = 0; + uid_t original_uid; + + assert(handle); + + /* Make this a NOP on non-logind systems */ + if (!logind_running()) + return PAM_SUCCESS; + + if (parse_argv(handle, + argc, argv, + &class_pam, + &type_pam, + &debug) < 0) + return PAM_SESSION_ERR; + + if (debug) + pam_syslog(handle, LOG_DEBUG, "pam-systemd initializing"); + + r = get_user_data(handle, &username, &pw); + if (r != PAM_SUCCESS) { + pam_syslog(handle, LOG_ERR, "Failed to get user data."); + return r; + } + + /* 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 + * "systemd-user" we simply set XDG_RUNTIME_DIR and + * leave. */ + + pam_get_item(handle, PAM_SERVICE, (const void**) &service); + if (streq_ptr(service, "systemd-user")) { + _cleanup_free_ char *rt = NULL; + + if (asprintf(&rt, "/run/user/"UID_FMT, pw->pw_uid) < 0) + return PAM_BUF_ERR; + + r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", rt, 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, rt); + if (r != PAM_SUCCESS) + return r; + + return PAM_SUCCESS; + } + + /* Otherwise, we ask logind to create a session for us */ + + pam_get_item(handle, PAM_XDISPLAY, (const void**) &display); + pam_get_item(handle, PAM_TTY, (const void**) &tty); + 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"); + + tty = strempty(tty); + + if (strchr(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; + } else if (streq(tty, "cron")) { + /* cron has been setting PAM_TTY to "cron" for a very + * long time and it probably shouldn't stop doing that + * for compatibility reasons. */ + type = "unspecified"; + class = "background"; + tty = NULL; + } else if (streq(tty, "ssh")) { + /* ssh has been setting PAM_TTY to "ssh" for a very + * long time and probably shouldn't stop doing that + * for compatibility reasons. */ + type ="tty"; + class = "user"; + tty = NULL; + } + + /* If this fails vtnr will be 0, that's intended */ + if (!isempty(cvtnr)) + (void) safe_atou32(cvtnr, &vtnr); + + if (!isempty(display) && !vtnr) { + if (isempty(seat)) + get_seat_from_display(display, &seat, &vtnr); + else if (streq(seat, "seat0")) + get_seat_from_display(display, NULL, &vtnr); + } + + if (seat && !streq(seat, "seat0") && vtnr != 0) { + pam_syslog(handle, LOG_DEBUG, "Ignoring vtnr %"PRIu32" for %s which is not seat0", vtnr, seat); + vtnr = 0; + } + + if (isempty(type)) + type = !isempty(display) ? "x11" : + !isempty(tty) ? "tty" : "unspecified"; + + if (isempty(class)) + class = streq(type, "unspecified") ? "background" : "user"; + + remote = !isempty(remote_host) && !is_localhost(remote_host); + + /* Talk to logind over the message bus */ + + r = sd_bus_open_system(&bus); + if (r < 0) { + pam_syslog(handle, LOG_ERR, "Failed to connect to system bus: %s", strerror(-r)); + return PAM_SESSION_ERR; + } + + if (debug) + pam_syslog(handle, LOG_DEBUG, "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", + pw->pw_uid, getpid(), + strempty(service), + type, class, strempty(desktop), + strempty(seat), vtnr, strempty(tty), strempty(display), + yes_no(remote), strempty(remote_user), strempty(remote_host)); + + r = sd_bus_call_method(bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "CreateSession", + &error, + &reply, + "uusssssussbssa(sv)", + (uint32_t) pw->pw_uid, + (uint32_t) getpid(), + service, + type, + class, + desktop, + seat, + vtnr, + tty, + display, + remote, + remote_user, + remote_host, + 0); + if (r < 0) { + if (sd_bus_error_has_name(&error, BUS_ERROR_SESSION_BUSY)) { + pam_syslog(handle, LOG_DEBUG, "Cannot create session: %s", bus_error_message(&error, r)); + return PAM_SUCCESS; + } else { + pam_syslog(handle, LOG_ERR, "Failed to create session: %s", bus_error_message(&error, r)); + return PAM_SYSTEM_ERR; + } + } + + r = sd_bus_message_read(reply, + "soshusub", + &id, + &object_path, + &runtime_path, + &session_fd, + &original_uid, + &seat, + &vtnr, + &existing); + if (r < 0) { + pam_syslog(handle, LOG_ERR, "Failed to parse message: %s", strerror(-r)); + return PAM_SESSION_ERR; + } + + if (debug) + pam_syslog(handle, LOG_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); + + r = pam_misc_setenv(handle, "XDG_SESSION_ID", id, 0); + if (r != PAM_SUCCESS) { + pam_syslog(handle, LOG_ERR, "Failed to set session id."); + return r; + } + + if (original_uid == pw->pw_uid) { + /* Don't set $XDG_RUNTIME_DIR if the user we now + * authenticated for does not match the original user + * of the session. We do this in order not to result + * 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); + 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; + } + } + + 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."); + return r; + } + } + + r = pam_set_data(handle, "systemd.existing", INT_TO_PTR(!!existing), NULL); + if (r != PAM_SUCCESS) { + pam_syslog(handle, LOG_ERR, "Failed to install existing flag."); + return r; + } + + if (session_fd >= 0) { + session_fd = fcntl(session_fd, F_DUPFD_CLOEXEC, 3); + if (session_fd < 0) { + pam_syslog(handle, LOG_ERR, "Failed to dup session fd: %m"); + return PAM_SESSION_ERR; + } + + r = pam_set_data(handle, "systemd.session-fd", FD_TO_PTR(session_fd), NULL); + if (r != PAM_SUCCESS) { + pam_syslog(handle, LOG_ERR, "Failed to install session fd."); + safe_close(session_fd); + return r; + } + } + + return PAM_SUCCESS; +} + +_public_ PAM_EXTERN int pam_sm_close_session( + pam_handle_t *handle, + int flags, + int argc, const char **argv) { + + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + const void *existing = NULL; + const char *id; + int r; + + assert(handle); + + /* Only release session if it wasn't pre-existing when we + * tried to create it */ + pam_get_data(handle, "systemd.existing", &existing); + + id = pam_getenv(handle, "XDG_SESSION_ID"); + if (id && !existing) { + + /* Before we go and close the FIFO we need to tell + * logind that this is a clean session shutdown, so + * that it doesn't just go and slaughter us + * immediately after closing the fd */ + + r = sd_bus_open_system(&bus); + if (r < 0) { + pam_syslog(handle, LOG_ERR, "Failed to connect to system bus: %s", strerror(-r)); + return PAM_SESSION_ERR; + } + + r = sd_bus_call_method(bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "ReleaseSession", + &error, + NULL, + "s", + id); + if (r < 0) { + pam_syslog(handle, LOG_ERR, "Failed to release session: %s", bus_error_message(&error, r)); + return PAM_SESSION_ERR; + } + } + + /* Note that we are knowingly leaking the FIFO fd here. This + * way, logind can watch us die. If we closed it here it would + * not have any clue when that is completed. Given that one + * cannot really have multiple PAM sessions open from the same + * process this means we will leak one FD at max. */ + + return PAM_SUCCESS; +} diff --git a/src/grp-login/pam_systemd/pam_systemd.sym b/src/grp-login/pam_systemd/pam_systemd.sym new file mode 100644 index 0000000000..23ff75f688 --- /dev/null +++ b/src/grp-login/pam_systemd/pam_systemd.sym @@ -0,0 +1,15 @@ +/*** + This file is part of systemd. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. +***/ + +{ +global: + pam_sm_close_session; + pam_sm_open_session; +local: *; +}; diff --git a/src/grp-login/pam_systemd/pam_systemd.xml b/src/grp-login/pam_systemd/pam_systemd.xml new file mode 100644 index 0000000000..ddda81bc90 --- /dev/null +++ b/src/grp-login/pam_systemd/pam_systemd.xml @@ -0,0 +1,296 @@ + + + + + + + + + pam_systemd + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + pam_systemd + 8 + + + + pam_systemd + Register user sessions in the systemd login manager + + + + pam_systemd.so + + + + Description + + pam_systemd registers user sessions with + the systemd login manager + systemd-logind.service8, + and hence the systemd control group hierarchy. + + On login, this module ensures the following: + + + If it does not exist yet, the user runtime + directory /run/user/$USER is created and + its ownership changed to the user that is logging + in. + + The $XDG_SESSION_ID + environment variable is initialized. If auditing is available + and pam_loginuid.so was run before this + module (which is highly recommended), the variable is + initialized from the auditing session id + (/proc/self/sessionid). Otherwise, an + independent session counter is used. + + A new systemd scope unit is created for the + session. If this is the first concurrent session of the user, an + implicit slice below user.slice is + automatically created and the scope placed into it. An instance + of the system service user@.service, which + runs the systemd user manager instance, is started. + + + + On logout, this module ensures the following: + + + If enabled in + logind.conf + 5, all processes of the + session are terminated. If the last concurrent session of a user + ends, the user's systemd instance will be terminated too, and so + will the user's slice unit. + + If the last concurrent session of a user ends, + the $XDG_RUNTIME_DIR directory and all its + contents are removed, too. + + + If the system was not booted up with systemd as init system, + this module does nothing and immediately returns + PAM_SUCCESS. + + + + + Options + + The following options are understood: + + + + + + + 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 + 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 an optional + boolean argument. If yes or without + the argument, the module will log + debugging information as it + operates. + + + + + + Module Types Provided + + Only is provided. + + + + Environment + + The following environment variables are set for 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. + + + + $XDG_RUNTIME_DIR + + Path to a user-private user-writable directory + that is bound to the user login time on the machine. It is + automatically created the first time a user logs in and + removed on the user's final logout. If a user logs in twice at + the same time, both sessions will see the same + $XDG_RUNTIME_DIR and the same contents. If + a user logs in once, then logs out again, and logs in again, + the directory contents will have been lost in between, but + applications should not rely on this behavior and must be able + to deal with stale files. To store session-private data in + this directory, the user should include the value of + $XDG_SESSION_ID in the filename. This + directory shall be used for runtime file system objects such + as AF_UNIX sockets, FIFOs, PID files and + similar. It is guaranteed that this directory is local and + offers the greatest possible file system feature set the + operating system provides. For further details, see the XDG + Base Directory Specification. + + + + + The following environment variables are read by the module + and may be used by the PAM service to pass metadata to the + module: + + + + $XDG_SESSION_TYPE + + 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. + + + + $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. + + + + $XDG_SEAT + + The seat name the session shall be registered + for, if any. + + + + $XDG_VTNR + + The VT number the session shall be registered + for, if any. (Only applies to seats with a VT available, such + as seat0) + + + + + + + Example + + #%PAM-1.0 +auth required pam_unix.so +auth required pam_nologin.so +account required pam_unix.so +password required pam_unix.so +session required pam_unix.so +session required pam_loginuid.so +session required pam_systemd.so + + + + See Also + + systemd1, + systemd-logind.service8, + logind.conf5, + loginctl1, + pam.conf5, + pam.d5, + pam8, + pam_loginuid8, + systemd.scope5, + systemd.slice5, + systemd.service5 + + + + -- cgit v1.2.3-54-g00ecf