mirror of
https://sourceware.org/git/glibc.git
synced 2025-05-30 04:04:54 +03:00
Update.
* nscd/connections.c: Implement r/o sharing of nscd's cache with client processes via shared memory. * nscd/nscd-client.h: Likewise. * nscd/nscd.h: Likewise. * nscd/nscd_conf.c: Likewise. * nscd/nscd_getgr_r.c: Likewise. * nscd/nscd_getpw_r.c: Likewise. * nscd/nscd_gethst_r.c: Likewise. * nscd/nscd.conf: Add new config parameters. * nscd/Makefile (aux): Add nscd_helper. * nscd/nscd_helper.c: New file. * nscd/mem.c (gc): Indicate beginning and end of the gc cycle. * nscd/hstcache.c: Simplify a lot. We cache only the request itself, no derived information. * connections.c (nscd_init): Fix bug in testing size of the persistent. * nis/Makefile (aux): Add nis_hash. * nis/nis_hash.c: New file. Split out from nis_util.c. * nis/nis_util.c: Move __nis_hash code in separate file. * csu/tst-atomic.c: Improve atomic_increment_val test which would not have found a ppc bug.
This commit is contained in:
parent
0a3ad40da9
commit
c207f23b0b
24
ChangeLog
24
ChangeLog
@ -1,5 +1,29 @@
|
|||||||
2004-09-08 Ulrich Drepper <drepper@redhat.com>
|
2004-09-08 Ulrich Drepper <drepper@redhat.com>
|
||||||
|
|
||||||
|
* nscd/connections.c: Implement r/o sharing of nscd's cache with client
|
||||||
|
processes via shared memory.
|
||||||
|
* nscd/nscd-client.h: Likewise.
|
||||||
|
* nscd/nscd.h: Likewise.
|
||||||
|
* nscd/nscd_conf.c: Likewise.
|
||||||
|
* nscd/nscd_getgr_r.c: Likewise.
|
||||||
|
* nscd/nscd_getpw_r.c: Likewise.
|
||||||
|
* nscd/nscd_gethst_r.c: Likewise.
|
||||||
|
* nscd/nscd.conf: Add new config parameters.
|
||||||
|
* nscd/Makefile (aux): Add nscd_helper.
|
||||||
|
* nscd/nscd_helper.c: New file.
|
||||||
|
* nscd/mem.c (gc): Indicate beginning and end of the gc cycle.
|
||||||
|
|
||||||
|
* nscd/hstcache.c: Simplify a lot. We cache only the request itself,
|
||||||
|
no derived information.
|
||||||
|
* connections.c (nscd_init): Fix bug in testing size of the persistent.
|
||||||
|
|
||||||
|
* nis/Makefile (aux): Add nis_hash.
|
||||||
|
* nis/nis_hash.c: New file. Split out from nis_util.c.
|
||||||
|
* nis/nis_util.c: Move __nis_hash code in separate file.
|
||||||
|
|
||||||
|
* csu/tst-atomic.c: Improve atomic_increment_val test which would
|
||||||
|
not have found a ppc bug.
|
||||||
|
|
||||||
* sysdeps/s390/fpu/bits/mathinline.h: Remove unnecessary includes.
|
* sysdeps/s390/fpu/bits/mathinline.h: Remove unnecessary includes.
|
||||||
|
|
||||||
* malloc/arena.c: Remove __MALLOC_P uses.
|
* malloc/arena.c: Remove __MALLOC_P uses.
|
||||||
|
@ -130,7 +130,8 @@ do_test (void)
|
|||||||
ret = 1;
|
ret = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (atomic_increment_val (&mem) != 1)
|
mem = 2;
|
||||||
|
if (atomic_increment_val (&mem) != 3)
|
||||||
{
|
{
|
||||||
puts ("atomic_increment_val test failed");
|
puts ("atomic_increment_val test failed");
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
#
|
#
|
||||||
subdir := nis
|
subdir := nis
|
||||||
|
|
||||||
|
aux := nis_hash
|
||||||
|
|
||||||
headers := $(wildcard rpcsvc/*.[hx])
|
headers := $(wildcard rpcsvc/*.[hx])
|
||||||
distribute := nss-nis.h nss-nisplus.h nis_intern.h Banner \
|
distribute := nss-nis.h nss-nisplus.h nis_intern.h Banner \
|
||||||
nisplus-parser.h nis_xdr.h nss
|
nisplus-parser.h nis_xdr.h nss
|
||||||
|
76
nis/nis_hash.c
Normal file
76
nis/nis_hash.c
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/* Copyright (c) 1997, 1998, 1999, 2004 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
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. */
|
||||||
|
|
||||||
|
#include <rpcsvc/nis.h>
|
||||||
|
|
||||||
|
/* This is from libc/db/hash/hash_func.c, hash3 is static there */
|
||||||
|
/*
|
||||||
|
* This is INCREDIBLY ugly, but fast. We break the string up into 8 byte
|
||||||
|
* units. On the first time through the loop we get the "leftover bytes"
|
||||||
|
* (strlen % 8). On every other iteration, we perform 8 HASHC's so we handle
|
||||||
|
* all 8 bytes. Essentially, this saves us 7 cmp & branch instructions. If
|
||||||
|
* this routine is heavily used enough, it's worth the ugly coding.
|
||||||
|
*
|
||||||
|
* OZ's original sdbm hash
|
||||||
|
*/
|
||||||
|
uint32_t
|
||||||
|
__nis_hash (const void *keyarg, register size_t len)
|
||||||
|
{
|
||||||
|
register const u_char *key;
|
||||||
|
register size_t loop;
|
||||||
|
register uint32_t h;
|
||||||
|
|
||||||
|
#define HASHC h = *key++ + 65599 * h
|
||||||
|
|
||||||
|
h = 0;
|
||||||
|
key = keyarg;
|
||||||
|
if (len > 0)
|
||||||
|
{
|
||||||
|
loop = (len + 8 - 1) >> 3;
|
||||||
|
switch (len & (8 - 1))
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
do {
|
||||||
|
HASHC;
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case 7:
|
||||||
|
HASHC;
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case 6:
|
||||||
|
HASHC;
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case 5:
|
||||||
|
HASHC;
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case 4:
|
||||||
|
HASHC;
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case 3:
|
||||||
|
HASHC;
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case 2:
|
||||||
|
HASHC;
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case 1:
|
||||||
|
HASHC;
|
||||||
|
} while (--loop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 1997, 1998, 1999 Free Software Foundation, Inc.
|
/* Copyright (c) 1997, 1998, 1999, 2004 Free Software Foundation, Inc.
|
||||||
This file is part of the GNU C Library.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
|
Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
|
||||||
|
|
||||||
@ -47,58 +47,6 @@ __nis_finddirectory (directory_obj *dir, const_nis_name name)
|
|||||||
return fd_res;
|
return fd_res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is from libc/db/hash/hash_func.c, hash3 is static there */
|
|
||||||
/*
|
|
||||||
* This is INCREDIBLY ugly, but fast. We break the string up into 8 byte
|
|
||||||
* units. On the first time through the loop we get the "leftover bytes"
|
|
||||||
* (strlen % 8). On every other iteration, we perform 8 HASHC's so we handle
|
|
||||||
* all 8 bytes. Essentially, this saves us 7 cmp & branch instructions. If
|
|
||||||
* this routine is heavily used enough, it's worth the ugly coding.
|
|
||||||
*
|
|
||||||
* OZ's original sdbm hash
|
|
||||||
*/
|
|
||||||
uint32_t
|
|
||||||
__nis_hash (const void *keyarg, register size_t len)
|
|
||||||
{
|
|
||||||
register const u_char *key;
|
|
||||||
register size_t loop;
|
|
||||||
register uint32_t h;
|
|
||||||
|
|
||||||
#define HASHC h = *key++ + 65599 * h
|
/* The hash implementation is in a separate file. */
|
||||||
|
#include "nis_hash.c"
|
||||||
h = 0;
|
|
||||||
key = keyarg;
|
|
||||||
if (len > 0)
|
|
||||||
{
|
|
||||||
loop = (len + 8 - 1) >> 3;
|
|
||||||
switch (len & (8 - 1))
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
do {
|
|
||||||
HASHC;
|
|
||||||
/* FALLTHROUGH */
|
|
||||||
case 7:
|
|
||||||
HASHC;
|
|
||||||
/* FALLTHROUGH */
|
|
||||||
case 6:
|
|
||||||
HASHC;
|
|
||||||
/* FALLTHROUGH */
|
|
||||||
case 5:
|
|
||||||
HASHC;
|
|
||||||
/* FALLTHROUGH */
|
|
||||||
case 4:
|
|
||||||
HASHC;
|
|
||||||
/* FALLTHROUGH */
|
|
||||||
case 3:
|
|
||||||
HASHC;
|
|
||||||
/* FALLTHROUGH */
|
|
||||||
case 2:
|
|
||||||
HASHC;
|
|
||||||
/* FALLTHROUGH */
|
|
||||||
case 1:
|
|
||||||
HASHC;
|
|
||||||
} while (--loop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (h);
|
|
||||||
}
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
subdir := nscd
|
subdir := nscd
|
||||||
|
|
||||||
routines := nscd_getpw_r nscd_getgr_r nscd_gethst_r
|
routines := nscd_getpw_r nscd_getgr_r nscd_gethst_r
|
||||||
|
aux := nscd_helper
|
||||||
|
|
||||||
include ../Makeconfig
|
include ../Makeconfig
|
||||||
|
|
||||||
|
@ -80,7 +80,10 @@ const char *serv2str[LASTREQ] =
|
|||||||
[GETHOSTBYADDRv6] = "GETHOSTBYADDRv6",
|
[GETHOSTBYADDRv6] = "GETHOSTBYADDRv6",
|
||||||
[SHUTDOWN] = "SHUTDOWN",
|
[SHUTDOWN] = "SHUTDOWN",
|
||||||
[GETSTAT] = "GETSTAT",
|
[GETSTAT] = "GETSTAT",
|
||||||
[INVALIDATE] = "INVALIDATE"
|
[INVALIDATE] = "INVALIDATE",
|
||||||
|
[GETFDPW] = "GETFDPW",
|
||||||
|
[GETFDGR] = "GETFDGR",
|
||||||
|
[GETFDHST] = "GETFDHST"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The control data structures for the services. */
|
/* The control data structures for the services. */
|
||||||
@ -91,6 +94,7 @@ struct database_dyn dbs[lastdb] =
|
|||||||
.enabled = 0,
|
.enabled = 0,
|
||||||
.check_file = 1,
|
.check_file = 1,
|
||||||
.persistent = 0,
|
.persistent = 0,
|
||||||
|
.shared = 0,
|
||||||
.filename = "/etc/passwd",
|
.filename = "/etc/passwd",
|
||||||
.db_filename = _PATH_NSCD_PASSWD_DB,
|
.db_filename = _PATH_NSCD_PASSWD_DB,
|
||||||
.disabled_iov = &pwd_iov_disabled,
|
.disabled_iov = &pwd_iov_disabled,
|
||||||
@ -105,6 +109,7 @@ struct database_dyn dbs[lastdb] =
|
|||||||
.enabled = 0,
|
.enabled = 0,
|
||||||
.check_file = 1,
|
.check_file = 1,
|
||||||
.persistent = 0,
|
.persistent = 0,
|
||||||
|
.shared = 0,
|
||||||
.filename = "/etc/group",
|
.filename = "/etc/group",
|
||||||
.db_filename = _PATH_NSCD_GROUP_DB,
|
.db_filename = _PATH_NSCD_GROUP_DB,
|
||||||
.disabled_iov = &grp_iov_disabled,
|
.disabled_iov = &grp_iov_disabled,
|
||||||
@ -119,6 +124,7 @@ struct database_dyn dbs[lastdb] =
|
|||||||
.enabled = 0,
|
.enabled = 0,
|
||||||
.check_file = 1,
|
.check_file = 1,
|
||||||
.persistent = 0,
|
.persistent = 0,
|
||||||
|
.shared = 0,
|
||||||
.filename = "/etc/hosts",
|
.filename = "/etc/hosts",
|
||||||
.db_filename = _PATH_NSCD_HOSTS_DB,
|
.db_filename = _PATH_NSCD_HOSTS_DB,
|
||||||
.disabled_iov = &hst_iov_disabled,
|
.disabled_iov = &hst_iov_disabled,
|
||||||
@ -132,7 +138,7 @@ struct database_dyn dbs[lastdb] =
|
|||||||
|
|
||||||
|
|
||||||
/* Mapping of request type to database. */
|
/* Mapping of request type to database. */
|
||||||
static struct database_dyn *const serv2db[LASTDBREQ + 1] =
|
static struct database_dyn *const serv2db[LASTREQ] =
|
||||||
{
|
{
|
||||||
[GETPWBYNAME] = &dbs[pwddb],
|
[GETPWBYNAME] = &dbs[pwddb],
|
||||||
[GETPWBYUID] = &dbs[pwddb],
|
[GETPWBYUID] = &dbs[pwddb],
|
||||||
@ -141,7 +147,10 @@ static struct database_dyn *const serv2db[LASTDBREQ + 1] =
|
|||||||
[GETHOSTBYNAME] = &dbs[hstdb],
|
[GETHOSTBYNAME] = &dbs[hstdb],
|
||||||
[GETHOSTBYNAMEv6] = &dbs[hstdb],
|
[GETHOSTBYNAMEv6] = &dbs[hstdb],
|
||||||
[GETHOSTBYADDR] = &dbs[hstdb],
|
[GETHOSTBYADDR] = &dbs[hstdb],
|
||||||
[GETHOSTBYADDRv6] = &dbs[hstdb]
|
[GETHOSTBYADDRv6] = &dbs[hstdb],
|
||||||
|
[GETFDPW] = &dbs[pwddb],
|
||||||
|
[GETFDGR] = &dbs[grpdb],
|
||||||
|
[GETFDHST] = &dbs[hstdb],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -158,9 +167,6 @@ static int sock;
|
|||||||
/* Number of times clients had to wait. */
|
/* Number of times clients had to wait. */
|
||||||
unsigned long int client_queued;
|
unsigned long int client_queued;
|
||||||
|
|
||||||
/* Alignment requirement of the beginning of the data region. */
|
|
||||||
#define ALIGN 16
|
|
||||||
|
|
||||||
|
|
||||||
/* Initialize database information structures. */
|
/* Initialize database information structures. */
|
||||||
void
|
void
|
||||||
@ -224,11 +230,10 @@ nscd_init (void)
|
|||||||
dbs[cnt].persistent = 0;
|
dbs[cnt].persistent = 0;
|
||||||
}
|
}
|
||||||
else if ((total = (sizeof (head)
|
else if ((total = (sizeof (head)
|
||||||
+ roundup (head.module
|
+ roundup (head.module * sizeof (ref_t),
|
||||||
* sizeof (struct hashentry),
|
|
||||||
ALIGN)
|
ALIGN)
|
||||||
+ head.data_size))
|
+ head.data_size))
|
||||||
< st.st_size)
|
> st.st_size)
|
||||||
{
|
{
|
||||||
dbg_log (_("invalid persistent database file \"%s\": %s"),
|
dbg_log (_("invalid persistent database file \"%s\": %s"),
|
||||||
dbs[cnt].db_filename,
|
dbs[cnt].db_filename,
|
||||||
@ -253,6 +258,7 @@ nscd_init (void)
|
|||||||
dbnames[cnt]);
|
dbnames[cnt]);
|
||||||
|
|
||||||
dbs[cnt].wr_fd = fd;
|
dbs[cnt].wr_fd = fd;
|
||||||
|
dbs[cnt].ro_fd = open (dbs[cnt].db_filename, O_RDONLY);
|
||||||
fd = -1;
|
fd = -1;
|
||||||
/* We also need a read-only descriptor. */
|
/* We also need a read-only descriptor. */
|
||||||
dbs[cnt].ro_fd = open (dbs[cnt].db_filename, O_RDONLY);
|
dbs[cnt].ro_fd = open (dbs[cnt].db_filename, O_RDONLY);
|
||||||
@ -439,6 +445,9 @@ cannot create read-only descriptor for \"%s\"; no mmap"),
|
|||||||
* dbs[cnt].head->module);
|
* dbs[cnt].head->module);
|
||||||
dbs[cnt].data = xmalloc (dbs[cnt].head->data_size);
|
dbs[cnt].data = xmalloc (dbs[cnt].head->data_size);
|
||||||
dbs[cnt].head->first_free = 0;
|
dbs[cnt].head->first_free = 0;
|
||||||
|
|
||||||
|
dbs[cnt].shared = 0;
|
||||||
|
assert (dbs[cnt].ro_fd == -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dbs[cnt].check_file)
|
if (dbs[cnt].check_file)
|
||||||
@ -529,6 +538,43 @@ invalidate_cache (char *key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef SCM_RIGHTS
|
||||||
|
static void
|
||||||
|
send_ro_fd (struct database_dyn *db, char *key, int fd)
|
||||||
|
{
|
||||||
|
/* If we do not have an read-only file descriptor do nothing. */
|
||||||
|
if (db->ro_fd == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* We need to send some data along with the descriptor. */
|
||||||
|
struct iovec iov[1];
|
||||||
|
iov[0].iov_base = key;
|
||||||
|
iov[0].iov_len = strlen (key) + 1;
|
||||||
|
|
||||||
|
/* Prepare the control message to transfer the descriptor. */
|
||||||
|
char buf[CMSG_SPACE (sizeof (int))];
|
||||||
|
struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1,
|
||||||
|
.msg_control = buf, .msg_controllen = sizeof (buf) };
|
||||||
|
struct cmsghdr *cmsg = CMSG_FIRSTHDR (&msg);
|
||||||
|
|
||||||
|
cmsg->cmsg_level = SOL_SOCKET;
|
||||||
|
cmsg->cmsg_type = SCM_RIGHTS;
|
||||||
|
cmsg->cmsg_len = CMSG_LEN (sizeof (int));
|
||||||
|
|
||||||
|
*(int *) CMSG_DATA (cmsg) = db->ro_fd;
|
||||||
|
|
||||||
|
msg.msg_controllen = cmsg->cmsg_len;
|
||||||
|
|
||||||
|
/* Send the control message. We repeat when we are interrupted but
|
||||||
|
everything else is ignored. */
|
||||||
|
(void) TEMP_FAILURE_RETRY (sendmsg (fd, &msg, 0));
|
||||||
|
|
||||||
|
if (__builtin_expect (debug_level > 0, 0))
|
||||||
|
dbg_log (_("provide access to FD %d, for %s"), db->ro_fd, key);
|
||||||
|
}
|
||||||
|
#endif /* SCM_RIGHTS */
|
||||||
|
|
||||||
|
|
||||||
/* Handle new request. */
|
/* Handle new request. */
|
||||||
static void
|
static void
|
||||||
handle_request (int fd, request_header *req, void *key, uid_t uid)
|
handle_request (int fd, request_header *req, void *key, uid_t uid)
|
||||||
@ -614,7 +660,7 @@ cannot handle old request version %d; current version is %d"),
|
|||||||
else if (__builtin_expect (debug_level, 0) > 0)
|
else if (__builtin_expect (debug_level, 0) > 0)
|
||||||
{
|
{
|
||||||
if (req->type == INVALIDATE)
|
if (req->type == INVALIDATE)
|
||||||
dbg_log ("\t%s (%s)", serv2str[req->type], (char *)key);
|
dbg_log ("\t%s (%s)", serv2str[req->type], (char *) key);
|
||||||
else
|
else
|
||||||
dbg_log ("\t%s", serv2str[req->type]);
|
dbg_log ("\t%s", serv2str[req->type]);
|
||||||
}
|
}
|
||||||
@ -697,6 +743,14 @@ cannot handle old request version %d; current version is %d"),
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case GETFDPW:
|
||||||
|
case GETFDGR:
|
||||||
|
case GETFDHST:
|
||||||
|
#ifdef SCM_RIGHTS
|
||||||
|
send_ro_fd (serv2db[req->type], key, fd);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* Ignore the command, it's nothing we know. */
|
/* Ignore the command, it's nothing we know. */
|
||||||
break;
|
break;
|
||||||
@ -733,7 +787,9 @@ nscd_run (void *p)
|
|||||||
int timeout = -1;
|
int timeout = -1;
|
||||||
if (run_prune)
|
if (run_prune)
|
||||||
{
|
{
|
||||||
now = time (NULL);
|
/* NB: we do not flush the timestamp update using msync since
|
||||||
|
this value doesnot matter on disk. */
|
||||||
|
dbs[my_number].head->timestamp = now = time (NULL);
|
||||||
timeout = now < next_prune ? 1000 * (next_prune - now) : 0;
|
timeout = now < next_prune ? 1000 * (next_prune - now) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
165
nscd/hstcache.c
165
nscd/hstcache.c
@ -77,7 +77,7 @@ static const hst_response_header notfound =
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
cache_addhst (struct database_dyn *db, int fd, request_header *req,
|
cache_addhst (struct database_dyn *db, int fd, request_header *req,
|
||||||
const void *key, struct hostent *hst, uid_t owner, int add_addr,
|
const void *key, struct hostent *hst, uid_t owner,
|
||||||
struct hashentry *he, struct datahead *dh, int errval)
|
struct hashentry *he, struct datahead *dh, int errval)
|
||||||
{
|
{
|
||||||
ssize_t total;
|
ssize_t total;
|
||||||
@ -208,7 +208,7 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
|
|||||||
the current cache handling cannot handle and it is more than
|
the current cache handling cannot handle and it is more than
|
||||||
questionable whether it is worthwhile complicating the cache
|
questionable whether it is worthwhile complicating the cache
|
||||||
handling just for handling such a special case. */
|
handling just for handling such a special case. */
|
||||||
if (he == NULL && (add_addr || hst->h_addr_list[1] == NULL))
|
if (he == NULL && hst->h_addr_list[1] == NULL)
|
||||||
{
|
{
|
||||||
dataset = (struct dataset *) mempool_alloc (db,
|
dataset = (struct dataset *) mempool_alloc (db,
|
||||||
total + req->key_len);
|
total + req->key_len);
|
||||||
@ -269,10 +269,7 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
|
|||||||
itself. This is the case if the resolver is used and the name
|
itself. This is the case if the resolver is used and the name
|
||||||
is extended by the domainnames from /etc/resolv.conf. Therefore
|
is extended by the domainnames from /etc/resolv.conf. Therefore
|
||||||
we explicitly add the name here. */
|
we explicitly add the name here. */
|
||||||
if (req->type == GETHOSTBYNAME || req->type == GETHOSTBYNAMEv6)
|
key_copy = memcpy (cp, key, req->key_len);
|
||||||
key_copy = memcpy (cp, key, req->key_len);
|
|
||||||
else
|
|
||||||
memset (cp, '\0', req->key_len);
|
|
||||||
|
|
||||||
/* Now we can determine whether on refill we have to create a new
|
/* Now we can determine whether on refill we have to create a new
|
||||||
record or not. */
|
record or not. */
|
||||||
@ -349,141 +346,21 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
|
|||||||
problem is that we always must add the hash table entry
|
problem is that we always must add the hash table entry
|
||||||
with the FIRST flag set first. Otherwise we get dangling
|
with the FIRST flag set first. Otherwise we get dangling
|
||||||
pointers in case memory allocation fails. */
|
pointers in case memory allocation fails. */
|
||||||
assert (add_addr || hst->h_addr_list[1] == NULL);
|
assert (hst->h_addr_list[1] == NULL);
|
||||||
|
|
||||||
/* Add the normal addresses. */
|
|
||||||
if (add_addr)
|
|
||||||
{
|
|
||||||
for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
|
|
||||||
{
|
|
||||||
if (cache_add (addr_list_type, addresses, hst->h_length,
|
|
||||||
&dataset->head, cnt == 0, db, owner) < 0)
|
|
||||||
{
|
|
||||||
/* Ensure the data can be recovered. */
|
|
||||||
if (cnt == 0)
|
|
||||||
dataset->head.usable = false;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
addresses += hst->h_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If necessary the IPv6 addresses. */
|
|
||||||
if (addr_list_type == GETHOSTBYADDR)
|
|
||||||
for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
|
|
||||||
{
|
|
||||||
if (cache_add (GETHOSTBYADDRv6, addresses, IN6ADDRSZ,
|
|
||||||
&dataset->head, false, db, owner) < 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
addresses += IN6ADDRSZ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Avoid adding names if more than one address is available. See
|
/* Avoid adding names if more than one address is available. See
|
||||||
above for more info. */
|
above for more info. */
|
||||||
else
|
assert (req->type == GETHOSTBYNAME
|
||||||
{
|
|| req->type == GETHOSTBYNAMEv6
|
||||||
assert (req->type == GETHOSTBYNAME
|
|| req->type == GETHOSTBYADDR
|
||||||
|| req->type == GETHOSTBYNAMEv6
|
|| req->type == GETHOSTBYADDRv6);
|
||||||
|| req->type == GETHOSTBYADDR
|
|
||||||
|| req->type == GETHOSTBYADDRv6);
|
|
||||||
|
|
||||||
/* If necessary add the key for this request. */
|
if (cache_add (req->type, key_copy, req->key_len,
|
||||||
if (req->type == GETHOSTBYNAME)
|
&dataset->head, true, db, owner) < 0)
|
||||||
{
|
/* Could not allocate memory. Make sure the
|
||||||
bool first = true;
|
data gets discarded. */
|
||||||
if (addr_list_type == GETHOSTBYADDR)
|
dataset->head.usable = false;
|
||||||
{
|
|
||||||
if (cache_add (GETHOSTBYNAME, key_copy, req->key_len,
|
|
||||||
&dataset->head, true, db, owner) < 0)
|
|
||||||
{
|
|
||||||
/* Could not allocate memory. Make sure the
|
|
||||||
data gets discarded. */
|
|
||||||
dataset->head.usable = false;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
if (cache_add (GETHOSTBYNAMEv6, key_copy, req->key_len,
|
|
||||||
&dataset->head, first, db, owner) < 0)
|
|
||||||
{
|
|
||||||
/* Could not allocate memory. Make sure the
|
|
||||||
data gets discarded. */
|
|
||||||
if (first)
|
|
||||||
dataset->head.usable = false;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (req->type == GETHOSTBYNAMEv6)
|
|
||||||
{
|
|
||||||
if (cache_add (GETHOSTBYNAMEv6, key_copy, req->key_len,
|
|
||||||
&dataset->head, true, db, owner) < 0)
|
|
||||||
{
|
|
||||||
/* Could not allocate memory. Make sure the
|
|
||||||
data gets discarded. */
|
|
||||||
dataset->head.usable = false;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addr_list_type == GETHOSTBYADDR
|
|
||||||
&& cache_add (GETHOSTBYNAME, key_copy, req->key_len,
|
|
||||||
&dataset->head, false, db, owner) < 0)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* And finally the name. We mark this as the last entry. */
|
|
||||||
if (addr_list_type == GETHOSTBYADDR
|
|
||||||
&& req->type == GETHOSTBYADDR
|
|
||||||
&& cache_add (GETHOSTBYNAME, dataset->strdata, h_name_len,
|
|
||||||
&dataset->head, true, db, owner) < 0)
|
|
||||||
{
|
|
||||||
/* Could not allocate memory. Make sure the
|
|
||||||
data gets discarded. */
|
|
||||||
dataset->head.usable = false;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cache_add (GETHOSTBYNAMEv6, dataset->strdata,
|
|
||||||
h_name_len, &dataset->head,
|
|
||||||
((req->type == GETHOSTBYADDR
|
|
||||||
&& addr_list_type != GETHOSTBYADDR)
|
|
||||||
|| req->type == GETHOSTBYADDRv6), db,
|
|
||||||
owner) < 0)
|
|
||||||
{
|
|
||||||
/* Could not allocate memory. Make sure the
|
|
||||||
data gets discarded. */
|
|
||||||
if ((req->type == GETHOSTBYADDR
|
|
||||||
&& addr_list_type != GETHOSTBYADDR)
|
|
||||||
|| req->type == GETHOSTBYADDRv6)
|
|
||||||
dataset->head.usable = false;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addr_list_type == GETHOSTBYADDR
|
|
||||||
&& req->type != GETHOSTBYADDR
|
|
||||||
&& cache_add (GETHOSTBYNAME, dataset->strdata, h_name_len,
|
|
||||||
&dataset->head, false, db, owner) < 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* First add all the aliases. */
|
|
||||||
for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
|
|
||||||
{
|
|
||||||
if (addr_list_type == GETHOSTBYADDR)
|
|
||||||
if (cache_add (GETHOSTBYNAME, aliases,
|
|
||||||
h_aliases_len[cnt], &dataset->head,
|
|
||||||
false, db, owner) < 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (cache_add (GETHOSTBYNAMEv6, aliases,
|
|
||||||
h_aliases_len[cnt], &dataset->head,
|
|
||||||
false, db, owner) < 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
aliases += h_aliases_len[cnt];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
pthread_rwlock_unlock (&db->lock);
|
pthread_rwlock_unlock (&db->lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -534,10 +411,18 @@ addhstbyX (struct database_dyn *db, int fd, request_header *req,
|
|||||||
|
|
||||||
if (__builtin_expect (debug_level > 0, 0))
|
if (__builtin_expect (debug_level > 0, 0))
|
||||||
{
|
{
|
||||||
if (he == NULL)
|
const char *str;
|
||||||
dbg_log (_("Haven't found \"%s\" in hosts cache!"), (char *) key);
|
char buf[INET6_ADDRSTRLEN + 1];
|
||||||
|
if (req->type == GETHOSTBYNAME || req->type == GETHOSTBYNAMEv6)
|
||||||
|
str = key;
|
||||||
else
|
else
|
||||||
dbg_log (_("Reloading \"%s\" in hosts cache!"), (char *) key);
|
str = inet_ntop (req->type == GETHOSTBYADDR ? AF_INET : AF_INET6,
|
||||||
|
key, buf, sizeof (buf));
|
||||||
|
|
||||||
|
if (he == NULL)
|
||||||
|
dbg_log (_("Haven't found \"%s\" in hosts cache!"), (char *) str);
|
||||||
|
else
|
||||||
|
dbg_log (_("Reloading \"%s\" in hosts cache!"), (char *) str);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (db->secure)
|
if (db->secure)
|
||||||
@ -583,7 +468,7 @@ addhstbyX (struct database_dyn *db, int fd, request_header *req,
|
|||||||
if (db->secure)
|
if (db->secure)
|
||||||
seteuid (oldeuid);
|
seteuid (oldeuid);
|
||||||
|
|
||||||
cache_addhst (db, fd, req, key, hst, uid, 0, he, dh,
|
cache_addhst (db, fd, req, key, hst, uid, he, dh,
|
||||||
h_errno == TRY_AGAIN ? errval : 0);
|
h_errno == TRY_AGAIN ? errval : 0);
|
||||||
|
|
||||||
if (use_malloc)
|
if (use_malloc)
|
||||||
|
11
nscd/mem.c
11
nscd/mem.c
@ -230,6 +230,12 @@ gc (struct database_dyn *db)
|
|||||||
++next_data;
|
++next_data;
|
||||||
|
|
||||||
|
|
||||||
|
/* Now we start modifying the data. Make sure all readers of the
|
||||||
|
data are aware of this and temporarily don't use the data. */
|
||||||
|
++db->head->gc_cycle;
|
||||||
|
assert ((db->head->gc_cycle & 1) == 1);
|
||||||
|
|
||||||
|
|
||||||
/* We do not perform the move operations right away since the
|
/* We do not perform the move operations right away since the
|
||||||
he_data array is not sorted by the address of the data. */
|
he_data array is not sorted by the address of the data. */
|
||||||
struct moveinfo
|
struct moveinfo
|
||||||
@ -445,6 +451,11 @@ gc (struct database_dyn *db)
|
|||||||
msync (db->head, db->data + db->head->first_free - (char *) db->head,
|
msync (db->head, db->data + db->head->first_free - (char *) db->head,
|
||||||
MS_ASYNC);
|
MS_ASYNC);
|
||||||
|
|
||||||
|
|
||||||
|
/* Now we are done modifying the data. */
|
||||||
|
++db->head->gc_cycle;
|
||||||
|
assert ((db->head->gc_cycle & 1) == 0);
|
||||||
|
|
||||||
/* We are done. */
|
/* We are done. */
|
||||||
out:
|
out:
|
||||||
pthread_mutex_unlock (&db->memlock);
|
pthread_mutex_unlock (&db->memlock);
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#ifndef _NSCD_CLIENT_H
|
#ifndef _NSCD_CLIENT_H
|
||||||
#define _NSCD_CLIENT_H 1
|
#define _NSCD_CLIENT_H 1
|
||||||
|
|
||||||
|
#include <atomic.h>
|
||||||
#include <nscd-types.h>
|
#include <nscd-types.h>
|
||||||
|
|
||||||
/* Version number of the daemon interface */
|
/* Version number of the daemon interface */
|
||||||
@ -53,6 +54,9 @@ typedef enum
|
|||||||
SHUTDOWN, /* Shut the server down. */
|
SHUTDOWN, /* Shut the server down. */
|
||||||
GETSTAT, /* Get the server statistic. */
|
GETSTAT, /* Get the server statistic. */
|
||||||
INVALIDATE, /* Invalidate one special cache. */
|
INVALIDATE, /* Invalidate one special cache. */
|
||||||
|
GETFDPW,
|
||||||
|
GETFDGR,
|
||||||
|
GETFDHST,
|
||||||
LASTREQ
|
LASTREQ
|
||||||
} request_type;
|
} request_type;
|
||||||
|
|
||||||
@ -110,9 +114,151 @@ typedef struct
|
|||||||
} hst_response_header;
|
} hst_response_header;
|
||||||
|
|
||||||
|
|
||||||
|
/* Type for offsets in data part of database. */
|
||||||
|
typedef uint32_t ref_t;
|
||||||
|
/* Value for invalid/no reference. */
|
||||||
|
#define ENDREF UINT32_MAX
|
||||||
|
|
||||||
|
/* Alignment requirement of the beginning of the data region. */
|
||||||
|
#define ALIGN 16
|
||||||
|
|
||||||
|
|
||||||
|
/* Head of record in data part of database. */
|
||||||
|
struct datahead
|
||||||
|
{
|
||||||
|
size_t allocsize; /* Allocated Bytes. */
|
||||||
|
size_t recsize; /* Size of the record. */
|
||||||
|
time_t timeout; /* Time when this entry becomes invalid. */
|
||||||
|
bool notfound; /* Nonzero if data for key has not been found. */
|
||||||
|
uint8_t nreloads; /* Reloads without use. */
|
||||||
|
bool usable; /* False if the entry must be ignored. */
|
||||||
|
|
||||||
|
/* We need to have the following element aligned for the response
|
||||||
|
header data types and their use in the 'struct dataset' types
|
||||||
|
defined in the XXXcache.c files. */
|
||||||
|
union
|
||||||
|
{
|
||||||
|
pw_response_header pwdata;
|
||||||
|
gr_response_header grdata;
|
||||||
|
hst_response_header hstdata;
|
||||||
|
ssize_t align1;
|
||||||
|
time_t align2;
|
||||||
|
} data[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Structure for one hash table entry. */
|
||||||
|
struct hashentry
|
||||||
|
{
|
||||||
|
request_type type:8; /* Which type of dataset. */
|
||||||
|
bool first; /* True if this was the original key. */
|
||||||
|
size_t len; /* Length of key. */
|
||||||
|
ref_t key; /* Pointer to key. */
|
||||||
|
uid_t owner; /* If secure table, this is the owner. */
|
||||||
|
ref_t next; /* Next entry in this hash bucket list. */
|
||||||
|
ref_t packet; /* Records for the result. */
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct hashentry *dellist; /* Next record to be deleted. This can be a
|
||||||
|
pointer since only nscd uses this field. */
|
||||||
|
ref_t *prevp; /* Pointer to field containing forward
|
||||||
|
reference. */
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Current persistent database version. */
|
||||||
|
#define DB_VERSION 1
|
||||||
|
|
||||||
|
/* Maximum time allowed between updates of the timestamp. */
|
||||||
|
#define MAPPING_TIMEOUT (5 * 60)
|
||||||
|
|
||||||
|
|
||||||
|
/* Header of persistent database file. */
|
||||||
|
struct database_pers_head
|
||||||
|
{
|
||||||
|
int version;
|
||||||
|
int header_size;
|
||||||
|
int gc_cycle;
|
||||||
|
volatile time_t timestamp;
|
||||||
|
|
||||||
|
size_t module;
|
||||||
|
size_t data_size;
|
||||||
|
|
||||||
|
size_t first_free; /* Offset of first free byte in data area. */
|
||||||
|
|
||||||
|
size_t nentries;
|
||||||
|
size_t maxnentries;
|
||||||
|
size_t maxnsearched;
|
||||||
|
|
||||||
|
uintmax_t poshit;
|
||||||
|
uintmax_t neghit;
|
||||||
|
uintmax_t posmiss;
|
||||||
|
uintmax_t negmiss;
|
||||||
|
|
||||||
|
uintmax_t rdlockdelayed;
|
||||||
|
uintmax_t wrlockdelayed;
|
||||||
|
|
||||||
|
uintmax_t addfailed;
|
||||||
|
|
||||||
|
ref_t array[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Mapped database record. */
|
||||||
|
struct mapped_database
|
||||||
|
{
|
||||||
|
const struct database_pers_head *head;
|
||||||
|
const char *data;
|
||||||
|
size_t mapsize;
|
||||||
|
int counter; /* > 0 indicates it isusable. */
|
||||||
|
};
|
||||||
|
#define NO_MAPPING ((struct mapped_database *) -1l)
|
||||||
|
|
||||||
|
struct locked_map_ptr
|
||||||
|
{
|
||||||
|
int lock;
|
||||||
|
struct mapped_database *mapped;
|
||||||
|
};
|
||||||
|
#define libc_locked_map_ptr(name) static struct locked_map_ptr name
|
||||||
|
|
||||||
|
|
||||||
/* Open socket connection to nscd server. */
|
/* Open socket connection to nscd server. */
|
||||||
extern int __nscd_open_socket (const char *key, size_t keylen,
|
extern int __nscd_open_socket (const char *key, size_t keylen,
|
||||||
request_type type, void *response,
|
request_type type, void *response,
|
||||||
size_t responselen) attribute_hidden;
|
size_t responselen) attribute_hidden;
|
||||||
|
|
||||||
|
/* Get reference of mapping. */
|
||||||
|
extern struct mapped_database *__nscd_get_map_ref (request_type type,
|
||||||
|
const char *name,
|
||||||
|
struct locked_map_ptr *mapptr,
|
||||||
|
int *gc_cyclep);
|
||||||
|
|
||||||
|
/* Unmap database. */
|
||||||
|
extern void __nscd_unmap (struct mapped_database *mapped);
|
||||||
|
|
||||||
|
/* Drop reference of mapping. */
|
||||||
|
static inline int __nscd_drop_map_ref (struct mapped_database *map,
|
||||||
|
int gc_cycle)
|
||||||
|
{
|
||||||
|
if (map != NO_MAPPING)
|
||||||
|
{
|
||||||
|
if (__builtin_expect (map->head->gc_cycle != gc_cycle, 0))
|
||||||
|
/* We might have read inconsistent data. */
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (atomic_decrement_val (&map->counter) == 0)
|
||||||
|
__nscd_unmap (map);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Search the mapped database. */
|
||||||
|
extern const struct datahead * __nscd_cache_search (request_type type,
|
||||||
|
const char *key,
|
||||||
|
size_t keylen,
|
||||||
|
const struct mapped_database *mapped);
|
||||||
|
|
||||||
#endif /* nscd.h */
|
#endif /* nscd.h */
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
# suggested-size <service> <prime number>
|
# suggested-size <service> <prime number>
|
||||||
# check-files <service> <yes|no>
|
# check-files <service> <yes|no>
|
||||||
# persistent <service> <yes|no>
|
# persistent <service> <yes|no>
|
||||||
|
# shared <service> <yes|no>
|
||||||
#
|
#
|
||||||
# Currently supported cache names (services): passwd, group, hosts
|
# Currently supported cache names (services): passwd, group, hosts
|
||||||
#
|
#
|
||||||
@ -37,6 +38,7 @@
|
|||||||
suggested-size passwd 211
|
suggested-size passwd 211
|
||||||
check-files passwd yes
|
check-files passwd yes
|
||||||
persistent passwd yes
|
persistent passwd yes
|
||||||
|
shared passwd yes
|
||||||
|
|
||||||
enable-cache group yes
|
enable-cache group yes
|
||||||
positive-time-to-live group 3600
|
positive-time-to-live group 3600
|
||||||
@ -44,6 +46,7 @@
|
|||||||
suggested-size group 211
|
suggested-size group 211
|
||||||
check-files group yes
|
check-files group yes
|
||||||
persistent group yes
|
persistent group yes
|
||||||
|
shared group yes
|
||||||
|
|
||||||
enable-cache hosts yes
|
enable-cache hosts yes
|
||||||
positive-time-to-live hosts 3600
|
positive-time-to-live hosts 3600
|
||||||
@ -51,3 +54,4 @@
|
|||||||
suggested-size hosts 211
|
suggested-size hosts 211
|
||||||
check-files hosts yes
|
check-files hosts yes
|
||||||
persistent hosts yes
|
persistent hosts yes
|
||||||
|
shared hosts yes
|
||||||
|
82
nscd/nscd.h
82
nscd/nscd.h
@ -42,30 +42,6 @@ typedef enum
|
|||||||
} dbtype;
|
} dbtype;
|
||||||
|
|
||||||
|
|
||||||
/* Head of record in data part of database. */
|
|
||||||
struct datahead
|
|
||||||
{
|
|
||||||
size_t allocsize; /* Allocated Bytes. */
|
|
||||||
size_t recsize; /* Size of the record. */
|
|
||||||
time_t timeout; /* Time when this entry becomes invalid. */
|
|
||||||
bool notfound; /* Nonzero if data for key has not been found. */
|
|
||||||
uint8_t nreloads; /* Reloads without use. */
|
|
||||||
bool usable; /* False if the entry must be ignored. */
|
|
||||||
|
|
||||||
/* We need to have the following element aligned for the response
|
|
||||||
header data types and their use in the 'struct dataset' types
|
|
||||||
defined in the XXXcache.c files. */
|
|
||||||
union
|
|
||||||
{
|
|
||||||
pw_response_header pwdata;
|
|
||||||
gr_response_header grdata;
|
|
||||||
hst_response_header hstdata;
|
|
||||||
ssize_t align1;
|
|
||||||
time_t align2;
|
|
||||||
} data[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* Default limit on the number of times a value gets reloaded without
|
/* Default limit on the number of times a value gets reloaded without
|
||||||
being used in the meantime. NSCD does not throw a value out as
|
being used in the meantime. NSCD does not throw a value out as
|
||||||
soon as it times out. It tries to reload the value from the
|
soon as it times out. It tries to reload the value from the
|
||||||
@ -74,63 +50,6 @@ struct datahead
|
|||||||
#define DEFAULT_RELOAD_LIMIT 5
|
#define DEFAULT_RELOAD_LIMIT 5
|
||||||
|
|
||||||
|
|
||||||
/* Type for offsets in data part of database. */
|
|
||||||
typedef uint32_t ref_t;
|
|
||||||
/* Value for invalid/no reference. */
|
|
||||||
#define ENDREF UINT32_MAX
|
|
||||||
|
|
||||||
|
|
||||||
/* Structure for one hash table entry. */
|
|
||||||
struct hashentry
|
|
||||||
{
|
|
||||||
request_type type:8; /* Which type of dataset. */
|
|
||||||
bool first; /* True if this was the original key. */
|
|
||||||
size_t len; /* Length of key. */
|
|
||||||
ref_t key; /* Pointer to key. */
|
|
||||||
uid_t owner; /* If secure table, this is the owner. */
|
|
||||||
ref_t next; /* Next entry in this hash bucket list. */
|
|
||||||
ref_t packet; /* Records for the result. */
|
|
||||||
union
|
|
||||||
{
|
|
||||||
struct hashentry *dellist; /* Next record to be deleted. This can be a
|
|
||||||
pointer since only nscd uses this field. */
|
|
||||||
ref_t *prevp; /* Pointer to field containing forward
|
|
||||||
reference. */
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* Current persistent database version. */
|
|
||||||
#define DB_VERSION 1
|
|
||||||
|
|
||||||
/* Header of persistent database file. */
|
|
||||||
struct database_pers_head
|
|
||||||
{
|
|
||||||
int version;
|
|
||||||
int header_size;
|
|
||||||
|
|
||||||
size_t module;
|
|
||||||
size_t data_size;
|
|
||||||
|
|
||||||
size_t first_free; /* Offset of first free byte in data area. */
|
|
||||||
|
|
||||||
size_t nentries;
|
|
||||||
size_t maxnentries;
|
|
||||||
size_t maxnsearched;
|
|
||||||
|
|
||||||
uintmax_t poshit;
|
|
||||||
uintmax_t neghit;
|
|
||||||
uintmax_t posmiss;
|
|
||||||
uintmax_t negmiss;
|
|
||||||
|
|
||||||
uintmax_t rdlockdelayed;
|
|
||||||
uintmax_t wrlockdelayed;
|
|
||||||
|
|
||||||
uintmax_t addfailed;
|
|
||||||
|
|
||||||
ref_t array[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Structure describing dynamic part of one database. */
|
/* Structure describing dynamic part of one database. */
|
||||||
struct database_dyn
|
struct database_dyn
|
||||||
{
|
{
|
||||||
@ -139,6 +58,7 @@ struct database_dyn
|
|||||||
int enabled;
|
int enabled;
|
||||||
int check_file;
|
int check_file;
|
||||||
int persistent;
|
int persistent;
|
||||||
|
int shared;
|
||||||
const char *filename;
|
const char *filename;
|
||||||
const char *db_filename;
|
const char *db_filename;
|
||||||
time_t file_mtime;
|
time_t file_mtime;
|
||||||
|
@ -216,6 +216,20 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb])
|
|||||||
if (cnt == lastdb)
|
if (cnt == lastdb)
|
||||||
dbg_log ("database %s is not supported\n", arg1);
|
dbg_log ("database %s is not supported\n", arg1);
|
||||||
}
|
}
|
||||||
|
else if (strcmp (entry, "shared") == 0)
|
||||||
|
{
|
||||||
|
for (cnt = 0; cnt < lastdb; ++cnt)
|
||||||
|
if (strcmp (arg1, dbnames[cnt]) == 0)
|
||||||
|
{
|
||||||
|
if (strcmp (arg2, "no") == 0)
|
||||||
|
dbs[cnt].shared = 0;
|
||||||
|
else if (strcmp (arg2, "yes") == 0)
|
||||||
|
dbs[cnt].shared = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (cnt == lastdb)
|
||||||
|
dbg_log ("database %s is not supported\n", arg1);
|
||||||
|
}
|
||||||
else if (strcmp (entry, "reload-count") == 0)
|
else if (strcmp (entry, "reload-count") == 0)
|
||||||
{
|
{
|
||||||
if (strcasecmp (arg1, "unlimited") == 0)
|
if (strcasecmp (arg1, "unlimited") == 0)
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
02111-1307 USA. */
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -25,6 +26,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
@ -64,36 +66,82 @@ __nscd_getgrgid_r (gid_t gid, struct group *resultbuf, char *buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
libc_locked_map_ptr (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)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (map_handle.mapped != NO_MAPPING)
|
||||||
|
free (map_handle.mapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
internal_function
|
internal_function
|
||||||
nscd_getgr_r (const char *key, size_t keylen, request_type type,
|
nscd_getgr_r (const char *key, size_t keylen, request_type type,
|
||||||
struct group *resultbuf, char *buffer, size_t buflen,
|
struct group *resultbuf, char *buffer, size_t buflen,
|
||||||
struct group **result)
|
struct group **result)
|
||||||
{
|
{
|
||||||
gr_response_header gr_resp;
|
const gr_response_header *gr_resp = NULL;
|
||||||
int sock = __nscd_open_socket (key, keylen, type, &gr_resp,
|
const uint32_t *len = NULL;
|
||||||
sizeof (gr_resp));
|
const char *gr_name = NULL;
|
||||||
if (sock == -1)
|
size_t gr_name_len = 0;
|
||||||
|
int retval = -1;
|
||||||
|
int gc_cycle;
|
||||||
|
const char *recend = (const char *) ~UINTMAX_C (0);
|
||||||
|
|
||||||
|
/* If the mapping is available, try to search there instead of
|
||||||
|
communicating with the nscd. */
|
||||||
|
struct mapped_database *mapped = __nscd_get_map_ref (GETFDGR, "group",
|
||||||
|
&map_handle, &gc_cycle);
|
||||||
|
retry:
|
||||||
|
if (mapped != NO_MAPPING)
|
||||||
{
|
{
|
||||||
__nss_not_use_nscd_group = 1;
|
const struct datahead *found = __nscd_cache_search (type, key, keylen,
|
||||||
return -1;
|
mapped);
|
||||||
|
if (found != NULL)
|
||||||
|
{
|
||||||
|
gr_resp = &found->data[0].grdata;
|
||||||
|
len = (const uint32_t *) (gr_resp + 1);
|
||||||
|
/* The alignment is always sufficient. */
|
||||||
|
assert (((uintptr_t) len & (__alignof__ (*len) - 1)) == 0);
|
||||||
|
gr_name = ((const char *) len
|
||||||
|
+ gr_resp->gr_mem_cnt * sizeof (uint32_t));
|
||||||
|
gr_name_len = gr_resp->gr_name_len + gr_resp->gr_passwd_len;
|
||||||
|
recend = (const char *) found->data + found->recsize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gr_response_header gr_resp_mem;
|
||||||
|
int sock = -1;
|
||||||
|
if (gr_resp == NULL)
|
||||||
|
{
|
||||||
|
sock = __nscd_open_socket (key, keylen, type, &gr_resp_mem,
|
||||||
|
sizeof (gr_resp_mem));
|
||||||
|
if (sock == -1)
|
||||||
|
{
|
||||||
|
__nss_not_use_nscd_group = 1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
gr_resp = &gr_resp_mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No value found so far. */
|
/* No value found so far. */
|
||||||
int retval = -1;
|
|
||||||
*result = NULL;
|
*result = NULL;
|
||||||
|
|
||||||
if (gr_resp.found == -1)
|
if (__builtin_expect (gr_resp->found == -1, 0))
|
||||||
{
|
{
|
||||||
/* The daemon does not cache this database. */
|
/* The daemon does not cache this database. */
|
||||||
__nss_not_use_nscd_group = 1;
|
__nss_not_use_nscd_group = 1;
|
||||||
goto out;
|
goto out_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gr_resp.found == 1)
|
if (gr_resp->found == 1)
|
||||||
{
|
{
|
||||||
struct iovec vec[2];
|
struct iovec vec[2];
|
||||||
uint32_t *len;
|
|
||||||
char *p = buffer;
|
char *p = buffer;
|
||||||
size_t total_len;
|
size_t total_len;
|
||||||
uintptr_t align;
|
uintptr_t align;
|
||||||
@ -103,71 +151,90 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
|
|||||||
align the pointer. */
|
align the pointer. */
|
||||||
align = ((__alignof__ (char *) - (p - ((char *) 0)))
|
align = ((__alignof__ (char *) - (p - ((char *) 0)))
|
||||||
& (__alignof__ (char *) - 1));
|
& (__alignof__ (char *) - 1));
|
||||||
total_len = align + (1 + gr_resp.gr_mem_cnt) * sizeof (char *)
|
total_len = (align + (1 + gr_resp->gr_mem_cnt) * sizeof (char *)
|
||||||
+ gr_resp.gr_name_len + gr_resp.gr_passwd_len;
|
+ gr_resp->gr_name_len + gr_resp->gr_passwd_len);
|
||||||
if (__builtin_expect (buflen < total_len, 0))
|
if (__builtin_expect (buflen < total_len, 0))
|
||||||
{
|
{
|
||||||
no_room:
|
no_room:
|
||||||
__set_errno (ERANGE);
|
__set_errno (ERANGE);
|
||||||
retval = ERANGE;
|
retval = ERANGE;
|
||||||
goto out;
|
goto out_close;
|
||||||
}
|
}
|
||||||
buflen -= total_len;
|
buflen -= total_len;
|
||||||
|
|
||||||
p += align;
|
p += align;
|
||||||
resultbuf->gr_mem = (char **) p;
|
resultbuf->gr_mem = (char **) p;
|
||||||
p += (1 + gr_resp.gr_mem_cnt) * sizeof (char *);
|
p += (1 + gr_resp->gr_mem_cnt) * sizeof (char *);
|
||||||
|
|
||||||
/* Set pointers for strings. */
|
/* Set pointers for strings. */
|
||||||
resultbuf->gr_name = p;
|
resultbuf->gr_name = p;
|
||||||
p += gr_resp.gr_name_len;
|
p += gr_resp->gr_name_len;
|
||||||
resultbuf->gr_passwd = p;
|
resultbuf->gr_passwd = p;
|
||||||
p += gr_resp.gr_passwd_len;
|
p += gr_resp->gr_passwd_len;
|
||||||
|
|
||||||
/* Fill in what we know now. */
|
/* Fill in what we know now. */
|
||||||
resultbuf->gr_gid = gr_resp.gr_gid;
|
resultbuf->gr_gid = gr_resp->gr_gid;
|
||||||
|
|
||||||
/* Allocate array to store lengths. */
|
/* Read the length information, group name, and password. */
|
||||||
len = (uint32_t *) alloca (gr_resp.gr_mem_cnt * sizeof (uint32_t));
|
if (len == NULL)
|
||||||
|
{
|
||||||
|
/* Allocate array to store lengths. */
|
||||||
|
len = (uint32_t *) alloca (gr_resp->gr_mem_cnt * sizeof (uint32_t));
|
||||||
|
|
||||||
total_len = gr_resp.gr_mem_cnt * sizeof (uint32_t);
|
vec[0].iov_base = (void *) len;
|
||||||
vec[0].iov_base = len;
|
vec[0].iov_len = gr_resp->gr_mem_cnt * sizeof (uint32_t);
|
||||||
vec[0].iov_len = total_len;
|
vec[1].iov_base = resultbuf->gr_name;
|
||||||
vec[1].iov_base = resultbuf->gr_name;
|
vec[1].iov_len = gr_resp->gr_name_len + gr_resp->gr_passwd_len;
|
||||||
vec[1].iov_len = gr_resp.gr_name_len + gr_resp.gr_passwd_len;
|
total_len = vec[0].iov_len + vec[1].iov_len;
|
||||||
total_len += gr_resp.gr_name_len + gr_resp.gr_passwd_len;
|
|
||||||
|
|
||||||
/* Get this data. */
|
/* Get this data. */
|
||||||
size_t n = TEMP_FAILURE_RETRY (__readv (sock, vec, 2));
|
size_t n = TEMP_FAILURE_RETRY (__readv (sock, vec, 2));
|
||||||
if (__builtin_expect (n != total_len, 0))
|
if (__builtin_expect (n != total_len, 0))
|
||||||
goto out;
|
goto out_close;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* We already have the data. Just copy the group name and
|
||||||
|
password. */
|
||||||
|
memcpy (resultbuf->gr_name, gr_name, gr_name_len);
|
||||||
|
|
||||||
/* Clear the terminating entry. */
|
/* Clear the terminating entry. */
|
||||||
resultbuf->gr_mem[gr_resp.gr_mem_cnt] = NULL;
|
resultbuf->gr_mem[gr_resp->gr_mem_cnt] = NULL;
|
||||||
|
|
||||||
/* Prepare reading the group members. */
|
/* Prepare reading the group members. */
|
||||||
total_len = 0;
|
total_len = 0;
|
||||||
for (cnt = 0; cnt < gr_resp.gr_mem_cnt; ++cnt)
|
for (cnt = 0; cnt < gr_resp->gr_mem_cnt; ++cnt)
|
||||||
{
|
{
|
||||||
resultbuf->gr_mem[cnt] = p;
|
resultbuf->gr_mem[cnt] = p;
|
||||||
total_len += len[cnt];
|
total_len += len[cnt];
|
||||||
p += len[cnt];
|
p += len[cnt];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (__builtin_expect (gr_name + gr_name_len + total_len > recend, 0))
|
||||||
|
goto out_close;
|
||||||
if (__builtin_expect (total_len > buflen, 0))
|
if (__builtin_expect (total_len > buflen, 0))
|
||||||
goto no_room;
|
goto no_room;
|
||||||
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
n = TEMP_FAILURE_RETRY (__read (sock, resultbuf->gr_mem[0],
|
if (gr_name == NULL)
|
||||||
total_len));
|
|
||||||
if (__builtin_expect (n != total_len, 0))
|
|
||||||
{
|
{
|
||||||
/* The `errno' to some value != ERANGE. */
|
size_t n = TEMP_FAILURE_RETRY (__read (sock, resultbuf->gr_mem[0],
|
||||||
__set_errno (ENOENT);
|
total_len));
|
||||||
retval = ENOENT;
|
if (__builtin_expect (n != total_len, 0))
|
||||||
|
{
|
||||||
|
/* The `errno' to some value != ERANGE. */
|
||||||
|
__set_errno (ENOENT);
|
||||||
|
retval = ENOENT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*result = resultbuf;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
*result = resultbuf;
|
{
|
||||||
|
/* Copy the group member names. */
|
||||||
|
memcpy (resultbuf->gr_mem[0], gr_name + gr_name_len, total_len);
|
||||||
|
|
||||||
|
*result = resultbuf;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -177,8 +244,15 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
|
|||||||
retval = 0;
|
retval = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out_close:
|
||||||
|
if (sock != -1)
|
||||||
|
close_not_cancel_no_status (sock);
|
||||||
out:
|
out:
|
||||||
close_not_cancel_no_status (sock);
|
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;
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
02111-1307 USA. */
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <resolv.h>
|
#include <resolv.h>
|
||||||
@ -26,9 +27,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <arpa/nameser.h>
|
#include <arpa/nameser.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/uio.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
#include <not-cancel.h>
|
#include <not-cancel.h>
|
||||||
|
|
||||||
#include "nscd-client.h"
|
#include "nscd-client.h"
|
||||||
@ -89,56 +88,15 @@ __nscd_gethostbyaddr_r (const void *addr, socklen_t len, int type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Create a socket connected to a name. */
|
libc_locked_map_ptr (map_handle);
|
||||||
int
|
/* Note that we only free the structure if necessary. The memory
|
||||||
__nscd_open_socket (const char *key, size_t keylen, request_type type,
|
mapping is not removed since it is not visible to the malloc
|
||||||
void *response, size_t responselen)
|
handling. */
|
||||||
|
libc_freeres_fn (gr_map_free)
|
||||||
{
|
{
|
||||||
struct sockaddr_un addr;
|
|
||||||
int sock;
|
|
||||||
int saved_errno = errno;
|
|
||||||
|
|
||||||
sock = __socket (PF_UNIX, SOCK_STREAM, 0);
|
if (map_handle.mapped != NO_MAPPING)
|
||||||
if (sock < 0)
|
free (map_handle.mapped);
|
||||||
{
|
|
||||||
__set_errno (saved_errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr.sun_family = AF_UNIX;
|
|
||||||
strcpy (addr.sun_path, _PATH_NSCDSOCKET);
|
|
||||||
if (__connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
|
|
||||||
{
|
|
||||||
__set_errno (saved_errno);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
request_header req;
|
|
||||||
req.version = NSCD_VERSION;
|
|
||||||
req.type = type;
|
|
||||||
req.key_len = keylen;
|
|
||||||
|
|
||||||
struct iovec vec[2];
|
|
||||||
vec[0].iov_base = &req;
|
|
||||||
vec[0].iov_len = sizeof (request_header);
|
|
||||||
vec[1].iov_base = (void *) key;
|
|
||||||
vec[1].iov_len = keylen;
|
|
||||||
|
|
||||||
ssize_t nbytes = TEMP_FAILURE_RETRY (__writev (sock, vec, 2));
|
|
||||||
if (nbytes != (ssize_t) (sizeof (request_header) + keylen))
|
|
||||||
{
|
|
||||||
out:
|
|
||||||
close_not_cancel_no_status (sock);
|
|
||||||
sock = -1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nbytes = TEMP_FAILURE_RETRY (__read (sock, response, responselen));
|
|
||||||
if (nbytes != (ssize_t) responselen)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sock;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -148,30 +106,89 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
|
|||||||
struct hostent *resultbuf, char *buffer, size_t buflen,
|
struct hostent *resultbuf, char *buffer, size_t buflen,
|
||||||
struct hostent **result, int *h_errnop)
|
struct hostent **result, int *h_errnop)
|
||||||
{
|
{
|
||||||
hst_response_header hst_resp;
|
const hst_response_header *hst_resp = NULL;
|
||||||
int sock = __nscd_open_socket (key, keylen, type, &hst_resp,
|
const char *h_name = NULL;
|
||||||
sizeof (hst_resp));
|
const uint32_t *aliases_len = NULL;
|
||||||
if (sock == -1)
|
const char *addr_list = NULL;
|
||||||
|
size_t addr_list_len = 0;
|
||||||
|
int retval = -1;
|
||||||
|
int gc_cycle;
|
||||||
|
const char *recend = (const char *) ~UINTMAX_C (0);
|
||||||
|
int sock = -1;
|
||||||
|
|
||||||
|
/* If the mapping is available, try to search there instead of
|
||||||
|
communicating with the nscd. */
|
||||||
|
struct mapped_database *mapped = __nscd_get_map_ref (GETFDHST, "hosts",
|
||||||
|
&map_handle, &gc_cycle);
|
||||||
|
retry:
|
||||||
|
if (mapped != MAP_FAILED)
|
||||||
{
|
{
|
||||||
__nss_not_use_nscd_hosts = 1;
|
const struct datahead *found = __nscd_cache_search (type, key, keylen,
|
||||||
return -1;
|
mapped);
|
||||||
|
if (found != NULL)
|
||||||
|
{
|
||||||
|
hst_resp = &found->data[0].hstdata;
|
||||||
|
h_name = (char *) (hst_resp + 1);
|
||||||
|
aliases_len = (uint32_t *) (h_name + hst_resp->h_name_len);
|
||||||
|
addr_list = ((char *) aliases_len
|
||||||
|
+ hst_resp->h_aliases_cnt * sizeof (uint32_t));
|
||||||
|
addr_list_len = hst_resp->h_addr_list_cnt * INADDRSZ;
|
||||||
|
|
||||||
|
#ifndef _STRING_ARCH_unaligned
|
||||||
|
/* The aliases_len array in the mapped database might very
|
||||||
|
well be unaligned. We will access it word-wise so on
|
||||||
|
platforms which do not tolerate unaligned accesses we
|
||||||
|
need to make an aligned copy. */
|
||||||
|
if (((uintptr_t) aliases_len & (__alignof__ (*aliases_len) - 1))
|
||||||
|
!= 0)
|
||||||
|
{
|
||||||
|
uint32_t *tmp = alloca (hst_resp->h_aliases_cnt
|
||||||
|
* sizeof (uint32_t));
|
||||||
|
aliases_len = memcpy (tmp, aliases_len,
|
||||||
|
hst_resp->h_aliases_cnt
|
||||||
|
* sizeof (uint32_t));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (type != GETHOSTBYADDR && type != GETHOSTBYNAME)
|
||||||
|
{
|
||||||
|
if (hst_resp->h_length == INADDRSZ)
|
||||||
|
addr_list += addr_list_len;
|
||||||
|
addr_list_len = hst_resp->h_addr_list_cnt * IN6ADDRSZ;
|
||||||
|
}
|
||||||
|
recend = (const char *) found->data + found->recsize;
|
||||||
|
if (__builtin_expect ((const char *) addr_list + addr_list_len
|
||||||
|
> recend, 0))
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hst_response_header hst_resp_mem;
|
||||||
|
if (hst_resp == NULL)
|
||||||
|
{
|
||||||
|
sock = __nscd_open_socket (key, keylen, type, &hst_resp_mem,
|
||||||
|
sizeof (hst_resp_mem));
|
||||||
|
if (sock == -1)
|
||||||
|
{
|
||||||
|
__nss_not_use_nscd_hosts = 1;
|
||||||
|
goto out;;
|
||||||
|
}
|
||||||
|
|
||||||
|
hst_resp = &hst_resp_mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No value found so far. */
|
/* No value found so far. */
|
||||||
int retval = -1;
|
|
||||||
*result = NULL;
|
*result = NULL;
|
||||||
|
|
||||||
if (hst_resp.found == -1)
|
if (__builtin_expect (hst_resp->found == -1, 0))
|
||||||
{
|
{
|
||||||
/* The daemon does not cache this database. */
|
/* The daemon does not cache this database. */
|
||||||
__nss_not_use_nscd_hosts = 1;
|
__nss_not_use_nscd_hosts = 1;
|
||||||
goto out;
|
goto out_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hst_resp.found == 1)
|
if (hst_resp->found == 1)
|
||||||
{
|
{
|
||||||
struct iovec vec[4];
|
struct iovec vec[4];
|
||||||
uint32_t *aliases_len;
|
|
||||||
char *cp = buffer;
|
char *cp = buffer;
|
||||||
uintptr_t align1;
|
uintptr_t align1;
|
||||||
uintptr_t align2;
|
uintptr_t align2;
|
||||||
@ -185,96 +202,110 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
|
|||||||
align the pointer and the base of the h_addr_list pointers. */
|
align the pointer and the base of the h_addr_list pointers. */
|
||||||
align1 = ((__alignof__ (char *) - (cp - ((char *) 0)))
|
align1 = ((__alignof__ (char *) - (cp - ((char *) 0)))
|
||||||
& (__alignof__ (char *) - 1));
|
& (__alignof__ (char *) - 1));
|
||||||
align2 = ((__alignof__ (char *) - ((cp + align1 + hst_resp.h_name_len)
|
align2 = ((__alignof__ (char *) - ((cp + align1 + hst_resp->h_name_len)
|
||||||
- ((char *) 0)))
|
- ((char *) 0)))
|
||||||
& (__alignof__ (char *) - 1));
|
& (__alignof__ (char *) - 1));
|
||||||
if (buflen < (align1 + hst_resp.h_name_len + align2
|
if (buflen < (align1 + hst_resp->h_name_len + align2
|
||||||
+ ((hst_resp.h_aliases_cnt + hst_resp.h_addr_list_cnt + 2)
|
+ ((hst_resp->h_aliases_cnt + hst_resp->h_addr_list_cnt
|
||||||
|
+ 2)
|
||||||
* sizeof (char *))
|
* sizeof (char *))
|
||||||
+ hst_resp.h_addr_list_cnt * (type == AF_INET
|
+ hst_resp->h_addr_list_cnt * (type == AF_INET
|
||||||
? INADDRSZ : IN6ADDRSZ)))
|
? INADDRSZ : IN6ADDRSZ)))
|
||||||
{
|
{
|
||||||
no_room:
|
no_room:
|
||||||
__set_errno (ERANGE);
|
__set_errno (ERANGE);
|
||||||
retval = ERANGE;
|
retval = ERANGE;
|
||||||
goto out;
|
goto out_close;
|
||||||
}
|
}
|
||||||
cp += align1;
|
cp += align1;
|
||||||
|
|
||||||
/* Prepare the result as far as we can. */
|
/* Prepare the result as far as we can. */
|
||||||
resultbuf->h_aliases = (char **) cp;
|
resultbuf->h_aliases = (char **) cp;
|
||||||
cp += (hst_resp.h_aliases_cnt + 1) * sizeof (char *);
|
cp += (hst_resp->h_aliases_cnt + 1) * sizeof (char *);
|
||||||
resultbuf->h_addr_list = (char **) cp;
|
resultbuf->h_addr_list = (char **) cp;
|
||||||
cp += (hst_resp.h_addr_list_cnt + 1) * sizeof (char *);
|
cp += (hst_resp->h_addr_list_cnt + 1) * sizeof (char *);
|
||||||
|
|
||||||
resultbuf->h_name = cp;
|
resultbuf->h_name = cp;
|
||||||
cp += hst_resp.h_name_len + align2;
|
cp += hst_resp->h_name_len + align2;
|
||||||
vec[0].iov_base = resultbuf->h_name;
|
|
||||||
vec[0].iov_len = hst_resp.h_name_len;
|
|
||||||
|
|
||||||
aliases_len = alloca (hst_resp.h_aliases_cnt * sizeof (uint32_t));
|
|
||||||
vec[1].iov_base = aliases_len;
|
|
||||||
vec[1].iov_len = hst_resp.h_aliases_cnt * sizeof (uint32_t);
|
|
||||||
|
|
||||||
total_len = (hst_resp.h_name_len
|
|
||||||
+ hst_resp.h_aliases_cnt * sizeof (uint32_t));
|
|
||||||
|
|
||||||
n = 2;
|
|
||||||
if (type == GETHOSTBYADDR || type == GETHOSTBYNAME)
|
if (type == GETHOSTBYADDR || type == GETHOSTBYNAME)
|
||||||
{
|
{
|
||||||
vec[2].iov_base = cp;
|
|
||||||
vec[2].iov_len = hst_resp.h_addr_list_cnt * INADDRSZ;
|
|
||||||
|
|
||||||
for (cnt = 0; cnt < hst_resp.h_addr_list_cnt; ++cnt)
|
|
||||||
{
|
|
||||||
resultbuf->h_addr_list[cnt] = cp;
|
|
||||||
cp += INADDRSZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
resultbuf->h_addrtype = AF_INET;
|
resultbuf->h_addrtype = AF_INET;
|
||||||
resultbuf->h_length = INADDRSZ;
|
resultbuf->h_length = INADDRSZ;
|
||||||
|
|
||||||
total_len += hst_resp.h_addr_list_cnt * INADDRSZ;
|
|
||||||
|
|
||||||
n = 3;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (hst_resp.h_length == INADDRSZ)
|
|
||||||
{
|
|
||||||
ignore = alloca (hst_resp.h_addr_list_cnt * INADDRSZ);
|
|
||||||
vec[2].iov_base = ignore;
|
|
||||||
vec[2].iov_len = hst_resp.h_addr_list_cnt * INADDRSZ;
|
|
||||||
|
|
||||||
total_len += hst_resp.h_addr_list_cnt * INADDRSZ;
|
|
||||||
|
|
||||||
n = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec[n].iov_base = cp;
|
|
||||||
vec[n].iov_len = hst_resp.h_addr_list_cnt * IN6ADDRSZ;
|
|
||||||
|
|
||||||
for (cnt = 0; cnt < hst_resp.h_addr_list_cnt; ++cnt)
|
|
||||||
{
|
|
||||||
resultbuf->h_addr_list[cnt] = cp;
|
|
||||||
cp += IN6ADDRSZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
resultbuf->h_addrtype = AF_INET6;
|
resultbuf->h_addrtype = AF_INET6;
|
||||||
resultbuf->h_length = IN6ADDRSZ;
|
resultbuf->h_length = IN6ADDRSZ;
|
||||||
|
}
|
||||||
total_len += hst_resp.h_addr_list_cnt * IN6ADDRSZ;
|
for (cnt = 0; cnt < hst_resp->h_addr_list_cnt; ++cnt)
|
||||||
|
{
|
||||||
++n;
|
resultbuf->h_addr_list[cnt] = cp;
|
||||||
|
cp += resultbuf->h_length;
|
||||||
}
|
}
|
||||||
resultbuf->h_addr_list[cnt] = NULL;
|
resultbuf->h_addr_list[cnt] = NULL;
|
||||||
|
|
||||||
if ((size_t) TEMP_FAILURE_RETRY (__readv (sock, vec, n)) != total_len)
|
if (h_name == NULL)
|
||||||
goto out;
|
{
|
||||||
|
vec[0].iov_base = resultbuf->h_name;
|
||||||
|
vec[0].iov_len = hst_resp->h_name_len;
|
||||||
|
total_len = hst_resp->h_name_len;
|
||||||
|
n = 1;
|
||||||
|
|
||||||
|
if (hst_resp->h_aliases_cnt > 0)
|
||||||
|
{
|
||||||
|
aliases_len = alloca (hst_resp->h_aliases_cnt
|
||||||
|
* sizeof (uint32_t));
|
||||||
|
vec[n].iov_base = (void *) aliases_len;
|
||||||
|
vec[n].iov_len = hst_resp->h_aliases_cnt * sizeof (uint32_t);
|
||||||
|
|
||||||
|
total_len += hst_resp->h_aliases_cnt * sizeof (uint32_t);
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == GETHOSTBYADDR || type == GETHOSTBYNAME)
|
||||||
|
{
|
||||||
|
vec[n].iov_base = resultbuf->h_addr_list[0];
|
||||||
|
vec[n].iov_len = hst_resp->h_addr_list_cnt * INADDRSZ;
|
||||||
|
|
||||||
|
total_len += hst_resp->h_addr_list_cnt * INADDRSZ;
|
||||||
|
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (hst_resp->h_length == INADDRSZ)
|
||||||
|
{
|
||||||
|
ignore = alloca (hst_resp->h_addr_list_cnt * INADDRSZ);
|
||||||
|
vec[n].iov_base = ignore;
|
||||||
|
vec[n].iov_len = hst_resp->h_addr_list_cnt * INADDRSZ;
|
||||||
|
|
||||||
|
total_len += hst_resp->h_addr_list_cnt * INADDRSZ;
|
||||||
|
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec[n].iov_base = resultbuf->h_addr_list[0];
|
||||||
|
vec[n].iov_len = hst_resp->h_addr_list_cnt * IN6ADDRSZ;
|
||||||
|
|
||||||
|
total_len += hst_resp->h_addr_list_cnt * IN6ADDRSZ;
|
||||||
|
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((size_t) TEMP_FAILURE_RETRY (__readv (sock, vec, n))
|
||||||
|
!= total_len)
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy (resultbuf->h_name, h_name, hst_resp->h_name_len);
|
||||||
|
memcpy (resultbuf->h_addr_list[0], addr_list, addr_list_len);
|
||||||
|
}
|
||||||
|
|
||||||
/* Now we also can read the aliases. */
|
/* Now we also can read the aliases. */
|
||||||
total_len = 0;
|
total_len = 0;
|
||||||
for (cnt = 0; cnt < hst_resp.h_aliases_cnt; ++cnt)
|
for (cnt = 0; cnt < hst_resp->h_aliases_cnt; ++cnt)
|
||||||
{
|
{
|
||||||
resultbuf->h_aliases[cnt] = cp;
|
resultbuf->h_aliases[cnt] = cp;
|
||||||
cp += aliases_len[cnt];
|
cp += aliases_len[cnt];
|
||||||
@ -282,14 +313,29 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
|
|||||||
}
|
}
|
||||||
resultbuf->h_aliases[cnt] = NULL;
|
resultbuf->h_aliases[cnt] = NULL;
|
||||||
|
|
||||||
|
if (__builtin_expect ((const char *) addr_list + addr_list_len
|
||||||
|
+ total_len > recend, 0))
|
||||||
|
goto out_close;
|
||||||
/* See whether this would exceed the buffer capacity. */
|
/* See whether this would exceed the buffer capacity. */
|
||||||
if (cp > buffer + buflen)
|
if (__builtin_expect (cp > buffer + buflen, 0))
|
||||||
goto no_room;
|
goto no_room;
|
||||||
|
|
||||||
/* And finally read the aliases. */
|
/* And finally read the aliases. */
|
||||||
if ((size_t) TEMP_FAILURE_RETRY (__read (sock, resultbuf->h_aliases[0],
|
if (addr_list == NULL)
|
||||||
total_len)) == total_len)
|
|
||||||
{
|
{
|
||||||
|
if ((size_t) TEMP_FAILURE_RETRY (__read (sock,
|
||||||
|
resultbuf->h_aliases[0],
|
||||||
|
total_len)) == total_len)
|
||||||
|
{
|
||||||
|
retval = 0;
|
||||||
|
*result = resultbuf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy (resultbuf->h_aliases[0],
|
||||||
|
(const char *) addr_list + addr_list_len, total_len);
|
||||||
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
*result = resultbuf;
|
*result = resultbuf;
|
||||||
}
|
}
|
||||||
@ -297,7 +343,7 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Store the error number. */
|
/* Store the error number. */
|
||||||
*h_errnop = hst_resp.error;
|
*h_errnop = hst_resp->error;
|
||||||
|
|
||||||
/* The `errno' to some value != ERANGE. */
|
/* The `errno' to some value != ERANGE. */
|
||||||
__set_errno (ENOENT);
|
__set_errno (ENOENT);
|
||||||
@ -305,8 +351,15 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
|
|||||||
retval = 0;
|
retval = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out_close:
|
||||||
|
if (sock != -1)
|
||||||
|
close_not_cancel_no_status (sock);
|
||||||
out:
|
out:
|
||||||
__close (sock);
|
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;
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
02111-1307 USA. */
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -24,6 +25,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
@ -64,70 +66,124 @@ __nscd_getpwuid_r (uid_t uid, struct passwd *resultbuf, char *buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
libc_locked_map_ptr (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)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (map_handle.mapped != NO_MAPPING)
|
||||||
|
free (map_handle.mapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
internal_function
|
internal_function
|
||||||
nscd_getpw_r (const char *key, size_t keylen, request_type type,
|
nscd_getpw_r (const char *key, size_t keylen, request_type type,
|
||||||
struct passwd *resultbuf, char *buffer, size_t buflen,
|
struct passwd *resultbuf, char *buffer, size_t buflen,
|
||||||
struct passwd **result)
|
struct passwd **result)
|
||||||
{
|
{
|
||||||
pw_response_header pw_resp;
|
const pw_response_header *pw_resp = NULL;
|
||||||
int sock = __nscd_open_socket (key, keylen, type, &pw_resp,
|
const char *pw_name = NULL;
|
||||||
sizeof (pw_resp));
|
int retval = -1;
|
||||||
if (sock == -1)
|
int gc_cycle;
|
||||||
|
const char *recend = (const char *) ~UINTMAX_C (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:
|
||||||
|
if (mapped != NO_MAPPING)
|
||||||
{
|
{
|
||||||
__nss_not_use_nscd_passwd = 1;
|
const struct datahead *found = __nscd_cache_search (type, key, keylen,
|
||||||
return -1;
|
mapped);
|
||||||
|
if (found != NULL)
|
||||||
|
{
|
||||||
|
pw_resp = &found->data[0].pwdata;
|
||||||
|
pw_name = (const char *) (pw_resp + 1);
|
||||||
|
recend = (const char *) found->data + found->recsize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pw_response_header pw_resp_mem;
|
||||||
|
int sock = -1;
|
||||||
|
if (pw_resp == NULL)
|
||||||
|
{
|
||||||
|
sock = __nscd_open_socket (key, keylen, type, &pw_resp_mem,
|
||||||
|
sizeof (pw_resp_mem));
|
||||||
|
if (sock == -1)
|
||||||
|
{
|
||||||
|
__nss_not_use_nscd_passwd = 1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
pw_resp = &pw_resp_mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No value found so far. */
|
/* No value found so far. */
|
||||||
int retval = -1;
|
|
||||||
*result = NULL;
|
*result = NULL;
|
||||||
|
|
||||||
if (__builtin_expect (pw_resp.found == -1, 0))
|
if (__builtin_expect (pw_resp->found == -1, 0))
|
||||||
{
|
{
|
||||||
/* The daemon does not cache this database. */
|
/* The daemon does not cache this database. */
|
||||||
__nss_not_use_nscd_passwd = 1;
|
__nss_not_use_nscd_passwd = 1;
|
||||||
goto out;
|
goto out_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pw_resp.found == 1)
|
if (pw_resp->found == 1)
|
||||||
{
|
{
|
||||||
char *p = buffer;
|
/* Set the information we already have. */
|
||||||
size_t total = (pw_resp.pw_name_len + pw_resp.pw_passwd_len
|
resultbuf->pw_uid = pw_resp->pw_uid;
|
||||||
+ pw_resp.pw_gecos_len + pw_resp.pw_dir_len
|
resultbuf->pw_gid = pw_resp->pw_gid;
|
||||||
+ pw_resp.pw_shell_len);
|
|
||||||
|
|
||||||
|
char *p = buffer;
|
||||||
|
/* get pw_name */
|
||||||
|
resultbuf->pw_name = p;
|
||||||
|
p += pw_resp->pw_name_len;
|
||||||
|
/* get pw_passwd */
|
||||||
|
resultbuf->pw_passwd = p;
|
||||||
|
p += pw_resp->pw_passwd_len;
|
||||||
|
/* get pw_gecos */
|
||||||
|
resultbuf->pw_gecos = p;
|
||||||
|
p += pw_resp->pw_gecos_len;
|
||||||
|
/* get pw_dir */
|
||||||
|
resultbuf->pw_dir = p;
|
||||||
|
p += pw_resp->pw_dir_len;
|
||||||
|
/* get pw_pshell */
|
||||||
|
resultbuf->pw_shell = p;
|
||||||
|
p += pw_resp->pw_shell_len;
|
||||||
|
|
||||||
|
ssize_t total = p - buffer;
|
||||||
|
if (__builtin_expect (pw_name + total > recend, 0))
|
||||||
|
goto out_close;
|
||||||
if (__builtin_expect (buflen < total, 0))
|
if (__builtin_expect (buflen < total, 0))
|
||||||
{
|
{
|
||||||
__set_errno (ERANGE);
|
__set_errno (ERANGE);
|
||||||
retval = ERANGE;
|
retval = ERANGE;
|
||||||
goto out;
|
goto out_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the information we already have. */
|
retval = 0;
|
||||||
resultbuf->pw_uid = pw_resp.pw_uid;
|
if (pw_name == NULL)
|
||||||
resultbuf->pw_gid = pw_resp.pw_gid;
|
|
||||||
|
|
||||||
/* get pw_name */
|
|
||||||
resultbuf->pw_name = p;
|
|
||||||
p += pw_resp.pw_name_len;
|
|
||||||
/* get pw_passwd */
|
|
||||||
resultbuf->pw_passwd = p;
|
|
||||||
p += pw_resp.pw_passwd_len;
|
|
||||||
/* get pw_gecos */
|
|
||||||
resultbuf->pw_gecos = p;
|
|
||||||
p += pw_resp.pw_gecos_len;
|
|
||||||
/* get pw_dir */
|
|
||||||
resultbuf->pw_dir = p;
|
|
||||||
p += pw_resp.pw_dir_len;
|
|
||||||
/* get pw_pshell */
|
|
||||||
resultbuf->pw_shell = p;
|
|
||||||
|
|
||||||
ssize_t nbytes = TEMP_FAILURE_RETRY (__read (sock, buffer, total));
|
|
||||||
|
|
||||||
if (nbytes == (ssize_t) total)
|
|
||||||
{
|
{
|
||||||
retval = 0;
|
ssize_t nbytes = TEMP_FAILURE_RETRY (__read (sock, buffer, total));
|
||||||
|
|
||||||
|
if (__builtin_expect (nbytes != total, 0))
|
||||||
|
{
|
||||||
|
/* The `errno' to some value != ERANGE. */
|
||||||
|
__set_errno (ENOENT);
|
||||||
|
retval = ENOENT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*result = resultbuf;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Copy the various strings. */
|
||||||
|
memcpy (resultbuf->pw_name, pw_name, total);
|
||||||
|
|
||||||
*result = resultbuf;
|
*result = resultbuf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,8 +195,15 @@ nscd_getpw_r (const char *key, size_t keylen, request_type type,
|
|||||||
retval = 0;
|
retval = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out_close:
|
||||||
|
if (sock != -1)
|
||||||
|
close_not_cancel_no_status (sock);
|
||||||
out:
|
out:
|
||||||
close_not_cancel_no_status (sock);
|
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;
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
335
nscd/nscd_helper.c
Normal file
335
nscd/nscd_helper.c
Normal file
@ -0,0 +1,335 @@
|
|||||||
|
/* Copyright (C) 1998-2002, 2003, 2004 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
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. */
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <not-cancel.h>
|
||||||
|
#include <nis/rpcsvc/nis.h>
|
||||||
|
|
||||||
|
#include "nscd-client.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
open_socket (void)
|
||||||
|
{
|
||||||
|
int sock = __socket (PF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (sock < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Make socket non-blocking. */
|
||||||
|
int fl = __fcntl (sock, F_GETFL);
|
||||||
|
if (fl != -1)
|
||||||
|
__fcntl (sock, F_SETFL, fl | O_NONBLOCK);
|
||||||
|
|
||||||
|
struct sockaddr_un sun;
|
||||||
|
sun.sun_family = AF_UNIX;
|
||||||
|
strcpy (sun.sun_path, _PATH_NSCDSOCKET);
|
||||||
|
if (__connect (sock, (struct sockaddr *) &sun, sizeof (sun)) < 0
|
||||||
|
&& errno != EINPROGRESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
struct pollfd fds[1];
|
||||||
|
fds[0].fd = sock;
|
||||||
|
fds[0].events = POLLOUT | POLLERR | POLLHUP;
|
||||||
|
if (__poll (fds, 1, 5 * 1000) > 0)
|
||||||
|
/* Success. We do not check for success of the connect call here.
|
||||||
|
If it failed, the following operations will fail. */
|
||||||
|
return sock;
|
||||||
|
|
||||||
|
out:
|
||||||
|
close_not_cancel_no_status (sock);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
__nscd_unmap (struct mapped_database *mapped)
|
||||||
|
{
|
||||||
|
assert (mapped->counter == 0);
|
||||||
|
munmap ((void *) mapped->head, mapped->mapsize);
|
||||||
|
free (mapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Try to get a file descriptor for the shared meory segment
|
||||||
|
containing the database. */
|
||||||
|
static struct mapped_database *
|
||||||
|
get_mapping (request_type type, const char *key,
|
||||||
|
struct mapped_database **mappedp)
|
||||||
|
{
|
||||||
|
struct mapped_database *result = NO_MAPPING;
|
||||||
|
#ifdef SCM_RIGHTS
|
||||||
|
const size_t keylen = strlen (key) + 1;
|
||||||
|
char resdata[keylen];
|
||||||
|
int saved_errno = errno;
|
||||||
|
|
||||||
|
int mapfd = -1;
|
||||||
|
|
||||||
|
/* Send the request. */
|
||||||
|
struct iovec iov[2];
|
||||||
|
request_header req;
|
||||||
|
|
||||||
|
int sock = open_socket ();
|
||||||
|
if (sock < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
req.version = NSCD_VERSION;
|
||||||
|
req.type = type;
|
||||||
|
req.key_len = keylen;
|
||||||
|
|
||||||
|
iov[0].iov_base = &req;
|
||||||
|
iov[0].iov_len = sizeof (req);
|
||||||
|
iov[1].iov_base = (void *) key;
|
||||||
|
iov[1].iov_len = keylen;
|
||||||
|
|
||||||
|
if (TEMP_FAILURE_RETRY (__writev (sock, iov, 2))
|
||||||
|
!= iov[0].iov_len + iov[1].iov_len)
|
||||||
|
/* We cannot even write the request. */
|
||||||
|
goto out_close2;
|
||||||
|
|
||||||
|
/* Room for the data sent along with the file descriptor. We expect
|
||||||
|
the key name back. */
|
||||||
|
iov[0].iov_base = resdata;
|
||||||
|
iov[0].iov_len = keylen;
|
||||||
|
|
||||||
|
char buf[CMSG_SPACE (sizeof (int))];
|
||||||
|
struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1,
|
||||||
|
.msg_control = buf, .msg_controllen = sizeof (buf) };
|
||||||
|
struct cmsghdr *cmsg = CMSG_FIRSTHDR (&msg);
|
||||||
|
|
||||||
|
cmsg->cmsg_level = SOL_SOCKET;
|
||||||
|
cmsg->cmsg_type = SCM_RIGHTS;
|
||||||
|
cmsg->cmsg_len = CMSG_LEN (sizeof (int));
|
||||||
|
|
||||||
|
*(int *) CMSG_DATA (cmsg) = -1;
|
||||||
|
|
||||||
|
msg.msg_controllen = cmsg->cmsg_len;
|
||||||
|
|
||||||
|
struct pollfd fds[1];
|
||||||
|
fds[0].fd = sock;
|
||||||
|
fds[0].events = POLLIN | POLLERR | POLLHUP;
|
||||||
|
if (__poll (fds, 1, 5 * 1000) <= 0)
|
||||||
|
/* Failure or timeout. */
|
||||||
|
goto out_close2;
|
||||||
|
|
||||||
|
if (TEMP_FAILURE_RETRY (__recvmsg (sock, &msg, 0)) != keylen
|
||||||
|
|| msg.msg_controllen != CMSG_LEN (sizeof (int)))
|
||||||
|
goto out_close2;
|
||||||
|
|
||||||
|
mapfd = *(int *) CMSG_DATA (cmsg);
|
||||||
|
|
||||||
|
struct stat64 st;
|
||||||
|
if (strcmp (resdata, key) != 0
|
||||||
|
|| fstat64 (mapfd, &st) != 0
|
||||||
|
|| st.st_size < sizeof (struct database_pers_head))
|
||||||
|
goto out_close;
|
||||||
|
|
||||||
|
struct database_pers_head head;
|
||||||
|
if (TEMP_FAILURE_RETRY (__pread (mapfd, &head, sizeof (head), 0))
|
||||||
|
!= sizeof (head))
|
||||||
|
goto out_close;
|
||||||
|
|
||||||
|
if (head.version != DB_VERSION || head.header_size != sizeof (head)
|
||||||
|
/* This really should not happen but who knows, maybe the update
|
||||||
|
thread got stuck. */
|
||||||
|
|| head.timestamp + MAPPING_TIMEOUT < time (NULL))
|
||||||
|
goto out_close;
|
||||||
|
|
||||||
|
size_t size = (sizeof (head) + roundup (head.module * sizeof (ref_t), ALIGN)
|
||||||
|
+ head.data_size);
|
||||||
|
|
||||||
|
if (st.st_size < size)
|
||||||
|
goto out_close;
|
||||||
|
|
||||||
|
/* The file is large enough, map it now. */
|
||||||
|
void *mapping = __mmap (NULL, size, PROT_READ, MAP_SHARED, mapfd, 0);
|
||||||
|
if (mapping != MAP_FAILED)
|
||||||
|
{
|
||||||
|
/* Allocate a record for the mapping. */
|
||||||
|
struct mapped_database *newp;
|
||||||
|
|
||||||
|
newp = malloc (sizeof (*newp));
|
||||||
|
if (newp == NULL)
|
||||||
|
{
|
||||||
|
/* Ugh, after all we went through the memory allocation failed. */
|
||||||
|
munmap (result, size);
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
newp->head = mapping;
|
||||||
|
newp->data = ((char *) mapping + head.header_size
|
||||||
|
+ roundup (head.module * sizeof (ref_t), ALIGN));
|
||||||
|
newp->mapsize = size;
|
||||||
|
/* Set counter to 1 to show it is usable. */
|
||||||
|
newp->counter = 1;
|
||||||
|
|
||||||
|
result = newp;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_close:
|
||||||
|
__close (mapfd);
|
||||||
|
out_close2:
|
||||||
|
__close (sock);
|
||||||
|
out:
|
||||||
|
__set_errno (saved_errno);
|
||||||
|
#endif /* SCM_RIGHTS */
|
||||||
|
|
||||||
|
struct mapped_database *oldval = *mappedp;
|
||||||
|
*mappedp = result;
|
||||||
|
|
||||||
|
if (oldval != NULL && atomic_decrement_val (&oldval->counter) == 0)
|
||||||
|
__nscd_unmap (oldval);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct mapped_database *
|
||||||
|
__nscd_get_map_ref (request_type type, const char *name,
|
||||||
|
struct locked_map_ptr *mapptr, int *gc_cyclep)
|
||||||
|
{
|
||||||
|
struct mapped_database *cur = mapptr->mapped;
|
||||||
|
if (cur == NO_MAPPING)
|
||||||
|
return cur;
|
||||||
|
|
||||||
|
int cnt = 0;
|
||||||
|
while (atomic_compare_and_exchange_val_acq (&mapptr->lock, 1, 0) != 0)
|
||||||
|
{
|
||||||
|
// XXX Best number of rounds?
|
||||||
|
if (++cnt > 5)
|
||||||
|
return NO_MAPPING;
|
||||||
|
|
||||||
|
atomic_delay ();
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = mapptr->mapped;
|
||||||
|
|
||||||
|
if (__builtin_expect (cur != NO_MAPPING, 1))
|
||||||
|
{
|
||||||
|
/* If not mapped or timestamp not updated, request new map. */
|
||||||
|
if (cur == NULL
|
||||||
|
// XXX The following syscalls increases the cost of the entire
|
||||||
|
// XXX lookup by a factor of 5 but unfortunately there is not
|
||||||
|
// XXX much we can do except hoping we get a userlevel
|
||||||
|
// XXX implementation soon.
|
||||||
|
|| cur->head->timestamp + MAPPING_TIMEOUT < time (NULL))
|
||||||
|
cur = get_mapping (type, name, &mapptr->mapped);
|
||||||
|
|
||||||
|
if (__builtin_expect (cur != NO_MAPPING, 1))
|
||||||
|
{
|
||||||
|
if (__builtin_expect (((*gc_cyclep = cur->head->gc_cycle) & 1) != 0,
|
||||||
|
0))
|
||||||
|
cur = NO_MAPPING;
|
||||||
|
else
|
||||||
|
atomic_increment (&cur->counter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mapptr->lock = 0;
|
||||||
|
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const struct datahead *
|
||||||
|
__nscd_cache_search (request_type type, const char *key, size_t keylen,
|
||||||
|
const struct mapped_database *mapped)
|
||||||
|
{
|
||||||
|
unsigned long int hash = __nis_hash (key, keylen) % mapped->head->module;
|
||||||
|
|
||||||
|
ref_t work = mapped->head->array[hash];
|
||||||
|
while (work != ENDREF)
|
||||||
|
{
|
||||||
|
struct hashentry *here = (struct hashentry *) (mapped->data + work);
|
||||||
|
|
||||||
|
if (type == here->type && keylen == here->len
|
||||||
|
&& memcmp (key, mapped->data + here->key, keylen) == 0)
|
||||||
|
{
|
||||||
|
/* We found the entry. Increment the appropriate counter. */
|
||||||
|
const struct datahead *dh
|
||||||
|
= (struct datahead *) (mapped->data + here->packet);
|
||||||
|
|
||||||
|
/* See whether we must ignore the entry or whether something
|
||||||
|
is wrong because garbage collection is in progress. */
|
||||||
|
if (dh->usable && ((char *) dh + dh->allocsize
|
||||||
|
<= (char *) mapped->head + mapped->mapsize))
|
||||||
|
return dh;
|
||||||
|
}
|
||||||
|
|
||||||
|
work = here->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Create a socket connected to a name. */
|
||||||
|
int
|
||||||
|
__nscd_open_socket (const char *key, size_t keylen, request_type type,
|
||||||
|
void *response, size_t responselen)
|
||||||
|
{
|
||||||
|
int saved_errno = errno;
|
||||||
|
|
||||||
|
int sock = open_socket ();
|
||||||
|
if (sock >= 0)
|
||||||
|
{
|
||||||
|
request_header req;
|
||||||
|
req.version = NSCD_VERSION;
|
||||||
|
req.type = type;
|
||||||
|
req.key_len = keylen;
|
||||||
|
|
||||||
|
struct iovec vec[2];
|
||||||
|
vec[0].iov_base = &req;
|
||||||
|
vec[0].iov_len = sizeof (request_header);
|
||||||
|
vec[1].iov_base = (void *) key;
|
||||||
|
vec[1].iov_len = keylen;
|
||||||
|
|
||||||
|
ssize_t nbytes = TEMP_FAILURE_RETRY (__writev (sock, vec, 2));
|
||||||
|
if (nbytes == (ssize_t) (sizeof (request_header) + keylen))
|
||||||
|
{
|
||||||
|
/* Wait for data. */
|
||||||
|
struct pollfd fds[1];
|
||||||
|
fds[0].fd = sock;
|
||||||
|
fds[0].events = POLLIN | POLLERR | POLLHUP;
|
||||||
|
if (__poll (fds, 1, 5 * 1000) > 0)
|
||||||
|
{
|
||||||
|
nbytes = TEMP_FAILURE_RETRY (__read (sock, response,
|
||||||
|
responselen));
|
||||||
|
if (nbytes == (ssize_t) responselen)
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close_not_cancel_no_status (sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
__set_errno (saved_errno);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user