]> 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)
committerTulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com>
Tue, 26 May 2015 19:47:54 +0000 (16:47 -0300)
Conflicts:
NEWS
nss/nss_files/files-hosts.c

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 a12d0b7c2a8021c614eee0e4cab69400e8008dcd..5c4e039b378ec812d02f5a680bc9068a9716724d 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-04-29  Florian Weimer  <fweimer@redhat.com>
 
        [BZ #18007]
diff --git a/NEWS b/NEWS
index 47ca8e6982259af4429b6c9b02e9c3b49a9a93fb..23ef0993e985117a82cae1ffabf8a8cf07a09eff 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -15,10 +15,9 @@ Version 2.18.1
   16618, 16885, 16916, 16943, 16958, 17048, 17137, 17187, 17325, 17625,
   17630, 18007, 18104, 18287.
 
-* 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.
 
 * A buffer overflow in gethostbyname_r and related functions performing DNS
   requests has been fixed.  If the NSS functions were called with a
index 72a9a7aa922d47e6fb026dc2ed35a1881db439e0..aace6b98f8a27a49f618225e5d55cb1ab0c403d2 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 f934fb24a189b4654d5bf1c755ce1129bba94d1a..1c0000e886eb9cb7de31fc35f693932e7225b2e6 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 e854b285d5c4a3dd4510b6de0b4ecd9ee3eb7654..ed67c4370bb99ccf842f76b84700ad9b033188e7 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 b3207e2bb92809025b776156c01c41861da7bbdc..489dc5d4ac08e9345a571ab12b8156c508def593 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);
 
@@ -182,7 +165,7 @@ CONCAT(_nss_files_end,ENTNAME) (void)
 /* 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)
 {
@@ -255,45 +238,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);
 
@@ -319,27 +271,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 8e9cd60bb9c6c5942a8d02fbfe1b3493dc35d1ff..650e0758cf80579ae6f3895753aa0c0b87226512 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 6db2535159e03f286c0cb968913fbad2d0809408..2a74d062bb2efa36a7482551875a914e3030f1ca 100644 (file)
@@ -105,22 +105,18 @@ _nss_files_get##name##_r (proto,                                        \
                          struct STRUCTURE *result, char *buffer,             \
                          size_t buflen, int *errnop H_ERRNO_PROTO)           \
 {                                                                            \
-  uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct hostent_data);    \
+  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)                                          \
     {                                                                        \
-      /* Tell getent function that we have repositioned the file pointer.  */ \
-      last_use = getby;                                                              \
-                                                                             \
-      while ((status = internal_getent (result, buffer, buflen, errnop       \
-                                       H_ERRNO_ARG EXTRA_ARGS_VALUE))        \
+      while ((status = internal_getent (stream, result, buffer, buflen,       \
+                                       errnop H_ERRNO_ARG EXTRA_ARGS_VALUE)) \
             == NSS_STATUS_SUCCESS)                                           \
        { break_if_match }                                                    \
                                                                              \
@@ -144,9 +140,9 @@ _nss_files_get##name##_r (proto,                                          \
          bufferend = (char *) &result->h_aliases[naliases + 1];              \
                                                                              \
        again:                                                                \
-         while ((status = internal_getent (&tmp_result_buf, tmp_buffer,      \
-                                           tmp_buflen, errnop H_ERRNO_ARG    \
-                                           EXTRA_ARGS_VALUE))                \
+         while ((status = internal_getent (stream, &tmp_result_buf,          \
+                                           tmp_buffer, tmp_buflen, errnop    \
+                                           H_ERRNO_ARG EXTRA_ARGS_VALUE))    \
                 == NSS_STATUS_SUCCESS)                                       \
            {                                                                 \
              int matches = 1;                                                \
@@ -321,12 +317,9 @@ _nss_files_get##name##_r (proto,                                         \
        }                                                                     \
                                                                              \
                                                                              \
-      if (! keep_stream)                                                     \
-       internal_endent ();                                                   \
+      internal_endent (&stream);                                             \
     }                                                                        \
                                                                              \
-  __libc_lock_unlock (lock);                                                 \
-                                                                             \
   return status;                                                             \
 }
 
@@ -365,22 +358,18 @@ DB_LOOKUP (hostbyaddr, ,,,
           }, const void *addr, socklen_t len, int af)
 #undef EXTRA_ARGS_VALUE
 
-
 enum nss_status
 _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)
@@ -392,7 +381,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
                                    H_ERRNO_ARG, AF_UNSPEC, 0);
          if (status != NSS_STATUS_SUCCESS)
            break;
@@ -468,8 +457,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)
     {
@@ -482,7 +470,5 @@ _nss_files_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
       *herrnop = NO_DATA;
     }
 
-  __libc_lock_unlock (lock);
-
   return status;
 }