nss-systemd,sysusers: make sure sysusers doesn't get confused by nss-systemd (#6812)
authorLennart Poettering <lennart@poettering.net>
Thu, 14 Sep 2017 04:20:39 +0000 (06:20 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 14 Sep 2017 04:20:39 +0000 (06:20 +0200)
In nss-systemd we synthesize user entries for "nobody" and "root", as
fallback if we boot up with an entirely empty /etc. This is supposed to
be a fallback only though, and it's intended that both users exists
regularly in /etc/passwd + /etc/group. Before this patch
systemd-sysusers would never create the entries however as it notices
the synthetic entries. Let's add a way how systemd-sysusers can tell
nss-systemd not to synthesize the entries for itself.

Fixes: #6808

src/nss-systemd/nss-systemd.c
src/sysusers/sysusers.c

index f404755..37745b3 100644 (file)
@@ -129,15 +129,17 @@ enum nss_status _nss_systemd_getpwnam_r(
                 goto not_found;
 
         /* Synthesize entries for the root and nobody users, in case they are missing in /etc/passwd */
-        if (streq(name, root_passwd.pw_name)) {
-                *pwd = root_passwd;
-                *errnop = 0;
-                return NSS_STATUS_SUCCESS;
-        }
-        if (streq(name, nobody_passwd.pw_name)) {
-                *pwd = nobody_passwd;
-                *errnop = 0;
-                return NSS_STATUS_SUCCESS;
+        if (getenv_bool("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
+                if (streq(name, root_passwd.pw_name)) {
+                        *pwd = root_passwd;
+                        *errnop = 0;
+                        return NSS_STATUS_SUCCESS;
+                }
+                if (streq(name, nobody_passwd.pw_name)) {
+                        *pwd = nobody_passwd;
+                        *errnop = 0;
+                        return NSS_STATUS_SUCCESS;
+                }
         }
 
         /* Make sure that we don't go in circles when allocating a dynamic UID by checking our own database */
@@ -231,15 +233,17 @@ enum nss_status _nss_systemd_getpwuid_r(
                 goto not_found;
 
         /* Synthesize data for the root user and for nobody in case they are missing from /etc/passwd */
-        if (uid == root_passwd.pw_uid) {
-                *pwd = root_passwd;
-                *errnop = 0;
-                return NSS_STATUS_SUCCESS;
-        }
-        if (uid == nobody_passwd.pw_uid) {
-                *pwd = nobody_passwd;
-                *errnop = 0;
-                return NSS_STATUS_SUCCESS;
+        if (getenv_bool("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
+                if (uid == root_passwd.pw_uid) {
+                        *pwd = root_passwd;
+                        *errnop = 0;
+                        return NSS_STATUS_SUCCESS;
+                }
+                if (uid == nobody_passwd.pw_uid) {
+                        *pwd = nobody_passwd;
+                        *errnop = 0;
+                        return NSS_STATUS_SUCCESS;
+                }
         }
 
         if (uid <= SYSTEM_UID_MAX)
@@ -331,15 +335,17 @@ enum nss_status _nss_systemd_getgrnam_r(
                 goto not_found;
 
         /* Synthesize records for root and nobody, in case they are missing form /etc/group */
-        if (streq(name, root_group.gr_name)) {
-                *gr = root_group;
-                *errnop = 0;
-                return NSS_STATUS_SUCCESS;
-        }
-        if (streq(name, nobody_group.gr_name)) {
-                *gr = nobody_group;
-                *errnop = 0;
-                return NSS_STATUS_SUCCESS;
+        if (getenv_bool("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
+                if (streq(name, root_group.gr_name)) {
+                        *gr = root_group;
+                        *errnop = 0;
+                        return NSS_STATUS_SUCCESS;
+                }
+                if (streq(name, nobody_group.gr_name)) {
+                        *gr = nobody_group;
+                        *errnop = 0;
+                        return NSS_STATUS_SUCCESS;
+                }
         }
 
         if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
@@ -430,15 +436,17 @@ enum nss_status _nss_systemd_getgrgid_r(
                 goto not_found;
 
         /* Synthesize records for root and nobody, in case they are missing from /etc/group */
-        if (gid == root_group.gr_gid) {
-                *gr = root_group;
-                *errnop = 0;
-                return NSS_STATUS_SUCCESS;
-        }
-        if (gid == nobody_group.gr_gid) {
-                *gr = nobody_group;
-                *errnop = 0;
-                return NSS_STATUS_SUCCESS;
+        if (getenv_bool("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
+                if (gid == root_group.gr_gid) {
+                        *gr = root_group;
+                        *errnop = 0;
+                        return NSS_STATUS_SUCCESS;
+                }
+                if (gid == nobody_group.gr_gid) {
+                        *gr = nobody_group;
+                        *errnop = 0;
+                        return NSS_STATUS_SUCCESS;
+                }
         }
 
         if (gid <= SYSTEM_GID_MAX)
index e384219..e9e6dae 100644 (file)
@@ -1811,6 +1811,16 @@ int main(int argc, char *argv[]) {
                 }
         }
 
+        /* Let's tell nss-systemd not to synthesize the "root" and "nobody" entries for it, so that our detection
+         * whether the names or UID/GID area already used otherwise doesn't get confused. After all, even though
+         * nss-systemd synthesizes these users/groups, they should still appear in /etc/passwd and /etc/group, as the
+         * synthesizing logic is merely supposed to be fallback for cases where we run with a completely unpopulated
+         * /etc. */
+        if (setenv("SYSTEMD_NSS_BYPASS_SYNTHETIC", "1", 1) < 0) {
+                r = log_error_errno(errno, "Failed to set SYSTEMD_NSS_BYPASS_SYNTHETIC environment variable: %m");
+                goto finish;
+        }
+
         if (!uid_range) {
                 /* Default to default range of 1..SYSTEMD_UID_MAX */
                 r = uid_range_add(&uid_range, &n_uid_range, 1, SYSTEM_UID_MAX);