diff -up Linux-PAM-1.1.8/modules/pam_loginuid/pam_loginuid.8.xml.containers Linux-PAM-1.1.8/modules/pam_loginuid/pam_loginuid.8.xml --- Linux-PAM-1.1.8/modules/pam_loginuid/pam_loginuid.8.xml.containers 2013-06-18 16:11:21.000000000 +0200 +++ Linux-PAM-1.1.8/modules/pam_loginuid/pam_loginuid.8.xml 2019-08-06 14:54:33.491053203 +0200 @@ -69,14 +69,31 @@ + PAM_SUCCESS + + + The loginuid value is set and auditd is running if check requested. + + + + + PAM_IGNORE + + + The /proc/self/loginuid file is not present on the system or the + login process runs inside uid namespace and kernel does not support + overwriting loginuid. + + + + PAM_SESSION_ERR - An error occurred during session management. + Any other error prevented setting loginuid or auditd is not running. - diff -up Linux-PAM-1.1.8/modules/pam_loginuid/pam_loginuid.c.containers Linux-PAM-1.1.8/modules/pam_loginuid/pam_loginuid.c --- Linux-PAM-1.1.8/modules/pam_loginuid/pam_loginuid.c.containers 2017-11-02 14:04:25.898425389 +0100 +++ Linux-PAM-1.1.8/modules/pam_loginuid/pam_loginuid.c 2019-08-06 14:51:31.905761192 +0200 @@ -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)]; + + /* 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); + } - count = snprintf(loginuid, sizeof(loginuid), "%lu", (unsigned long)uid); - fd = open("/proc/self/loginuid", O_NOFOLLOW|O_WRONLY|O_TRUNC); + 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 fl { 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 fl 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 @@ -199,10 +236,10 @@ _pam_loginuid(pam_handle_t *pamh, int fl int rc = check_auditd(); if (rc != PAM_SUCCESS) pam_syslog(pamh, LOG_ERR, "required running auditd not detected"); - return rc; + return rc != PAM_SUCCESS ? rc : ret; } else #endif - return PAM_SUCCESS; + return ret; } /*