X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flogin%2Fpam-module.c;h=45428a090f40e767bbd500350cc20f50efeab309;hb=d9e34bfda3d34dcde00a876cb052e7de0655e1cb;hp=3667425a8cabd8fd18374e7776f7a4522620f87c;hpb=ffcfcb6b2c068a5869cffad8a59d72b888bcb940;p=elogind.git diff --git a/src/login/pam-module.c b/src/login/pam-module.c index 3667425a8..45428a090 100644 --- a/src/login/pam-module.c +++ b/src/login/pam-module.c @@ -40,11 +40,13 @@ #include "def.h" #include "socket-util.h" #include "fileio.h" +#include "bus-error.h" -static int parse_argv(pam_handle_t *handle, - int argc, const char **argv, - const char **class, - bool *debug) { +static int parse_argv( + pam_handle_t *handle, + int argc, const char **argv, + const char **class, + bool *debug) { unsigned i; @@ -82,31 +84,24 @@ static int get_user_data( const char *username = NULL; struct passwd *pw = NULL; - uid_t uid; int r; assert(handle); assert(ret_username); assert(ret_pw); - r = audit_loginuid_from_pid(0, &uid); - if (r >= 0) - pw = pam_modutil_getpwuid(handle, uid); - else { - 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; - } + r = pam_get_user(handle, &username, NULL); + if (r != PAM_SUCCESS) { + pam_syslog(handle, LOG_ERR, "Failed to get user name."); + return r; + } - pw = pam_modutil_getpwnam(handle, username); + 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; @@ -119,16 +114,14 @@ static int get_user_data( } static int get_seat_from_display(const char *display, const char **seat, uint32_t *vtnr) { - _cleanup_free_ char *p = NULL; - int r; - _cleanup_close_ int fd = -1; union sockaddr_union sa = { .un.sun_family = AF_UNIX, }; + _cleanup_free_ char *p = NULL, *tty = NULL; + _cleanup_close_ int fd = -1; struct ucred ucred; socklen_t l; - _cleanup_free_ char *tty = NULL; - int v; + int v, r; assert(display); assert(vtnr); @@ -178,24 +171,25 @@ _public_ PAM_EXTERN int pam_sm_open_session( int flags, int argc, const char **argv) { - struct passwd *pw; - bool debug = false; - 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, *cvtnr = NULL; - uint32_t uid, pid; - int session_fd = -1; - bool remote, existing; - uint32_t vtnr = 0; - int r; - - _cleanup_bus_unref_ sd_bus *bus = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_bus_message_unref_ 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, *cvtnr = NULL; + _cleanup_bus_unref_ 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); - if (debug) - pam_syslog(handle, LOG_INFO, "pam-systemd initializing"); - /* Make this a NOP on non-logind systems */ if (!logind_running()) return PAM_SUCCESS; @@ -203,14 +197,17 @@ _public_ PAM_EXTERN int pam_sm_open_session( if (parse_argv(handle, argc, argv, &class_pam, - &debug) < 0) { - r = PAM_SESSION_ERR; - goto finish; - } + &debug) < 0) + return PAM_SESSION_ERR; + + if (debug) + pam_syslog(handle, LOG_INFO, "pam-systemd initializing"); r = get_user_data(handle, &username, &pw); - if (r != PAM_SUCCESS) - goto finish; + 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 @@ -244,9 +241,6 @@ _public_ PAM_EXTERN int pam_sm_open_session( /* Otherwise, we ask logind to create a session for us */ - uid = pw->pw_uid; - pid = getpid(); - 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); @@ -260,12 +254,8 @@ _public_ PAM_EXTERN int pam_sm_open_session( if (isempty(cvtnr)) cvtnr = getenv("XDG_VTNR"); - service = strempty(service); tty = strempty(tty); display = strempty(display); - remote_user = strempty(remote_user); - remote_host = strempty(remote_host); - seat = strempty(seat); if (strchr(tty, ':')) { /* A tty with a colon is usually an X11 display, @@ -294,7 +284,7 @@ _public_ PAM_EXTERN int pam_sm_open_session( 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")) @@ -314,10 +304,10 @@ _public_ PAM_EXTERN int pam_sm_open_session( class = streq(type, "unspecified") ? "background" : "user"; remote = !isempty(remote_host) && - !streq(remote_host, "localhost") && - !streq(remote_host, "localhost.localdomain"); + !streq_ptr(remote_host, "localhost") && + !streq_ptr(remote_host, "localhost.localdomain"); - /* Talk to logind over the message bug */ + /* Talk to logind over the message bus */ r = sd_bus_open_system(&bus); if (r < 0) { @@ -328,7 +318,11 @@ _public_ PAM_EXTERN int pam_sm_open_session( 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, pid, service, type, class, seat, vtnr, tty, display, yes_no(remote), remote_user, remote_host); + pw->pw_uid, getpid(), + strempty(service), + type, class, + strempty(seat), vtnr, tty, strempty(display), + yes_no(remote), strempty(remote_user), strempty(remote_host)); r = sd_bus_call_method(bus, "org.freedesktop.login1", @@ -338,101 +332,105 @@ _public_ PAM_EXTERN int pam_sm_open_session( &error, &reply, "uussssussbssa(sv)", - uid, - pid, - service, + (uint32_t) pw->pw_uid, + (uint32_t) getpid(), + strempty(service), type, class, - seat, + strempty(seat), vtnr, tty, - display, + strempty(display), remote, - remote_user, - remote_host, + strempty(remote_user), + strempty(remote_host), 0); if (r < 0) { - pam_syslog(handle, LOG_ERR, "Failed to communicate with systemd-logind: %s", strerror(-r)); - if (error.name || error.message) - pam_syslog(handle, LOG_ERR, "systemd-logind returned %s: %s", - error.name ?: "unknown error", - error.message ?: "no message"); + 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, - "soshsub", + "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)); - r = PAM_SESSION_ERR; - goto finish; + 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", - id, object_path, runtime_path, session_fd, seat, vtnr); + "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."); - goto finish; + return r; } - 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."); - goto finish; + 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; + } } 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."); - goto finish; + return r; } } if (vtnr > 0) { - char buf[11]; - snprintf(buf, sizeof(buf), "%u", vtnr); - char_array_0(buf); + 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."); - goto finish; + 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."); - goto finish; + return r; } if (session_fd >= 0) { + session_fd = dup(session_fd); + 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", INT_TO_PTR(session_fd+1), NULL); if (r != PAM_SUCCESS) { pam_syslog(handle, LOG_ERR, "Failed to install session fd."); - goto finish; + close_nointr_nofail(session_fd); + return r; } } return PAM_SUCCESS; - -finish: - if (session_fd >= 0) - close_nointr_nofail(session_fd); - - return r; } _public_ PAM_EXTERN int pam_sm_close_session( @@ -440,14 +438,12 @@ _public_ PAM_EXTERN int pam_sm_close_session( int flags, int argc, const char **argv) { + _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 char *id; int r; - _cleanup_bus_unref_ sd_bus *bus = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - assert(handle); /* Only release session if it wasn't pre-existing when we @@ -481,11 +477,7 @@ _public_ PAM_EXTERN int pam_sm_close_session( id); if (r < 0) { pam_syslog(handle, LOG_ERR, - "Failed to release session: %s", strerror(-r)); - if (error.name || error.message) - pam_syslog(handle, LOG_ERR, "systemd-logind returned %s: %s", - error.name ?: "unknown error", - error.message ?: "no message"); + "Failed to release session: %s", bus_error_message(&error, r)); r = PAM_SESSION_ERR; goto finish;