diff options
Diffstat (limited to 'modules/pam_loginuid/pam_loginuid.c')
-rw-r--r-- | modules/pam_loginuid/pam_loginuid.c | 95 |
1 files changed, 61 insertions, 34 deletions
diff --git a/modules/pam_loginuid/pam_loginuid.c b/modules/pam_loginuid/pam_loginuid.c index 06479973..96bfd98e 100644 --- a/modules/pam_loginuid/pam_loginuid.c +++ b/modules/pam_loginuid/pam_loginuid.c @@ -47,25 +47,56 @@ /* * This function writes the loginuid to the /proc system. It returns - * 0 on success and 1 on failure. + * PAM_SUCCESS on success, + * PAM_IGNORE when /proc/self/loginuid does not exist, + * PAM_SESSION_ERR in case of any other error. */ static int set_loginuid(pam_handle_t *pamh, uid_t uid) { - int fd, count, rc = 0; - char loginuid[24]; + int fd, count, rc = PAM_SESSION_ERR; + char loginuid[24], buf[24]; + static const char host_uid_map[] = " 0 0 4294967295\n"; + char uid_map[sizeof(host_uid_map)]; - count = snprintf(loginuid, sizeof(loginuid), "%lu", (unsigned long)uid); - fd = open("/proc/self/loginuid", O_NOFOLLOW|O_WRONLY|O_TRUNC); + /* loginuid in user namespaces currently isn't writable and in some + case, not even readable, so consider any failure as ignorable (but try + anyway, in case we hit a kernel which supports it). */ + fd = open("/proc/self/uid_map", O_RDONLY); + if (fd >= 0) { + count = pam_modutil_read(fd, uid_map, sizeof(uid_map)); + if (strncmp(uid_map, host_uid_map, count) != 0) + rc = PAM_IGNORE; + close(fd); + } + + fd = open("/proc/self/loginuid", O_NOFOLLOW|O_RDWR); if (fd < 0) { - if (errno != ENOENT) { - rc = 1; - pam_syslog(pamh, LOG_ERR, - "Cannot open /proc/self/loginuid: %m"); + if (errno == ENOENT) { + rc = PAM_IGNORE; + } + if (rc != PAM_IGNORE) { + pam_syslog(pamh, LOG_ERR, "Cannot open %s: %m", + "/proc/self/loginuid"); } return rc; } - if (pam_modutil_write(fd, loginuid, count) != count) - rc = 1; + + count = snprintf(loginuid, sizeof(loginuid), "%lu", (unsigned long)uid); + if (pam_modutil_read(fd, buf, sizeof(buf)) == count && + memcmp(buf, loginuid, count) == 0) { + rc = PAM_SUCCESS; + goto done; /* already correct */ + } + if (lseek(fd, 0, SEEK_SET) == 0 && ftruncate(fd, 0) == 0 && + pam_modutil_write(fd, loginuid, count) == count) { + rc = PAM_SUCCESS; + } else { + if (rc != PAM_IGNORE) { + pam_syslog(pamh, LOG_ERR, "Error writing %s: %m", + "/proc/self/loginuid"); + } + } + done: close(fd); return rc; } @@ -165,6 +196,7 @@ _pam_loginuid(pam_handle_t *pamh, int flags UNUSED, { const char *user = NULL; struct passwd *pwd; + int ret; #ifdef HAVE_LIBAUDIT int require_auditd = 0; #endif @@ -183,9 +215,14 @@ _pam_loginuid(pam_handle_t *pamh, int flags UNUSED, return PAM_SESSION_ERR; } - if (set_loginuid(pamh, pwd->pw_uid)) { - pam_syslog(pamh, LOG_ERR, "set_loginuid failed\n"); - return PAM_SESSION_ERR; + ret = set_loginuid(pamh, pwd->pw_uid); + switch (ret) { + case PAM_SUCCESS: + case PAM_IGNORE: + break; + default: + pam_syslog(pamh, LOG_ERR, "set_loginuid failed"); + return ret; } #ifdef HAVE_LIBAUDIT @@ -195,11 +232,14 @@ _pam_loginuid(pam_handle_t *pamh, int flags UNUSED, argv++; } - if (require_auditd) - return check_auditd(); - else + if (require_auditd) { + int rc = check_auditd(); + if (rc != PAM_SUCCESS) + pam_syslog(pamh, LOG_ERR, "required running auditd not detected"); + return rc != PAM_SUCCESS ? rc : ret; + } else #endif - return PAM_SUCCESS; + return ret; } /* @@ -207,34 +247,21 @@ _pam_loginuid(pam_handle_t *pamh, int flags UNUSED, * * This is here for vsftpd which doesn't seem to run the session stack */ -PAM_EXTERN int +int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) { return _pam_loginuid(pamh, flags, argc, argv); } -PAM_EXTERN int +int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { return _pam_loginuid(pamh, flags, argc, argv); } -PAM_EXTERN int +int pam_sm_close_session(pam_handle_t *pamh UNUSED, int flags UNUSED, int argc UNUSED, const char **argv UNUSED) { return PAM_SUCCESS; } - -/* static module data */ -#ifdef PAM_STATIC -struct pam_module _pam_loginuid_modstruct = { - "pam_loginuid", - NULL, - NULL, - pam_sm_acct_mgmt, - pam_sm_open_session, - pam_sm_close_session, - NULL -}; -#endif |