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++)
+ 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
pam_syslog(handle, LOG_WARNING, "Unknown parameter '%s', ignoring", argv[i]);
+ }
return 0;
}
_cleanup_free_ char *p = NULL, *tty = NULL;
_cleanup_close_ int fd = -1;
struct ucred ucred;
- socklen_t l;
int v, r;
assert(display);
if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0)
return -errno;
- l = sizeof(ucred);
- r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l);
+ r = getpeercred(fd, &ucred);
if (r < 0)
- return -errno;
+ return r;
r = get_ctty(ucred.pid, NULL, &tty);
if (r < 0)
return 0;
}
+static int export_legacy_dbus_address(
+ pam_handle_t *handle,
+ uid_t uid,
+ const char *runtime) {
+
+#ifdef ENABLE_KDBUS
+ _cleanup_free_ char *s = NULL;
+ int r;
+
+ /* skip export if kdbus is not active */
+ if (access("/dev/kdbus", F_OK) < 0)
+ return PAM_SUCCESS;
+
+ if (asprintf(&s, KERNEL_USER_BUS_FMT ";" UNIX_USER_BUS_FMT,
+ (unsigned long) uid, runtime) < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to set bus variable.");
+ return PAM_BUF_ERR;
+ }
+
+ r = pam_misc_setenv(handle, "DBUS_SESSION_BUS_ADDRESS", s, 0);
+ if (r != PAM_SUCCESS) {
+ pam_syslog(handle, LOG_ERR, "Failed to set bus variable.");
+ return r;
+ }
+#endif
+ return PAM_SUCCESS;
+}
+
_public_ PAM_EXTERN int pam_sm_open_session(
pam_handle_t *handle,
int flags,
*remote_user = NULL, *remote_host = NULL,
*seat = NULL,
*type = NULL, *class = NULL,
- *class_pam = NULL, *cvtnr = NULL;
+ *class_pam = NULL, *type_pam = NULL, *cvtnr = NULL, *desktop = NULL;
_cleanup_bus_unref_ sd_bus *bus = NULL;
int session_fd = -1, existing, r;
bool debug = false, remote;
if (parse_argv(handle,
argc, argv,
&class_pam,
+ &type_pam,
&debug) < 0)
return PAM_SESSION_ERR;
if (debug)
- pam_syslog(handle, LOG_INFO, "pam-systemd initializing");
+ 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 set runtime dir.");
return r;
}
+
+ r = export_legacy_dbus_address(handle, pw->pw_uid, rt);
+ if (r != PAM_SUCCESS)
+ return r;
}
return PAM_SUCCESS;
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);
- display = strempty(display);
if (strchr(tty, ':')) {
/* A tty with a colon is usually an X11 display,
if (isempty(display))
display = tty;
- 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. */
- tty = "";
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. */
- tty = "";
type ="tty";
+ class = "user";
+ tty = NULL;
}
/* If this fails vtnr will be 0, that's intended */
if (!isempty(cvtnr))
safe_atou32(cvtnr, &vtnr);
- if (!isempty(display) && vtnr <= 0) {
+ 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 (!type)
+ if (seat && !streq(seat, "seat0") && vtnr != 0) {
+ pam_syslog(handle, LOG_DEBUG, "Ignoring vtnr %d for %s which is not seat0", vtnr, seat);
+ vtnr = 0;
+ }
+
+ if (isempty(type))
type = !isempty(display) ? "x11" :
- !isempty(tty) ? "tty" : "unspecified";
+ !isempty(tty) ? "tty" : "unspecified";
- class = pam_getenv(handle, "XDG_SESSION_CLASS");
- if (isempty(class))
- class = getenv("XDG_SESSION_CLASS");
- if (isempty(class))
- class = class_pam;
if (isempty(class))
class = streq(type, "unspecified") ? "background" : "user";
if (debug)
pam_syslog(handle, LOG_DEBUG, "Asking logind to create session: "
- "uid=%u pid=%u service=%s type=%s class=%s seat=%s vtnr=%u tty=%s display=%s remote=%s remote_user=%s remote_host=%s",
+ "uid=%u pid=%u service=%s type=%s class=%s desktop=%s seat=%s vtnr=%u tty=%s display=%s remote=%s remote_user=%s remote_host=%s",
pw->pw_uid, getpid(),
strempty(service),
- type, class,
- strempty(seat), vtnr, tty, strempty(display),
+ 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,
"CreateSession",
&error,
&reply,
- "uussssussbssa(sv)",
+ "uusssssussbssa(sv)",
(uint32_t) pw->pw_uid,
(uint32_t) getpid(),
- strempty(service),
+ service,
type,
class,
- strempty(seat),
+ desktop,
+ seat,
vtnr,
tty,
- strempty(display),
+ display,
remote,
- strempty(remote_user),
- strempty(remote_host),
+ remote_user,
+ remote_host,
0);
if (r < 0) {
pam_syslog(handle, LOG_ERR, "Failed to create session: %s", bus_error_message(&error, r));
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)) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_unref_ sd_bus *bus = NULL;
- const void *p = NULL, *existing = NULL;
+ const void *existing = NULL;
const char *id;
int r;
r = sd_bus_open_system(&bus);
if (r < 0) {
- pam_syslog(handle, LOG_ERR,
- "Failed to connect to system bus: %s", strerror(-r));
- r = PAM_SESSION_ERR;
- goto finish;
+ pam_syslog(handle, LOG_ERR, "Failed to connect to system bus: %s", strerror(-r));
+ return PAM_SESSION_ERR;
}
r = sd_bus_call_method(bus,
"s",
id);
if (r < 0) {
- pam_syslog(handle, LOG_ERR,
- "Failed to release session: %s", bus_error_message(&error, r));
-
- r = PAM_SESSION_ERR;
- goto finish;
+ pam_syslog(handle, LOG_ERR, "Failed to release session: %s", bus_error_message(&error, r));
+ return PAM_SESSION_ERR;
}
}
- r = PAM_SUCCESS;
+ /* 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. */
-finish:
- pam_get_data(handle, "systemd.session-fd", &p);
- if (p)
- close_nointr(PTR_TO_INT(p) - 1);
-
- return r;
+ return PAM_SUCCESS;
}