Blob Blame History Raw
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;
 }
 
 /*