-/* Copyright (C) 1998, 1999, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 1998-2019 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1998.
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA. */
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
#include <assert.h>
#include <errno.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <not-cancel.h>
-#include <stdio-common/_itoa.h>
+#include <_itoa.h>
#include "nscd-client.h"
#include "nscd_proto.h"
static int nscd_getpw_r (const char *key, size_t keylen, request_type type,
struct passwd *resultbuf, char *buffer,
- size_t buflen, struct passwd **result)
- internal_function;
+ size_t buflen, struct passwd **result);
int
__nscd_getpwnam_r (const char *name, struct passwd *resultbuf, char *buffer,
}
-libc_locked_map_ptr (map_handle);
+libc_locked_map_ptr (static, map_handle);
/* Note that we only free the structure if necessary. The memory
mapping is not removed since it is not visible to the malloc
handling. */
-libc_freeres_fn (gr_map_free)
+libc_freeres_fn (pw_map_free)
{
-
if (map_handle.mapped != NO_MAPPING)
- free (map_handle.mapped);
+ {
+ void *p = map_handle.mapped;
+ map_handle.mapped = NO_MAPPING;
+ free (p);
+ }
}
static int
-internal_function
nscd_getpw_r (const char *key, size_t keylen, request_type type,
struct passwd *resultbuf, char *buffer, size_t buflen,
struct passwd **result)
{
- const pw_response_header *pw_resp = NULL;
- const char *pw_name = NULL;
- int retval = -1;
int gc_cycle;
- const char *recend = (const char *) ~UINTMAX_C (0);
+ int nretries = 0;
/* If the mapping is available, try to search there instead of
communicating with the nscd. */
- struct mapped_database *mapped = __nscd_get_map_ref (GETFDPW, "passwd",
- &map_handle, &gc_cycle);
- retry:
+ struct mapped_database *mapped;
+ mapped = __nscd_get_map_ref (GETFDPW, "passwd", &map_handle, &gc_cycle);
+
+ retry:;
+ const char *pw_name = NULL;
+ int retval = -1;
+ const char *recend = (const char *) ~UINTMAX_C (0);
+ pw_response_header pw_resp;
+
if (mapped != NO_MAPPING)
{
- const struct datahead *found = __nscd_cache_search (type, key, keylen,
- mapped);
+ struct datahead *found = __nscd_cache_search (type, key, keylen, mapped,
+ sizeof pw_resp);
if (found != NULL)
{
- pw_resp = &found->data[0].pwdata;
- pw_name = (const char *) (pw_resp + 1);
+ pw_name = (const char *) (&found->data[0].pwdata + 1);
+ pw_resp = found->data[0].pwdata;
recend = (const char *) found->data + found->recsize;
+ /* Now check if we can trust pw_resp fields. If GC is
+ in progress, it can contain anything. */
+ if (mapped->head->gc_cycle != gc_cycle)
+ {
+ retval = -2;
+ goto out;
+ }
}
}
- pw_response_header pw_resp_mem;
int sock = -1;
- if (pw_resp == NULL)
+ if (pw_name == NULL)
{
- sock = __nscd_open_socket (key, keylen, type, &pw_resp_mem,
- sizeof (pw_resp_mem));
+ sock = __nscd_open_socket (key, keylen, type, &pw_resp,
+ sizeof (pw_resp));
if (sock == -1)
{
__nss_not_use_nscd_passwd = 1;
goto out;
}
-
- pw_resp = &pw_resp_mem;
}
/* No value found so far. */
*result = NULL;
- if (__builtin_expect (pw_resp->found == -1, 0))
+ if (__glibc_unlikely (pw_resp.found == -1))
{
/* The daemon does not cache this database. */
__nss_not_use_nscd_passwd = 1;
goto out_close;
}
- if (pw_resp->found == 1)
+ if (pw_resp.found == 1)
{
/* Set the information we already have. */
- resultbuf->pw_uid = pw_resp->pw_uid;
- resultbuf->pw_gid = pw_resp->pw_gid;
+ resultbuf->pw_uid = pw_resp.pw_uid;
+ resultbuf->pw_gid = pw_resp.pw_gid;
char *p = buffer;
/* get pw_name */
resultbuf->pw_name = p;
- p += pw_resp->pw_name_len;
+ p += pw_resp.pw_name_len;
/* get pw_passwd */
resultbuf->pw_passwd = p;
- p += pw_resp->pw_passwd_len;
+ p += pw_resp.pw_passwd_len;
/* get pw_gecos */
resultbuf->pw_gecos = p;
- p += pw_resp->pw_gecos_len;
+ p += pw_resp.pw_gecos_len;
/* get pw_dir */
resultbuf->pw_dir = p;
- p += pw_resp->pw_dir_len;
+ p += pw_resp.pw_dir_len;
/* get pw_pshell */
resultbuf->pw_shell = p;
- p += pw_resp->pw_shell_len;
+ p += pw_resp.pw_shell_len;
ssize_t total = p - buffer;
- if (__builtin_expect (pw_name + total > recend, 0))
+ if (__glibc_unlikely (pw_name + total > recend))
goto out_close;
- if (__builtin_expect (buflen < total, 0))
+ if (__glibc_unlikely (buflen < total))
{
__set_errno (ERANGE);
retval = ERANGE;
retval = 0;
if (pw_name == NULL)
{
- ssize_t nbytes = TEMP_FAILURE_RETRY (__read (sock, buffer, total));
+ ssize_t nbytes = __readall (sock, buffer, total);
- if (__builtin_expect (nbytes != total, 0))
+ if (__glibc_unlikely (nbytes != total))
{
/* The `errno' to some value != ERANGE. */
__set_errno (ENOENT);
/* Copy the various strings. */
memcpy (resultbuf->pw_name, pw_name, total);
+ /* Try to detect corrupt databases. */
+ if (resultbuf->pw_name[pw_resp.pw_name_len - 1] != '\0'
+ || resultbuf->pw_passwd[pw_resp.pw_passwd_len - 1] != '\0'
+ || resultbuf->pw_gecos[pw_resp.pw_gecos_len - 1] != '\0'
+ || resultbuf->pw_dir[pw_resp.pw_dir_len - 1] != '\0'
+ || resultbuf->pw_shell[pw_resp.pw_shell_len - 1] != '\0')
+ {
+ /* We cannot use the database. */
+ retval = mapped->head->gc_cycle != gc_cycle ? -2 : -1;
+ goto out_close;
+ }
+
*result = resultbuf;
}
}
else
{
- /* The `errno' to some value != ERANGE. */
- __set_errno (ENOENT);
+ /* Set errno to 0 to indicate no error, just no found record. */
+ __set_errno (0);
/* Even though we have not found anything, the result is zero. */
retval = 0;
}
out_close:
if (sock != -1)
- close_not_cancel_no_status (sock);
+ __close_nocancel_nostatus (sock);
out:
- if (__nscd_drop_map_ref (mapped, gc_cycle) != 0)
- /* When we come here this means there has been a GC cycle while we
- were looking for the data. This means the data might have been
- inconsistent. Retry. */
- goto retry;
+ if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
+ {
+ /* When we come here this means there has been a GC cycle while we
+ were looking for the data. This means the data might have been
+ inconsistent. Retry if possible. */
+ if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
+ {
+ /* nscd is just running gc now. Disable using the mapping. */
+ if (atomic_decrement_val (&mapped->counter) == 0)
+ __nscd_unmap (mapped);
+ mapped = NO_MAPPING;
+ }
+
+ if (retval != -1)
+ goto retry;
+ }
return retval;
}