ff6046
From 34bb0461192c9feba0c0f05a8baf8fefcd9d835e Mon Sep 17 00:00:00 2001
ff6046
From: Yu Watanabe <watanabe.yu+github@gmail.com>
ff6046
Date: Sun, 15 Jul 2018 23:00:00 +0900
ff6046
Subject: [PATCH] nss: do not modify errno when NSS_STATUS_NOTFOUND or
ff6046
 NSS_STATUS_SUCCESS
ff6046
ff6046
This also adds PROTECT_ERRNO for all nss module functions.
ff6046
ff6046
C.f. glibc NSS documents https://www.gnu.org/software/libc/manual/html_node/NSS-Modules-Interface.html
ff6046
and discussion in https://sourceware.org/bugzilla/show_bug.cgi?id=23410.
ff6046
ff6046
Fixes #9585.
ff6046
ff6046
(cherry picked from commit 06202b9e659e5cc72aeecc5200155b7c012fccbc)
ff6046
ff6046
Resolves: #1691691
ff6046
---
ff6046
 src/nss-myhostname/nss-myhostname.c | 16 +++---
ff6046
 src/nss-mymachines/nss-mymachines.c | 88 ++++++++++++-----------------
ff6046
 src/nss-resolve/nss-resolve.c       | 87 +++++++++++++---------------
ff6046
 src/nss-systemd/nss-systemd.c       | 74 +++++++++---------------
ff6046
 4 files changed, 108 insertions(+), 157 deletions(-)
ff6046
ff6046
diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c
ff6046
index f82ce59f2c..5abc0c91bf 100644
ff6046
--- a/src/nss-myhostname/nss-myhostname.c
ff6046
+++ b/src/nss-myhostname/nss-myhostname.c
ff6046
@@ -45,6 +45,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
ff6046
         char *r_name;
ff6046
         unsigned n;
ff6046
 
ff6046
+        PROTECT_ERRNO;
ff6046
         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
ff6046
 
ff6046
         assert(name);
ff6046
@@ -64,7 +65,6 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
ff6046
 
ff6046
                 n_addresses = local_gateways(NULL, 0, AF_UNSPEC, &addresses);
ff6046
                 if (n_addresses <= 0) {
ff6046
-                        *errnop = ENOENT;
ff6046
                         *h_errnop = HOST_NOT_FOUND;
ff6046
                         return NSS_STATUS_NOTFOUND;
ff6046
                 }
ff6046
@@ -81,7 +81,6 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
ff6046
 
ff6046
                 /* We respond to our local host name, our hostname suffixed with a single dot. */
ff6046
                 if (!streq(name, hn) && !streq_ptr(startswith(name, hn), ".")) {
ff6046
-                        *errnop = ENOENT;
ff6046
                         *h_errnop = HOST_NOT_FOUND;
ff6046
                         return NSS_STATUS_NOTFOUND;
ff6046
                 }
ff6046
@@ -157,8 +156,8 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
ff6046
         if (ttlp)
ff6046
                 *ttlp = 0;
ff6046
 
ff6046
-        /* Explicitly reset all error variables */
ff6046
-        *errnop = 0;
ff6046
+        /* Explicitly reset both *h_errnop and h_errno to work around
ff6046
+         * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
ff6046
         *h_errnop = NETDB_SUCCESS;
ff6046
         h_errno = 0;
ff6046
 
ff6046
@@ -286,8 +285,8 @@ static enum nss_status fill_in_hostent(
ff6046
         if (canonp)
ff6046
                 *canonp = r_name;
ff6046
 
ff6046
-        /* Explicitly reset all error variables */
ff6046
-        *errnop = 0;
ff6046
+        /* Explicitly reset both *h_errnop and h_errno to work around
ff6046
+         * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
ff6046
         *h_errnop = NETDB_SUCCESS;
ff6046
         h_errno = 0;
ff6046
 
ff6046
@@ -309,6 +308,7 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
ff6046
         uint32_t local_address_ipv4 = 0;
ff6046
         int n_addresses = 0;
ff6046
 
ff6046
+        PROTECT_ERRNO;
ff6046
         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
ff6046
 
ff6046
         assert(name);
ff6046
@@ -334,7 +334,6 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
ff6046
 
ff6046
                 n_addresses = local_gateways(NULL, 0, af, &addresses);
ff6046
                 if (n_addresses <= 0) {
ff6046
-                        *errnop = ENOENT;
ff6046
                         *h_errnop = HOST_NOT_FOUND;
ff6046
                         return NSS_STATUS_NOTFOUND;
ff6046
                 }
ff6046
@@ -350,7 +349,6 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
ff6046
                 }
ff6046
 
ff6046
                 if (!streq(name, hn) && !streq_ptr(startswith(name, hn), ".")) {
ff6046
-                        *errnop = ENOENT;
ff6046
                         *h_errnop = HOST_NOT_FOUND;
ff6046
                         return NSS_STATUS_NOTFOUND;
ff6046
                 }
ff6046
@@ -393,6 +391,7 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r(
ff6046
         bool additional_from_hostname = false;
ff6046
         unsigned n;
ff6046
 
ff6046
+        PROTECT_ERRNO;
ff6046
         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
ff6046
 
ff6046
         assert(addr);
ff6046
@@ -455,7 +454,6 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r(
ff6046
                 }
ff6046
         }
ff6046
 
ff6046
-        *errnop = ENOENT;
ff6046
         *h_errnop = HOST_NOT_FOUND;
ff6046
         return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
diff --git a/src/nss-mymachines/nss-mymachines.c b/src/nss-mymachines/nss-mymachines.c
ff6046
index 8d6caa0ada..9b81cd9ad1 100644
ff6046
--- a/src/nss-mymachines/nss-mymachines.c
ff6046
+++ b/src/nss-mymachines/nss-mymachines.c
ff6046
@@ -80,6 +80,7 @@ enum nss_status _nss_mymachines_gethostbyname4_r(
ff6046
         char *r_name;
ff6046
         int n_ifindices, r;
ff6046
 
ff6046
+        PROTECT_ERRNO;
ff6046
         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
ff6046
 
ff6046
         assert(name);
ff6046
@@ -126,7 +127,6 @@ enum nss_status _nss_mymachines_gethostbyname4_r(
ff6046
                 goto fail;
ff6046
 
ff6046
         if (c <= 0) {
ff6046
-                *errnop = ESRCH;
ff6046
                 *h_errnop = HOST_NOT_FOUND;
ff6046
                 return NSS_STATUS_NOTFOUND;
ff6046
         }
ff6046
@@ -200,8 +200,8 @@ enum nss_status _nss_mymachines_gethostbyname4_r(
ff6046
         if (ttlp)
ff6046
                 *ttlp = 0;
ff6046
 
ff6046
-        /* Explicitly reset all error variables */
ff6046
-        *errnop = 0;
ff6046
+        /* Explicitly reset both *h_errnop and h_errno to work around
ff6046
+         * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
ff6046
         *h_errnop = NETDB_SUCCESS;
ff6046
         h_errno = 0;
ff6046
 
ff6046
@@ -230,6 +230,7 @@ enum nss_status _nss_mymachines_gethostbyname3_r(
ff6046
         size_t l, idx, ms, alen;
ff6046
         int r;
ff6046
 
ff6046
+        PROTECT_ERRNO;
ff6046
         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
ff6046
 
ff6046
         assert(name);
ff6046
@@ -278,7 +279,6 @@ enum nss_status _nss_mymachines_gethostbyname3_r(
ff6046
                 goto fail;
ff6046
 
ff6046
         if (c <= 0) {
ff6046
-                *errnop = ENOENT;
ff6046
                 *h_errnop = HOST_NOT_FOUND;
ff6046
                 return NSS_STATUS_NOTFOUND;
ff6046
         }
ff6046
@@ -364,8 +364,8 @@ enum nss_status _nss_mymachines_gethostbyname3_r(
ff6046
         if (canonp)
ff6046
                 *canonp = r_name;
ff6046
 
ff6046
-        /* Explicitly reset all error variables */
ff6046
-        *errnop = 0;
ff6046
+        /* Explicitly reset both *h_errnop and h_errno to work around
ff6046
+         * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
ff6046
         *h_errnop = NETDB_SUCCESS;
ff6046
         h_errno = 0;
ff6046
 
ff6046
@@ -394,6 +394,7 @@ enum nss_status _nss_mymachines_getpwnam_r(
ff6046
         size_t l;
ff6046
         int r;
ff6046
 
ff6046
+        PROTECT_ERRNO;
ff6046
         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
ff6046
 
ff6046
         assert(name);
ff6046
@@ -401,28 +402,28 @@ enum nss_status _nss_mymachines_getpwnam_r(
ff6046
 
ff6046
         p = startswith(name, "vu-");
ff6046
         if (!p)
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         e = strrchr(p, '-');
ff6046
         if (!e || e == p)
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         if (e - p > HOST_NAME_MAX - 1) /* -1 for the last dash */
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         r = parse_uid(e + 1, &uid);
ff6046
         if (r < 0)
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         machine = strndupa(p, e - p);
ff6046
         if (!machine_name_is_valid(machine))
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
ff6046
                 /* Make sure we can't deadlock if we are invoked by dbus-daemon. This way, it won't be able to resolve
ff6046
                  * these UIDs, but that should be unproblematic as containers should never be able to connect to a bus
ff6046
                  * running on the host. */
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         r = sd_bus_open_system(&bus;;
ff6046
         if (r < 0)
ff6046
@@ -439,7 +440,7 @@ enum nss_status _nss_mymachines_getpwnam_r(
ff6046
                                machine, (uint32_t) uid);
ff6046
         if (r < 0) {
ff6046
                 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING))
ff6046
-                        goto not_found;
ff6046
+                        return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
                 goto fail;
ff6046
         }
ff6046
@@ -450,7 +451,7 @@ enum nss_status _nss_mymachines_getpwnam_r(
ff6046
 
ff6046
         /* Refuse to work if the mapped address is in the host UID range, or if there was no mapping at all. */
ff6046
         if (mapped < HOST_UID_LIMIT || mapped == uid)
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         l = strlen(name);
ff6046
         if (buflen < l+1) {
ff6046
@@ -468,13 +469,8 @@ enum nss_status _nss_mymachines_getpwnam_r(
ff6046
         pwd->pw_dir = (char*) "/";
ff6046
         pwd->pw_shell = (char*) "/sbin/nologin";
ff6046
 
ff6046
-        *errnop = 0;
ff6046
         return NSS_STATUS_SUCCESS;
ff6046
 
ff6046
-not_found:
ff6046
-        *errnop = 0;
ff6046
-        return NSS_STATUS_NOTFOUND;
ff6046
-
ff6046
 fail:
ff6046
         *errnop = -r;
ff6046
         return NSS_STATUS_UNAVAIL;
ff6046
@@ -493,17 +489,18 @@ enum nss_status _nss_mymachines_getpwuid_r(
ff6046
         uint32_t mapped;
ff6046
         int r;
ff6046
 
ff6046
+        PROTECT_ERRNO;
ff6046
         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
ff6046
 
ff6046
         if (!uid_is_valid(uid))
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         /* We consider all uids < 65536 host uids */
ff6046
         if (uid < HOST_UID_LIMIT)
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         r = sd_bus_open_system(&bus;;
ff6046
         if (r < 0)
ff6046
@@ -520,7 +517,7 @@ enum nss_status _nss_mymachines_getpwuid_r(
ff6046
                                (uint32_t) uid);
ff6046
         if (r < 0) {
ff6046
                 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING))
ff6046
-                        goto not_found;
ff6046
+                        return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
                 goto fail;
ff6046
         }
ff6046
@@ -530,7 +527,7 @@ enum nss_status _nss_mymachines_getpwuid_r(
ff6046
                 goto fail;
ff6046
 
ff6046
         if (mapped == uid)
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         if (snprintf(buffer, buflen, "vu-%s-" UID_FMT, machine, (uid_t) mapped) >= (int) buflen) {
ff6046
                 *errnop = ERANGE;
ff6046
@@ -545,13 +542,8 @@ enum nss_status _nss_mymachines_getpwuid_r(
ff6046
         pwd->pw_dir = (char*) "/";
ff6046
         pwd->pw_shell = (char*) "/sbin/nologin";
ff6046
 
ff6046
-        *errnop = 0;
ff6046
         return NSS_STATUS_SUCCESS;
ff6046
 
ff6046
-not_found:
ff6046
-        *errnop = 0;
ff6046
-        return NSS_STATUS_NOTFOUND;
ff6046
-
ff6046
 fail:
ff6046
         *errnop = -r;
ff6046
         return NSS_STATUS_UNAVAIL;
ff6046
@@ -574,6 +566,7 @@ enum nss_status _nss_mymachines_getgrnam_r(
ff6046
         size_t l;
ff6046
         int r;
ff6046
 
ff6046
+        PROTECT_ERRNO;
ff6046
         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
ff6046
 
ff6046
         assert(name);
ff6046
@@ -581,25 +574,25 @@ enum nss_status _nss_mymachines_getgrnam_r(
ff6046
 
ff6046
         p = startswith(name, "vg-");
ff6046
         if (!p)
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         e = strrchr(p, '-');
ff6046
         if (!e || e == p)
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         if (e - p > HOST_NAME_MAX - 1)  /* -1 for the last dash */
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         r = parse_gid(e + 1, &gid;;
ff6046
         if (r < 0)
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         machine = strndupa(p, e - p);
ff6046
         if (!machine_name_is_valid(machine))
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         r = sd_bus_open_system(&bus;;
ff6046
         if (r < 0)
ff6046
@@ -616,7 +609,7 @@ enum nss_status _nss_mymachines_getgrnam_r(
ff6046
                                machine, (uint32_t) gid);
ff6046
         if (r < 0) {
ff6046
                 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING))
ff6046
-                        goto not_found;
ff6046
+                        return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
                 goto fail;
ff6046
         }
ff6046
@@ -626,7 +619,7 @@ enum nss_status _nss_mymachines_getgrnam_r(
ff6046
                 goto fail;
ff6046
 
ff6046
         if (mapped < HOST_GID_LIMIT || mapped == gid)
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         l = sizeof(char*) + strlen(name) + 1;
ff6046
         if (buflen < l) {
ff6046
@@ -642,13 +635,8 @@ enum nss_status _nss_mymachines_getgrnam_r(
ff6046
         gr->gr_passwd = (char*) "*"; /* locked */
ff6046
         gr->gr_mem = (char**) buffer;
ff6046
 
ff6046
-        *errnop = 0;
ff6046
         return NSS_STATUS_SUCCESS;
ff6046
 
ff6046
-not_found:
ff6046
-        *errnop = 0;
ff6046
-        return NSS_STATUS_NOTFOUND;
ff6046
-
ff6046
 fail:
ff6046
         *errnop = -r;
ff6046
         return NSS_STATUS_UNAVAIL;
ff6046
@@ -667,17 +655,18 @@ enum nss_status _nss_mymachines_getgrgid_r(
ff6046
         uint32_t mapped;
ff6046
         int r;
ff6046
 
ff6046
+        PROTECT_ERRNO;
ff6046
         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
ff6046
 
ff6046
         if (!gid_is_valid(gid))
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         /* We consider all gids < 65536 host gids */
ff6046
         if (gid < HOST_GID_LIMIT)
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         r = sd_bus_open_system(&bus;;
ff6046
         if (r < 0)
ff6046
@@ -694,7 +683,7 @@ enum nss_status _nss_mymachines_getgrgid_r(
ff6046
                                (uint32_t) gid);
ff6046
         if (r < 0) {
ff6046
                 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING))
ff6046
-                        goto not_found;
ff6046
+                        return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
                 goto fail;
ff6046
         }
ff6046
@@ -704,7 +693,7 @@ enum nss_status _nss_mymachines_getgrgid_r(
ff6046
                 goto fail;
ff6046
 
ff6046
         if (mapped == gid)
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         if (buflen < sizeof(char*) + 1) {
ff6046
                 *errnop = ERANGE;
ff6046
@@ -722,13 +711,8 @@ enum nss_status _nss_mymachines_getgrgid_r(
ff6046
         gr->gr_passwd = (char*) "*"; /* locked */
ff6046
         gr->gr_mem = (char**) buffer;
ff6046
 
ff6046
-        *errnop = 0;
ff6046
         return NSS_STATUS_SUCCESS;
ff6046
 
ff6046
-not_found:
ff6046
-        *errnop = 0;
ff6046
-        return NSS_STATUS_NOTFOUND;
ff6046
-
ff6046
 fail:
ff6046
         *errnop = -r;
ff6046
         return NSS_STATUS_UNAVAIL;
ff6046
diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c
ff6046
index eb3d2d977f..b2bb698ded 100644
ff6046
--- a/src/nss-resolve/nss-resolve.c
ff6046
+++ b/src/nss-resolve/nss-resolve.c
ff6046
@@ -108,6 +108,7 @@ enum nss_status _nss_resolve_gethostbyname4_r(
ff6046
         char *r_name;
ff6046
         int c, r, i = 0;
ff6046
 
ff6046
+        PROTECT_ERRNO;
ff6046
         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
ff6046
 
ff6046
         assert(name);
ff6046
@@ -140,20 +141,15 @@ enum nss_status _nss_resolve_gethostbyname4_r(
ff6046
 
ff6046
         r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
ff6046
         if (r < 0) {
ff6046
-                if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN")) {
ff6046
-                        *errnop = ESRCH;
ff6046
-                        *h_errnop = HOST_NOT_FOUND;
ff6046
-                        return NSS_STATUS_NOTFOUND;
ff6046
-                }
ff6046
+                if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN") ||
ff6046
+                    !bus_error_shall_fallback(&error))
ff6046
+                        goto not_found;
ff6046
 
ff6046
                 /* Return NSS_STATUS_UNAVAIL when communication with systemd-resolved fails,
ff6046
                    allowing falling back to other nss modules. Treat all other error conditions as
ff6046
                    NOTFOUND. This includes DNSSEC errors and suchlike. (We don't use UNAVAIL in this
ff6046
                    case so that the nsswitch.conf configuration can distuingish such executed but
ff6046
                    negative replies from complete failure to talk to resolved). */
ff6046
-                if (!bus_error_shall_fallback(&error))
ff6046
-                        ret = NSS_STATUS_NOTFOUND;
ff6046
-
ff6046
                 goto fail;
ff6046
         }
ff6046
 
ff6046
@@ -162,11 +158,8 @@ enum nss_status _nss_resolve_gethostbyname4_r(
ff6046
                 r = c;
ff6046
                 goto fail;
ff6046
         }
ff6046
-        if (c == 0) {
ff6046
-                *errnop = ESRCH;
ff6046
-                *h_errnop = HOST_NOT_FOUND;
ff6046
-                return NSS_STATUS_NOTFOUND;
ff6046
-        }
ff6046
+        if (c == 0)
ff6046
+                goto not_found;
ff6046
 
ff6046
         if (isempty(canonical))
ff6046
                 canonical = name;
ff6046
@@ -247,8 +240,8 @@ enum nss_status _nss_resolve_gethostbyname4_r(
ff6046
         if (ttlp)
ff6046
                 *ttlp = 0;
ff6046
 
ff6046
-        /* Explicitly reset all error variables */
ff6046
-        *errnop = 0;
ff6046
+        /* Explicitly reset both *h_errnop and h_errno to work around
ff6046
+         * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
ff6046
         *h_errnop = NETDB_SUCCESS;
ff6046
         h_errno = 0;
ff6046
 
ff6046
@@ -258,6 +251,10 @@ fail:
ff6046
         *errnop = -r;
ff6046
         *h_errnop = NO_RECOVERY;
ff6046
         return ret;
ff6046
+
ff6046
+not_found:
ff6046
+        *h_errnop = HOST_NOT_FOUND;
ff6046
+        return NSS_STATUS_NOTFOUND;
ff6046
 }
ff6046
 
ff6046
 enum nss_status _nss_resolve_gethostbyname3_r(
ff6046
@@ -278,6 +275,7 @@ enum nss_status _nss_resolve_gethostbyname3_r(
ff6046
         const char *canonical;
ff6046
         int c, r, i = 0;
ff6046
 
ff6046
+        PROTECT_ERRNO;
ff6046
         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
ff6046
 
ff6046
         assert(name);
ff6046
@@ -318,14 +316,9 @@ enum nss_status _nss_resolve_gethostbyname3_r(
ff6046
 
ff6046
         r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
ff6046
         if (r < 0) {
ff6046
-                if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN")) {
ff6046
-                        *errnop = ESRCH;
ff6046
-                        *h_errnop = HOST_NOT_FOUND;
ff6046
-                        return NSS_STATUS_NOTFOUND;
ff6046
-                }
ff6046
-
ff6046
-                if (!bus_error_shall_fallback(&error))
ff6046
-                        ret = NSS_STATUS_NOTFOUND;
ff6046
+                if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN") ||
ff6046
+                    !bus_error_shall_fallback(&error))
ff6046
+                        goto not_found;
ff6046
 
ff6046
                 goto fail;
ff6046
         }
ff6046
@@ -335,11 +328,8 @@ enum nss_status _nss_resolve_gethostbyname3_r(
ff6046
                 r = c;
ff6046
                 goto fail;
ff6046
         }
ff6046
-        if (c == 0) {
ff6046
-                *errnop = ESRCH;
ff6046
-                *h_errnop = HOST_NOT_FOUND;
ff6046
-                return NSS_STATUS_NOTFOUND;
ff6046
-        }
ff6046
+        if (c == 0)
ff6046
+                goto not_found;
ff6046
 
ff6046
         if (isempty(canonical))
ff6046
                 canonical = name;
ff6046
@@ -427,23 +417,27 @@ enum nss_status _nss_resolve_gethostbyname3_r(
ff6046
         result->h_length = alen;
ff6046
         result->h_addr_list = (char**) r_addr_list;
ff6046
 
ff6046
-        /* Explicitly reset all error variables */
ff6046
-        *errnop = 0;
ff6046
-        *h_errnop = NETDB_SUCCESS;
ff6046
-        h_errno = 0;
ff6046
-
ff6046
         if (ttlp)
ff6046
                 *ttlp = 0;
ff6046
 
ff6046
         if (canonp)
ff6046
                 *canonp = r_name;
ff6046
 
ff6046
+        /* Explicitly reset both *h_errnop and h_errno to work around
ff6046
+         * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
ff6046
+        *h_errnop = NETDB_SUCCESS;
ff6046
+        h_errno = 0;
ff6046
+
ff6046
         return NSS_STATUS_SUCCESS;
ff6046
 
ff6046
 fail:
ff6046
         *errnop = -r;
ff6046
         *h_errnop = NO_RECOVERY;
ff6046
         return ret;
ff6046
+
ff6046
+not_found:
ff6046
+        *h_errnop = HOST_NOT_FOUND;
ff6046
+        return NSS_STATUS_NOTFOUND;
ff6046
 }
ff6046
 
ff6046
 enum nss_status _nss_resolve_gethostbyaddr2_r(
ff6046
@@ -464,6 +458,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
ff6046
         const char *n;
ff6046
         int r, ifindex;
ff6046
 
ff6046
+        PROTECT_ERRNO;
ff6046
         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
ff6046
 
ff6046
         assert(addr);
ff6046
@@ -516,14 +511,9 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
ff6046
 
ff6046
         r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
ff6046
         if (r < 0) {
ff6046
-                if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN")) {
ff6046
-                        *errnop = ESRCH;
ff6046
-                        *h_errnop = HOST_NOT_FOUND;
ff6046
-                        return NSS_STATUS_NOTFOUND;
ff6046
-                }
ff6046
-
ff6046
-                if (!bus_error_shall_fallback(&error))
ff6046
-                        ret = NSS_STATUS_NOTFOUND;
ff6046
+                if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN") ||
ff6046
+                    !bus_error_shall_fallback(&error))
ff6046
+                        goto not_found;
ff6046
 
ff6046
                 goto fail;
ff6046
         }
ff6046
@@ -549,11 +539,8 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
ff6046
         if (r < 0)
ff6046
                 return r;
ff6046
 
ff6046
-        if (c <= 0) {
ff6046
-                *errnop = ESRCH;
ff6046
-                *h_errnop = HOST_NOT_FOUND;
ff6046
-                return NSS_STATUS_NOTFOUND;
ff6046
-        }
ff6046
+        if (c <= 0)
ff6046
+                goto not_found;
ff6046
 
ff6046
         ms += ALIGN(len) +              /* the address */
ff6046
               2 * sizeof(char*) +       /* pointers to the address, plus trailing NULL */
ff6046
@@ -612,8 +599,8 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
ff6046
         if (ttlp)
ff6046
                 *ttlp = 0;
ff6046
 
ff6046
-        /* Explicitly reset all error variables */
ff6046
-        *errnop = 0;
ff6046
+        /* Explicitly reset both *h_errnop and h_errno to work around
ff6046
+         * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
ff6046
         *h_errnop = NETDB_SUCCESS;
ff6046
         h_errno = 0;
ff6046
 
ff6046
@@ -623,6 +610,10 @@ fail:
ff6046
         *errnop = -r;
ff6046
         *h_errnop = NO_RECOVERY;
ff6046
         return ret;
ff6046
+
ff6046
+not_found:
ff6046
+        *h_errnop = HOST_NOT_FOUND;
ff6046
+        return NSS_STATUS_NOTFOUND;
ff6046
 }
ff6046
 
ff6046
 NSS_GETHOSTBYNAME_FALLBACKS(resolve);
ff6046
diff --git a/src/nss-systemd/nss-systemd.c b/src/nss-systemd/nss-systemd.c
ff6046
index f516b84c63..f554828d49 100644
ff6046
--- a/src/nss-systemd/nss-systemd.c
ff6046
+++ b/src/nss-systemd/nss-systemd.c
ff6046
@@ -145,6 +145,7 @@ enum nss_status _nss_systemd_getpwnam_r(
ff6046
         size_t l;
ff6046
         int bypass, r;
ff6046
 
ff6046
+        PROTECT_ERRNO;
ff6046
         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
ff6046
 
ff6046
         assert(name);
ff6046
@@ -153,26 +154,24 @@ enum nss_status _nss_systemd_getpwnam_r(
ff6046
         /* If the username is not valid, then we don't know it. Ideally libc would filter these for us anyway. We don't
ff6046
          * generate EINVAL here, because it isn't really out business to complain about invalid user names. */
ff6046
         if (!valid_user_group_name(name))
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         /* Synthesize entries for the root and nobody users, in case they are missing in /etc/passwd */
ff6046
         if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
ff6046
                 if (streq(name, root_passwd.pw_name)) {
ff6046
                         *pwd = root_passwd;
ff6046
-                        *errnop = 0;
ff6046
                         return NSS_STATUS_SUCCESS;
ff6046
                 }
ff6046
                 if (synthesize_nobody() &&
ff6046
                     streq(name, nobody_passwd.pw_name)) {
ff6046
                         *pwd = nobody_passwd;
ff6046
-                        *errnop = 0;
ff6046
                         return NSS_STATUS_SUCCESS;
ff6046
                 }
ff6046
         }
ff6046
 
ff6046
         /* Make sure that we don't go in circles when allocating a dynamic UID by checking our own database */
ff6046
         if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         bypass = getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
ff6046
         if (bypass <= 0) {
ff6046
@@ -184,7 +183,7 @@ enum nss_status _nss_systemd_getpwnam_r(
ff6046
         if (bypass > 0) {
ff6046
                 r = direct_lookup_name(name, (uid_t*) &translated);
ff6046
                 if (r == -ENOENT)
ff6046
-                        goto not_found;
ff6046
+                        return NSS_STATUS_NOTFOUND;
ff6046
                 if (r < 0)
ff6046
                         goto fail;
ff6046
         } else {
ff6046
@@ -199,7 +198,7 @@ enum nss_status _nss_systemd_getpwnam_r(
ff6046
                                        name);
ff6046
                 if (r < 0) {
ff6046
                         if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_DYNAMIC_USER))
ff6046
-                                goto not_found;
ff6046
+                                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
                         goto fail;
ff6046
                 }
ff6046
@@ -225,13 +224,8 @@ enum nss_status _nss_systemd_getpwnam_r(
ff6046
         pwd->pw_dir = (char*) DYNAMIC_USER_DIR;
ff6046
         pwd->pw_shell = (char*) DYNAMIC_USER_SHELL;
ff6046
 
ff6046
-        *errnop = 0;
ff6046
         return NSS_STATUS_SUCCESS;
ff6046
 
ff6046
-not_found:
ff6046
-        *errnop = 0;
ff6046
-        return NSS_STATUS_NOTFOUND;
ff6046
-
ff6046
 fail:
ff6046
         *errnop = -r;
ff6046
         return NSS_STATUS_UNAVAIL;
ff6046
@@ -251,31 +245,30 @@ enum nss_status _nss_systemd_getpwuid_r(
ff6046
         size_t l;
ff6046
         int bypass, r;
ff6046
 
ff6046
+        PROTECT_ERRNO;
ff6046
         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
ff6046
 
ff6046
         if (!uid_is_valid(uid))
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         /* Synthesize data for the root user and for nobody in case they are missing from /etc/passwd */
ff6046
         if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
ff6046
                 if (uid == root_passwd.pw_uid) {
ff6046
                         *pwd = root_passwd;
ff6046
-                        *errnop = 0;
ff6046
                         return NSS_STATUS_SUCCESS;
ff6046
                 }
ff6046
                 if (synthesize_nobody() &&
ff6046
                     uid == nobody_passwd.pw_uid) {
ff6046
                         *pwd = nobody_passwd;
ff6046
-                        *errnop = 0;
ff6046
                         return NSS_STATUS_SUCCESS;
ff6046
                 }
ff6046
         }
ff6046
 
ff6046
         if (!uid_is_dynamic(uid))
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         bypass = getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
ff6046
         if (bypass <= 0) {
ff6046
@@ -287,7 +280,7 @@ enum nss_status _nss_systemd_getpwuid_r(
ff6046
         if (bypass > 0) {
ff6046
                 r = direct_lookup_uid(uid, &direct);
ff6046
                 if (r == -ENOENT)
ff6046
-                        goto not_found;
ff6046
+                        return NSS_STATUS_NOTFOUND;
ff6046
                 if (r < 0)
ff6046
                         goto fail;
ff6046
 
ff6046
@@ -305,7 +298,7 @@ enum nss_status _nss_systemd_getpwuid_r(
ff6046
                                        (uint32_t) uid);
ff6046
                 if (r < 0) {
ff6046
                         if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_DYNAMIC_USER))
ff6046
-                                goto not_found;
ff6046
+                                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
                         goto fail;
ff6046
                 }
ff6046
@@ -331,13 +324,8 @@ enum nss_status _nss_systemd_getpwuid_r(
ff6046
         pwd->pw_dir = (char*) DYNAMIC_USER_DIR;
ff6046
         pwd->pw_shell = (char*) DYNAMIC_USER_SHELL;
ff6046
 
ff6046
-        *errnop = 0;
ff6046
         return NSS_STATUS_SUCCESS;
ff6046
 
ff6046
-not_found:
ff6046
-        *errnop = 0;
ff6046
-        return NSS_STATUS_NOTFOUND;
ff6046
-
ff6046
 fail:
ff6046
         *errnop = -r;
ff6046
         return NSS_STATUS_UNAVAIL;
ff6046
@@ -358,31 +346,30 @@ enum nss_status _nss_systemd_getgrnam_r(
ff6046
         size_t l;
ff6046
         int bypass, r;
ff6046
 
ff6046
+        PROTECT_ERRNO;
ff6046
         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
ff6046
 
ff6046
         assert(name);
ff6046
         assert(gr);
ff6046
 
ff6046
         if (!valid_user_group_name(name))
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         /* Synthesize records for root and nobody, in case they are missing form /etc/group */
ff6046
         if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
ff6046
                 if (streq(name, root_group.gr_name)) {
ff6046
                         *gr = root_group;
ff6046
-                        *errnop = 0;
ff6046
                         return NSS_STATUS_SUCCESS;
ff6046
                 }
ff6046
                 if (synthesize_nobody() &&
ff6046
                     streq(name, nobody_group.gr_name)) {
ff6046
                         *gr = nobody_group;
ff6046
-                        *errnop = 0;
ff6046
                         return NSS_STATUS_SUCCESS;
ff6046
                 }
ff6046
         }
ff6046
 
ff6046
         if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         bypass = getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
ff6046
         if (bypass <= 0) {
ff6046
@@ -394,7 +381,7 @@ enum nss_status _nss_systemd_getgrnam_r(
ff6046
         if (bypass > 0) {
ff6046
                 r = direct_lookup_name(name, (uid_t*) &translated);
ff6046
                 if (r == -ENOENT)
ff6046
-                        goto not_found;
ff6046
+                        return NSS_STATUS_NOTFOUND;
ff6046
                 if (r < 0)
ff6046
                         goto fail;
ff6046
         } else {
ff6046
@@ -409,7 +396,7 @@ enum nss_status _nss_systemd_getgrnam_r(
ff6046
                                        name);
ff6046
                 if (r < 0) {
ff6046
                         if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_DYNAMIC_USER))
ff6046
-                                goto not_found;
ff6046
+                                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
                         goto fail;
ff6046
                 }
ff6046
@@ -433,13 +420,8 @@ enum nss_status _nss_systemd_getgrnam_r(
ff6046
         gr->gr_passwd = (char*) DYNAMIC_USER_PASSWD;
ff6046
         gr->gr_mem = (char**) buffer;
ff6046
 
ff6046
-        *errnop = 0;
ff6046
         return NSS_STATUS_SUCCESS;
ff6046
 
ff6046
-not_found:
ff6046
-        *errnop = 0;
ff6046
-        return NSS_STATUS_NOTFOUND;
ff6046
-
ff6046
 fail:
ff6046
         *errnop = -r;
ff6046
         return NSS_STATUS_UNAVAIL;
ff6046
@@ -459,31 +441,30 @@ enum nss_status _nss_systemd_getgrgid_r(
ff6046
         size_t l;
ff6046
         int bypass, r;
ff6046
 
ff6046
+        PROTECT_ERRNO;
ff6046
         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
ff6046
 
ff6046
         if (!gid_is_valid(gid))
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         /* Synthesize records for root and nobody, in case they are missing from /etc/group */
ff6046
         if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
ff6046
                 if (gid == root_group.gr_gid) {
ff6046
                         *gr = root_group;
ff6046
-                        *errnop = 0;
ff6046
                         return NSS_STATUS_SUCCESS;
ff6046
                 }
ff6046
                 if (synthesize_nobody() &&
ff6046
                     gid == nobody_group.gr_gid) {
ff6046
                         *gr = nobody_group;
ff6046
-                        *errnop = 0;
ff6046
                         return NSS_STATUS_SUCCESS;
ff6046
                 }
ff6046
         }
ff6046
 
ff6046
         if (!gid_is_dynamic(gid))
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
ff6046
-                goto not_found;
ff6046
+                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
         bypass = getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
ff6046
         if (bypass <= 0) {
ff6046
@@ -495,7 +476,7 @@ enum nss_status _nss_systemd_getgrgid_r(
ff6046
         if (bypass > 0) {
ff6046
                 r = direct_lookup_uid(gid, &direct);
ff6046
                 if (r == -ENOENT)
ff6046
-                        goto not_found;
ff6046
+                        return NSS_STATUS_NOTFOUND;
ff6046
                 if (r < 0)
ff6046
                         goto fail;
ff6046
 
ff6046
@@ -513,7 +494,7 @@ enum nss_status _nss_systemd_getgrgid_r(
ff6046
                                        (uint32_t) gid);
ff6046
                 if (r < 0) {
ff6046
                         if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_DYNAMIC_USER))
ff6046
-                                goto not_found;
ff6046
+                                return NSS_STATUS_NOTFOUND;
ff6046
 
ff6046
                         goto fail;
ff6046
                 }
ff6046
@@ -537,13 +518,8 @@ enum nss_status _nss_systemd_getgrgid_r(
ff6046
         gr->gr_passwd = (char*) DYNAMIC_USER_PASSWD;
ff6046
         gr->gr_mem = (char**) buffer;
ff6046
 
ff6046
-        *errnop = 0;
ff6046
         return NSS_STATUS_SUCCESS;
ff6046
 
ff6046
-not_found:
ff6046
-        *errnop = 0;
ff6046
-        return NSS_STATUS_NOTFOUND;
ff6046
-
ff6046
 fail:
ff6046
         *errnop = -r;
ff6046
         return NSS_STATUS_UNAVAIL;
ff6046
@@ -598,6 +574,7 @@ static void systemd_endent(GetentData *data) {
ff6046
 }
ff6046
 
ff6046
 static enum nss_status nss_systemd_endent(GetentData *p) {
ff6046
+        PROTECT_ERRNO;
ff6046
         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
ff6046
 
ff6046
         assert_se(pthread_mutex_lock(&p->mutex) == 0);
ff6046
@@ -668,6 +645,7 @@ static enum nss_status systemd_setent(GetentData *p) {
ff6046
         uid_t id;
ff6046
         int bypass, r;
ff6046
 
ff6046
+        PROTECT_ERRNO;
ff6046
         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
ff6046
 
ff6046
         assert(p);
ff6046
@@ -750,6 +728,7 @@ enum nss_status _nss_systemd_getpwent_r(struct passwd *result, char *buffer, siz
ff6046
         UserEntry *p;
ff6046
         size_t len;
ff6046
 
ff6046
+        PROTECT_ERRNO;
ff6046
         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
ff6046
 
ff6046
         assert(result);
ff6046
@@ -778,7 +757,6 @@ enum nss_status _nss_systemd_getpwent_r(struct passwd *result, char *buffer, siz
ff6046
                 break;
ff6046
         }
ff6046
         if (!p) {
ff6046
-                *errnop = ENOENT;
ff6046
                 ret = NSS_STATUS_NOTFOUND;
ff6046
                 goto finalize;
ff6046
         }
ff6046
@@ -801,6 +779,7 @@ enum nss_status _nss_systemd_getgrent_r(struct group *result, char *buffer, size
ff6046
         UserEntry *p;
ff6046
         size_t len;
ff6046
 
ff6046
+        PROTECT_ERRNO;
ff6046
         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
ff6046
 
ff6046
         assert(result);
ff6046
@@ -827,7 +806,6 @@ enum nss_status _nss_systemd_getgrent_r(struct group *result, char *buffer, size
ff6046
                 break;
ff6046
         }
ff6046
         if (!p) {
ff6046
-                *errnop = ENOENT;
ff6046
                 ret = NSS_STATUS_NOTFOUND;
ff6046
                 goto finalize;
ff6046
         }