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 @@
<para>
<variablelist>
<varlistentry>
+ <term>PAM_SUCCESS</term>
+ <listitem>
+ <para>
+ The loginuid value is set and auditd is running if check requested.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>PAM_IGNORE</term>
+ <listitem>
+ <para>
+ 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.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term>PAM_SESSION_ERR</term>
<listitem>
<para>
- An error occurred during session management.
+ Any other error prevented setting loginuid or auditd is not running.
</para>
</listitem>
</varlistentry>
-
</variablelist>
</para>
</refsect1>
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;
}
/*