]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Separate internal state between getXXent and getXXbyYY NSS calls (bug 18007)
authorAndreas Schwab <schwab@suse.de>
Wed, 25 Mar 2015 15:35:46 +0000 (16:35 +0100)
committerAndreas Schwab <schwab@suse.de>
Mon, 11 May 2015 08:41:49 +0000 (10:41 +0200)
ChangeLog
NEWS
nis/nss_compat/compat-grp.c
nis/nss_compat/compat-pwd.c
nis/nss_compat/compat-spwd.c
nss/nss_files/files-XXX.c
nss/nss_files/files-alias.c
nss/nss_files/files-hosts.c

index 8ff45d4ef9823b5057bccabca10cb8bdab826af0..05c23e75b10d7c43ecbc24333325bd24ab5eaf78 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,41 @@
+2015-05-11  Andreas Schwab  <schwab@suse.de>
+
+       [BZ #18007]
+       * nis/nss_compat/compat-grp.c (internal_endgrent): Don't call
+       nss_endgrent.
+       (_nss_compat_endgrent): Call nss_endgrent.
+       * nis/nss_compat/compat-pwd.c (internal_endpwent): Don't call
+       nss_endpwent.
+       (_nss_compat_endpwent): Call nss_endpwent.
+       * nis/nss_compat/compat-spwd.c (internal_setspent): Add parameter
+       needent, call nss_setspent only if non-zero.
+       (_nss_compat_setspent, _nss_compat_getspent_r): Pass non-zero.
+       (internal_endspent): Don't call nss_endspent.
+       (_nss_compat_endspent): Call nss_endspent.
+       * nss/nss_files/files-XXX.c (position, last_use, keep_stream):
+       Remove.  All uses removed.
+       (internal_setent): Remove parameter stayopen, add parameter
+       stream.  Use it instead of global variable.
+       (CONCAT(_nss_files_set,ENTNAME)): Pass global stream.
+       (internal_endent, internal_getent): Add parameter stream.  Use it
+       instead of global variable.
+       (CONCAT(_nss_files_end,ENTNAME))
+       (CONCAT(_nss_files_get,ENTNAME_r)): Pass global stream.
+       (_nss_files_get##name##_r): Pass local stream.  Remove locking.
+       * nss/nss_files/files-alias.c (position, last_use): Remove.  All
+       uses removed.
+       (internal_setent, internal_endent): Add parameter stream.  Use it
+       instead of global variable.
+       (_nss_files_setaliasent, _nss_files_endaliasent): Pass global
+       stream.
+       (get_next_alias): Add parameter stream.
+       (_nss_files_getaliasent_r): Pass global stream.
+       (_nss_files_getaliasbyname_r): Pass local stream.  Remove locking.
+       * nss/nss_files/files-hosts.c (_nss_files_gethostbyname3_r)
+       (_nss_files_gethostbyname4_r): Pass local stream to
+       internal_setent, internal_getent and internal_endent.  Remove
+       locking.
+
 2015-05-11  Stefan Liebler  <stli@linux.vnet.ibm.com>
 
        * tst-strfmon1.c (tests): Update expected currency symbol.
diff --git a/NEWS b/NEWS
index fb4228330adff1b5da60f4295b8570de53f07daf..c1054ccbdb156b23d7526f2f3893096e92b370ba 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -44,10 +44,9 @@ Version 2.22
   Hat).  These updates cause user visible changes, such as the fix for bug
   17998.
 
-* CVE-2014-8121 The NSS files backend would reset the file pointer used by
-  the get*ent functions if any of the query functions for the same database
-  are used during the iteration, causing a denial-of-service condition in
-  some applications.
+* CVE-2014-8121 The NSS backends shared internal state between the getXXent
+  and getXXbyYY NSS calls for the same database, causing a denial-of-service
+  condition in some applications.
 \f
 Version 2.21
 
index 5e9c52796470e59188d4658b05af3367fc2fd675..d8ef4be63be421840f07a60da23d711cc3b2a004 100644 (file)
@@ -194,9 +194,6 @@ _nss_compat_setgrent (int stayopen)
 static enum nss_status
 internal_endgrent (ent_t *ent)
 {
-  if (nss_endgrent)
-    nss_endgrent ();
-
   if (ent->stream != NULL)
     {
       fclose (ent->stream);
@@ -222,6 +219,9 @@ _nss_compat_endgrent (void)
 
   __libc_lock_lock (lock);
 
+  if (nss_endgrent)
+    nss_endgrent ();
+
   result = internal_endgrent (&ext_ent);
 
   __libc_lock_unlock (lock);
index e3e3dbb308c2cca45fa26a2631dd6deaf9ee3efd..9b1d671d17a077e420aad88c8d381c8a246f27ab 100644 (file)
@@ -311,9 +311,6 @@ _nss_compat_setpwent (int stayopen)
 static enum nss_status
 internal_endpwent (ent_t *ent)
 {
-  if (nss_endpwent)
-    nss_endpwent ();
-
   if (ent->stream != NULL)
     {
       fclose (ent->stream);
@@ -346,6 +343,9 @@ _nss_compat_endpwent (void)
 
   __libc_lock_lock (lock);
 
+  if (nss_endpwent)
+    nss_endpwent ();
+
   result = internal_endpwent (&ext_ent);
 
   __libc_lock_unlock (lock);
index 73c2ed3fe0bcd3044d9f181ce0e5f2038d159258..5e4bf78e4792d4d1987f5e9ec5e003099ca60f59 100644 (file)
@@ -169,7 +169,7 @@ copy_spwd_changes (struct spwd *dest, struct spwd *src,
 }
 
 static enum nss_status
-internal_setspent (ent_t *ent, int stayopen)
+internal_setspent (ent_t *ent, int stayopen, int needent)
 {
   enum nss_status status = NSS_STATUS_SUCCESS;
 
@@ -239,7 +239,7 @@ internal_setspent (ent_t *ent, int stayopen)
 
   give_spwd_free (&ent->pwd);
 
-  if (status == NSS_STATUS_SUCCESS && nss_setspent)
+  if (needent && status == NSS_STATUS_SUCCESS && nss_setspent)
     ent->setent_status = nss_setspent (stayopen);
 
   return status;
@@ -256,7 +256,7 @@ _nss_compat_setspent (int stayopen)
   if (ni == NULL)
     init_nss_interface ();
 
-  result = internal_setspent (&ext_ent, stayopen);
+  result = internal_setspent (&ext_ent, stayopen, 1);
 
   __libc_lock_unlock (lock);
 
@@ -267,9 +267,6 @@ _nss_compat_setspent (int stayopen)
 static enum nss_status
 internal_endspent (ent_t *ent)
 {
-  if (nss_endspent)
-    nss_endspent ();
-
   if (ent->stream != NULL)
     {
       fclose (ent->stream);
@@ -303,6 +300,9 @@ _nss_compat_endspent (void)
 
   __libc_lock_lock (lock);
 
+  if (nss_endspent)
+    nss_endspent ();
+
   result = internal_endspent (&ext_ent);
 
   __libc_lock_unlock (lock);
@@ -658,7 +658,7 @@ _nss_compat_getspent_r (struct spwd *pwd, char *buffer, size_t buflen,
     init_nss_interface ();
 
   if (ext_ent.stream == NULL)
-    result = internal_setspent (&ext_ent, 1);
+    result = internal_setspent (&ext_ent, 1, 1);
 
   if (result == NSS_STATUS_SUCCESS)
     result = internal_getspent_r (pwd, &ext_ent, buffer, buflen, errnop);
@@ -830,7 +830,7 @@ _nss_compat_getspnam_r (const char *name, struct spwd *pwd,
 
   __libc_lock_unlock (lock);
 
-  result = internal_setspent (&ent, 0);
+  result = internal_setspent (&ent, 0, 0);
 
   if (result == NSS_STATUS_SUCCESS)
     result = internal_getspnam_r (name, pwd, &ent, buffer, buflen, errnop);
index a7ce5ea97e80b06c1c39b4ca50aa7087e91a3e62..f002f431e58af686a4afe1f07e98cb2008b09f17 100644 (file)
 /* Locks the static variables in this file.  */
 __libc_lock_define_initialized (static, lock)
 \f
-/* Maintenance of the shared stream open on the database file.  */
+/* Maintenance of the stream open on the database file.  For getXXent
+   operations the stream needs to be held open across calls, the other
+   getXXbyYY operations all use their own stream.  */
 
 static FILE *stream;
-static fpos_t position;
-static enum { nouse, getent, getby } last_use;
-static int keep_stream;
 
 /* Open database file if not already opened.  */
 static enum nss_status
-internal_setent (int stayopen)
+internal_setent (FILE **stream)
 {
   enum nss_status status = NSS_STATUS_SUCCESS;
 
-  if (stream == NULL)
+  if (*stream == NULL)
     {
-      stream = fopen (DATAFILE, "rce");
+      *stream = fopen (DATAFILE, "rce");
 
-      if (stream == NULL)
+      if (*stream == NULL)
        status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
       else
        {
@@ -90,7 +89,7 @@ internal_setent (int stayopen)
              int result;
              int flags;
 
-             result = flags = fcntl (fileno (stream), F_GETFD, 0);
+             result = flags = fcntl (fileno (*stream), F_GETFD, 0);
              if (result >= 0)
                {
 # ifdef O_CLOEXEC
@@ -100,15 +99,15 @@ internal_setent (int stayopen)
 # endif
                    {
                      flags |= FD_CLOEXEC;
-                     result = fcntl (fileno (stream), F_SETFD, flags);
+                     result = fcntl (fileno (*stream), F_SETFD, flags);
                    }
                }
              if (result < 0)
                {
                  /* Something went wrong.  Close the stream and return a
                     failure.  */
-                 fclose (stream);
-                 stream = NULL;
+                 fclose (*stream);
+                 *stream = NULL;
                  status = NSS_STATUS_UNAVAIL;
                }
            }
@@ -116,11 +115,7 @@ internal_setent (int stayopen)
        }
     }
   else
-    rewind (stream);
-
-  /* Remember STAYOPEN flag.  */
-  if (stream != NULL)
-    keep_stream |= stayopen;
+    rewind (*stream);
 
   return status;
 }
@@ -134,16 +129,7 @@ CONCAT(_nss_files_set,ENTNAME) (int stayopen)
 
   __libc_lock_lock (lock);
 
-  status = internal_setent (1);
-
-  if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0)
-    {
-      fclose (stream);
-      stream = NULL;
-      status = NSS_STATUS_UNAVAIL;
-    }
-
-  last_use = getent;
+  status = internal_setent (&stream);
 
   __libc_lock_unlock (lock);
 
@@ -153,12 +139,12 @@ CONCAT(_nss_files_set,ENTNAME) (int stayopen)
 
 /* Close the database file.  */
 static void
-internal_endent (void)
+internal_endent (FILE **stream)
 {
-  if (stream != NULL)
+  if (*stream != NULL)
     {
-      fclose (stream);
-      stream = NULL;
+      fclose (*stream);
+      *stream = NULL;
     }
 }
 
@@ -169,10 +155,7 @@ CONCAT(_nss_files_end,ENTNAME) (void)
 {
   __libc_lock_lock (lock);
 
-  internal_endent ();
-
-  /* Reset STAYOPEN flag.  */
-  keep_stream = 0;
+  internal_endent (&stream);
 
   __libc_lock_unlock (lock);
 
@@ -227,7 +210,7 @@ get_contents (char *linebuf, size_t len, FILE *stream)
 
 /* Parsing the database file into `struct STRUCTURE' data structures.  */
 static enum nss_status
-internal_getent (struct STRUCTURE *result,
+internal_getent (FILE *stream, struct STRUCTURE *result,
                 char *buffer, size_t buflen, int *errnop H_ERRNO_PROTO
                 EXTRA_ARGS_DECL)
 {
@@ -300,45 +283,14 @@ CONCAT(_nss_files_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer,
     {
       int save_errno = errno;
 
-      status = internal_setent (0);
+      status = internal_setent (&stream);
 
       __set_errno (save_errno);
-
-      if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0)
-       {
-         fclose (stream);
-         stream = NULL;
-         status = NSS_STATUS_UNAVAIL;
-       }
     }
 
   if (status == NSS_STATUS_SUCCESS)
-    {
-      /* If the last use was not by the getent function we need the
-        position the stream.  */
-      if (last_use != getent)
-       {
-         if (fsetpos (stream, &position) < 0)
-           status = NSS_STATUS_UNAVAIL;
-         else
-           last_use = getent;
-       }
-
-      if (status == NSS_STATUS_SUCCESS)
-       {
-         status = internal_getent (result, buffer, buflen, errnop
-                                   H_ERRNO_ARG EXTRA_ARGS_VALUE);
-
-         /* Remember this position if we were successful.  If the
-            operation failed we give the user a chance to repeat the
-            operation (perhaps the buffer was too small).  */
-         if (status == NSS_STATUS_SUCCESS)
-           fgetpos (stream, &position);
-         else
-           /* We must make sure we reposition the stream the next call.  */
-           last_use = nouse;
-       }
-    }
+    status = internal_getent (stream, result, buffer, buflen, errnop
+                             H_ERRNO_ARG EXTRA_ARGS_VALUE);
 
   __libc_lock_unlock (lock);
 
@@ -364,27 +316,20 @@ _nss_files_get##name##_r (proto,                                        \
                          size_t buflen, int *errnop H_ERRNO_PROTO)           \
 {                                                                            \
   enum nss_status status;                                                    \
+  FILE *stream = NULL;                                                       \
                                                                              \
-  __libc_lock_lock (lock);                                                   \
-                                                                             \
-  /* Reset file pointer to beginning or open file.  */                       \
-  status = internal_setent (keep_stream);                                    \
+  /* Open file.  */                                                          \
+  status = internal_setent (&stream);                                        \
                                                                              \
   if (status == NSS_STATUS_SUCCESS)                                          \
     {                                                                        \
-      /* Tell getent function that we have repositioned the file pointer.  */ \
-      last_use = getby;                                                              \
-                                                                             \
-      while ((status = internal_getent (result, buffer, buflen, errnop       \
+      while ((status = internal_getent (stream, result, buffer, buflen, errnop \
                                        H_ERRNO_ARG EXTRA_ARGS_VALUE))        \
             == NSS_STATUS_SUCCESS)                                           \
        { break_if_match }                                                    \
                                                                              \
-      if (! keep_stream)                                                     \
-       internal_endent ();                                                   \
+      internal_endent (&stream);                                             \
     }                                                                        \
                                                                              \
-  __libc_lock_unlock (lock);                                                 \
-                                                                             \
   return status;                                                             \
 }
index d5c5089e2efc02ed6b4a358a936f77e659f2ba40..071c01d158984b2b6ba705ed92a5e1eb2f61c135 100644 (file)
 /* Locks the static variables in this file.  */
 __libc_lock_define_initialized (static, lock)
 \f
-/* Maintenance of the shared stream open on the database file.  */
+/* Maintenance of the stream open on the database file.  For getXXent
+   operations the stream needs to be held open across calls, the other
+   getXXbyYY operations all use their own stream.  */
 
 static FILE *stream;
-static fpos_t position;
-static enum { nouse, getent, getby } last_use;
 
 
 static enum nss_status
-internal_setent (void)
+internal_setent (FILE **stream)
 {
   enum nss_status status = NSS_STATUS_SUCCESS;
 
-  if (stream == NULL)
+  if (*stream == NULL)
     {
-      stream = fopen ("/etc/aliases", "rce");
+      *stream = fopen ("/etc/aliases", "rce");
 
-      if (stream == NULL)
+      if (*stream == NULL)
        status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
       else
        {
@@ -62,7 +62,7 @@ internal_setent (void)
              int result;
              int flags;
 
-             result = flags = fcntl (fileno (stream), F_GETFD, 0);
+             result = flags = fcntl (fileno (*stream), F_GETFD, 0);
              if (result >= 0)
                {
 # ifdef O_CLOEXEC
@@ -72,14 +72,14 @@ internal_setent (void)
 # endif
                    {
                      flags |= FD_CLOEXEC;
-                     result = fcntl (fileno (stream), F_SETFD, flags);
+                     result = fcntl (fileno (*stream), F_SETFD, flags);
                    }
                }
              if (result < 0)
                {
                  /* Something went wrong.  Close the stream and return a
                     failure.  */
-                 fclose (stream);
+                 fclose (*stream);
                  stream = NULL;
                  status = NSS_STATUS_UNAVAIL;
                }
@@ -88,7 +88,7 @@ internal_setent (void)
        }
     }
   else
-    rewind (stream);
+    rewind (*stream);
 
   return status;
 }
@@ -102,16 +102,7 @@ _nss_files_setaliasent (void)
 
   __libc_lock_lock (lock);
 
-  status = internal_setent ();
-
-  if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0)
-    {
-      fclose (stream);
-      stream = NULL;
-      status = NSS_STATUS_UNAVAIL;
-    }
-
-  last_use = getent;
+  status = internal_setent (&stream);
 
   __libc_lock_unlock (lock);
 
@@ -121,12 +112,12 @@ _nss_files_setaliasent (void)
 
 /* Close the database file.  */
 static void
-internal_endent (void)
+internal_endent (FILE **stream)
 {
-  if (stream != NULL)
+  if (*stream != NULL)
     {
-      fclose (stream);
-      stream = NULL;
+      fclose (*stream);
+      *stream = NULL;
     }
 }
 
@@ -137,7 +128,7 @@ _nss_files_endaliasent (void)
 {
   __libc_lock_lock (lock);
 
-  internal_endent ();
+  internal_endent (&stream);
 
   __libc_lock_unlock (lock);
 
@@ -146,7 +137,7 @@ _nss_files_endaliasent (void)
 \f
 /* Parsing the database file into `struct aliasent' data structures.  */
 static enum nss_status
-get_next_alias (const char *match, struct aliasent *result,
+get_next_alias (FILE *stream, const char *match, struct aliasent *result,
                char *buffer, size_t buflen, int *errnop)
 {
   enum nss_status status = NSS_STATUS_NOTFOUND;
@@ -397,35 +388,16 @@ _nss_files_getaliasent_r (struct aliasent *result, char *buffer, size_t buflen,
 
   /* Be prepared that the set*ent function was not called before.  */
   if (stream == NULL)
-    status = internal_setent ();
+    status = internal_setent (&stream);
 
   if (status == NSS_STATUS_SUCCESS)
     {
-      /* If the last use was not by the getent function we need the
-        position the stream.  */
-      if (last_use != getent)
-       {
-         if (fsetpos (stream, &position) < 0)
-           status = NSS_STATUS_UNAVAIL;
-         else
-           last_use = getent;
-       }
+      result->alias_local = 1;
 
-      if (status == NSS_STATUS_SUCCESS)
-       {
-         result->alias_local = 1;
-
-         /* Read lines until we get a definite result.  */
-         do
-           status = get_next_alias (NULL, result, buffer, buflen, errnop);
-         while (status == NSS_STATUS_RETURN);
-
-         /* If we successfully read an entry remember this position.  */
-         if (status == NSS_STATUS_SUCCESS)
-           fgetpos (stream, &position);
-         else
-           last_use = nouse;
-       }
+      /* Read lines until we get a definite result.  */
+      do
+       status = get_next_alias (stream, NULL, result, buffer, buflen, errnop);
+      while (status == NSS_STATUS_RETURN);
     }
 
   __libc_lock_unlock (lock);
@@ -440,6 +412,7 @@ _nss_files_getaliasbyname_r (const char *name, struct aliasent *result,
 {
   /* Return next entry in host file.  */
   enum nss_status status = NSS_STATUS_SUCCESS;
+  FILE *stream = NULL;
 
   if (name == NULL)
     {
@@ -447,11 +420,8 @@ _nss_files_getaliasbyname_r (const char *name, struct aliasent *result,
       return NSS_STATUS_UNAVAIL;
     }
 
-  __libc_lock_lock (lock);
-
-  /* Open the stream or rest it.  */
-  status = internal_setent ();
-  last_use = getby;
+  /* Open the stream.  */
+  status = internal_setent (&stream);
 
   if (status == NSS_STATUS_SUCCESS)
     {
@@ -459,13 +429,11 @@ _nss_files_getaliasbyname_r (const char *name, struct aliasent *result,
 
       /* Read lines until we get a definite result.  */
       do
-       status = get_next_alias (name, result, buffer, buflen, errnop);
+       status = get_next_alias (stream, name, result, buffer, buflen, errnop);
       while (status == NSS_STATUS_RETURN);
     }
 
-  internal_endent ();
-
-  __libc_lock_unlock (lock);
+  internal_endent (&stream);
 
   return status;
 }
index 4c51c90b4a99cd42e8d2fb449d0b028c82a4bcb4..4117458c92e95378c454b55089944608ab6d88b5 100644 (file)
@@ -120,14 +120,13 @@ _nss_files_gethostbyname3_r (const char *name, int af, struct hostent *result,
                             char *buffer, size_t buflen, int *errnop,
                             int *herrnop, int32_t *ttlp, char **canonp)
 {
+  FILE *stream = NULL;
   uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct hostent_data);
   buffer += pad;
   buflen = buflen > pad ? buflen - pad : 0;
 
-  __libc_lock_lock (lock);
-
-  /* Reset file pointer to beginning or open file.  */
-  enum nss_status status = internal_setent (keep_stream);
+  /* Open file.  */
+  enum nss_status status = internal_setent (&stream);
 
   if (status == NSS_STATUS_SUCCESS)
     {
@@ -135,10 +134,7 @@ _nss_files_gethostbyname3_r (const char *name, int af, struct hostent *result,
          addresses to IPv6 addresses really the right thing to do?  */
       int flags = ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0);
 
-      /* Tell getent function that we have repositioned the file pointer.  */
-      last_use = getby;
-
-      while ((status = internal_getent (result, buffer, buflen, errnop,
+      while ((status = internal_getent (stream, result, buffer, buflen, errnop,
                                        herrnop, af, flags))
             == NSS_STATUS_SUCCESS)
        {
@@ -165,7 +161,7 @@ _nss_files_gethostbyname3_r (const char *name, int af, struct hostent *result,
          bufferend = (char *) &result->h_aliases[naliases + 1];
 
        again:
-         while ((status = internal_getent (&tmp_result_buf, tmp_buffer,
+         while ((status = internal_getent (stream, &tmp_result_buf, tmp_buffer,
                                            tmp_buflen, errnop, herrnop, af,
                                            flags))
                 == NSS_STATUS_SUCCESS)
@@ -341,15 +337,12 @@ _nss_files_gethostbyname3_r (const char *name, int af, struct hostent *result,
            free (tmp_buffer);
        }
 
-      if (! keep_stream)
-       internal_endent ();
+      internal_endent (&stream);
     }
 
   if (canonp && status == NSS_STATUS_SUCCESS)
     *canonp = result->h_name;
 
-  __libc_lock_unlock (lock);
-
   return status;
 }
 
@@ -378,16 +371,13 @@ _nss_files_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
                             char *buffer, size_t buflen, int *errnop,
                             int *herrnop, int32_t *ttlp)
 {
-  __libc_lock_lock (lock);
+  FILE *stream = NULL;
 
-  /* Reset file pointer to beginning or open file.  */
-  enum nss_status status = internal_setent (keep_stream);
+  /* Open file.  */
+  enum nss_status status = internal_setent (&stream);
 
   if (status == NSS_STATUS_SUCCESS)
     {
-      /* Tell getent function that we have repositioned the file pointer.  */
-      last_use = getby;
-
       bool any = false;
       bool got_canon = false;
       while (1)
@@ -399,7 +389,7 @@ _nss_files_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
          buflen = buflen > pad ? buflen - pad : 0;
 
          struct hostent result;
-         status = internal_getent (&result, buffer, buflen, errnop,
+         status = internal_getent (stream, &result, buffer, buflen, errnop,
                                    herrnop, AF_UNSPEC, 0);
          if (status != NSS_STATUS_SUCCESS)
            break;
@@ -475,8 +465,7 @@ _nss_files_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
          status = NSS_STATUS_SUCCESS;
        }
 
-      if (! keep_stream)
-       internal_endent ();
+      internal_endent (&stream);
     }
   else if (status == NSS_STATUS_TRYAGAIN)
     {
@@ -489,7 +478,5 @@ _nss_files_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
       *herrnop = NO_DATA;
     }
 
-  __libc_lock_unlock (lock);
-
   return status;
 }