public inbox for glibc-cvs@sourceware.org
help / color / mirror / Atom feed
* [glibc/maskray/grte] Update passwd.borg handling to use passwd.borg.real
@ 2021-08-28  0:32 Fangrui Song
  0 siblings, 0 replies; 3+ messages in thread
From: Fangrui Song @ 2021-08-28  0:32 UTC (permalink / raw)
  To: glibc-cvs

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=86079708ee6532d458cdb1107787b6587cbd3906

commit 86079708ee6532d458cdb1107787b6587cbd3906
Author: Stan Shebs <stanshebs@google.com>
Date:   Fri Dec 20 13:58:35 2019 -0800

    Update passwd.borg handling to use passwd.borg.real

Diff:
---
 nss/nss_borg/borg-pwd.c | 215 ++++++++++++++++++++++++++++++++++--------------
 1 file changed, 151 insertions(+), 64 deletions(-)

diff --git a/nss/nss_borg/borg-pwd.c b/nss/nss_borg/borg-pwd.c
index a0eb0e3954..2e50b287a9 100644
--- a/nss/nss_borg/borg-pwd.c
+++ b/nss/nss_borg/borg-pwd.c
@@ -2,58 +2,85 @@
 // /etc/passwd.borg and /etc/passwd.borg.base
 // passwd.borg.base is a subset of passwd.borg that is used as a fallback.
 
-#include <stdio.h>
-#include <pwd.h>
-#include <sys/types.h>
-#include <nss.h>
 #include <errno.h>
+#include <nss.h>
+#include <pwd.h>
+#include <stdio.h>
 #include <string.h>
+#include <sys/types.h>
+#include <syslog.h>
 
 #include <libc-lock.h>
-__libc_lock_define_initialized (static, lock)
-#define NSSBORG_LOCK  __libc_lock_lock (lock)
-#define NSSBORG_UNLOCK  __libc_lock_unlock (lock);
+__libc_lock_define_initialized(static, lock)
+#define NSSBORG_LOCK __libc_lock_lock(lock)
+#define NSSBORG_UNLOCK __libc_lock_unlock(lock);
+
+#define EXEC_NAME_SIZE 4096
 
 static FILE *f;
 static FILE *fb;
-
+static bool fb_eof;
+static FILE *fbr;
+static bool fbr_eof;
+static char exec_name[EXEC_NAME_SIZE];
+
+// This library will log into syslog any attempt to fetch a username from
+// /etc/passwd.borg file, but only if /etc/passwd.borg.real file is present.
+// This module makes the user lookup in following order:
+// /etc/passwd.borg.real
+// /etc/passwd.borg.base
+// /etc/passwd.borg
+
+
+// non_borg_user_lookup_warn is supposed to prevent log spew from a single
+// process.
+static int non_borg_user_lookup_warn = 0;
+
+#define LOGNSS(priority, fmt, ...)                   \
+  do {                                               \
+    openlog("nss_borg", LOG_PID, 0);                 \
+    syslog(LOG_USER | priority, fmt, ##__VA_ARGS__); \
+    closelog();                                      \
+  } while (0)
 #define DEBUG(fmt, ...)
+#define WARN(fmt, ...) LOGNSS(LOG_WARNING, fmt, ##__VA_ARGS__)
 
 // _nss_borg_setpwent_locked()
 // Internal setup routine
-
 static enum nss_status _nss_borg_setpwent_locked(void) {
-
+  int readlink_ret;
   DEBUG("Opening passwd.borg\n");
   f = fopen("/etc/passwd.borg", "r");
 
   DEBUG("Opening passwd.borg.base\n");
   fb = fopen("/etc/passwd.borg.base", "r");
+  fb_eof = false;
+
+  DEBUG("Opening passwd.borg.real\n");
+  fbr = fopen("/etc/passwd.borg.real", "r");
+  fbr_eof = false;
+
+  DEBUG("Reading /proc/self/exe");
+  // readlink does not append null-byte, so we reserve last byte for it.
+  readlink_ret = readlink("/proc/self/exe", exec_name,
+                          sizeof(exec_name) - 1);
+  if (readlink_ret == -1) {
+    DEBUG("Failed to readlink /proc/self/exe error: %d", errno);
+    strncpy(exec_name, "__unknown__", sizeof(exec_name));
+  } else {
+    exec_name[readlink_ret] = '\0';
+  }
 
-  if (f||fb) {
+  if (f || fb || fbr) {
     return NSS_STATUS_SUCCESS;
   } else {
     return NSS_STATUS_UNAVAIL;
   }
 }
 
-// _nss_borg_setpwent()
-// Called by NSS to open the passwd file
-// Oddly, NSS passes a boolean saying whether to keep the database file open; ignore it
-
-enum nss_status _nss_borg_setpwent(int stayopen) {
-  enum nss_status ret;
-  NSSBORG_LOCK;
-  ret = _nss_borg_setpwent_locked();
-  NSSBORG_UNLOCK;
-  return ret;
-}
-
 // _nss_borg_endpwent_locked()
 // Internal close routine
-
 static enum nss_status _nss_borg_endpwent_locked(void) {
-
   DEBUG("Closing passwd.borg\n");
   if (f) {
     fclose(f);
@@ -64,40 +91,62 @@ static enum nss_status _nss_borg_endpwent_locked(void) {
     fclose(fb);
     fb = NULL;
   }
+  DEBUG("Closing passwd.borg.real\n");
+  if (fbr) {
+    fclose(fbr);
+    fbr = NULL;
+  }
   return NSS_STATUS_SUCCESS;
 }
 
-// _nss_borg_endpwent()
-// Called by NSS to close the passwd file
-
-enum nss_status _nss_borg_endpwent(void) {
-  enum nss_status ret;
-  NSSBORG_LOCK;
-  ret = _nss_borg_endpwent_locked();
-  NSSBORG_UNLOCK;
-  return ret;
+// Called internally. It's a wrapper around fgetpwent_r that prevents from
+// multiple read calls once EOF was reached (b/72036184)
+static int _nss_borg_fgetpwent_r_eof(FILE *fp, struct passwd *pwbuf,
+                                           char *buf, size_t buflen,
+                                           struct passwd **pwbufp, bool *eof) {
+  if (*eof) {
+    *pwbufp = NULL;
+    return ENOENT;
+  } else {
+    int ret = fgetpwent_r(fp, pwbuf, buf, buflen, pwbufp);
+    if (ret == ENOENT) {
+      *eof = true;
+    }
+    return ret;
+  }
 }
 
 // _nss_borg_getpwent_r_locked()
 // Called internally to return the next entry from the passwd file
-
 static enum nss_status _nss_borg_getpwent_r_locked(struct passwd *result,
                                                    char *buffer, size_t buflen,
-                                                   int *errnop) {
-
+                                                   int *errnop,
+                                                   int *non_borg_user) {
   enum nss_status ret;
   // Save a copy of the buffer address, in case first call errors
   // and sets it to 0.
   struct passwd *sparecopy = result;
-  if (
-      f != NULL && (fgetpwent_r(f, result, buffer, buflen, &result) == 0)) {
-    DEBUG("Returning borg user %d:%s\n", result->pw_uid, result->pw_name);
+  if (fbr != NULL && (_nss_borg_fgetpwent_r_eof(fbr, result, buffer, buflen,
+                                                &result, &fbr_eof) == 0)) {
+    DEBUG("Returning real borg user %d:%s\n", result->pw_uid, result->pw_name);
+    ret = NSS_STATUS_SUCCESS;
+  } else if (
+      // Yes, this is one of those cases where an assign makes sense.
+      fb != NULL && (result = sparecopy) &&
+      (_nss_borg_fgetpwent_r_eof(fb, result, buffer, buflen, &result,
+                                 &fb_eof) == 0)) {
+    DEBUG("Returning base borg user %d:%s\n", result->pw_uid, result->pw_name);
     ret = NSS_STATUS_SUCCESS;
   } else if (
-	     // Yes, this is one of those cases where an assign makes sense.
-	     // NB: passwd.borg.base is not ordered by UID as of cl/201005022.
-	     fb != NULL && (result = sparecopy) && (fgetpwent_r(fb, result, buffer, buflen, &result) == 0)) {
-    DEBUG("Returning base user %d:%s\n", result->pw_uid, result->pw_name);
+    // Yes, this is one of those cases where an assign makes sense.
+    // NB: passwd.borg.base is not ordered by UID as of cl/201005022.
+      f != NULL && (result = sparecopy) &&
+          (fgetpwent_r(f, result, buffer, buflen, &result) == 0)) {
+    DEBUG("Returning non borg user %d:%s\n", result->pw_uid, result->pw_name);
+    // Log only if passwd.borg.real file is present.
+    if (fbr) {
+      *non_borg_user = 1;
+    }
     ret = NSS_STATUS_SUCCESS;
   } else {
     *errnop = errno;
@@ -114,36 +163,70 @@ static enum nss_status _nss_borg_getpwent_r_locked(struct passwd *result,
   return ret;
 }
 
+// All methods below are public interface of this library.
+
+// _nss_borg_setpwent()
+// Called by NSS to open the passwd file
+// Oddly, NSS passes a boolean saying whether to keep the database file open;
+// ignore it
+enum nss_status _nss_borg_setpwent(int stayopen) {
+  enum nss_status ret;
+  NSSBORG_LOCK;
+  ret = _nss_borg_setpwent_locked();
+  NSSBORG_UNLOCK;
+  return ret;
+}
+
+// _nss_borg_endpwent()
+// Called by NSS to close the passwd file
+enum nss_status _nss_borg_endpwent(void) {
+  enum nss_status ret;
+  NSSBORG_LOCK;
+  ret = _nss_borg_endpwent_locked();
+  NSSBORG_UNLOCK;
+  return ret;
+}
+
 // _nss_borg_getpwent_r()
 // Called by NSS (I think) to look up next entry in passwd file
-enum nss_status _nss_borg_getpwent_r(struct passwd *result,
-                                     char *buffer, size_t buflen,
-                                     int *errnop) {
+enum nss_status _nss_borg_getpwent_r(struct passwd *result, char *buffer,
+                                     size_t buflen, int *errnop) {
   enum nss_status ret;
+  int non_borg_user = 0;
   NSSBORG_LOCK;
-  ret = _nss_borg_getpwent_r_locked(result, buffer, buflen, errnop);
+  ret = _nss_borg_getpwent_r_locked(result, buffer, buflen, errnop,
+                                    &non_borg_user);
+  if (non_borg_user && !non_borg_user_lookup_warn) {
+    non_borg_user_lookup_warn = 1;
+    WARN("Reached non borg section in getpwent call "
+         "in process: %s running as: %d\n", exec_name, getuid());
+  }
   NSSBORG_UNLOCK;
   return ret;
 }
 
 // _nss_borg_getpwuid_r()
-// Find a user account by uid
-
+// Called by NSS to find a user account by uid
 enum nss_status _nss_borg_getpwuid_r(uid_t uid, struct passwd *result,
-                                     char *buffer, size_t buflen,
-                                     int *errnop) {
-
+                                     char *buffer, size_t buflen, int *errnop) {
   enum nss_status ret;
+  int non_borg_user = 0;
 
   NSSBORG_LOCK;
   ret = _nss_borg_setpwent_locked();
   DEBUG("Looking for uid %d\n", uid);
 
   if (ret == NSS_STATUS_SUCCESS) {
-    while ((ret = _nss_borg_getpwent_r_locked(result, buffer, buflen, errnop))
-           == NSS_STATUS_SUCCESS) {
-      if (result->pw_uid == uid)
+    while ((ret = _nss_borg_getpwent_r_locked(result, buffer, buflen, errnop,
+                                              &non_borg_user)) ==
+           NSS_STATUS_SUCCESS) {
+      if (result->pw_uid == uid) {
+        if (non_borg_user) {
+          WARN("Returning non borg user %d:%s in process: %s running as: %d\n",
+               result->pw_uid, result->pw_name, exec_name, getuid());
+        }
         break;
+      }
     }
   }
 
@@ -154,23 +237,27 @@ enum nss_status _nss_borg_getpwuid_r(uid_t uid, struct passwd *result,
 }
 
 // _nss_borg_getpwnam_r()
-// Find a user account by name
-
+// Called by NSS to find a user account by name
 enum nss_status _nss_borg_getpwnam_r(const char *name, struct passwd *result,
-                                     char *buffer, size_t buflen,
-                                     int *errnop) {
-
+                                     char *buffer, size_t buflen, int *errnop) {
   enum nss_status ret;
+  int non_borg_user = 0;
 
   NSSBORG_LOCK;
   ret = _nss_borg_setpwent_locked();
   DEBUG("Looking for user %s\n", name);
 
   if (ret == NSS_STATUS_SUCCESS) {
-    while ((ret = _nss_borg_getpwent_r_locked(result, buffer, buflen, errnop))
-           == NSS_STATUS_SUCCESS) {
-      if (!strcmp(result->pw_name, name))
+    while ((ret = _nss_borg_getpwent_r_locked(result, buffer, buflen, errnop,
+                                              &non_borg_user)) ==
+           NSS_STATUS_SUCCESS) {
+      if (!strcmp(result->pw_name, name)) {
+        if (non_borg_user) {
+          WARN("Returning non borg user %d:%s in process: %s running as: %d\n",
+               result->pw_uid, result->pw_name, exec_name, getuid());
+        }
         break;
+      }
     }
   }


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [glibc/maskray/grte] Update passwd.borg handling to use passwd.borg.real
@ 2021-08-28  0:28 Fangrui Song
  0 siblings, 0 replies; 3+ messages in thread
From: Fangrui Song @ 2021-08-28  0:28 UTC (permalink / raw)
  To: glibc-cvs

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=f2cb1ce4ea828cda665403f7f119850de51622e2

commit f2cb1ce4ea828cda665403f7f119850de51622e2
Author: Stan Shebs <stanshebs@google.com>
Date:   Fri Dec 20 13:58:35 2019 -0800

    Update passwd.borg handling to use passwd.borg.real

Diff:
---
 nss/nss_borg/borg-pwd.c | 215 ++++++++++++++++++++++++++++++++++--------------
 1 file changed, 151 insertions(+), 64 deletions(-)

diff --git a/nss/nss_borg/borg-pwd.c b/nss/nss_borg/borg-pwd.c
index a0eb0e3954..2e50b287a9 100644
--- a/nss/nss_borg/borg-pwd.c
+++ b/nss/nss_borg/borg-pwd.c
@@ -2,58 +2,85 @@
 // /etc/passwd.borg and /etc/passwd.borg.base
 // passwd.borg.base is a subset of passwd.borg that is used as a fallback.
 
-#include <stdio.h>
-#include <pwd.h>
-#include <sys/types.h>
-#include <nss.h>
 #include <errno.h>
+#include <nss.h>
+#include <pwd.h>
+#include <stdio.h>
 #include <string.h>
+#include <sys/types.h>
+#include <syslog.h>
 
 #include <libc-lock.h>
-__libc_lock_define_initialized (static, lock)
-#define NSSBORG_LOCK  __libc_lock_lock (lock)
-#define NSSBORG_UNLOCK  __libc_lock_unlock (lock);
+__libc_lock_define_initialized(static, lock)
+#define NSSBORG_LOCK __libc_lock_lock(lock)
+#define NSSBORG_UNLOCK __libc_lock_unlock(lock);
+
+#define EXEC_NAME_SIZE 4096
 
 static FILE *f;
 static FILE *fb;
-
+static bool fb_eof;
+static FILE *fbr;
+static bool fbr_eof;
+static char exec_name[EXEC_NAME_SIZE];
+
+// This library will log into syslog any attempt to fetch a username from
+// /etc/passwd.borg file, but only if /etc/passwd.borg.real file is present.
+// This module makes the user lookup in following order:
+// /etc/passwd.borg.real
+// /etc/passwd.borg.base
+// /etc/passwd.borg
+
+
+// non_borg_user_lookup_warn is supposed to prevent log spew from a single
+// process.
+static int non_borg_user_lookup_warn = 0;
+
+#define LOGNSS(priority, fmt, ...)                   \
+  do {                                               \
+    openlog("nss_borg", LOG_PID, 0);                 \
+    syslog(LOG_USER | priority, fmt, ##__VA_ARGS__); \
+    closelog();                                      \
+  } while (0)
 #define DEBUG(fmt, ...)
+#define WARN(fmt, ...) LOGNSS(LOG_WARNING, fmt, ##__VA_ARGS__)
 
 // _nss_borg_setpwent_locked()
 // Internal setup routine
-
 static enum nss_status _nss_borg_setpwent_locked(void) {
-
+  int readlink_ret;
   DEBUG("Opening passwd.borg\n");
   f = fopen("/etc/passwd.borg", "r");
 
   DEBUG("Opening passwd.borg.base\n");
   fb = fopen("/etc/passwd.borg.base", "r");
+  fb_eof = false;
+
+  DEBUG("Opening passwd.borg.real\n");
+  fbr = fopen("/etc/passwd.borg.real", "r");
+  fbr_eof = false;
+
+  DEBUG("Reading /proc/self/exe");
+  // readlink does not append null-byte, so we reserve last byte for it.
+  readlink_ret = readlink("/proc/self/exe", exec_name,
+                          sizeof(exec_name) - 1);
+  if (readlink_ret == -1) {
+    DEBUG("Failed to readlink /proc/self/exe error: %d", errno);
+    strncpy(exec_name, "__unknown__", sizeof(exec_name));
+  } else {
+    exec_name[readlink_ret] = '\0';
+  }
 
-  if (f||fb) {
+  if (f || fb || fbr) {
     return NSS_STATUS_SUCCESS;
   } else {
     return NSS_STATUS_UNAVAIL;
   }
 }
 
-// _nss_borg_setpwent()
-// Called by NSS to open the passwd file
-// Oddly, NSS passes a boolean saying whether to keep the database file open; ignore it
-
-enum nss_status _nss_borg_setpwent(int stayopen) {
-  enum nss_status ret;
-  NSSBORG_LOCK;
-  ret = _nss_borg_setpwent_locked();
-  NSSBORG_UNLOCK;
-  return ret;
-}
-
 // _nss_borg_endpwent_locked()
 // Internal close routine
-
 static enum nss_status _nss_borg_endpwent_locked(void) {
-
   DEBUG("Closing passwd.borg\n");
   if (f) {
     fclose(f);
@@ -64,40 +91,62 @@ static enum nss_status _nss_borg_endpwent_locked(void) {
     fclose(fb);
     fb = NULL;
   }
+  DEBUG("Closing passwd.borg.real\n");
+  if (fbr) {
+    fclose(fbr);
+    fbr = NULL;
+  }
   return NSS_STATUS_SUCCESS;
 }
 
-// _nss_borg_endpwent()
-// Called by NSS to close the passwd file
-
-enum nss_status _nss_borg_endpwent(void) {
-  enum nss_status ret;
-  NSSBORG_LOCK;
-  ret = _nss_borg_endpwent_locked();
-  NSSBORG_UNLOCK;
-  return ret;
+// Called internally. It's a wrapper around fgetpwent_r that prevents from
+// multiple read calls once EOF was reached (b/72036184)
+static int _nss_borg_fgetpwent_r_eof(FILE *fp, struct passwd *pwbuf,
+                                           char *buf, size_t buflen,
+                                           struct passwd **pwbufp, bool *eof) {
+  if (*eof) {
+    *pwbufp = NULL;
+    return ENOENT;
+  } else {
+    int ret = fgetpwent_r(fp, pwbuf, buf, buflen, pwbufp);
+    if (ret == ENOENT) {
+      *eof = true;
+    }
+    return ret;
+  }
 }
 
 // _nss_borg_getpwent_r_locked()
 // Called internally to return the next entry from the passwd file
-
 static enum nss_status _nss_borg_getpwent_r_locked(struct passwd *result,
                                                    char *buffer, size_t buflen,
-                                                   int *errnop) {
-
+                                                   int *errnop,
+                                                   int *non_borg_user) {
   enum nss_status ret;
   // Save a copy of the buffer address, in case first call errors
   // and sets it to 0.
   struct passwd *sparecopy = result;
-  if (
-      f != NULL && (fgetpwent_r(f, result, buffer, buflen, &result) == 0)) {
-    DEBUG("Returning borg user %d:%s\n", result->pw_uid, result->pw_name);
+  if (fbr != NULL && (_nss_borg_fgetpwent_r_eof(fbr, result, buffer, buflen,
+                                                &result, &fbr_eof) == 0)) {
+    DEBUG("Returning real borg user %d:%s\n", result->pw_uid, result->pw_name);
+    ret = NSS_STATUS_SUCCESS;
+  } else if (
+      // Yes, this is one of those cases where an assign makes sense.
+      fb != NULL && (result = sparecopy) &&
+      (_nss_borg_fgetpwent_r_eof(fb, result, buffer, buflen, &result,
+                                 &fb_eof) == 0)) {
+    DEBUG("Returning base borg user %d:%s\n", result->pw_uid, result->pw_name);
     ret = NSS_STATUS_SUCCESS;
   } else if (
-	     // Yes, this is one of those cases where an assign makes sense.
-	     // NB: passwd.borg.base is not ordered by UID as of cl/201005022.
-	     fb != NULL && (result = sparecopy) && (fgetpwent_r(fb, result, buffer, buflen, &result) == 0)) {
-    DEBUG("Returning base user %d:%s\n", result->pw_uid, result->pw_name);
+    // Yes, this is one of those cases where an assign makes sense.
+    // NB: passwd.borg.base is not ordered by UID as of cl/201005022.
+      f != NULL && (result = sparecopy) &&
+          (fgetpwent_r(f, result, buffer, buflen, &result) == 0)) {
+    DEBUG("Returning non borg user %d:%s\n", result->pw_uid, result->pw_name);
+    // Log only if passwd.borg.real file is present.
+    if (fbr) {
+      *non_borg_user = 1;
+    }
     ret = NSS_STATUS_SUCCESS;
   } else {
     *errnop = errno;
@@ -114,36 +163,70 @@ static enum nss_status _nss_borg_getpwent_r_locked(struct passwd *result,
   return ret;
 }
 
+// All methods below are public interface of this library.
+
+// _nss_borg_setpwent()
+// Called by NSS to open the passwd file
+// Oddly, NSS passes a boolean saying whether to keep the database file open;
+// ignore it
+enum nss_status _nss_borg_setpwent(int stayopen) {
+  enum nss_status ret;
+  NSSBORG_LOCK;
+  ret = _nss_borg_setpwent_locked();
+  NSSBORG_UNLOCK;
+  return ret;
+}
+
+// _nss_borg_endpwent()
+// Called by NSS to close the passwd file
+enum nss_status _nss_borg_endpwent(void) {
+  enum nss_status ret;
+  NSSBORG_LOCK;
+  ret = _nss_borg_endpwent_locked();
+  NSSBORG_UNLOCK;
+  return ret;
+}
+
 // _nss_borg_getpwent_r()
 // Called by NSS (I think) to look up next entry in passwd file
-enum nss_status _nss_borg_getpwent_r(struct passwd *result,
-                                     char *buffer, size_t buflen,
-                                     int *errnop) {
+enum nss_status _nss_borg_getpwent_r(struct passwd *result, char *buffer,
+                                     size_t buflen, int *errnop) {
   enum nss_status ret;
+  int non_borg_user = 0;
   NSSBORG_LOCK;
-  ret = _nss_borg_getpwent_r_locked(result, buffer, buflen, errnop);
+  ret = _nss_borg_getpwent_r_locked(result, buffer, buflen, errnop,
+                                    &non_borg_user);
+  if (non_borg_user && !non_borg_user_lookup_warn) {
+    non_borg_user_lookup_warn = 1;
+    WARN("Reached non borg section in getpwent call "
+         "in process: %s running as: %d\n", exec_name, getuid());
+  }
   NSSBORG_UNLOCK;
   return ret;
 }
 
 // _nss_borg_getpwuid_r()
-// Find a user account by uid
-
+// Called by NSS to find a user account by uid
 enum nss_status _nss_borg_getpwuid_r(uid_t uid, struct passwd *result,
-                                     char *buffer, size_t buflen,
-                                     int *errnop) {
-
+                                     char *buffer, size_t buflen, int *errnop) {
   enum nss_status ret;
+  int non_borg_user = 0;
 
   NSSBORG_LOCK;
   ret = _nss_borg_setpwent_locked();
   DEBUG("Looking for uid %d\n", uid);
 
   if (ret == NSS_STATUS_SUCCESS) {
-    while ((ret = _nss_borg_getpwent_r_locked(result, buffer, buflen, errnop))
-           == NSS_STATUS_SUCCESS) {
-      if (result->pw_uid == uid)
+    while ((ret = _nss_borg_getpwent_r_locked(result, buffer, buflen, errnop,
+                                              &non_borg_user)) ==
+           NSS_STATUS_SUCCESS) {
+      if (result->pw_uid == uid) {
+        if (non_borg_user) {
+          WARN("Returning non borg user %d:%s in process: %s running as: %d\n",
+               result->pw_uid, result->pw_name, exec_name, getuid());
+        }
         break;
+      }
     }
   }
 
@@ -154,23 +237,27 @@ enum nss_status _nss_borg_getpwuid_r(uid_t uid, struct passwd *result,
 }
 
 // _nss_borg_getpwnam_r()
-// Find a user account by name
-
+// Called by NSS to find a user account by name
 enum nss_status _nss_borg_getpwnam_r(const char *name, struct passwd *result,
-                                     char *buffer, size_t buflen,
-                                     int *errnop) {
-
+                                     char *buffer, size_t buflen, int *errnop) {
   enum nss_status ret;
+  int non_borg_user = 0;
 
   NSSBORG_LOCK;
   ret = _nss_borg_setpwent_locked();
   DEBUG("Looking for user %s\n", name);
 
   if (ret == NSS_STATUS_SUCCESS) {
-    while ((ret = _nss_borg_getpwent_r_locked(result, buffer, buflen, errnop))
-           == NSS_STATUS_SUCCESS) {
-      if (!strcmp(result->pw_name, name))
+    while ((ret = _nss_borg_getpwent_r_locked(result, buffer, buflen, errnop,
+                                              &non_borg_user)) ==
+           NSS_STATUS_SUCCESS) {
+      if (!strcmp(result->pw_name, name)) {
+        if (non_borg_user) {
+          WARN("Returning non borg user %d:%s in process: %s running as: %d\n",
+               result->pw_uid, result->pw_name, exec_name, getuid());
+        }
         break;
+      }
     }
   }


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [glibc/maskray/grte] Update passwd.borg handling to use passwd.borg.real
@ 2021-08-27 23:45 Fangrui Song
  0 siblings, 0 replies; 3+ messages in thread
From: Fangrui Song @ 2021-08-27 23:45 UTC (permalink / raw)
  To: glibc-cvs

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=5f2404b6ed2feb66724b3737ac2aebfca4ac7592

commit 5f2404b6ed2feb66724b3737ac2aebfca4ac7592
Author: Stan Shebs <stanshebs@google.com>
Date:   Fri Dec 20 13:58:35 2019 -0800

    Update passwd.borg handling to use passwd.borg.real

Diff:
---
 nss/nss_borg/borg-pwd.c | 215 ++++++++++++++++++++++++++++++++++--------------
 1 file changed, 151 insertions(+), 64 deletions(-)

diff --git a/nss/nss_borg/borg-pwd.c b/nss/nss_borg/borg-pwd.c
index a0eb0e3954..2e50b287a9 100644
--- a/nss/nss_borg/borg-pwd.c
+++ b/nss/nss_borg/borg-pwd.c
@@ -2,58 +2,85 @@
 // /etc/passwd.borg and /etc/passwd.borg.base
 // passwd.borg.base is a subset of passwd.borg that is used as a fallback.
 
-#include <stdio.h>
-#include <pwd.h>
-#include <sys/types.h>
-#include <nss.h>
 #include <errno.h>
+#include <nss.h>
+#include <pwd.h>
+#include <stdio.h>
 #include <string.h>
+#include <sys/types.h>
+#include <syslog.h>
 
 #include <libc-lock.h>
-__libc_lock_define_initialized (static, lock)
-#define NSSBORG_LOCK  __libc_lock_lock (lock)
-#define NSSBORG_UNLOCK  __libc_lock_unlock (lock);
+__libc_lock_define_initialized(static, lock)
+#define NSSBORG_LOCK __libc_lock_lock(lock)
+#define NSSBORG_UNLOCK __libc_lock_unlock(lock);
+
+#define EXEC_NAME_SIZE 4096
 
 static FILE *f;
 static FILE *fb;
-
+static bool fb_eof;
+static FILE *fbr;
+static bool fbr_eof;
+static char exec_name[EXEC_NAME_SIZE];
+
+// This library will log into syslog any attempt to fetch a username from
+// /etc/passwd.borg file, but only if /etc/passwd.borg.real file is present.
+// This module makes the user lookup in following order:
+// /etc/passwd.borg.real
+// /etc/passwd.borg.base
+// /etc/passwd.borg
+
+
+// non_borg_user_lookup_warn is supposed to prevent log spew from a single
+// process.
+static int non_borg_user_lookup_warn = 0;
+
+#define LOGNSS(priority, fmt, ...)                   \
+  do {                                               \
+    openlog("nss_borg", LOG_PID, 0);                 \
+    syslog(LOG_USER | priority, fmt, ##__VA_ARGS__); \
+    closelog();                                      \
+  } while (0)
 #define DEBUG(fmt, ...)
+#define WARN(fmt, ...) LOGNSS(LOG_WARNING, fmt, ##__VA_ARGS__)
 
 // _nss_borg_setpwent_locked()
 // Internal setup routine
-
 static enum nss_status _nss_borg_setpwent_locked(void) {
-
+  int readlink_ret;
   DEBUG("Opening passwd.borg\n");
   f = fopen("/etc/passwd.borg", "r");
 
   DEBUG("Opening passwd.borg.base\n");
   fb = fopen("/etc/passwd.borg.base", "r");
+  fb_eof = false;
+
+  DEBUG("Opening passwd.borg.real\n");
+  fbr = fopen("/etc/passwd.borg.real", "r");
+  fbr_eof = false;
+
+  DEBUG("Reading /proc/self/exe");
+  // readlink does not append null-byte, so we reserve last byte for it.
+  readlink_ret = readlink("/proc/self/exe", exec_name,
+                          sizeof(exec_name) - 1);
+  if (readlink_ret == -1) {
+    DEBUG("Failed to readlink /proc/self/exe error: %d", errno);
+    strncpy(exec_name, "__unknown__", sizeof(exec_name));
+  } else {
+    exec_name[readlink_ret] = '\0';
+  }
 
-  if (f||fb) {
+  if (f || fb || fbr) {
     return NSS_STATUS_SUCCESS;
   } else {
     return NSS_STATUS_UNAVAIL;
   }
 }
 
-// _nss_borg_setpwent()
-// Called by NSS to open the passwd file
-// Oddly, NSS passes a boolean saying whether to keep the database file open; ignore it
-
-enum nss_status _nss_borg_setpwent(int stayopen) {
-  enum nss_status ret;
-  NSSBORG_LOCK;
-  ret = _nss_borg_setpwent_locked();
-  NSSBORG_UNLOCK;
-  return ret;
-}
-
 // _nss_borg_endpwent_locked()
 // Internal close routine
-
 static enum nss_status _nss_borg_endpwent_locked(void) {
-
   DEBUG("Closing passwd.borg\n");
   if (f) {
     fclose(f);
@@ -64,40 +91,62 @@ static enum nss_status _nss_borg_endpwent_locked(void) {
     fclose(fb);
     fb = NULL;
   }
+  DEBUG("Closing passwd.borg.real\n");
+  if (fbr) {
+    fclose(fbr);
+    fbr = NULL;
+  }
   return NSS_STATUS_SUCCESS;
 }
 
-// _nss_borg_endpwent()
-// Called by NSS to close the passwd file
-
-enum nss_status _nss_borg_endpwent(void) {
-  enum nss_status ret;
-  NSSBORG_LOCK;
-  ret = _nss_borg_endpwent_locked();
-  NSSBORG_UNLOCK;
-  return ret;
+// Called internally. It's a wrapper around fgetpwent_r that prevents from
+// multiple read calls once EOF was reached (b/72036184)
+static int _nss_borg_fgetpwent_r_eof(FILE *fp, struct passwd *pwbuf,
+                                           char *buf, size_t buflen,
+                                           struct passwd **pwbufp, bool *eof) {
+  if (*eof) {
+    *pwbufp = NULL;
+    return ENOENT;
+  } else {
+    int ret = fgetpwent_r(fp, pwbuf, buf, buflen, pwbufp);
+    if (ret == ENOENT) {
+      *eof = true;
+    }
+    return ret;
+  }
 }
 
 // _nss_borg_getpwent_r_locked()
 // Called internally to return the next entry from the passwd file
-
 static enum nss_status _nss_borg_getpwent_r_locked(struct passwd *result,
                                                    char *buffer, size_t buflen,
-                                                   int *errnop) {
-
+                                                   int *errnop,
+                                                   int *non_borg_user) {
   enum nss_status ret;
   // Save a copy of the buffer address, in case first call errors
   // and sets it to 0.
   struct passwd *sparecopy = result;
-  if (
-      f != NULL && (fgetpwent_r(f, result, buffer, buflen, &result) == 0)) {
-    DEBUG("Returning borg user %d:%s\n", result->pw_uid, result->pw_name);
+  if (fbr != NULL && (_nss_borg_fgetpwent_r_eof(fbr, result, buffer, buflen,
+                                                &result, &fbr_eof) == 0)) {
+    DEBUG("Returning real borg user %d:%s\n", result->pw_uid, result->pw_name);
+    ret = NSS_STATUS_SUCCESS;
+  } else if (
+      // Yes, this is one of those cases where an assign makes sense.
+      fb != NULL && (result = sparecopy) &&
+      (_nss_borg_fgetpwent_r_eof(fb, result, buffer, buflen, &result,
+                                 &fb_eof) == 0)) {
+    DEBUG("Returning base borg user %d:%s\n", result->pw_uid, result->pw_name);
     ret = NSS_STATUS_SUCCESS;
   } else if (
-	     // Yes, this is one of those cases where an assign makes sense.
-	     // NB: passwd.borg.base is not ordered by UID as of cl/201005022.
-	     fb != NULL && (result = sparecopy) && (fgetpwent_r(fb, result, buffer, buflen, &result) == 0)) {
-    DEBUG("Returning base user %d:%s\n", result->pw_uid, result->pw_name);
+    // Yes, this is one of those cases where an assign makes sense.
+    // NB: passwd.borg.base is not ordered by UID as of cl/201005022.
+      f != NULL && (result = sparecopy) &&
+          (fgetpwent_r(f, result, buffer, buflen, &result) == 0)) {
+    DEBUG("Returning non borg user %d:%s\n", result->pw_uid, result->pw_name);
+    // Log only if passwd.borg.real file is present.
+    if (fbr) {
+      *non_borg_user = 1;
+    }
     ret = NSS_STATUS_SUCCESS;
   } else {
     *errnop = errno;
@@ -114,36 +163,70 @@ static enum nss_status _nss_borg_getpwent_r_locked(struct passwd *result,
   return ret;
 }
 
+// All methods below are public interface of this library.
+
+// _nss_borg_setpwent()
+// Called by NSS to open the passwd file
+// Oddly, NSS passes a boolean saying whether to keep the database file open;
+// ignore it
+enum nss_status _nss_borg_setpwent(int stayopen) {
+  enum nss_status ret;
+  NSSBORG_LOCK;
+  ret = _nss_borg_setpwent_locked();
+  NSSBORG_UNLOCK;
+  return ret;
+}
+
+// _nss_borg_endpwent()
+// Called by NSS to close the passwd file
+enum nss_status _nss_borg_endpwent(void) {
+  enum nss_status ret;
+  NSSBORG_LOCK;
+  ret = _nss_borg_endpwent_locked();
+  NSSBORG_UNLOCK;
+  return ret;
+}
+
 // _nss_borg_getpwent_r()
 // Called by NSS (I think) to look up next entry in passwd file
-enum nss_status _nss_borg_getpwent_r(struct passwd *result,
-                                     char *buffer, size_t buflen,
-                                     int *errnop) {
+enum nss_status _nss_borg_getpwent_r(struct passwd *result, char *buffer,
+                                     size_t buflen, int *errnop) {
   enum nss_status ret;
+  int non_borg_user = 0;
   NSSBORG_LOCK;
-  ret = _nss_borg_getpwent_r_locked(result, buffer, buflen, errnop);
+  ret = _nss_borg_getpwent_r_locked(result, buffer, buflen, errnop,
+                                    &non_borg_user);
+  if (non_borg_user && !non_borg_user_lookup_warn) {
+    non_borg_user_lookup_warn = 1;
+    WARN("Reached non borg section in getpwent call "
+         "in process: %s running as: %d\n", exec_name, getuid());
+  }
   NSSBORG_UNLOCK;
   return ret;
 }
 
 // _nss_borg_getpwuid_r()
-// Find a user account by uid
-
+// Called by NSS to find a user account by uid
 enum nss_status _nss_borg_getpwuid_r(uid_t uid, struct passwd *result,
-                                     char *buffer, size_t buflen,
-                                     int *errnop) {
-
+                                     char *buffer, size_t buflen, int *errnop) {
   enum nss_status ret;
+  int non_borg_user = 0;
 
   NSSBORG_LOCK;
   ret = _nss_borg_setpwent_locked();
   DEBUG("Looking for uid %d\n", uid);
 
   if (ret == NSS_STATUS_SUCCESS) {
-    while ((ret = _nss_borg_getpwent_r_locked(result, buffer, buflen, errnop))
-           == NSS_STATUS_SUCCESS) {
-      if (result->pw_uid == uid)
+    while ((ret = _nss_borg_getpwent_r_locked(result, buffer, buflen, errnop,
+                                              &non_borg_user)) ==
+           NSS_STATUS_SUCCESS) {
+      if (result->pw_uid == uid) {
+        if (non_borg_user) {
+          WARN("Returning non borg user %d:%s in process: %s running as: %d\n",
+               result->pw_uid, result->pw_name, exec_name, getuid());
+        }
         break;
+      }
     }
   }
 
@@ -154,23 +237,27 @@ enum nss_status _nss_borg_getpwuid_r(uid_t uid, struct passwd *result,
 }
 
 // _nss_borg_getpwnam_r()
-// Find a user account by name
-
+// Called by NSS to find a user account by name
 enum nss_status _nss_borg_getpwnam_r(const char *name, struct passwd *result,
-                                     char *buffer, size_t buflen,
-                                     int *errnop) {
-
+                                     char *buffer, size_t buflen, int *errnop) {
   enum nss_status ret;
+  int non_borg_user = 0;
 
   NSSBORG_LOCK;
   ret = _nss_borg_setpwent_locked();
   DEBUG("Looking for user %s\n", name);
 
   if (ret == NSS_STATUS_SUCCESS) {
-    while ((ret = _nss_borg_getpwent_r_locked(result, buffer, buflen, errnop))
-           == NSS_STATUS_SUCCESS) {
-      if (!strcmp(result->pw_name, name))
+    while ((ret = _nss_borg_getpwent_r_locked(result, buffer, buflen, errnop,
+                                              &non_borg_user)) ==
+           NSS_STATUS_SUCCESS) {
+      if (!strcmp(result->pw_name, name)) {
+        if (non_borg_user) {
+          WARN("Returning non borg user %d:%s in process: %s running as: %d\n",
+               result->pw_uid, result->pw_name, exec_name, getuid());
+        }
         break;
+      }
     }
   }


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2021-08-28  0:32 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-28  0:32 [glibc/maskray/grte] Update passwd.borg handling to use passwd.borg.real Fangrui Song
  -- strict thread matches above, loose matches on Subject: below --
2021-08-28  0:28 Fangrui Song
2021-08-27 23:45 Fangrui Song

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).