summaryrefslogtreecommitdiff
path: root/nscd
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2007-07-12 18:26:36 +0000
committerJakub Jelinek <jakub@redhat.com>2007-07-12 18:26:36 +0000
commit0ecb606cb6cf65de1d9fc8a919bceb4be476c602 (patch)
tree2ea1f8305970753e4a657acb2ccc15ca3eec8e2c /nscd
parent7d58530341304d403a6626d7f7a1913165fe2f32 (diff)
downloadglibc-0ecb606cb6cf65de1d9fc8a919bceb4be476c602.tar.gz
2.5-18.1
Diffstat (limited to 'nscd')
-rw-r--r--nscd/Makefile45
-rw-r--r--nscd/aicache.c60
-rw-r--r--nscd/cache.c97
-rw-r--r--nscd/connections.c587
-rw-r--r--nscd/dbg_log.c24
-rw-r--r--nscd/gai.c21
-rw-r--r--nscd/getgrgid_r.c22
-rw-r--r--nscd/getgrnam_r.c22
-rw-r--r--nscd/gethstbyad_r.c22
-rw-r--r--nscd/gethstbynm2_r.c22
-rw-r--r--nscd/getpwnam_r.c22
-rw-r--r--nscd/getpwuid_r.c22
-rw-r--r--nscd/grpcache.c80
-rw-r--r--nscd/hstcache.c58
-rw-r--r--nscd/initgrcache.c63
-rw-r--r--nscd/mem.c52
-rw-r--r--nscd/nscd-client.h26
-rw-r--r--nscd/nscd.c102
-rw-r--r--nscd/nscd.conf11
-rw-r--r--nscd/nscd.h34
-rw-r--r--nscd/nscd.init43
-rw-r--r--nscd/nscd_conf.c194
-rw-r--r--nscd/nscd_getai.c83
-rw-r--r--nscd/nscd_getgr_r.c114
-rw-r--r--nscd/nscd_gethst_r.c159
-rw-r--r--nscd/nscd_getpw_r.c74
-rw-r--r--nscd/nscd_helper.c253
-rw-r--r--nscd/nscd_initgroups.c77
-rw-r--r--nscd/nscd_nischeck.c96
-rw-r--r--nscd/nscd_setup_thread.c26
-rw-r--r--nscd/nscd_stat.c26
-rw-r--r--nscd/pwdcache.c77
-rw-r--r--nscd/selinux.c154
-rw-r--r--nscd/selinux.h12
34 files changed, 1873 insertions, 907 deletions
diff --git a/nscd/Makefile b/nscd/Makefile
index 70a35198c2..9c98018217 100644
--- a/nscd/Makefile
+++ b/nscd/Makefile
@@ -1,4 +1,5 @@
-# Copyright (C) 1998, 2000, 2002, 2003, 2004 Free Software Foundation, Inc.
+# Copyright (C) 1998,2000,2002,2003,2004,2005,2006
+# Free Software Foundation, Inc.
# This file is part of the GNU C Library.
# The GNU C Library is free software; you can redistribute it and/or
@@ -36,13 +37,12 @@ nscd-modules := nscd connections pwdcache getpwnam_r getpwuid_r grpcache \
ifeq ($(have-thread-library),yes)
-others := nscd_nischeck
ifneq (yesyes,$(have-fpie)$(build-shared))
others += nscd
endif
-install-sbin := nscd nscd_nischeck
+install-sbin := nscd
-extra-objs := $(nscd-modules:=.o) nscd_nischeck.o
+extra-objs := $(nscd-modules:=.o)
endif
@@ -51,15 +51,32 @@ otherlibs += $(nssobjdir)/libnss_files.a $(resolvobjdir)/libnss_dns.a \
$(resolvobjdir)/libresolv.a
endif
+all-nscd-modules := $(nscd-modules) selinux
ifeq (yes,$(have-selinux))
+ifeq (yes,$(have-libaudit))
+libaudit = -laudit
+ifeq (yes,$(have-libcap))
+libcap = -lcap
+endif
+endif
+
nscd-modules += selinux
-selinux-LIBS := -lselinux
+selinux-LIBS := -lselinux $(libaudit) $(libcap)
+
+# The configure.in check for libselinux and its headers did not use
+# $SYSINCLUDES. The directory specified by --with-headers usually
+# contains only the basic kernel interface headers, not something like
+# libselinux. So the simplest thing is to presume that the standard
+# system headers will be ok for this file.
+$(objpfx)nscd_stat.o: sysincludes = # nothing
+$(objpfx)selinux.o: sysincludes = # nothing
endif
+LDLIBS-nscd = $(selinux-LIBS)
+
distribute := nscd.h nscd-client.h dbg_log.h \
- $(addsuffix .c, $(filter-out xmalloc, $(nscd-modules))) \
- nscd_nischeck.c nscd.conf nscd.init nscd_proto.h \
- nscd-types.h
+ $(addsuffix .c, $(filter-out xmalloc,$(all-nscd-modules))) \
+ nscd.conf nscd.init nscd_proto.h nscd-types.h
include ../Rules
@@ -69,10 +86,13 @@ CFLAGS-nscd_gethst_r.c = -fexceptions
CFLAGS-nscd_getai.c = -fexceptions
CFLAGS-nscd_initgroups.c = -fexceptions
-nscd-cflags = -DIS_IN_nscd=1
+nscd-cflags = -DIS_IN_nscd=1 -D_FORTIFY_SOURCE=2
ifeq (yesyes,$(have-fpie)$(build-shared))
nscd-cflags += -fpie
endif
+ifeq (yes,$(have-ssp))
+nscd-cflags += -fstack-protector
+endif
CFLAGS-nscd.c += $(nscd-cflags)
CFLAGS-connections.c += $(nscd-cflags)
@@ -104,13 +124,13 @@ relro-LDFLAGS += -Wl,-z,now
endif
$(objpfx)nscd: $(addprefix $(objpfx),$(nscd-modules:=.o))
- $(LINK.o) -pie -Wl,-O1 \
+ $(LINK.o) -pie -Wl,-O1 $(nscd-cflags) \
$(sysdep-LDFLAGS) $(config-LDFLAGS) $(relro-LDFLAGS) \
$(extra-B-$(@F:lib%.so=%).so) -B$(csu-objpfx) \
$(extra-B-$(@F:lib%.so=%).so) $(load-map-file) \
$(LDFLAGS) $(LDFLAGS-$(@F)) \
-L$(subst :, -L,$(rpath-link)) -Wl,-rpath-link=$(rpath-link) \
- -o $@ $^ $(selinux-LIBS) $(common-objpfx)libc_nonshared.a
+ -o $@ $^ $(LDLIBS-nscd) $(common-objpfx)libc_nonshared.a
endif
# This makes sure -DNOT_IN_libc is passed for all these modules.
@@ -119,14 +139,11 @@ lib := nonlib
include $(patsubst %,$(..)cppflags-iterator.mk,$(cpp-srcs-left))
$(objpfx)nscd: $(nscd-modules:%=$(objpfx)%.o)
-$(objpfx)nscd_nischeck: $(objpfx)nscd_nischeck.o
ifeq ($(build-shared),yes)
$(objpfx)nscd: $(common-objpfx)rt/librt.so $(shared-thread-library) \
$(common-objpfx)nis/libnsl.so
-$(objpfx)nscd_nischeck: $(common-objpfx)nis/libnsl.so
else
$(objpfx)nscd: $(common-objpfx)rt/librt.a $(static-thread-library) \
$(common-objpfx)nis/libnsl.a
-$(objpfx)nscd_nischeck: $(common-objpfx)nis/libnsl.a
endif
diff --git a/nscd/aicache.c b/nscd/aicache.c
index 4e0496ff44..4640b4df94 100644
--- a/nscd/aicache.c
+++ b/nscd/aicache.c
@@ -1,22 +1,20 @@
/* Cache handling for host lookup.
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
- 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.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
- The GNU C Library is distributed in the hope that it will be useful,
+ This program 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU 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. */
+ You should have received a copy of the GNU General Public License
+ along with this program; 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>
@@ -26,8 +24,12 @@
#include <time.h>
#include <unistd.h>
#include <sys/mman.h>
-#include <dbg_log.h>
-#include <nscd.h>
+
+#include "dbg_log.h"
+#include "nscd.h"
+#ifdef HAVE_SENDFILE
+# include <kernel-features.h>
+#endif
typedef enum nss_status (*nss_gethostbyname3_r)
@@ -310,7 +312,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
*family++ = th[j].h_addrtype;
}
- char *cp = family;
+ void *cp = family;
if (canon != NULL)
cp = mempcpy (cp, canon, canonlen);
@@ -365,7 +367,31 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
wait. */
assert (fd != -1);
- TEMP_FAILURE_RETRY (write (fd, &dataset->resp, total));
+#ifdef HAVE_SENDFILE
+ if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
+ {
+ assert (db->wr_fd != -1);
+ assert ((char *) &dataset->resp > (char *) db->data);
+ assert ((char *) &dataset->resp - (char *) db->head
+ + total
+ <= (sizeof (struct database_pers_head)
+ + db->head->module * sizeof (ref_t)
+ + db->head->data_size));
+ ssize_t written;
+ written = sendfileall (fd, db->wr_fd,
+ (char *) &dataset->resp
+ - (char *) db->head, total);
+# ifndef __ASSUME_SENDFILE
+ if (written == -1 && errno == ENOSYS)
+ goto use_write;
+# endif
+ }
+ else
+# ifndef __ASSUME_SENDFILE
+ use_write:
+# endif
+#endif
+ writeall (fd, &dataset->resp, total);
}
goto out;
@@ -399,7 +425,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
total = sizeof (notfound);
if (fd != -1)
- TEMP_FAILURE_RETRY (write (fd, &notfound, total));
+ TEMP_FAILURE_RETRY (send (fd, &notfound, total, MSG_NOSIGNAL));
dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len);
/* If we cannot permanently store the result, so be it. */
diff --git a/nscd/cache.c b/nscd/cache.c
index efac4b3bcc..be9be2aa4f 100644
--- a/nscd/cache.c
+++ b/nscd/cache.c
@@ -1,26 +1,25 @@
-/* Copyright (c) 1998, 1999, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (c) 1998, 1999, 2003-2005, 2006 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.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
- The GNU C Library is distributed in the hope that it will be useful,
+ This program 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU 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. */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <assert.h>
#include <atomic.h>
#include <errno.h>
#include <error.h>
+#include <inttypes.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
@@ -169,6 +168,12 @@ cache_add (int type, const void *key, size_t len, struct datahead *packet,
if (nentries > table->head->maxnentries)
table->head->maxnentries = nentries;
+ if (table->persistent)
+ // XXX async OK?
+ msync ((void *) table->head,
+ (char *) &table->head->array[hash] - (char *) table->head
+ + sizeof (ref_t), MS_ASYNC);
+
return 0;
}
@@ -185,21 +190,42 @@ cache_add (int type, const void *key, size_t len, struct datahead *packet,
free the data structures since some hash table entries share the same
data. */
void
-prune_cache (struct database_dyn *table, time_t now)
+prune_cache (struct database_dyn *table, time_t now, int fd)
{
size_t cnt = table->head->module;
/* If this table is not actually used don't do anything. */
if (cnt == 0)
- return;
+ {
+ if (fd != -1)
+ {
+ /* Reply to the INVALIDATE initiator. */
+ int32_t resp = 0;
+ writeall (fd, &resp, sizeof (resp));
+ }
+ return;
+ }
+
+ /* This function can be called from the cleanup thread but also in
+ response to an invalidate command. Make sure only one thread is
+ running. When not serving INVALIDATE request, no need for the
+ second to wait around. */
+ if (fd == -1)
+ {
+ if (pthread_mutex_trylock (&table->prunelock) != 0)
+ /* The work is already being done. */
+ return;
+ }
+ else
+ pthread_mutex_lock (&table->prunelock);
/* If we check for the modification of the underlying file we invalidate
the entries also in this case. */
if (table->check_file)
{
- struct stat st;
+ struct stat64 st;
- if (stat (table->filename, &st) < 0)
+ if (stat64 (table->filename, &st) < 0)
{
char buf[128];
/* We cannot stat() the file, disable file checking if the
@@ -232,6 +258,10 @@ prune_cache (struct database_dyn *table, time_t now)
char *const data = table->data;
bool any = false;
+ if (__builtin_expect (debug_level > 2, 0))
+ dbg_log (_("pruning %s cache; time %ld"),
+ dbnames[table - dbs], (long int) now);
+
do
{
ref_t run = table->head->array[--cnt];
@@ -241,6 +271,25 @@ prune_cache (struct database_dyn *table, time_t now)
struct hashentry *runp = (struct hashentry *) (data + run);
struct datahead *dh = (struct datahead *) (data + runp->packet);
+ /* Some debug support. */
+ if (__builtin_expect (debug_level > 2, 0))
+ {
+ char buf[INET6_ADDRSTRLEN];
+ const char *str;
+
+ if (runp->type == GETHOSTBYADDR || runp->type == GETHOSTBYADDRv6)
+ {
+ inet_ntop (runp->type == GETHOSTBYADDR ? AF_INET : AF_INET6,
+ data + runp->key, buf, sizeof (buf));
+ str = buf;
+ }
+ else
+ str = data + runp->key;
+
+ dbg_log (_("considering %s entry \"%s\", timeout %" PRIu64),
+ serv2str[runp->type], str, dh->timeout);
+ }
+
/* Check whether the entry timed out. */
if (dh->timeout < now)
{
@@ -339,6 +388,14 @@ prune_cache (struct database_dyn *table, time_t now)
}
while (cnt > 0);
+ if (fd != -1)
+ {
+ /* Reply to the INVALIDATE initiator that the cache has been
+ invalidated. */
+ int32_t resp = 0;
+ writeall (fd, &resp, sizeof (resp));
+ }
+
if (first <= last)
{
struct hashentry *head = NULL;
@@ -395,7 +452,7 @@ prune_cache (struct database_dyn *table, time_t now)
/* Make sure the data is saved to disk. */
if (table->persistent)
msync (table->head,
- table->data + table->head->first_free - (char *) table->head,
+ data + table->head->first_free - (char *) table->head,
MS_ASYNC);
/* One extra pass if we do debugging. */
@@ -411,11 +468,11 @@ prune_cache (struct database_dyn *table, time_t now)
if (runp->type == GETHOSTBYADDR || runp->type == GETHOSTBYADDRv6)
{
inet_ntop (runp->type == GETHOSTBYADDR ? AF_INET : AF_INET6,
- table->data + runp->key, buf, sizeof (buf));
+ data + runp->key, buf, sizeof (buf));
str = buf;
}
else
- str = table->data + runp->key;
+ str = data + runp->key;
dbg_log ("remove %s entry \"%s\"", serv2str[runp->type], str);
@@ -427,4 +484,6 @@ prune_cache (struct database_dyn *table, time_t now)
/* Run garbage collection if any entry has been removed or replaced. */
if (any)
gc (table);
+
+ pthread_mutex_unlock (&table->prunelock);
}
diff --git a/nscd/connections.c b/nscd/connections.c
index f22d72e265..8f11421431 100644
--- a/nscd/connections.c
+++ b/nscd/connections.c
@@ -1,22 +1,20 @@
/* Inner loops of cache daemon.
- Copyright (C) 1998-2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1998-2003, 2004, 2005, 2006 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.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
- The GNU C Library is distributed in the hope that it will be useful,
+ This program 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU 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. */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <alloca.h>
#include <assert.h>
@@ -39,6 +37,9 @@
#include <sys/mman.h>
#include <sys/param.h>
#include <sys/poll.h>
+#ifdef HAVE_SENDFILE
+# include <sys/sendfile.h>
+#endif
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
@@ -46,10 +47,9 @@
#include "nscd.h"
#include "dbg_log.h"
#include "selinux.h"
-
-
-/* Number of bytes of data we initially reserve for each hash table bucket. */
-#define DEFAULT_DATASIZE_PER_BUCKET 1024
+#ifdef HAVE_SENDFILE
+# include <kernel-features.h>
+#endif
/* Wrapper functions with error checking for standard functions. */
@@ -68,6 +68,7 @@ static gid_t *server_groups;
# define NGROUPS 32
#endif
static int server_ngroups;
+static volatile int sighup_pending;
static pthread_attr_t attr;
@@ -100,10 +101,13 @@ struct database_dyn dbs[lastdb] =
{
[pwddb] = {
.lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
+ .prunelock = PTHREAD_MUTEX_INITIALIZER,
.enabled = 0,
.check_file = 1,
.persistent = 0,
+ .propagate = 1,
.shared = 0,
+ .max_db_size = DEFAULT_MAX_DB_SIZE,
.filename = "/etc/passwd",
.db_filename = _PATH_NSCD_PASSWD_DB,
.disabled_iov = &pwd_iov_disabled,
@@ -115,10 +119,13 @@ struct database_dyn dbs[lastdb] =
},
[grpdb] = {
.lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
+ .prunelock = PTHREAD_MUTEX_INITIALIZER,
.enabled = 0,
.check_file = 1,
.persistent = 0,
+ .propagate = 1,
.shared = 0,
+ .max_db_size = DEFAULT_MAX_DB_SIZE,
.filename = "/etc/group",
.db_filename = _PATH_NSCD_GROUP_DB,
.disabled_iov = &grp_iov_disabled,
@@ -130,10 +137,13 @@ struct database_dyn dbs[lastdb] =
},
[hstdb] = {
.lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
+ .prunelock = PTHREAD_MUTEX_INITIALIZER,
.enabled = 0,
.check_file = 1,
.persistent = 0,
+ .propagate = 0, /* Not used. */
.shared = 0,
+ .max_db_size = DEFAULT_MAX_DB_SIZE,
.filename = "/etc/hosts",
.db_filename = _PATH_NSCD_HOSTS_DB,
.disabled_iov = &hst_iov_disabled,
@@ -181,20 +191,252 @@ static int sock;
unsigned long int client_queued;
-/* Initialize database information structures. */
-void
-nscd_init (void)
+ssize_t
+writeall (int fd, const void *buf, size_t len)
{
- struct sockaddr_un sock_addr;
- size_t cnt;
+ size_t n = len;
+ ssize_t ret;
+ do
+ {
+ ret = TEMP_FAILURE_RETRY (send (fd, buf, n, MSG_NOSIGNAL));
+ if (ret <= 0)
+ break;
+ buf = (const char *) buf + ret;
+ n -= ret;
+ }
+ while (n > 0);
+ return ret < 0 ? ret : len - n;
+}
+
+
+#ifdef HAVE_SENDFILE
+ssize_t
+sendfileall (int tofd, int fromfd, off_t off, size_t len)
+{
+ ssize_t n = len;
+ ssize_t ret;
- /* Secure mode and unprivileged mode are incompatible */
- if (server_user != NULL && secure_in_use)
+ do
{
- dbg_log (_("Cannot run nscd in secure mode as unprivileged user"));
- exit (1);
+ ret = TEMP_FAILURE_RETRY (sendfile (tofd, fromfd, &off, n));
+ if (ret <= 0)
+ break;
+ n -= ret;
+ }
+ while (n > 0);
+ return ret < 0 ? ret : len - n;
+}
+#endif
+
+
+enum usekey
+ {
+ use_not = 0,
+ /* The following three are not really used, they are symbolic constants. */
+ use_first = 16,
+ use_begin = 32,
+ use_end = 64,
+
+ use_he = 1,
+ use_he_begin = use_he | use_begin,
+ use_he_end = use_he | use_end,
+#if SEPARATE_KEY
+ use_key = 2,
+ use_key_begin = use_key | use_begin,
+ use_key_end = use_key | use_end,
+ use_key_first = use_key_begin | use_first,
+#endif
+ use_data = 3,
+ use_data_begin = use_data | use_begin,
+ use_data_end = use_data | use_end,
+ use_data_first = use_data_begin | use_first
+ };
+
+
+static int
+check_use (const char *data, nscd_ssize_t first_free, uint8_t *usemap,
+ enum usekey use, ref_t start, size_t len)
+{
+ assert (len >= 2);
+
+ if (start > first_free || start + len > first_free
+ || (start & BLOCK_ALIGN_M1))
+ return 0;
+
+ if (usemap[start] == use_not)
+ {
+ /* Add the start marker. */
+ usemap[start] = use | use_begin;
+ use &= ~use_first;
+
+ while (--len > 0)
+ if (usemap[++start] != use_not)
+ return 0;
+ else
+ usemap[start] = use;
+
+ /* Add the end marker. */
+ usemap[start] = use | use_end;
+ }
+ else if ((usemap[start] & ~use_first) == ((use | use_begin) & ~use_first))
+ {
+ /* Hash entries can't be shared. */
+ if (use == use_he)
+ return 0;
+
+ usemap[start] |= (use & use_first);
+ use &= ~use_first;
+
+ while (--len > 1)
+ if (usemap[++start] != use)
+ return 0;
+
+ if (usemap[++start] != (use | use_end))
+ return 0;
+ }
+ else
+ /* Points to a wrong object or somewhere in the middle. */
+ return 0;
+
+ return 1;
+}
+
+
+/* Verify data in persistent database. */
+static int
+verify_persistent_db (void *mem, struct database_pers_head *readhead, int dbnr)
+{
+ assert (dbnr == pwddb || dbnr == grpdb || dbnr == hstdb);
+
+ time_t now = time (NULL);
+
+ struct database_pers_head *head = mem;
+ struct database_pers_head head_copy = *head;
+
+ /* Check that the header that was read matches the head in the database. */
+ if (readhead != NULL && memcmp (head, readhead, sizeof (*head)) != 0)
+ return 0;
+
+ /* First some easy tests: make sure the database header is sane. */
+ if (head->version != DB_VERSION
+ || head->header_size != sizeof (*head)
+ /* We allow a timestamp to be one hour ahead of the current time.
+ This should cover daylight saving time changes. */
+ || head->timestamp > now + 60 * 60 + 60
+ || (head->gc_cycle & 1)
+ || (size_t) head->module > INT32_MAX / sizeof (ref_t)
+ || (size_t) head->data_size > INT32_MAX - head->module * sizeof (ref_t)
+ || head->first_free < 0
+ || head->first_free > head->data_size
+ || (head->first_free & BLOCK_ALIGN_M1) != 0
+ || head->maxnentries < 0
+ || head->maxnsearched < 0)
+ return 0;
+
+ uint8_t *usemap = calloc (head->first_free, 1);
+ if (usemap == NULL)
+ return 0;
+
+ const char *data = (char *) &head->array[roundup (head->module,
+ ALIGN / sizeof (ref_t))];
+
+ nscd_ssize_t he_cnt = 0;
+ for (nscd_ssize_t cnt = 0; cnt < head->module; ++cnt)
+ {
+ ref_t work = head->array[cnt];
+
+ while (work != ENDREF)
+ {
+ if (! check_use (data, head->first_free, usemap, use_he, work,
+ sizeof (struct hashentry)))
+ goto fail;
+
+ /* Now we know we can dereference the record. */
+ struct hashentry *here = (struct hashentry *) (data + work);
+
+ ++he_cnt;
+
+ /* Make sure the record is for this type of service. */
+ if (here->type >= LASTREQ
+ || serv2db[here->type] != &dbs[dbnr])
+ goto fail;
+
+ /* Validate boolean field value. */
+ if (here->first != false && here->first != true)
+ goto fail;
+
+ if (here->len < 0)
+ goto fail;
+
+ /* Now the data. */
+ if (here->packet < 0
+ || here->packet > head->first_free
+ || here->packet + sizeof (struct datahead) > head->first_free)
+ goto fail;
+
+ struct datahead *dh = (struct datahead *) (data + here->packet);
+
+ if (! check_use (data, head->first_free, usemap,
+ use_data | (here->first ? use_first : 0),
+ here->packet, dh->allocsize))
+ goto fail;
+
+ if (dh->allocsize < sizeof (struct datahead)
+ || dh->recsize > dh->allocsize
+ || (dh->notfound != false && dh->notfound != true)
+ || (dh->usable != false && dh->usable != true))
+ goto fail;
+
+ if (here->key < here->packet + sizeof (struct datahead)
+ || here->key > here->packet + dh->allocsize
+ || here->key + here->len > here->packet + dh->allocsize)
+ {
+#if SEPARATE_KEY
+ /* If keys can appear outside of data, this should be done
+ instead. But gc doesn't mark the data in that case. */
+ if (! check_use (data, head->first_free, usemap,
+ use_key | (here->first ? use_first : 0),
+ here->key, here->len))
+#endif
+ goto fail;
+ }
+
+ work = here->next;
+ }
+ }
+
+ if (he_cnt != head->nentries)
+ goto fail;
+
+ /* See if all data and keys had at least one reference from
+ he->first == true hashentry. */
+ for (ref_t idx = 0; idx < head->first_free; ++idx)
+ {
+#if SEPARATE_KEY
+ if (usemap[idx] == use_key_begin)
+ goto fail;
+#endif
+ if (usemap[idx] == use_data_begin)
+ goto fail;
}
+ /* Finally, make sure the database hasn't changed since the first test. */
+ if (memcmp (mem, &head_copy, sizeof (*head)) != 0)
+ goto fail;
+
+ free (usemap);
+ return 1;
+
+fail:
+ free (usemap);
+ return 0;
+}
+
+
+/* Initialize database information structures. */
+void
+nscd_init (void)
+{
/* Look up unprivileged uid/gid/groups before we start listening on the
socket */
if (server_user != NULL)
@@ -204,7 +446,7 @@ nscd_init (void)
/* No configuration for this value, assume a default. */
nthreads = 2 * lastdb;
- for (cnt = 0; cnt < lastdb; ++cnt)
+ for (size_t cnt = 0; cnt < lastdb; ++cnt)
if (dbs[cnt].enabled)
{
pthread_rwlock_init (&dbs[cnt].lock, NULL);
@@ -227,7 +469,7 @@ nscd_init (void)
fail_db:
dbg_log (_("invalid persistent database file \"%s\": %s"),
dbs[cnt].db_filename, strerror (errno));
- dbs[cnt].persistent = 0;
+ unlink (dbs[cnt].db_filename);
}
else if (head.module == 0 && head.data_size == 0)
{
@@ -240,22 +482,39 @@ nscd_init (void)
dbg_log (_("invalid persistent database file \"%s\": %s"),
dbs[cnt].db_filename,
_("header size does not match"));
- dbs[cnt].persistent = 0;
+ unlink (dbs[cnt].db_filename);
}
else if ((total = (sizeof (head)
+ roundup (head.module * sizeof (ref_t),
ALIGN)
+ head.data_size))
- > st.st_size)
+ > st.st_size
+ || total < sizeof (head))
{
dbg_log (_("invalid persistent database file \"%s\": %s"),
dbs[cnt].db_filename,
_("file size does not match"));
- dbs[cnt].persistent = 0;
+ unlink (dbs[cnt].db_filename);
}
- else if ((mem = mmap (NULL, total, PROT_READ | PROT_WRITE,
- MAP_SHARED, fd, 0)) == MAP_FAILED)
+ /* Note we map with the maximum size allowed for the
+ database. This is likely much larger than the
+ actual file size. This is OK on most OSes since
+ extensions of the underlying file will
+ automatically translate more pages available for
+ memory access. */
+ else if ((mem = mmap (NULL, dbs[cnt].max_db_size,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0))
+ == MAP_FAILED)
goto fail_db;
+ else if (!verify_persistent_db (mem, &head, cnt))
+ {
+ munmap (mem, total);
+ dbg_log (_("invalid persistent database file \"%s\": %s"),
+ dbs[cnt].db_filename,
+ _("verification failed"));
+ unlink (dbs[cnt].db_filename);
+ }
else
{
/* Success. We have the database. */
@@ -378,20 +637,23 @@ cannot create read-only descriptor for \"%s\"; no mmap"),
if (offset % ps != 0)
{
towrite = MIN (remaining, ps - (offset % ps));
- pwrite (fd, tmpbuf, towrite, offset);
+ if (pwrite (fd, tmpbuf, towrite, offset) != towrite)
+ goto write_fail;
offset += towrite;
remaining -= towrite;
}
while (remaining > ps)
{
- pwrite (fd, tmpbuf, ps, offset);
+ if (pwrite (fd, tmpbuf, ps, offset) == -1)
+ goto write_fail;
offset += ps;
remaining -= ps;
}
- if (remaining > 0)
- pwrite (fd, tmpbuf, remaining, offset);
+ if (remaining > 0
+ && pwrite (fd, tmpbuf, remaining, offset) != remaining)
+ goto write_fail;
/* Create the header of the file. */
struct database_pers_head head =
@@ -407,10 +669,13 @@ cannot create read-only descriptor for \"%s\"; no mmap"),
if ((TEMP_FAILURE_RETRY (write (fd, &head, sizeof (head)))
!= sizeof (head))
- || ftruncate (fd, total) != 0
- || (mem = mmap (NULL, total, PROT_READ | PROT_WRITE,
+ || (TEMP_FAILURE_RETRY_VAL (posix_fallocate (fd, 0, total))
+ != 0)
+ || (mem = mmap (NULL, dbs[cnt].max_db_size,
+ PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0)) == MAP_FAILED)
{
+ write_fail:
unlink (dbs[cnt].db_filename);
dbg_log (_("cannot write to database file %s: %s"),
dbs[cnt].db_filename, strerror (errno));
@@ -461,7 +726,7 @@ cannot set socket to close on exec: %s; disabling paranoia mode"),
dbs[cnt].head = xmalloc (sizeof (struct database_pers_head)
+ (dbs[cnt].suggested_module
* sizeof (ref_t)));
- memset (dbs[cnt].head, '\0', sizeof (dbs[cnt].head));
+ memset (dbs[cnt].head, '\0', sizeof (struct database_pers_head));
assert (~ENDREF == 0);
memset (dbs[cnt].head->array, '\xff',
dbs[cnt].suggested_module * sizeof (ref_t));
@@ -478,9 +743,9 @@ cannot set socket to close on exec: %s; disabling paranoia mode"),
if (dbs[cnt].check_file)
{
/* We need the modification date of the file. */
- struct stat st;
+ struct stat64 st;
- if (stat (dbs[cnt].filename, &st) < 0)
+ if (stat64 (dbs[cnt].filename, &st) < 0)
{
/* We cannot stat() the file, disable file checking. */
dbg_log (_("cannot stat() file `%s': %s"),
@@ -497,15 +762,16 @@ cannot set socket to close on exec: %s; disabling paranoia mode"),
if (sock < 0)
{
dbg_log (_("cannot open socket: %s"), strerror (errno));
- exit (1);
+ exit (errno == EACCES ? 4 : 1);
}
/* Bind a name to the socket. */
+ struct sockaddr_un sock_addr;
sock_addr.sun_family = AF_UNIX;
strcpy (sock_addr.sun_path, _PATH_NSCDSOCKET);
if (bind (sock, (struct sockaddr *) &sock_addr, sizeof (sock_addr)) < 0)
{
dbg_log ("%s: %s", _PATH_NSCDSOCKET, strerror (errno));
- exit (1);
+ exit (errno == EACCES ? 4 : 1);
}
/* We don't want to get stuck on accept. */
@@ -551,9 +817,10 @@ close_sockets (void)
static void
-invalidate_cache (char *key)
+invalidate_cache (char *key, int fd)
{
dbtype number;
+ int32_t resp;
if (strcmp (key, "passwd") == 0)
number = pwddb;
@@ -567,10 +834,19 @@ invalidate_cache (char *key)
res_init ();
}
else
- return;
+ {
+ resp = EINVAL;
+ writeall (fd, &resp, sizeof (resp));
+ return;
+ }
if (dbs[number].enabled)
- prune_cache (&dbs[number], LONG_MAX);
+ prune_cache (&dbs[number], LONG_MAX, fd);
+ else
+ {
+ resp = 0;
+ writeall (fd, &resp, sizeof (resp));
+ }
}
@@ -588,9 +864,14 @@ send_ro_fd (struct database_dyn *db, char *key, int fd)
iov[0].iov_len = strlen (key) + 1;
/* Prepare the control message to transfer the descriptor. */
- char buf[CMSG_SPACE (sizeof (int))];
+ union
+ {
+ struct cmsghdr hdr;
+ char bytes[CMSG_SPACE (sizeof (int))];
+ } buf;
struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1,
- .msg_control = buf, .msg_controllen = sizeof (buf) };
+ .msg_control = buf.bytes,
+ .msg_controllen = sizeof (buf) };
struct cmsghdr *cmsg = CMSG_FIRSTHDR (&msg);
cmsg->cmsg_level = SOL_SOCKET;
@@ -603,7 +884,10 @@ send_ro_fd (struct database_dyn *db, char *key, int fd)
/* Send the control message. We repeat when we are interrupted but
everything else is ignored. */
- (void) TEMP_FAILURE_RETRY (sendmsg (fd, &msg, 0));
+#ifndef MSG_NOSIGNAL
+# define MSG_NOSIGNAL 0
+#endif
+ (void) TEMP_FAILURE_RETRY (sendmsg (fd, &msg, MSG_NOSIGNAL));
if (__builtin_expect (debug_level > 0, 0))
dbg_log (_("provide access to FD %d, for %s"), db->ro_fd, key);
@@ -660,8 +944,9 @@ cannot handle old request version %d; current version is %d"),
if (!db->enabled)
{
/* No, sent the prepared record. */
- if (TEMP_FAILURE_RETRY (write (fd, db->disabled_iov->iov_base,
- db->disabled_iov->iov_len))
+ if (TEMP_FAILURE_RETRY (send (fd, db->disabled_iov->iov_base,
+ db->disabled_iov->iov_len,
+ MSG_NOSIGNAL))
!= (ssize_t) db->disabled_iov->iov_len
&& __builtin_expect (debug_level, 0) > 0)
{
@@ -688,8 +973,34 @@ cannot handle old request version %d; current version is %d"),
if (cached != NULL)
{
/* Hurray it's in the cache. */
- if (TEMP_FAILURE_RETRY (write (fd, cached->data, cached->recsize))
- != cached->recsize
+ ssize_t nwritten;
+
+#ifdef HAVE_SENDFILE
+ if (db->mmap_used || !cached->notfound)
+ {
+ assert (db->wr_fd != -1);
+ assert ((char *) cached->data > (char *) db->data);
+ assert ((char *) cached->data - (char *) db->head
+ + cached->recsize
+ <= (sizeof (struct database_pers_head)
+ + db->head->module * sizeof (ref_t)
+ + db->head->data_size));
+ nwritten = sendfileall (fd, db->wr_fd,
+ (char *) cached->data
+ - (char *) db->head, cached->recsize);
+# ifndef __ASSUME_SENDFILE
+ if (nwritten == -1 && errno == ENOSYS)
+ goto use_write;
+# endif
+ }
+ else
+# ifndef __ASSUME_SENDFILE
+ use_write:
+# endif
+#endif
+ nwritten = writeall (fd, cached->data, cached->recsize);
+
+ if (nwritten != cached->recsize
&& __builtin_expect (debug_level, 0) > 0)
{
/* We have problems sending the result. */
@@ -759,29 +1070,28 @@ cannot handle old request version %d; current version is %d"),
case GETSTAT:
case SHUTDOWN:
case INVALIDATE:
- if (! secure_in_use)
- {
- /* Get the callers credentials. */
+ {
+ /* Get the callers credentials. */
#ifdef SO_PEERCRED
- struct ucred caller;
- socklen_t optlen = sizeof (caller);
+ struct ucred caller;
+ socklen_t optlen = sizeof (caller);
- if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
- {
- char buf[256];
+ if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
+ {
+ char buf[256];
- dbg_log (_("error getting callers id: %s"),
- strerror_r (errno, buf, sizeof (buf)));
- break;
- }
+ dbg_log (_("error getting caller's id: %s"),
+ strerror_r (errno, buf, sizeof (buf)));
+ break;
+ }
- uid = caller.uid;
+ uid = caller.uid;
#else
- /* Some systems have no SO_PEERCRED implementation. They don't
- care about security so we don't as well. */
- uid = 0;
+ /* Some systems have no SO_PEERCRED implementation. They don't
+ care about security so we don't as well. */
+ uid = 0;
#endif
- }
+ }
/* Accept shutdown, getstat and invalidate only from root. For
the stat call also allow the user specified in the config file. */
@@ -793,7 +1103,7 @@ cannot handle old request version %d; current version is %d"),
else if (uid == 0)
{
if (req->type == INVALIDATE)
- invalidate_cache (key);
+ invalidate_cache (key, fd);
else
termination_handler (0);
}
@@ -880,7 +1190,7 @@ cannot open /proc/self/cmdline: %s; disabling paranoia mode"),
/* Second, change back to the old user if we changed it. */
if (server_user != NULL)
{
- if (setuid (old_uid) != 0)
+ if (setresuid (old_uid, old_uid, old_uid) != 0)
{
dbg_log (_("\
cannot change to old UID: %s; disabling paranoia mode"),
@@ -890,7 +1200,7 @@ cannot change to old UID: %s; disabling paranoia mode"),
return;
}
- if (setgid (old_gid) != 0)
+ if (setresgid (old_gid, old_gid, old_gid) != 0)
{
dbg_log (_("\
cannot change to old GID: %s; disabling paranoia mode"),
@@ -941,7 +1251,9 @@ cannot change to old working directory: %s; disabling paranoia mode"),
setuid (server_uid);
setgid (server_gid);
}
- chdir ("/");
+ if (chdir ("/") != 0)
+ dbg_log (_("cannot change current working directory to \"/\": %s"),
+ strerror (errno));
paranoia = 0;
}
@@ -1018,6 +1330,10 @@ nscd_run (void *p)
if (readylist == NULL && to == ETIMEDOUT)
{
--nready;
+
+ if (sighup_pending)
+ goto sighup_prune;
+
pthread_mutex_unlock (&readylist_lock);
goto only_prune;
}
@@ -1027,6 +1343,34 @@ nscd_run (void *p)
pthread_cond_wait (&readylist_cond, &readylist_lock);
}
+ if (sighup_pending)
+ {
+ --nready;
+ pthread_cond_signal (&readylist_cond);
+ sighup_prune:
+ sighup_pending = 0;
+ pthread_mutex_unlock (&readylist_lock);
+
+ /* Prune the password database. */
+ if (dbs[pwddb].enabled)
+ prune_cache (&dbs[pwddb], LONG_MAX, -1);
+
+ /* Prune the group database. */
+ if (dbs[grpdb].enabled)
+ prune_cache (&dbs[grpdb], LONG_MAX, -1);
+
+ /* Prune the host database. */
+ if (dbs[hstdb].enabled)
+ prune_cache (&dbs[hstdb], LONG_MAX, -1);
+
+ /* Re-locking. */
+ pthread_mutex_lock (&readylist_lock);
+
+ /* One more thread available. */
+ ++nready;
+ continue;
+ }
+
struct fdlist *it = readylist->next;
if (readylist->next == readylist)
/* Just one entry on the list. */
@@ -1073,25 +1417,7 @@ nscd_run (void *p)
#ifdef SO_PEERCRED
pid_t pid = 0;
- if (secure_in_use)
- {
- struct ucred caller;
- socklen_t optlen = sizeof (caller);
-
- if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
- {
- dbg_log (_("error getting callers id: %s"),
- strerror_r (errno, buf, sizeof (buf)));
- goto close_and_out;
- }
-
- if (req.type < GETPWBYNAME || req.type > LASTDBREQ
- || serv2db[req.type]->secure)
- uid = caller.uid;
-
- pid = caller.pid;
- }
- else if (__builtin_expect (debug_level > 0, 0))
+ if (__builtin_expect (debug_level > 0, 0))
{
struct ucred caller;
socklen_t optlen = sizeof (caller);
@@ -1155,8 +1481,7 @@ handle_request: request received (Version = %d)"), req.version);
/* The pthread_cond_timedwait() call timed out. It is time
to clean up the cache. */
assert (my_number < lastdb);
- prune_cache (&dbs[my_number],
- prune_ts.tv_sec + (prune_ts.tv_nsec >= 500000000));
+ prune_cache (&dbs[my_number], time (NULL), -1);
if (clock_gettime (timeout_clock, &prune_ts) == -1)
/* Should never happen. */
@@ -1217,7 +1542,7 @@ fd_ready (int fd)
{
/* We got another thread. */
++nthreads;
- /* The new thread might new a kick. */
+ /* The new thread might need a kick. */
do_signal = true;
}
@@ -1280,18 +1605,24 @@ main_loop_poll (void)
/* We have a new incoming connection. Accept the connection. */
int fd = TEMP_FAILURE_RETRY (accept (sock, NULL, NULL));
- /* use the descriptor if we have not reached the limit. */
- if (fd >= 0 && firstfree < nconns)
+ /* Use the descriptor if we have not reached the limit. */
+ if (fd >= 0)
{
- conns[firstfree].fd = fd;
- conns[firstfree].events = POLLRDNORM;
- starttime[firstfree] = now;
- if (firstfree >= nused)
- nused = firstfree + 1;
-
- do
- ++firstfree;
- while (firstfree < nused && conns[firstfree].fd != -1);
+ if (firstfree < nconns)
+ {
+ conns[firstfree].fd = fd;
+ conns[firstfree].events = POLLRDNORM;
+ starttime[firstfree] = now;
+ if (firstfree >= nused)
+ nused = firstfree + 1;
+
+ do
+ ++firstfree;
+ while (firstfree < nused && conns[firstfree].fd != -1);
+ }
+ else
+ /* We cannot use the connection so close it. */
+ close (fd);
}
--n;
@@ -1402,10 +1733,9 @@ main_loop_epoll (int efd)
else
{
/* Remove the descriptor from the epoll descriptor. */
- struct epoll_event ev = { 0, };
- (void) epoll_ctl (efd, EPOLL_CTL_DEL, revs[cnt].data.fd, &ev);
+ (void) epoll_ctl (efd, EPOLL_CTL_DEL, revs[cnt].data.fd, NULL);
- /* Get a worked to handle the request. */
+ /* Get a worker to handle the request. */
fd_ready (revs[cnt].data.fd);
/* Reset the time. */
@@ -1425,8 +1755,7 @@ main_loop_epoll (int efd)
if (cnt != sock && starttime[cnt] != 0 && starttime[cnt] < laststart)
{
/* We are waiting for this one for too long. Close it. */
- struct epoll_event ev = {0, };
- (void) epoll_ctl (efd, EPOLL_CTL_DEL, cnt, &ev);
+ (void) epoll_ctl (efd, EPOLL_CTL_DEL, cnt, NULL);
(void) close (cnt);
@@ -1579,23 +1908,49 @@ begin_drop_privileges (void)
static void
finish_drop_privileges (void)
{
+#if defined HAVE_LIBAUDIT && defined HAVE_LIBCAP
+ /* We need to preserve the capabilities to connect to the audit daemon. */
+ cap_t new_caps = preserve_capabilities ();
+#endif
+
if (setgroups (server_ngroups, server_groups) == -1)
{
dbg_log (_("Failed to run nscd as user '%s'"), server_user);
error (EXIT_FAILURE, errno, _("setgroups failed"));
}
- if (setgid (server_gid) == -1)
+ int res;
+ if (paranoia)
+ res = setresgid (server_gid, server_gid, old_gid);
+ else
+ res = setgid (server_gid);
+ if (res == -1)
{
dbg_log (_("Failed to run nscd as user '%s'"), server_user);
perror ("setgid");
- exit (1);
+ exit (4);
}
- if (setuid (server_uid) == -1)
+ if (paranoia)
+ res = setresuid (server_uid, server_uid, old_uid);
+ else
+ res = setuid (server_uid);
+ if (res == -1)
{
dbg_log (_("Failed to run nscd as user '%s'"), server_user);
perror ("setuid");
- exit (1);
+ exit (4);
}
+
+#if defined HAVE_LIBAUDIT && defined HAVE_LIBCAP
+ /* Remove the temporary capabilities. */
+ install_real_capabilities (new_caps);
+#endif
+}
+
+/* Handle the HUP signal which will force a dump of the cache */
+void
+sighup_handler (int signum)
+{
+ sighup_pending = 1;
}
diff --git a/nscd/dbg_log.c b/nscd/dbg_log.c
index afa06dcbe9..d64afc7e8d 100644
--- a/nscd/dbg_log.c
+++ b/nscd/dbg_log.c
@@ -1,21 +1,19 @@
-/* Copyright (c) 1998, 2000, 2004 Free Software Foundation, Inc.
+/* Copyright (c) 1998, 2000, 2004, 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
- The GNU C Library is distributed in the hope that it will be useful,
+ This program 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU 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. */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <stdarg.h>
#include <stdio.h>
@@ -44,7 +42,7 @@ init_logfile (void)
{
if (logfilename)
{
- dbgout = fopen (logfilename, "a");
+ dbgout = fopen64 (logfilename, "a");
return dbgout == NULL ? 0 : 1;
}
return 1;
diff --git a/nscd/gai.c b/nscd/gai.c
index 722c7e415d..68719d876a 100644
--- a/nscd/gai.c
+++ b/nscd/gai.c
@@ -1,3 +1,21 @@
+/* Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 2004.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <alloca.h>
/* This file uses the getaddrinfo code but it compiles it without NSCD
support. We just need a few symbol renames. */
#define __getservbyname_r getservbyname_r
@@ -8,6 +26,9 @@
#define __bind bind
#define __sendto sendto
#define __strchrnul strchrnul
+#define __getline getline
+/* nscd uses 1MB or 2MB thread stacks. */
+#define __libc_use_alloca(size) (size <= __MAX_ALLOCA_CUTOFF)
#include <getaddrinfo.c>
diff --git a/nscd/getgrgid_r.c b/nscd/getgrgid_r.c
index d46fb0fcac..037509d8aa 100644
--- a/nscd/getgrgid_r.c
+++ b/nscd/getgrgid_r.c
@@ -1,21 +1,19 @@
-/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998, 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
- 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.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
- The GNU C Library is distributed in the hope that it will be useful,
+ This program 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU 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. */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <grp.h>
diff --git a/nscd/getgrnam_r.c b/nscd/getgrnam_r.c
index 42daa16177..8fc74dcbaf 100644
--- a/nscd/getgrnam_r.c
+++ b/nscd/getgrnam_r.c
@@ -1,21 +1,19 @@
-/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998, 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
- 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.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
- The GNU C Library is distributed in the hope that it will be useful,
+ This program 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU 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. */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <grp.h>
diff --git a/nscd/gethstbyad_r.c b/nscd/gethstbyad_r.c
index 47ed3e22e7..4c02492101 100644
--- a/nscd/gethstbyad_r.c
+++ b/nscd/gethstbyad_r.c
@@ -1,21 +1,19 @@
-/* Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1996,1997,1998,1999,2000,2005 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
- 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.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
- The GNU C Library is distributed in the hope that it will be useful,
+ This program 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU 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. */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <netdb.h>
diff --git a/nscd/gethstbynm2_r.c b/nscd/gethstbynm2_r.c
index b0cc713a84..416b5ceafa 100644
--- a/nscd/gethstbynm2_r.c
+++ b/nscd/gethstbynm2_r.c
@@ -1,21 +1,19 @@
-/* Copyright (C) 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998, 2000, 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
- 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.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
- The GNU C Library is distributed in the hope that it will be useful,
+ This program 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU 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. */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <ctype.h>
#include <errno.h>
diff --git a/nscd/getpwnam_r.c b/nscd/getpwnam_r.c
index df73b99e4a..c92209a0cf 100644
--- a/nscd/getpwnam_r.c
+++ b/nscd/getpwnam_r.c
@@ -1,21 +1,19 @@
-/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998, 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
- 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.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
- The GNU C Library is distributed in the hope that it will be useful,
+ This program 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU 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. */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <pwd.h>
diff --git a/nscd/getpwuid_r.c b/nscd/getpwuid_r.c
index 015a521bbe..f68951511e 100644
--- a/nscd/getpwuid_r.c
+++ b/nscd/getpwuid_r.c
@@ -1,21 +1,19 @@
-/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998, 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
- 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.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
- The GNU C Library is distributed in the hope that it will be useful,
+ This program 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU 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. */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <pwd.h>
diff --git a/nscd/grpcache.c b/nscd/grpcache.c
index c565f5a682..c207492cc0 100644
--- a/nscd/grpcache.c
+++ b/nscd/grpcache.c
@@ -1,22 +1,20 @@
/* Cache handling for group lookup.
- Copyright (C) 1998-2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1998-2005, 2006, 2007 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.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
- The GNU C Library is distributed in the hope that it will be useful,
+ This program 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU 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. */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <alloca.h>
#include <assert.h>
@@ -32,10 +30,14 @@
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
+#include <sys/socket.h>
#include <stackinfo.h>
#include "nscd.h"
#include "dbg_log.h"
+#ifdef HAVE_SENDFILE
+# include <kernel-features.h>
+#endif
/* This is the standard reply in case the service is disabled. */
static const gr_response_header disabled =
@@ -107,7 +109,8 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req,
case. */
total = sizeof (notfound);
- written = TEMP_FAILURE_RETRY (write (fd, &notfound, total));
+ written = TEMP_FAILURE_RETRY (send (fd, &notfound, total,
+ MSG_NOSIGNAL));
dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len);
/* If we cannot permanently store the result, so be it. */
@@ -167,7 +170,7 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req,
char *gr_name;
char *cp;
const size_t key_len = strlen (key);
- const size_t buf_len = 3 + sizeof (grp->gr_gid) + key_len + 1;
+ const size_t buf_len = 3 * sizeof (grp->gr_gid) + key_len + 1;
char *buf = alloca (buf_len);
ssize_t n;
size_t cnt;
@@ -276,6 +279,7 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req,
/* Adjust pointers into the memory block. */
gr_name = (char *) newp + (gr_name - (char *) dataset);
cp = (char *) newp + (cp - (char *) dataset);
+ key_copy = (char *) newp + (key_copy - (char *) dataset);
dataset = memcpy (newp, dataset, total + n);
alloca_used = false;
@@ -292,7 +296,30 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req,
unnecessarily let the receiver wait. */
assert (fd != -1);
- written = TEMP_FAILURE_RETRY (write (fd, &dataset->resp, total));
+#ifdef HAVE_SENDFILE
+ if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
+ {
+ assert (db->wr_fd != -1);
+ assert ((char *) &dataset->resp > (char *) db->data);
+ assert ((char *) &dataset->resp - (char *) db->head
+ + total
+ <= (sizeof (struct database_pers_head)
+ + db->head->module * sizeof (ref_t)
+ + db->head->data_size));
+ written = sendfileall (fd, db->wr_fd,
+ (char *) &dataset->resp
+ - (char *) db->head, total);
+# ifndef __ASSUME_SENDFILE
+ if (written == -1 && errno == ENOSYS)
+ goto use_write;
+# endif
+ }
+ else
+# ifndef __ASSUME_SENDFILE
+ use_write:
+# endif
+#endif
+ written = writeall (fd, &dataset->resp, total);
}
/* Add the record to the database. But only if it has not been
@@ -316,10 +343,10 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req,
marked with FIRST first. Otherwise we end up with
dangling "pointers" in case a latter hash entry cannot be
added. */
- bool first = req->type == GETGRBYNAME;
+ bool first = true;
/* If the request was by GID, add that entry first. */
- if (req->type != GETGRBYNAME)
+ if (req->type == GETGRBYGID)
{
if (cache_add (GETGRBYGID, cp, key_offset, &dataset->head, true,
db, owner) < 0)
@@ -329,12 +356,14 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req,
dataset->head.usable = false;
goto out;
}
+
+ first = false;
}
/* If the key is different from the name add a separate entry. */
else if (strcmp (key_copy, gr_name) != 0)
{
if (cache_add (GETGRBYNAME, key_copy, key_len + 1,
- &dataset->head, first, db, owner) < 0)
+ &dataset->head, true, db, owner) < 0)
{
/* Could not allocate memory. Make sure the data gets
discarded. */
@@ -346,11 +375,13 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req,
}
/* We have to add the value for both, byname and byuid. */
- if (__builtin_expect (cache_add (GETGRBYNAME, gr_name, gr_name_len,
- &dataset->head, first, db, owner)
- == 0, 1))
+ if ((req->type == GETGRBYNAME || db->propagate)
+ && __builtin_expect (cache_add (GETGRBYNAME, gr_name,
+ gr_name_len,
+ &dataset->head, first, db, owner)
+ == 0, 1))
{
- if (req->type == GETGRBYNAME)
+ if (req->type == GETGRBYNAME && db->propagate)
(void) cache_add (GETGRBYGID, cp, key_offset, &dataset->head,
req->type != GETGRBYNAME, db, owner);
}
@@ -429,11 +460,10 @@ addgrbyX (struct database_dyn *db, int fd, request_header *req,
{
char *old_buffer = buffer;
errno = 0;
-#define INCR 1024
if (__builtin_expect (buflen > 32768, 0))
{
- buflen += INCR;
+ buflen *= 2;
buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
if (buffer == NULL)
{
@@ -454,7 +484,7 @@ addgrbyX (struct database_dyn *db, int fd, request_header *req,
else
/* Allocate a new buffer on the stack. If possible combine it
with the previously allocated buffer. */
- buffer = (char *) extend_alloca (buffer, buflen, buflen + INCR);
+ buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
}
#if 0
diff --git a/nscd/hstcache.c b/nscd/hstcache.c
index 99d2998f49..e27ece5bc6 100644
--- a/nscd/hstcache.c
+++ b/nscd/hstcache.c
@@ -1,22 +1,20 @@
/* Cache handling for host lookup.
- Copyright (C) 1998-2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1998-2005, 2006 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.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
- The GNU C Library is distributed in the hope that it will be useful,
+ This program 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU 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. */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <alloca.h>
#include <assert.h>
@@ -38,6 +36,9 @@
#include "nscd.h"
#include "dbg_log.h"
+#ifdef HAVE_SENDFILE
+# include <kernel-features.h>
+#endif
/* This is the standard reply in case the service is disabled. */
@@ -115,7 +116,8 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
written = total = sizeof (notfound);
if (fd != -1)
- written = TEMP_FAILURE_RETRY (write (fd, &notfound, total));
+ written = TEMP_FAILURE_RETRY (send (fd, &notfound, total,
+ MSG_NOSIGNAL));
dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len);
/* If we cannot permanently store the result, so be it. */
@@ -327,7 +329,30 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
unnecessarily keep the receiver waiting. */
assert (fd != -1);
- written = TEMP_FAILURE_RETRY (write (fd, &dataset->resp, total));
+#ifdef HAVE_SENDFILE
+ if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
+ {
+ assert (db->wr_fd != -1);
+ assert ((char *) &dataset->resp > (char *) db->data);
+ assert ((char *) &dataset->resp - (char *) db->head
+ + total
+ <= (sizeof (struct database_pers_head)
+ + db->head->module * sizeof (ref_t)
+ + db->head->data_size));
+ written = sendfileall (fd, db->wr_fd,
+ (char *) &dataset->resp
+ - (char *) db->head, total);
+# ifndef __ASSUME_SENDFILE
+ if (written == -1 && errno == ENOSYS)
+ goto use_write;
+# endif
+ }
+ else
+# ifndef __ASSUME_SENDFILE
+ use_write:
+# endif
+#endif
+ written = writeall (fd, &dataset->resp, total);
}
/* Add the record to the database. But only if it has not been
@@ -453,11 +478,10 @@ addhstbyX (struct database_dyn *db, int fd, request_header *req,
{
char *old_buffer = buffer;
errno = 0;
-#define INCR 1024
if (__builtin_expect (buflen > 32768, 0))
{
- buflen += INCR;
+ buflen *= 2;
buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
if (buffer == NULL)
{
@@ -478,7 +502,7 @@ addhstbyX (struct database_dyn *db, int fd, request_header *req,
else
/* Allocate a new buffer on the stack. If possible combine it
with the previously allocated buffer. */
- buffer = (char *) extend_alloca (buffer, buflen, buflen + INCR);
+ buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
}
#if 0
diff --git a/nscd/initgrcache.c b/nscd/initgrcache.c
index b46433716b..f1f859c552 100644
--- a/nscd/initgrcache.c
+++ b/nscd/initgrcache.c
@@ -1,22 +1,20 @@
/* Cache handling for host lookup.
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
- 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.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
- The GNU C Library is distributed in the hope that it will be useful,
+ This program 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU 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. */
+ You should have received a copy of the GNU General Public License
+ along with this program; 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>
@@ -26,8 +24,12 @@
#include <time.h>
#include <unistd.h>
#include <sys/mman.h>
-#include <dbg_log.h>
-#include <nscd.h>
+
+#include "dbg_log.h"
+#include "nscd.h"
+#ifdef HAVE_SENDFILE
+# include <kernel-features.h>
+#endif
#include "../nss/nsswitch.h"
@@ -105,6 +107,7 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req,
long int start = 0;
bool all_tryagain = true;
+ bool any_success = false;
/* This is temporary memory, we need not (ad must not) call
mempool_alloc. */
@@ -156,6 +159,8 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req,
if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN)
__libc_fatal ("illegal status in internal_getgrouplist");
+ any_success |= status == NSS_STATUS_SUCCESS;
+
if (status != NSS_STATUS_SUCCESS
&& nss_next_action (nip, status) == NSS_ACTION_RETURN)
break;
@@ -169,7 +174,7 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req,
ssize_t total;
ssize_t written;
out:
- if (start == 0)
+ if (!any_success)
{
/* Nothing found. Create a negative result record. */
written = total = sizeof (notfound);
@@ -188,7 +193,8 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req,
/* We have no data. This means we send the standard reply for this
case. */
if (fd != -1)
- written = TEMP_FAILURE_RETRY (write (fd, &notfound, total));
+ written = TEMP_FAILURE_RETRY (send (fd, &notfound, total,
+ MSG_NOSIGNAL));
dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len);
/* If we cannot permanently store the result, so be it. */
@@ -343,7 +349,30 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req,
unnecessarily let the receiver wait. */
assert (fd != -1);
- written = TEMP_FAILURE_RETRY (write (fd, &dataset->resp, total));
+#ifdef HAVE_SENDFILE
+ if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
+ {
+ assert (db->wr_fd != -1);
+ assert ((char *) &dataset->resp > (char *) db->data);
+ assert ((char *) &dataset->resp - (char *) db->head
+ + total
+ <= (sizeof (struct database_pers_head)
+ + db->head->module * sizeof (ref_t)
+ + db->head->data_size));
+ written = sendfileall (fd, db->wr_fd,
+ (char *) &dataset->resp
+ - (char *) db->head, total);
+# ifndef __ASSUME_SENDFILE
+ if (written == -1 && errno == ENOSYS)
+ goto use_write;
+# endif
+ }
+ else
+# ifndef __ASSUME_SENDFILE
+ use_write:
+# endif
+#endif
+ written = writeall (fd, &dataset->resp, total);
}
diff --git a/nscd/mem.c b/nscd/mem.c
index c3a0f96702..5206c5af38 100644
--- a/nscd/mem.c
+++ b/nscd/mem.c
@@ -1,26 +1,25 @@
/* Cache memory handling.
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
- 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.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
- The GNU C Library is distributed in the hope that it will be useful,
+ This program 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU 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. */
+ You should have received a copy of the GNU General Public License
+ along with this program; 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 <error.h>
+#include <fcntl.h>
#include <inttypes.h>
#include <libintl.h>
#include <limits.h>
@@ -34,12 +33,6 @@
#include "nscd.h"
-/* Maximum alignment requirement we will encounter. */
-#define BLOCK_ALIGN_LOG 3
-#define BLOCK_ALIGN (1 << BLOCK_ALIGN_LOG)
-#define BLOCK_ALIGN_M1 (BLOCK_ALIGN - 1)
-
-
static int
sort_he (const void *p1, const void *p2)
{
@@ -194,7 +187,7 @@ gc (struct database_dyn *db)
highref -= BLOCK_ALIGN;
}
- /* No we can iterate over the MARK array and find bits which are not
+ /* Now we can iterate over the MARK array and find bits which are not
set. These represent memory which can be recovered. */
size_t byte = 0;
/* Find the first gap. */
@@ -486,17 +479,26 @@ mempool_alloc (struct database_dyn *db, size_t len)
if (! tried_resize)
{
/* Try to resize the database. Grow size of 1/8th. */
- size_t new_data_size = db->head->data_size + db->head->data_size / 8;
size_t oldtotal = (sizeof (struct database_pers_head)
- + db->head->module * sizeof (ref_t)
+ + roundup (db->head->module * sizeof (ref_t), ALIGN)
+ db->head->data_size);
+ size_t new_data_size = (db->head->data_size
+ + MAX (2 * len, db->head->data_size / 8));
size_t newtotal = (sizeof (struct database_pers_head)
- + db->head->module * sizeof (ref_t)
+ + roundup (db->head->module * sizeof (ref_t), ALIGN)
+ new_data_size);
+ if (newtotal > db->max_db_size)
+ {
+ new_data_size -= newtotal - db->max_db_size;
+ newtotal = db->max_db_size;
+ }
- if ((!db->mmap_used || ftruncate (db->wr_fd, newtotal) != 0)
- /* Try to resize the mapping. Note: no MREMAP_MAYMOVE. */
- && mremap (db->head, oldtotal, newtotal, 0) == 0)
+ if (db->mmap_used && newtotal > oldtotal
+ /* We only have to adjust the file size. The new pages
+ become magically available. */
+ && TEMP_FAILURE_RETRY_VAL (posix_fallocate (db->wr_fd, oldtotal,
+ newtotal
+ - oldtotal)) == 0)
{
db->head->data_size = new_data_size;
tried_resize = true;
diff --git a/nscd/nscd-client.h b/nscd/nscd-client.h
index d49cb8136c..8946b6315b 100644
--- a/nscd/nscd-client.h
+++ b/nscd/nscd-client.h
@@ -1,4 +1,5 @@
-/* Copyright (c) 1998, 1999, 2000, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (c) 1998, 1999, 2000, 2003, 2004, 2005, 2006, 2007
+ Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
@@ -28,6 +29,7 @@
#include <sys/types.h>
#include <atomic.h>
#include <nscd-types.h>
+#include <sys/uio.h>
/* Version number of the daemon interface */
@@ -256,6 +258,7 @@ struct mapped_database
const char *data;
size_t mapsize;
int counter; /* > 0 indicates it is usable. */
+ size_t datasize;
};
#define NO_MAPPING ((struct mapped_database *) -1l)
@@ -275,7 +278,7 @@ extern int __nscd_open_socket (const char *key, size_t keylen,
/* Get reference of mapping. */
extern struct mapped_database *__nscd_get_map_ref (request_type type,
const char *name,
- struct locked_map_ptr *mapptr,
+ volatile struct locked_map_ptr *mapptr,
int *gc_cyclep);
/* Unmap database. */
@@ -304,9 +307,20 @@ static inline int __nscd_drop_map_ref (struct mapped_database *map,
/* 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);
+extern struct datahead *__nscd_cache_search (request_type type,
+ const char *key,
+ size_t keylen,
+ const struct mapped_database *mapped);
+
+/* Wrappers around read, readv and write that only read/write less than LEN
+ bytes on error or EOF. */
+extern ssize_t __readall (int fd, void *buf, size_t len)
+ attribute_hidden;
+extern ssize_t __readvall (int fd, const struct iovec *iov, int iovcnt)
+ attribute_hidden;
+extern ssize_t writeall (int fd, const void *buf, size_t len)
+ attribute_hidden;
+extern ssize_t sendfileall (int tofd, int fromfd, off_t off, size_t len)
+ attribute_hidden;
#endif /* nscd.h */
diff --git a/nscd/nscd.c b/nscd/nscd.c
index 0cc1818d9d..588b09d4fb 100644
--- a/nscd/nscd.c
+++ b/nscd/nscd.c
@@ -1,21 +1,19 @@
-/* Copyright (c) 1998-2003, 2004 Free Software Foundation, Inc.
+/* Copyright (c) 1998-2003, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@suse.de>, 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.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
- The GNU C Library is distributed in the hope that it will be useful,
+ This program 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU 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. */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* nscd - Name Service Cache Daemon. Caches passwd, group, and hosts. */
@@ -72,7 +70,6 @@ int disabled_passwd;
int disabled_group;
int go_background = 1;
-int secure_in_use;
static const char *conffile = _PATH_NSCDCONF;
time_t start_time;
@@ -122,6 +119,9 @@ static struct argp argp =
options, parse_opt, NULL, doc,
};
+/* The SIGHUP handler is extern to this file */
+extern void sighup_handler(int signum);
+
/* True if only statistics are requested. */
static bool get_stats;
@@ -145,17 +145,15 @@ main (int argc, char **argv)
{
error (0, 0, gettext ("wrong number of arguments"));
argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
- exit (EXIT_FAILURE);
+ exit (1);
}
/* Read the configuration file. */
if (nscd_parse_file (conffile, dbs) != 0)
- {
- /* We couldn't read the configuration file. We don't start the
- server. */
- dbg_log (_("cannot read configuration file; this is fatal"));
- exit (1);
- }
+ /* We couldn't read the configuration file. We don't start the
+ server. */
+ error (EXIT_FAILURE, 0,
+ _("failure while reading configuration file; this is fatal"));
/* Do we only get statistics? */
if (get_stats)
@@ -240,7 +238,9 @@ main (int argc, char **argv)
setsid ();
- chdir ("/");
+ if (chdir ("/") != 0)
+ error (EXIT_FAILURE, errno,
+ _("cannot change current working directory to \"/\""));
openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
@@ -266,6 +266,7 @@ main (int argc, char **argv)
signal (SIGINT, termination_handler);
signal (SIGQUIT, termination_handler);
signal (SIGTERM, termination_handler);
+ signal (SIGHUP, sighup_handler);
signal (SIGPIPE, SIG_IGN);
/* Cleanup files created by a previous 'bind'. */
@@ -301,7 +302,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
case 'K':
if (getuid () != 0)
- error (EXIT_FAILURE, 0, _("Only root is allowed to use this option!"));
+ error (4, 0, _("Only root is allowed to use this option!"));
{
int sock = nscd_open_socket ();
request_header req;
@@ -313,8 +314,9 @@ parse_opt (int key, char *arg, struct argp_state *state)
req.version = NSCD_VERSION;
req.type = SHUTDOWN;
req.key_len = 0;
- nbytes = TEMP_FAILURE_RETRY (write (sock, &req,
- sizeof (request_header)));
+ nbytes = TEMP_FAILURE_RETRY (send (sock, &req,
+ sizeof (request_header),
+ MSG_NOSIGNAL));
close (sock);
exit (nbytes != sizeof (request_header) ? EXIT_FAILURE : EXIT_SUCCESS);
}
@@ -325,7 +327,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
case 'i':
if (getuid () != 0)
- error (EXIT_FAILURE, 0, _("Only root is allowed to use this option!"));
+ error (4, 0, _("Only root is allowed to use this option!"));
else
{
int sock = nscd_open_socket ();
@@ -334,9 +336,6 @@ parse_opt (int key, char *arg, struct argp_state *state)
exit (EXIT_FAILURE);
request_header req;
- ssize_t nbytes;
- struct iovec iov[2];
-
if (strcmp (arg, "passwd") == 0)
req.key_len = sizeof "passwd";
else if (strcmp (arg, "group") == 0)
@@ -349,17 +348,38 @@ parse_opt (int key, char *arg, struct argp_state *state)
req.version = NSCD_VERSION;
req.type = INVALIDATE;
+ struct iovec iov[2];
iov[0].iov_base = &req;
iov[0].iov_len = sizeof (req);
iov[1].iov_base = arg;
iov[1].iov_len = req.key_len;
- nbytes = TEMP_FAILURE_RETRY (writev (sock, iov, 2));
+ ssize_t nbytes = TEMP_FAILURE_RETRY (writev (sock, iov, 2));
+
+ if (nbytes != iov[0].iov_len + iov[1].iov_len)
+ {
+ int err = errno;
+ close (sock);
+ error (EXIT_FAILURE, err, _("write incomplete"));
+ }
+
+ /* Wait for ack. Older nscd just closed the socket when
+ prune_cache finished, silently ignore that. */
+ int32_t resp = 0;
+ nbytes = TEMP_FAILURE_RETRY (read (sock, &resp, sizeof (resp)));
+ if (nbytes != 0 && nbytes != sizeof (resp))
+ {
+ int err = errno;
+ close (sock);
+ error (EXIT_FAILURE, err, _("cannot read invalidate ACK"));
+ }
close (sock);
- exit (nbytes != iov[0].iov_len + iov[1].iov_len
- ? EXIT_FAILURE : EXIT_SUCCESS);
+ if (resp != 0)
+ error (EXIT_FAILURE, resp, _("invalidation failed"));
+
+ exit (0);
}
case 't':
@@ -367,16 +387,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
break;
case 'S':
-#if 0
- if (strcmp (arg, "passwd,yes") == 0)
- secure_in_use = dbs[pwddb].secure = 1;
- else if (strcmp (arg, "group,yes") == 0)
- secure_in_use = dbs[grpdb].secure = 1;
- else if (strcmp (arg, "hosts,yes") == 0)
- secure_in_use = dbs[hstdb].secure = 1;
-#else
error (0, 0, _("secure services not implemented anymore"));
-#endif
break;
default:
@@ -395,7 +406,7 @@ print_version (FILE *stream, struct argp_state *state)
Copyright (C) %s Free Software Foundation, Inc.\n\
This is free software; see the source for copying conditions. There is NO\n\
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
-"), "2004");
+"), "2006");
fprintf (stream, gettext ("Written by %s.\n"),
"Thorsten Kukuk and Ulrich Drepper");
}
@@ -442,6 +453,9 @@ termination_handler (int signum)
/* Synchronize memory. */
for (int cnt = 0; cnt < lastdb; ++cnt)
{
+ if (!dbs[cnt].enabled)
+ continue;
+
/* Make sure nobody keeps using the database. */
dbs[cnt].head->timestamp = 0;
@@ -495,10 +509,10 @@ write_pid (const char *file)
return -1;
fprintf (fp, "%d\n", getpid ());
- if (fflush (fp) || ferror (fp))
- return -1;
+
+ int result = fflush (fp) || ferror (fp) ? -1 : 0;
fclose (fp);
- return 0;
+ return result;
}
diff --git a/nscd/nscd.conf b/nscd/nscd.conf
index 87e7a84487..954eafd554 100644
--- a/nscd/nscd.conf
+++ b/nscd/nscd.conf
@@ -23,6 +23,8 @@
# check-files <service> <yes|no>
# persistent <service> <yes|no>
# shared <service> <yes|no>
+# max-db-size <service> <number bytes>
+# auto-propagate <service> <yes|no>
#
# Currently supported cache names (services): passwd, group, hosts
#
@@ -31,8 +33,8 @@
# logfile /var/log/nscd.log
# threads 6
# max-threads 128
-# server-user nobody
-# stat-user somebody
+ server-user nscd
+# stat-user nocpulse
debug-level 0
# reload-count 5
paranoia no
@@ -45,6 +47,8 @@
check-files passwd yes
persistent passwd yes
shared passwd yes
+ max-db-size passwd 33554432
+ auto-propagate passwd yes
enable-cache group yes
positive-time-to-live group 3600
@@ -53,6 +57,8 @@
check-files group yes
persistent group yes
shared group yes
+ max-db-size group 33554432
+ auto-propagate group yes
enable-cache hosts yes
positive-time-to-live hosts 3600
@@ -61,3 +67,4 @@
check-files hosts yes
persistent hosts yes
shared hosts yes
+ max-db-size hosts 33554432
diff --git a/nscd/nscd.h b/nscd/nscd.h
index d5dc613d22..5c2ff3a95b 100644
--- a/nscd/nscd.h
+++ b/nscd/nscd.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 1998, 1999, 2000, 2001, 2003, 2004
+/* Copyright (c) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
@@ -58,16 +58,18 @@ typedef enum
struct database_dyn
{
pthread_rwlock_t lock;
+ pthread_mutex_t prunelock;
int enabled;
int check_file;
int persistent;
int shared;
- const char *filename;
+ int propagate;
+ const char filename[12];
const char *db_filename;
time_t file_mtime;
size_t suggested_module;
- int secure;
+ size_t max_db_size;
unsigned long int postimeout; /* In seconds. */
unsigned long int negtimeout; /* In seconds. */
@@ -94,6 +96,17 @@ struct database_dyn
/* Path used when not using persistent storage. */
#define _PATH_NSCD_XYZ_DB_TMP "/var/run/nscd/dbXXXXXX"
+/* Maximum alignment requirement we will encounter. */
+#define BLOCK_ALIGN_LOG 3
+#define BLOCK_ALIGN (1 << BLOCK_ALIGN_LOG)
+#define BLOCK_ALIGN_M1 (BLOCK_ALIGN - 1)
+
+/* Default value for the maximum size of the database files. */
+#define DEFAULT_MAX_DB_SIZE (32 * 1024 * 1024)
+
+/* Number of bytes of data we initially reserve for each hash table bucket. */
+#define DEFAULT_DATASIZE_PER_BUCKET 1024
+
/* Global variables. */
extern struct database_dyn dbs[lastdb];
@@ -110,9 +123,6 @@ extern int nthreads;
/* Maximum number of threads to use. */
extern int max_nthreads;
-/* Tables for which we cache data with uid. */
-extern int secure_in_use; /* Is one of the above 1? */
-
/* User name to run server processes as. */
extern const char *server_user;
@@ -175,7 +185,7 @@ extern struct datahead *cache_search (request_type, void *key, size_t len,
extern int cache_add (int type, const void *key, size_t len,
struct datahead *packet, bool first,
struct database_dyn *table, uid_t owner);
-extern void prune_cache (struct database_dyn *table, time_t now);
+extern void prune_cache (struct database_dyn *table, time_t now, int fd);
/* pwdcache.c */
extern void addpwbyname (struct database_dyn *db, int fd, request_header *req,
@@ -236,4 +246,14 @@ extern void gc (struct database_dyn *db);
/* nscd_setup_thread.c */
extern void setup_thread (struct database_dyn *db);
+
+/* Special version of TEMP_FAILURE_RETRY for functions returning error
+ values. */
+#define TEMP_FAILURE_RETRY_VAL(expression) \
+ (__extension__ \
+ ({ long int __result; \
+ do __result = (long int) (expression); \
+ while (__result == EINTR); \
+ __result; }))
+
#endif /* nscd.h */
diff --git a/nscd/nscd.init b/nscd/nscd.init
index d5c1cb9ae3..1fba72f5c3 100644
--- a/nscd/nscd.init
+++ b/nscd/nscd.init
@@ -9,7 +9,18 @@
# slow naming services like NIS, NIS+, LDAP, or hesiod.
# processname: /usr/sbin/nscd
# config: /etc/nscd.conf
+# config: /etc/sysconfig/nscd
#
+### BEGIN INIT INFO
+# Provides: nscd
+# Required-Start: $syslog
+# Default-Stop: 0 1 6
+# Short-Description: Starts the Name Switch Cache Daemon
+# Description: This is a daemon which handles passwd and group lookups \
+# for running programs and cache the results for the next \
+# query. You should start this daemon if you use \
+# slow naming services like NIS, NIS+, LDAP, or hesiod.
+### END INIT INFO
# Sanity checks.
[ -f /etc/nscd.conf ] || exit 0
@@ -18,20 +29,8 @@
# Source function library.
. /etc/init.d/functions
-# nscd does not run on any kernel lower than 2.2.0 because of threading
-# problems, so we require that in first place.
-case $(uname -r) in
- 2.[2-9].*)
- # this is okay
- ;;
- [3-9]*)
- # these are of course also okay
- ;;
- *)
- #this is not
- exit 0
- ;;
-esac
+# Source an auxiliary options file if we have one, and pick up NSCD_OPTIONS.
+[ -r /etc/sysconfig/nscd ] && . /etc/sysconfig/nscd
RETVAL=0
prog=nscd
@@ -47,7 +46,7 @@ start () {
# fi
# done
echo -n $"Starting $prog: "
- daemon /usr/sbin/nscd $secure
+ daemon /usr/sbin/nscd $secure $NSCD_OPTIONS
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/nscd
@@ -88,21 +87,23 @@ case "$1" in
RETVAL=$?
;;
status)
- status nscd
+ status nscd
RETVAL=$?
- ;;
+ ;;
restart)
restart
RETVAL=$?
;;
- condrestart)
+ try-restart | condrestart)
[ -e /var/lock/subsys/nscd ] && restart
RETVAL=$?
;;
- reload)
- killproc /usr/sbin/nscd -HUP
+ force-reload | reload)
+ echo -n $"Reloading $prog: "
+ killproc /usr/sbin/nscd -HUP
RETVAL=$?
- ;;
+ echo
+ ;;
*)
echo $"Usage: $0 {start|stop|status|restart|reload|condrestart}"
RETVAL=1
diff --git a/nscd/nscd_conf.c b/nscd/nscd_conf.c
index d21f2fc501..2048eca886 100644
--- a/nscd/nscd_conf.c
+++ b/nscd/nscd_conf.c
@@ -1,24 +1,23 @@
-/* Copyright (c) 1998, 2000, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (c) 1998,2000,2003,2004,2005,2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@suse.de>, 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.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
- The GNU C Library is distributed in the hope that it will be useful,
+ This program 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU 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. */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <ctype.h>
#include <errno.h>
+#include <error.h>
#include <libintl.h>
#include <malloc.h>
#include <pwd.h>
@@ -45,6 +44,18 @@ const char *dbnames[lastdb] =
[hstdb] = "hosts"
};
+
+static int
+find_db (const char *name)
+{
+ for (int cnt = 0; cnt < lastdb; ++cnt)
+ if (strcmp (name, dbnames[cnt]) == 0)
+ return cnt;
+
+ error (0, 0, _("database %s is not supported\n"), name);
+ return -1;
+}
+
int
nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb])
{
@@ -52,6 +63,7 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb])
char *line, *cp, *entry, *arg1, *arg2;
size_t len;
int cnt;
+ const unsigned int initial_error_message_count = error_message_count;
/* Open the configuration file. */
fp = fopen (fname, "r");
@@ -91,7 +103,7 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb])
++arg1;
*cp = '\0';
if (strlen (entry) == 0)
- dbg_log (_("Parse error: %s"), line);
+ error (0, 0, _("Parse error: %s"), line);
while (isspace (*arg1) && *arg1 != '\0')
++arg1;
cp = arg1;
@@ -112,64 +124,49 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb])
if (strcmp (entry, "positive-time-to-live") == 0)
{
- for (cnt = 0; cnt < lastdb; ++cnt)
- if (strcmp (arg1, dbnames[cnt]) == 0)
- {
- dbs[cnt].postimeout = atol (arg2);
- break;
- }
- if (cnt == lastdb)
- dbg_log ("database %s is not supported\n", arg1);
+ int idx = find_db (arg1);
+ if (idx >= 0)
+ dbs[idx].postimeout = atol (arg2);
}
else if (strcmp (entry, "negative-time-to-live") == 0)
{
- for (cnt = 0; cnt < lastdb; ++cnt)
- if (strcmp (arg1, dbnames[cnt]) == 0)
- {
- dbs[cnt].negtimeout = atol (arg2);
- break;
- }
- if (cnt == lastdb)
- dbg_log ("database %s is not supported\n", arg1);
+ int idx = find_db (arg1);
+ if (idx >= 0)
+ dbs[idx].negtimeout = atol (arg2);
}
else if (strcmp (entry, "suggested-size") == 0)
{
- for (cnt = 0; cnt < lastdb; ++cnt)
- if (strcmp (arg1, dbnames[cnt]) == 0)
- {
- dbs[cnt].suggested_module = atol (arg2);
- break;
- }
- if (cnt == lastdb)
- dbg_log ("database %s is not supported\n", arg1);
+ int idx = find_db (arg1);
+ if (idx >= 0)
+ dbs[idx].suggested_module = atol (arg2);
}
else if (strcmp (entry, "enable-cache") == 0)
{
- for (cnt = 0; cnt < lastdb; ++cnt)
- if (strcmp (arg1, dbnames[cnt]) == 0)
- {
- if (strcmp (arg2, "no") == 0)
- dbs[cnt].enabled = 0;
- else if (strcmp (arg2, "yes") == 0)
- dbs[cnt].enabled = 1;
- break;
- }
- if (cnt == lastdb)
- dbg_log ("database %s is not supported\n", arg1);
+ int idx = find_db (arg1);
+ if (idx >= 0)
+ {
+ if (strcmp (arg2, "no") == 0)
+ dbs[idx].enabled = 0;
+ else if (strcmp (arg2, "yes") == 0)
+ dbs[idx].enabled = 1;
+ }
}
else if (strcmp (entry, "check-files") == 0)
{
- for (cnt = 0; cnt < lastdb; ++cnt)
- if (strcmp (arg1, dbnames[cnt]) == 0)
- {
- if (strcmp (arg2, "no") == 0)
- dbs[cnt].check_file = 0;
- else if (strcmp (arg2, "yes") == 0)
- dbs[cnt].check_file = 1;
- break;
- }
- if (cnt == lastdb)
- dbg_log ("database %s is not supported\n", arg1);
+ int idx = find_db (arg1);
+ if (idx >= 0)
+ {
+ if (strcmp (arg2, "no") == 0)
+ dbs[idx].check_file = 0;
+ else if (strcmp (arg2, "yes") == 0)
+ dbs[idx].check_file = 1;
+ }
+ }
+ else if (strcmp (entry, "max-db-size") == 0)
+ {
+ int idx = find_db (arg1);
+ if (idx >= 0)
+ dbs[idx].max_db_size = atol (arg2);
}
else if (strcmp (entry, "logfile") == 0)
set_logfile (arg1);
@@ -191,14 +188,14 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb])
else if (strcmp (entry, "server-user") == 0)
{
if (!arg1)
- dbg_log (_("Must specify user name for server-user option"));
+ error (0, 0, _("Must specify user name for server-user option"));
else
server_user = xstrdup (arg1);
}
else if (strcmp (entry, "stat-user") == 0)
{
if (arg1 == NULL)
- dbg_log (_("Must specify user name for stat-user option"));
+ error (0, 0, _("Must specify user name for stat-user option"));
else
{
stat_user = xstrdup (arg1);
@@ -210,31 +207,25 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb])
}
else if (strcmp (entry, "persistent") == 0)
{
- for (cnt = 0; cnt < lastdb; ++cnt)
- if (strcmp (arg1, dbnames[cnt]) == 0)
- {
- if (strcmp (arg2, "no") == 0)
- dbs[cnt].persistent = 0;
- else if (strcmp (arg2, "yes") == 0)
- dbs[cnt].persistent = 1;
- break;
- }
- if (cnt == lastdb)
- dbg_log ("database %s is not supported\n", arg1);
+ int idx = find_db (arg1);
+ if (idx >= 0)
+ {
+ if (strcmp (arg2, "no") == 0)
+ dbs[idx].persistent = 0;
+ else if (strcmp (arg2, "yes") == 0)
+ dbs[idx].persistent = 1;
+ }
}
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);
+ int idx = find_db (arg1);
+ if (idx >= 0)
+ {
+ if (strcmp (arg2, "no") == 0)
+ dbs[idx].shared = 0;
+ else if (strcmp (arg2, "yes") == 0)
+ dbs[idx].shared = 1;
+ }
}
else if (strcmp (entry, "reload-count") == 0)
{
@@ -248,7 +239,7 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb])
else if (count >= 0)
reload_count = count;
else
- dbg_log (_("invalid value for 'reload-count': %u"), count);
+ error (0, 0, _("invalid value for 'reload-count': %u"), count);
}
}
else if (strcmp (entry, "paranoia") == 0)
@@ -263,10 +254,21 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb])
if (arg1 != NULL)
restart_interval = atol (arg1);
else
- dbg_log (_("Must specify value for restart-interval option"));
+ error (0, 0, _("Must specify value for restart-interval option"));
+ }
+ else if (strcmp (entry, "auto-propagate") == 0)
+ {
+ int idx = find_db (arg1);
+ if (idx >= 0)
+ {
+ if (strcmp (arg2, "no") == 0)
+ dbs[idx].propagate = 0;
+ else if (strcmp (arg2, "yes") == 0)
+ dbs[idx].propagate = 1;
+ }
}
else
- dbg_log (_("Unknown option: %s %s %s"), entry, arg1, arg2);
+ error (0, 0, _("Unknown option: %s %s %s"), entry, arg1, arg2);
}
while (!feof_unlocked (fp));
@@ -279,7 +281,7 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb])
oldcwd = get_current_dir_name ();
if (oldcwd == NULL)
{
- dbg_log (_("\
+ error (0, 0, _("\
cannot get current working directory: %s; disabling paranoia mode"),
strerror (errno));
paranoia = 0;
@@ -290,10 +292,26 @@ cannot get current working directory: %s; disabling paranoia mode"),
if (max_nthreads < nthreads)
max_nthreads = nthreads;
+ for (cnt = 0; cnt < lastdb; ++cnt)
+ {
+ size_t datasize = (sizeof (struct database_pers_head)
+ + roundup (dbs[cnt].suggested_module
+ * sizeof (ref_t), ALIGN)
+ + (dbs[cnt].suggested_module
+ * DEFAULT_DATASIZE_PER_BUCKET));
+ if (datasize > dbs[cnt].max_db_size)
+ {
+ error (0, 0, _("maximum file size for %s database too small"),
+ dbnames[cnt]);
+ dbs[cnt].max_db_size = datasize;
+ }
+
+ }
+
/* Free the buffer. */
free (line);
/* Close configuration file. */
fclose (fp);
- return 0;
+ return error_message_count != initial_error_message_count;
}
diff --git a/nscd/nscd_getai.c b/nscd/nscd_getai.c
index 24b374b0dc..5df32dc6dc 100644
--- a/nscd/nscd_getai.c
+++ b/nscd/nscd_getai.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004 Free Software Foundation, Inc.
+/* Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
@@ -34,7 +34,7 @@ extern int __nss_not_use_nscd_hosts;
/* We use the mapping from nscd_gethst. */
-libc_locked_map_ptr (extern, __hst_map_handle);
+libc_locked_map_ptr (extern, __hst_map_handle) attribute_hidden;
int
@@ -42,6 +42,7 @@ __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop)
{
size_t keylen = strlen (key) + 1;
int gc_cycle;
+ int nretries = 0;
/* If the mapping is available, try to search there instead of
communicating with the nscd. */
@@ -50,49 +51,53 @@ __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop)
&gc_cycle);
retry:;
- const ai_response_header *ai_resp = NULL;
struct nscd_ai_result *resultbuf = NULL;
const char *recend = (const char *) ~UINTMAX_C (0);
char *respdata = NULL;
int retval = -1;
int sock = -1;
+ ai_response_header ai_resp;
if (mapped != NO_MAPPING)
{
- const struct datahead *found = __nscd_cache_search (GETAI, key, keylen,
- mapped);
+ struct datahead *found = __nscd_cache_search (GETAI, key, keylen,
+ mapped);
if (found != NULL)
{
- ai_resp = &found->data[0].aidata;
- respdata = (char *) (ai_resp + 1);
+ respdata = (char *) (&found->data[0].aidata + 1);
+ ai_resp = found->data[0].aidata;
recend = (const char *) found->data + found->recsize;
+ /* Now check if we can trust ai_resp fields. If GC is
+ in progress, it can contain anything. */
+ if (mapped->head->gc_cycle != gc_cycle)
+ {
+ retval = -2;
+ goto out;
+ }
}
}
/* If we do not have the cache mapped, try to get the data over the
socket. */
- ai_response_header ai_resp_mem;
- if (ai_resp == NULL)
+ if (respdata == NULL)
{
- sock = __nscd_open_socket (key, keylen, GETAI, &ai_resp_mem,
- sizeof (ai_resp_mem));
+ sock = __nscd_open_socket (key, keylen, GETAI, &ai_resp,
+ sizeof (ai_resp));
if (sock == -1)
{
- /* nscd not running or wrong version or hosts caching disabled. */
+ /* nscd not running or wrong version. */
__nss_not_use_nscd_hosts = 1;
goto out;
}
-
- ai_resp = &ai_resp_mem;
}
- if (ai_resp->found == 1)
+ if (ai_resp.found == 1)
{
- size_t datalen = ai_resp->naddrs + ai_resp->addrslen + ai_resp->canonlen;
+ size_t datalen = ai_resp.naddrs + ai_resp.addrslen + ai_resp.canonlen;
- /* This check is really only affects the case where the data
+ /* This check really only affects the case where the data
comes from the mapped cache. */
- if ((char *) (ai_resp + 1) + datalen > recend)
+ if (respdata + datalen > recend)
{
assert (sock == -1);
goto out;
@@ -108,10 +113,10 @@ __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop)
}
/* Set up the data structure, including pointers. */
- resultbuf->naddrs = ai_resp->naddrs;
+ resultbuf->naddrs = ai_resp.naddrs;
resultbuf->addrs = (char *) (resultbuf + 1);
- resultbuf->family = (uint8_t *) (resultbuf->addrs + ai_resp->addrslen);
- if (ai_resp->canonlen != 0)
+ resultbuf->family = (uint8_t *) (resultbuf->addrs + ai_resp.addrslen);
+ if (ai_resp.canonlen != 0)
resultbuf->canon = (char *) (resultbuf->family + resultbuf->naddrs);
else
resultbuf->canon = NULL;
@@ -119,8 +124,7 @@ __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop)
if (respdata == NULL)
{
/* Read the data from the socket. */
- if ((size_t) TEMP_FAILURE_RETRY (__read (sock, resultbuf + 1,
- datalen)) == datalen)
+ if ((size_t) __readall (sock, resultbuf + 1, datalen) == datalen)
{
retval = 0;
*result = resultbuf;
@@ -138,10 +142,13 @@ __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop)
/* Try to detect corrupt databases. */
if (resultbuf->canon != NULL
- && resultbuf->canon[ai_resp->canonlen - 1] != '\0')
+ && resultbuf->canon[ai_resp.canonlen - 1] != '\0')
/* We cannot use the database. */
{
- free (resultbuf);
+ if (mapped->head->gc_cycle != gc_cycle)
+ retval = -2;
+ else
+ free (resultbuf);
goto out_close;
}
@@ -151,8 +158,15 @@ __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop)
}
else
{
+ if (__builtin_expect (ai_resp.found == -1, 0))
+ {
+ /* The daemon does not cache this database. */
+ __nss_not_use_nscd_hosts = 1;
+ goto out_close;
+ }
+
/* Store the error number. */
- *h_errnop = ai_resp->error;
+ *h_errnop = ai_resp.error;
/* The `errno' to some value != ERANGE. */
__set_errno (ENOENT);
@@ -164,22 +178,25 @@ __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop)
if (sock != -1)
close_not_cancel_no_status (sock);
out:
- if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0 && retval != -1)
+ 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)
+ if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
{
/* nscd is just running gc now. Disable using the mapping. */
- __nscd_unmap (mapped);
+ if (atomic_decrement_val (&mapped->counter) == 0)
+ __nscd_unmap (mapped);
mapped = NO_MAPPING;
}
- *result = NULL;
- free (resultbuf);
-
- goto retry;
+ if (retval != -1)
+ {
+ *result = NULL;
+ free (resultbuf);
+ goto retry;
+ }
}
return retval;
diff --git a/nscd/nscd_getgr_r.c b/nscd/nscd_getgr_r.c
index 282912db3e..fc036f2888 100644
--- a/nscd/nscd_getgr_r.c
+++ b/nscd/nscd_getgr_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004
+/* Copyright (C) 1998-2000, 2002-2005, 2006, 2007
Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1998.
@@ -67,7 +67,7 @@ __nscd_getgrgid_r (gid_t gid, struct group *resultbuf, char *buffer,
}
-libc_locked_map_ptr (,__gr_map_handle);
+libc_locked_map_ptr (,__gr_map_handle) attribute_hidden;
/* Note that we only free the structure if necessary. The memory
mapping is not removed since it is not visible to the malloc
handling. */
@@ -89,6 +89,7 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
struct group **result)
{
int gc_cycle;
+ int nretries = 0;
const uint32_t *len = NULL;
size_t lensize = 0;
@@ -98,55 +99,59 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
&__gr_map_handle,
&gc_cycle);
retry:;
- const gr_response_header *gr_resp = NULL;
const char *gr_name = NULL;
size_t gr_name_len = 0;
int retval = -1;
const char *recend = (const char *) ~UINTMAX_C (0);
+ gr_response_header gr_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);
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);
+ len = (const uint32_t *) (&found->data[0].grdata + 1);
+ gr_resp = found->data[0].grdata;
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;
+ + 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;
+ /* Now check if we can trust gr_resp fields. If GC is
+ in progress, it can contain anything. */
+ if (mapped->head->gc_cycle != gc_cycle)
+ {
+ retval = -2;
+ goto out;
+ }
+
+ /* The alignment is always sufficient, unless GC is in progress. */
+ assert (((uintptr_t) len & (__alignof__ (*len) - 1)) == 0);
}
}
- gr_response_header gr_resp_mem;
int sock = -1;
- if (gr_resp == NULL)
+ if (gr_name == NULL)
{
- sock = __nscd_open_socket (key, keylen, type, &gr_resp_mem,
- sizeof (gr_resp_mem));
+ sock = __nscd_open_socket (key, keylen, type, &gr_resp,
+ sizeof (gr_resp));
if (sock == -1)
{
__nss_not_use_nscd_group = 1;
goto out;
}
-
- gr_resp = &gr_resp_mem;
}
/* No value found so far. */
*result = NULL;
- if (__builtin_expect (gr_resp->found == -1, 0))
+ if (__builtin_expect (gr_resp.found == -1, 0))
{
/* The daemon does not cache this database. */
__nss_not_use_nscd_group = 1;
goto out_close;
}
- if (gr_resp->found == 1)
+ if (gr_resp.found == 1)
{
struct iovec vec[2];
char *p = buffer;
@@ -158,8 +163,8 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
align the pointer. */
align = ((__alignof__ (char *) - (p - ((char *) 0)))
& (__alignof__ (char *) - 1));
- total_len = (align + (1 + gr_resp->gr_mem_cnt) * sizeof (char *)
- + gr_resp->gr_name_len + gr_resp->gr_passwd_len);
+ total_len = (align + (1 + gr_resp.gr_mem_cnt) * sizeof (char *)
+ + gr_resp.gr_name_len + gr_resp.gr_passwd_len);
if (__builtin_expect (buflen < total_len, 0))
{
no_room:
@@ -171,16 +176,16 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
p += align;
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. */
resultbuf->gr_name = p;
- p += gr_resp->gr_name_len;
+ p += gr_resp.gr_name_len;
resultbuf->gr_passwd = p;
- p += gr_resp->gr_passwd_len;
+ p += gr_resp.gr_passwd_len;
/* Fill in what we know now. */
- resultbuf->gr_gid = gr_resp->gr_gid;
+ resultbuf->gr_gid = gr_resp.gr_gid;
/* Read the length information, group name, and password. */
if (gr_name == NULL)
@@ -188,21 +193,21 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
/* Allocate array to store lengths. */
if (lensize == 0)
{
- lensize = gr_resp->gr_mem_cnt * sizeof (uint32_t);
+ lensize = gr_resp.gr_mem_cnt * sizeof (uint32_t);
len = (uint32_t *) alloca (lensize);
}
- else if (gr_resp->gr_mem_cnt * sizeof (uint32_t) > lensize)
+ else if (gr_resp.gr_mem_cnt * sizeof (uint32_t) > lensize)
len = extend_alloca (len, lensize,
- gr_resp->gr_mem_cnt * sizeof (uint32_t));
+ gr_resp.gr_mem_cnt * sizeof (uint32_t));
vec[0].iov_base = (void *) len;
- vec[0].iov_len = gr_resp->gr_mem_cnt * sizeof (uint32_t);
+ vec[0].iov_len = gr_resp.gr_mem_cnt * sizeof (uint32_t);
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;
/* Get this data. */
- size_t n = TEMP_FAILURE_RETRY (__readv (sock, vec, 2));
+ size_t n = __readvall (sock, vec, 2);
if (__builtin_expect (n != total_len, 0))
goto out_close;
}
@@ -210,14 +215,14 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
/* We already have the data. Just copy the group name and
password. */
memcpy (resultbuf->gr_name, gr_name,
- gr_resp->gr_name_len + gr_resp->gr_passwd_len);
+ gr_resp.gr_name_len + gr_resp.gr_passwd_len);
/* 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. */
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;
total_len += len[cnt];
@@ -225,15 +230,30 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
}
if (__builtin_expect (gr_name + gr_name_len + total_len > recend, 0))
- goto out_close;
+ {
+ /* len array might contain garbage during nscd GC cycle,
+ retry rather than fail in that case. */
+ if (gr_name != NULL && mapped->head->gc_cycle != gc_cycle)
+ retval = -2;
+ goto out_close;
+ }
if (__builtin_expect (total_len > buflen, 0))
- goto no_room;
+ {
+ /* len array might contain garbage during nscd GC cycle,
+ retry rather than fail in that case. */
+ if (gr_name != NULL && mapped->head->gc_cycle != gc_cycle)
+ {
+ retval = -2;
+ goto out_close;
+ }
+ else
+ goto no_room;
+ }
retval = 0;
if (gr_name == NULL)
{
- size_t n = TEMP_FAILURE_RETRY (__read (sock, resultbuf->gr_mem[0],
- total_len));
+ size_t n = __readall (sock, resultbuf->gr_mem[0], total_len);
if (__builtin_expect (n != total_len, 0))
{
/* The `errno' to some value != ERANGE. */
@@ -250,14 +270,14 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
/* Try to detect corrupt databases. */
if (resultbuf->gr_name[gr_name_len - 1] != '\0'
- || resultbuf->gr_passwd[gr_resp->gr_passwd_len - 1] != '\0'
- || ({for (cnt = 0; cnt < gr_resp->gr_mem_cnt; ++cnt)
+ || resultbuf->gr_passwd[gr_resp.gr_passwd_len - 1] != '\0'
+ || ({for (cnt = 0; cnt < gr_resp.gr_mem_cnt; ++cnt)
if (resultbuf->gr_mem[cnt][len[cnt] - 1] != '\0')
break;
- cnt < gr_resp->gr_mem_cnt; }))
+ cnt < gr_resp.gr_mem_cnt; }))
{
/* We cannot use the database. */
- retval = -1;
+ retval = mapped->head->gc_cycle != gc_cycle ? -2 : -1;
goto out_close;
}
@@ -276,19 +296,21 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
if (sock != -1)
close_not_cancel_no_status (sock);
out:
- if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0 && retval != -1)
+ 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)
+ if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
{
/* nscd is just running gc now. Disable using the mapping. */
- __nscd_unmap (mapped);
+ if (atomic_decrement_val (&mapped->counter) == 0)
+ __nscd_unmap (mapped);
mapped = NO_MAPPING;
}
- goto retry;
+ if (retval != -1)
+ goto retry;
}
return retval;
diff --git a/nscd/nscd_gethst_r.c b/nscd/nscd_gethst_r.c
index 5d9d569107..90e1815bdd 100644
--- a/nscd/nscd_gethst_r.c
+++ b/nscd/nscd_gethst_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1998-2002, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 1998-2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
@@ -87,7 +87,7 @@ __nscd_gethostbyaddr_r (const void *addr, socklen_t len, int type,
}
-libc_locked_map_ptr (, __hst_map_handle);
+libc_locked_map_ptr (, __hst_map_handle) attribute_hidden;
/* Note that we only free the structure if necessary. The memory
mapping is not removed since it is not visible to the malloc
handling. */
@@ -118,7 +118,6 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
&gc_cycle);
retry:;
- const hst_response_header *hst_resp = NULL;
const char *h_name = NULL;
const uint32_t *aliases_len = NULL;
const char *addr_list = NULL;
@@ -126,18 +125,27 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
int retval = -1;
const char *recend = (const char *) ~UINTMAX_C (0);
int sock = -1;
+ hst_response_header hst_resp;
if (mapped != NO_MAPPING)
{
- const struct datahead *found = __nscd_cache_search (type, key, keylen,
- mapped);
+ /* No const qualifier, as it can change during garbage collection. */
+ struct datahead *found = __nscd_cache_search (type, key, keylen, 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);
+ h_name = (char *) (&found->data[0].hstdata + 1);
+ hst_resp = found->data[0].hstdata;
+ 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;
+ + hst_resp.h_aliases_cnt * sizeof (uint32_t));
+ addr_list_len = hst_resp.h_addr_list_cnt * INADDRSZ;
+ recend = (const char *) found->data + found->recsize;
+ /* Now check if we can trust hst_resp fields. If GC is
+ in progress, it can contain anything. */
+ if (mapped->head->gc_cycle != gc_cycle)
+ {
+ retval = -2;
+ goto out;
+ }
#ifndef _STRING_ARCH_unaligned
/* The aliases_len array in the mapped database might very
@@ -147,51 +155,47 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
if (((uintptr_t) aliases_len & (__alignof__ (*aliases_len) - 1))
!= 0)
{
- uint32_t *tmp = alloca (hst_resp->h_aliases_cnt
+ uint32_t *tmp = alloca (hst_resp.h_aliases_cnt
* sizeof (uint32_t));
aliases_len = memcpy (tmp, aliases_len,
- hst_resp->h_aliases_cnt
+ hst_resp.h_aliases_cnt
* sizeof (uint32_t));
}
#endif
if (type != GETHOSTBYADDR && type != GETHOSTBYNAME)
{
- if (hst_resp->h_length == INADDRSZ)
+ if (hst_resp.h_length == INADDRSZ)
addr_list += addr_list_len;
- addr_list_len = hst_resp->h_addr_list_cnt * IN6ADDRSZ;
+ 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;
+ goto out;
}
}
- hst_response_header hst_resp_mem;
- if (hst_resp == NULL)
+ if (h_name == NULL)
{
- sock = __nscd_open_socket (key, keylen, type, &hst_resp_mem,
- sizeof (hst_resp_mem));
+ sock = __nscd_open_socket (key, keylen, type, &hst_resp,
+ sizeof (hst_resp));
if (sock == -1)
{
__nss_not_use_nscd_hosts = 1;
- goto out;;
+ goto out;
}
-
- hst_resp = &hst_resp_mem;
}
/* No value found so far. */
*result = NULL;
- if (__builtin_expect (hst_resp->found == -1, 0))
+ if (__builtin_expect (hst_resp.found == -1, 0))
{
/* The daemon does not cache this database. */
__nss_not_use_nscd_hosts = 1;
goto out_close;
}
- if (hst_resp->found == 1)
+ if (hst_resp.found == 1)
{
struct iovec vec[4];
char *cp = buffer;
@@ -207,17 +211,18 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
align the pointer and the base of the h_addr_list pointers. */
align1 = ((__alignof__ (char *) - (cp - ((char *) 0)))
& (__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)))
& (__alignof__ (char *) - 1));
- if (buflen < (align1 + hst_resp->h_name_len + align2
- + ((hst_resp->h_aliases_cnt + hst_resp->h_addr_list_cnt
+ if (buflen < (align1 + hst_resp.h_name_len + align2
+ + ((hst_resp.h_aliases_cnt + hst_resp.h_addr_list_cnt
+ 2)
* sizeof (char *))
- + hst_resp->h_addr_list_cnt * (type == AF_INET
- ? INADDRSZ : IN6ADDRSZ)))
+ + hst_resp.h_addr_list_cnt * (type == AF_INET
+ ? INADDRSZ : IN6ADDRSZ)))
{
no_room:
+ *h_errnop = NETDB_INTERNAL;
__set_errno (ERANGE);
retval = ERANGE;
goto out_close;
@@ -226,12 +231,12 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
/* Prepare the result as far as we can. */
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;
- cp += (hst_resp->h_addr_list_cnt + 1) * sizeof (char *);
+ cp += (hst_resp.h_addr_list_cnt + 1) * sizeof (char *);
resultbuf->h_name = cp;
- cp += hst_resp->h_name_len + align2;
+ cp += hst_resp.h_name_len + align2;
if (type == GETHOSTBYADDR || type == GETHOSTBYNAME)
{
@@ -243,7 +248,7 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
resultbuf->h_addrtype = AF_INET6;
resultbuf->h_length = IN6ADDRSZ;
}
- for (cnt = 0; cnt < hst_resp->h_addr_list_cnt; ++cnt)
+ for (cnt = 0; cnt < hst_resp.h_addr_list_cnt; ++cnt)
{
resultbuf->h_addr_list[cnt] = cp;
cp += resultbuf->h_length;
@@ -253,64 +258,63 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
if (h_name == NULL)
{
vec[0].iov_base = resultbuf->h_name;
- vec[0].iov_len = hst_resp->h_name_len;
- total_len = hst_resp->h_name_len;
+ 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)
+ if (hst_resp.h_aliases_cnt > 0)
{
- aliases_len = alloca (hst_resp->h_aliases_cnt
+ 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);
+ vec[n].iov_len = hst_resp.h_aliases_cnt * sizeof (uint32_t);
- total_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;
+ vec[n].iov_len = hst_resp.h_addr_list_cnt * INADDRSZ;
- total_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)
+ if (hst_resp.h_length == INADDRSZ)
{
- ignore = alloca (hst_resp->h_addr_list_cnt * 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;
+ vec[n].iov_len = hst_resp.h_addr_list_cnt * INADDRSZ;
- total_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;
+ vec[n].iov_len = hst_resp.h_addr_list_cnt * IN6ADDRSZ;
- total_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)
+ if ((size_t) __readvall (sock, vec, n) != total_len)
goto out_close;
}
else
{
- memcpy (resultbuf->h_name, h_name, hst_resp->h_name_len);
+ 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. */
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;
cp += aliases_len[cnt];
@@ -320,17 +324,32 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
if (__builtin_expect ((const char *) addr_list + addr_list_len
+ total_len > recend, 0))
- goto out_close;
+ {
+ /* aliases_len array might contain garbage during nscd GC cycle,
+ retry rather than fail in that case. */
+ if (addr_list != NULL && mapped->head->gc_cycle != gc_cycle)
+ retval = -2;
+ goto out_close;
+ }
/* See whether this would exceed the buffer capacity. */
if (__builtin_expect (cp > buffer + buflen, 0))
- goto no_room;
+ {
+ /* aliases_len array might contain garbage during nscd GC cycle,
+ retry rather than fail in that case. */
+ if (addr_list != NULL && mapped->head->gc_cycle != gc_cycle)
+ {
+ retval = -2;
+ goto out_close;
+ }
+ goto no_room;
+ }
/* And finally read the aliases. */
if (addr_list == NULL)
{
- if ((size_t) TEMP_FAILURE_RETRY (__read (sock,
- resultbuf->h_aliases[0],
- total_len)) == total_len)
+ if (total_len == 0
+ || ((size_t) __readall (sock, resultbuf->h_aliases[0], total_len)
+ == total_len))
{
retval = 0;
*result = resultbuf;
@@ -342,14 +361,18 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
(const char *) addr_list + addr_list_len, total_len);
/* Try to detect corrupt databases. */
- if (resultbuf->h_name[hst_resp->h_name_len - 1] != '\0'
- || ({for (cnt = 0; cnt < hst_resp->h_aliases_cnt; ++cnt)
+ if (resultbuf->h_name[hst_resp.h_name_len - 1] != '\0'
+ || ({for (cnt = 0; cnt < hst_resp.h_aliases_cnt; ++cnt)
if (resultbuf->h_aliases[cnt][aliases_len[cnt] - 1]
!= '\0')
break;
- cnt < hst_resp->h_aliases_cnt; }))
- /* We cannot use the database. */
- goto out_close;
+ cnt < hst_resp.h_aliases_cnt; }))
+ {
+ /* We cannot use the database. */
+ if (mapped->head->gc_cycle != gc_cycle)
+ retval = -2;
+ goto out_close;
+ }
retval = 0;
*result = resultbuf;
@@ -358,7 +381,7 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
else
{
/* Store the error number. */
- *h_errnop = hst_resp->error;
+ *h_errnop = hst_resp.error;
/* The `errno' to some value != ERANGE. */
__set_errno (ENOENT);
@@ -370,19 +393,21 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
if (sock != -1)
close_not_cancel_no_status (sock);
out:
- if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0 && retval != -1)
+ 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)
+ if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
{
/* nscd is just running gc now. Disable using the mapping. */
- __nscd_unmap (mapped);
+ if (atomic_decrement_val (&mapped->counter) == 0)
+ __nscd_unmap (mapped);
mapped = NO_MAPPING;
}
- goto retry;
+ if (retval != -1)
+ goto retry;
}
return retval;
diff --git a/nscd/nscd_getpw_r.c b/nscd/nscd_getpw_r.c
index fe5fb43ca1..b84baa1a66 100644
--- a/nscd/nscd_getpw_r.c
+++ b/nscd/nscd_getpw_r.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1998, 1999, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 1998, 1999, 2003, 2004, 2005, 2007
+ Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1998.
@@ -88,76 +89,81 @@ nscd_getpw_r (const char *key, size_t keylen, request_type type,
struct passwd **result)
{
int gc_cycle;
+ int nretries = 0;
+
/* If the mapping is available, try to search there instead of
communicating with the nscd. */
struct mapped_database *mapped;
mapped = __nscd_get_map_ref (GETFDPW, "passwd", &map_handle, &gc_cycle);
retry:;
- const pw_response_header *pw_resp = NULL;
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);
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 (__builtin_expect (pw_resp.found == -1, 0))
{
/* 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))
@@ -172,7 +178,7 @@ nscd_getpw_r (const char *key, size_t keylen, request_type type,
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))
{
@@ -189,14 +195,14 @@ nscd_getpw_r (const char *key, size_t keylen, request_type type,
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')
+ 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 = -1;
+ retval = mapped->head->gc_cycle != gc_cycle ? -2 : -1;
goto out_close;
}
@@ -215,21 +221,21 @@ nscd_getpw_r (const char *key, size_t keylen, request_type type,
if (sock != -1)
close_not_cancel_no_status (sock);
out:
- if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0 && retval != -1)
+ 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)
+ if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
{
/* nscd is just running gc now. Disable using the mapping. */
- __nscd_unmap (mapped);
+ if (atomic_decrement_val (&mapped->counter) == 0)
+ __nscd_unmap (mapped);
mapped = NO_MAPPING;
}
- free (resultbuf);
-
- goto retry;
+ if (retval != -1)
+ goto retry;
}
return retval;
diff --git a/nscd/nscd_helper.c b/nscd/nscd_helper.c
index 0e16cb8aeb..71ea53e19d 100644
--- a/nscd/nscd_helper.c
+++ b/nscd/nscd_helper.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1998-2002, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 1998-2002,2003,2004,2005,2006,2007
+ Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
@@ -21,11 +22,14 @@
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
+#include <string.h>
+#include <time.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/stat.h>
+#include <sys/time.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <not-cancel.h>
@@ -34,6 +38,64 @@
#include "nscd-client.h"
+ssize_t
+__readall (int fd, void *buf, size_t len)
+{
+ size_t n = len;
+ ssize_t ret;
+ do
+ {
+ ret = TEMP_FAILURE_RETRY (__read (fd, buf, n));
+ if (ret <= 0)
+ break;
+ buf = (char *) buf + ret;
+ n -= ret;
+ }
+ while (n > 0);
+ return ret < 0 ? ret : len - n;
+}
+
+
+ssize_t
+__readvall (int fd, const struct iovec *iov, int iovcnt)
+{
+ ssize_t ret = TEMP_FAILURE_RETRY (__readv (fd, iov, iovcnt));
+ if (ret <= 0)
+ return ret;
+
+ size_t total = 0;
+ for (int i = 0; i < iovcnt; ++i)
+ total += iov[i].iov_len;
+
+ if (ret < total)
+ {
+ struct iovec iov_buf[iovcnt];
+ ssize_t r = ret;
+
+ struct iovec *iovp = memcpy (iov_buf, iov, iovcnt * sizeof (*iov));
+ do
+ {
+ while (iovp->iov_len <= r)
+ {
+ r -= iovp->iov_len;
+ --iovcnt;
+ ++iovp;
+ }
+ iovp->iov_base = (char *) iovp->iov_base + r;
+ iovp->iov_len -= r;
+ r = TEMP_FAILURE_RETRY (__readv (fd, iovp, iovcnt));
+ if (r <= 0)
+ break;
+ ret += r;
+ }
+ while (ret < total);
+ if (r < 0)
+ ret = r;
+ }
+ return ret;
+}
+
+
static int
open_socket (void)
{
@@ -77,6 +139,36 @@ __nscd_unmap (struct mapped_database *mapped)
}
+static int
+wait_on_socket (int sock)
+{
+ struct pollfd fds[1];
+ fds[0].fd = sock;
+ fds[0].events = POLLIN | POLLERR | POLLHUP;
+ int n = __poll (fds, 1, 5 * 1000);
+ if (n == -1 && __builtin_expect (errno == EINTR, 0))
+ {
+ /* Handle the case where the poll() call is interrupted by a
+ signal. We cannot just use TEMP_FAILURE_RETRY since it might
+ lead to infinite loops. */
+ struct timeval now;
+ (void) __gettimeofday (&now, NULL);
+ long int end = (now.tv_sec + 5) * 1000 + (now.tv_usec + 500) / 1000;
+ while (1)
+ {
+ long int timeout = end - (now.tv_sec * 1000
+ + (now.tv_usec + 500) / 1000);
+ n = __poll (fds, 1, timeout);
+ if (n != -1 || errno != EINTR)
+ break;
+ (void) __gettimeofday (&now, NULL);
+ }
+ }
+
+ return n;
+}
+
+
/* Try to get a file descriptor for the shared meory segment
containing the database. */
static struct mapped_database *
@@ -86,102 +178,115 @@ get_mapping (request_type type, const char *key,
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;
+ struct
+ {
+ request_header req;
+ char key[keylen];
+ } reqdata;
+ size_t real_sizeof_reqdata = sizeof (request_header) + keylen;
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)
+ reqdata.req.version = NSCD_VERSION;
+ reqdata.req.type = type;
+ reqdata.req.key_len = keylen;
+ memcpy (reqdata.key, key, keylen);
+
+# ifndef MSG_NOSIGNAL
+# define MSG_NOSIGNAL 0
+# endif
+ if (__builtin_expect (TEMP_FAILURE_RETRY (__send (sock, &reqdata,
+ real_sizeof_reqdata,
+ MSG_NOSIGNAL))
+ != real_sizeof_reqdata, 0))
/* 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. */
+# define resdata reqdata.key
+ struct iovec iov[1];
iov[0].iov_base = resdata;
iov[0].iov_len = keylen;
- char buf[CMSG_SPACE (sizeof (int))];
+ union
+ {
+ struct cmsghdr hdr;
+ char bytes[CMSG_SPACE (sizeof (int))];
+ } buf;
struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1,
- .msg_control = buf, .msg_controllen = sizeof (buf) };
+ .msg_control = buf.bytes,
+ .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));
+ /* This access is well-aligned since BUF is correctly aligned for an
+ int and CMSG_DATA preserves this alignment. */
*(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. */
+ if (wait_on_socket (sock) <= 0)
goto out_close2;
- if (TEMP_FAILURE_RETRY (__recvmsg (sock, &msg, 0)) != keylen)
+ if (__builtin_expect (TEMP_FAILURE_RETRY (__recvmsg (sock, &msg, 0))
+ != keylen, 0))
goto out_close2;
- mapfd = *(int *) CMSG_DATA (cmsg);
+ if (__builtin_expect (CMSG_FIRSTHDR (&msg) == NULL
+ || (CMSG_FIRSTHDR (&msg)->cmsg_len
+ != CMSG_LEN (sizeof (int))), 0))
+ goto out_close2;
- if (CMSG_FIRSTHDR (&msg)->cmsg_len != CMSG_LEN (sizeof (int)))
- goto out_close;
+ 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))
+ if (__builtin_expect (strcmp (resdata, key) != 0, 0)
+ || __builtin_expect (fstat64 (mapfd, &st) != 0, 0)
+ || __builtin_expect (st.st_size < sizeof (struct database_pers_head), 0))
goto out_close;
struct database_pers_head head;
- if (TEMP_FAILURE_RETRY (__pread (mapfd, &head, sizeof (head), 0))
- != sizeof (head))
+ if (__builtin_expect (TEMP_FAILURE_RETRY (__pread (mapfd, &head,
+ sizeof (head), 0))
+ != sizeof (head), 0))
goto out_close;
- if (head.version != DB_VERSION || head.header_size != sizeof (head)
+ if (__builtin_expect (head.version != DB_VERSION, 0)
+ || __builtin_expect (head.header_size != sizeof (head), 0)
/* This really should not happen but who knows, maybe the update
thread got stuck. */
- || (! head.nscd_certainly_running
- && head.timestamp + MAPPING_TIMEOUT < time (NULL)))
+ || __builtin_expect (! head.nscd_certainly_running
+ && head.timestamp + MAPPING_TIMEOUT < time (NULL),
+ 0))
goto out_close;
size_t size = (sizeof (head) + roundup (head.module * sizeof (ref_t), ALIGN)
+ head.data_size);
- if (st.st_size < size)
+ if (__builtin_expect (st.st_size < size, 0))
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)
+ if (__builtin_expect (mapping != MAP_FAILED, 1))
{
/* Allocate a record for the mapping. */
- struct mapped_database *newp;
-
- newp = malloc (sizeof (*newp));
+ struct mapped_database *newp = malloc (sizeof (*newp));
if (newp == NULL)
{
/* Ugh, after all we went through the memory allocation failed. */
- __munmap (result, size);
+ __munmap (mapping, size);
goto out_close;
}
@@ -189,6 +294,7 @@ get_mapping (request_type type, const char *key,
newp->data = ((char *) mapping + head.header_size
+ roundup (head.module * sizeof (ref_t), ALIGN));
newp->mapsize = size;
+ newp->datasize = head.data_size;
/* Set counter to 1 to show it is usable. */
newp->counter = 1;
@@ -215,17 +321,18 @@ get_mapping (request_type type, const char *key,
struct mapped_database *
__nscd_get_map_ref (request_type type, const char *name,
- struct locked_map_ptr *mapptr, int *gc_cyclep)
+ volatile 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)
+ while (__builtin_expect (atomic_compare_and_exchange_val_acq (&mapptr->lock,
+ 1, 0) != 0, 0))
{
// XXX Best number of rounds?
- if (++cnt > 5)
+ if (__builtin_expect (++cnt > 5, 0))
return NO_MAPPING;
atomic_delay ();
@@ -238,8 +345,10 @@ __nscd_get_map_ref (request_type type, const char *name,
/* If not mapped or timestamp not updated, request new map. */
if (cur == NULL
|| (cur->head->nscd_certainly_running == 0
- && cur->head->timestamp + MAPPING_TIMEOUT < time (NULL)))
- cur = get_mapping (type, name, &mapptr->mapped);
+ && cur->head->timestamp + MAPPING_TIMEOUT < time (NULL))
+ || cur->head->data_size > cur->datasize)
+ cur = get_mapping (type, name,
+ (struct mapped_database **) &mapptr->mapped);
if (__builtin_expect (cur != NO_MAPPING, 1))
{
@@ -257,28 +366,50 @@ __nscd_get_map_ref (request_type type, const char *name,
}
-const struct datahead *
+/* Don't return const struct datahead *, as eventhough the record
+ is normally constant, it can change arbitrarily during nscd
+ garbage collection. */
+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;
+ size_t datasize = mapped->datasize;
ref_t work = mapped->head->array[hash];
- while (work != ENDREF)
+ while (work != ENDREF && work + sizeof (struct hashentry) <= datasize)
{
struct hashentry *here = (struct hashentry *) (mapped->data + work);
- if (type == here->type && keylen == here->len
- && memcmp (key, mapped->data + here->key, keylen) == 0)
+#ifndef _STRING_ARCH_unaligned
+ /* Although during garbage collection when moving struct hashentry
+ records around we first copy from old to new location and then
+ adjust pointer from previous hashentry to it, there is no barrier
+ between those memory writes. It is very unlikely to hit it,
+ so check alignment only if a misaligned load can crash the
+ application. */
+ if ((uintptr_t) here & (__alignof__ (*here) - 1))
+ return NULL;
+#endif
+
+ if (type == here->type
+ && keylen == here->len
+ && here->key + keylen <= datasize
+ && memcmp (key, mapped->data + here->key, keylen) == 0
+ && here->packet + sizeof (struct datahead) <= datasize)
{
/* We found the entry. Increment the appropriate counter. */
- const struct datahead *dh
+ struct datahead *dh
= (struct datahead *) (mapped->data + here->packet);
+#ifndef _STRING_ARCH_unaligned
+ if ((uintptr_t) dh & (__alignof__ (*dh) - 1))
+ return NULL;
+#endif
+
/* 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))
+ if (dh->usable && here->packet + dh->allocsize <= datasize)
return dh;
}
@@ -311,19 +442,13 @@ __nscd_open_socket (const char *key, size_t keylen, request_type type,
vec[1].iov_len = keylen;
ssize_t nbytes = TEMP_FAILURE_RETRY (__writev (sock, vec, 2));
- if (nbytes == (ssize_t) (sizeof (request_header) + keylen))
- {
+ 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;
- }
+ && wait_on_socket (sock) > 0)
+ {
+ nbytes = TEMP_FAILURE_RETRY (__read (sock, response, responselen));
+ if (nbytes == (ssize_t) responselen)
+ return sock;
}
close_not_cancel_no_status (sock);
diff --git a/nscd/nscd_initgroups.c b/nscd/nscd_initgroups.c
index 2ea9e7f862..866455a96c 100644
--- a/nscd/nscd_initgroups.c
+++ b/nscd/nscd_initgroups.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004 Free Software Foundation, Inc.
+/* Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
@@ -30,7 +30,7 @@
/* We use the same mapping as in nscd_getgr. */
-libc_locked_map_ptr (extern, __gr_map_handle);
+libc_locked_map_ptr (extern, __gr_map_handle) attribute_hidden;
int
@@ -39,6 +39,7 @@ __nscd_getgrouplist (const char *user, gid_t group, long int *size,
{
size_t userlen = strlen (user) + 1;
int gc_cycle;
+ int nretries = 0;
/* If the mapping is available, try to search there instead of
communicating with the nscd. */
@@ -46,44 +47,49 @@ __nscd_getgrouplist (const char *user, gid_t group, long int *size,
mapped = __nscd_get_map_ref (GETFDGR, "group", &__gr_map_handle, &gc_cycle);
retry:;
- const initgr_response_header *initgr_resp = NULL;
char *respdata = NULL;
int retval = -1;
int sock = -1;
+ initgr_response_header initgr_resp;
if (mapped != NO_MAPPING)
{
- const struct datahead *found = __nscd_cache_search (INITGROUPS, user,
- userlen, mapped);
+ struct datahead *found = __nscd_cache_search (INITGROUPS, user,
+ userlen, mapped);
if (found != NULL)
{
- initgr_resp = &found->data[0].initgrdata;
- respdata = (char *) (initgr_resp + 1);
+ respdata = (char *) (&found->data[0].initgrdata + 1);
+ initgr_resp = found->data[0].initgrdata;
char *recend = (char *) found->data + found->recsize;
- if (respdata + initgr_resp->ngrps * sizeof (int32_t) > recend)
+ /* Now check if we can trust initgr_resp fields. If GC is
+ in progress, it can contain anything. */
+ if (mapped->head->gc_cycle != gc_cycle)
+ {
+ retval = -2;
+ goto out;
+ }
+
+ if (respdata + initgr_resp.ngrps * sizeof (int32_t) > recend)
goto out;
}
}
/* If we do not have the cache mapped, try to get the data over the
socket. */
- initgr_response_header initgr_resp_mem;
- if (initgr_resp == NULL)
+ if (respdata == NULL)
{
- sock = __nscd_open_socket (user, userlen, INITGROUPS, &initgr_resp_mem,
- sizeof (initgr_resp_mem));
+ sock = __nscd_open_socket (user, userlen, INITGROUPS, &initgr_resp,
+ sizeof (initgr_resp));
if (sock == -1)
{
- /* nscd not running or wrong version or hosts caching disabled. */
+ /* nscd not running or wrong version. */
__nss_not_use_nscd_group = 1;
goto out;
}
-
- initgr_resp = &initgr_resp_mem;
}
- if (initgr_resp->found == 1)
+ if (initgr_resp.found == 1)
{
/* The following code assumes that gid_t and int32_t are the
same size. This is the case for al existing implementation.
@@ -91,40 +97,46 @@ __nscd_getgrouplist (const char *user, gid_t group, long int *size,
doesn't use memcpy but instead copies each array element one
by one. */
assert (sizeof (int32_t) == sizeof (gid_t));
- assert (initgr_resp->ngrps > 0);
+ assert (initgr_resp.ngrps >= 0);
/* Make sure we have enough room. We always count GROUP in even
though we might not end up adding it. */
- if (*size < initgr_resp->ngrps + 1)
+ if (*size < initgr_resp.ngrps + 1)
{
gid_t *newp = realloc (*groupsp,
- (initgr_resp->ngrps + 1) * sizeof (gid_t));
+ (initgr_resp.ngrps + 1) * sizeof (gid_t));
if (newp == NULL)
/* We cannot increase the buffer size. */
- goto out;
+ goto out_close;
*groupsp = newp;
- *size = initgr_resp->ngrps + 1;
+ *size = initgr_resp.ngrps + 1;
}
if (respdata == NULL)
{
/* Read the data from the socket. */
- if ((size_t) TEMP_FAILURE_RETRY (__read (sock, *groupsp,
- initgr_resp->ngrps
- * sizeof (gid_t)))
- == initgr_resp->ngrps * sizeof (gid_t))
- retval = initgr_resp->ngrps;
+ if ((size_t) __readall (sock, *groupsp, initgr_resp.ngrps
+ * sizeof (gid_t))
+ == initgr_resp.ngrps * sizeof (gid_t))
+ retval = initgr_resp.ngrps;
}
else
{
/* Just copy the data. */
- retval = initgr_resp->ngrps;
+ retval = initgr_resp.ngrps;
memcpy (*groupsp, respdata, retval * sizeof (gid_t));
}
}
else
{
+ if (__builtin_expect (initgr_resp.found == -1, 0))
+ {
+ /* The daemon does not cache this database. */
+ __nss_not_use_nscd_group = 1;
+ goto out_close;
+ }
+
/* No group found yet. */
retval = 0;
@@ -143,22 +155,25 @@ __nscd_getgrouplist (const char *user, gid_t group, long int *size,
(*groupsp)[retval++] = group;
}
+ out_close:
if (sock != -1)
close_not_cancel_no_status (sock);
out:
- if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0 && retval != -1)
+ 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)
+ if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
{
/* nscd is just running gc now. Disable using the mapping. */
- __nscd_unmap (mapped);
+ if (atomic_decrement_val (&mapped->counter) == 0)
+ __nscd_unmap (mapped);
mapped = NO_MAPPING;
}
- goto retry;
+ if (retval != -1)
+ goto retry;
}
return retval;
diff --git a/nscd/nscd_nischeck.c b/nscd/nscd_nischeck.c
deleted file mode 100644
index a6817cf79e..0000000000
--- a/nscd/nscd_nischeck.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/* Copyright (c) 1999, 2002, 2003, 2004 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Thorsten Kukuk <kukuk@suse.de>, 1999.
-
- 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. */
-
-/* nscd_nischeck: Check, if everybody has read permissions for NIS+ table.
- Return value:
- 0: Everybody can read the NIS+ table
- 1: Only authenticated users could read the NIS+ table */
-
-#include <argp.h>
-#include <error.h>
-#include <stdlib.h>
-#include <libintl.h>
-#include <locale.h>
-#include <rpcsvc/nis.h>
-
-/* Get libc version number. */
-#include <version.h>
-
-#define PACKAGE _libc_intl_domainname
-
-/* Name and version of program. */
-static void print_version (FILE *stream, struct argp_state *state);
-void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
-
-/* Data structure to communicate with argp functions. */
-static struct argp argp =
-{
- NULL, NULL, NULL, NULL,
-};
-
-int
-main (int argc, char **argv)
-{
- int remaining;
- nis_result *res;
- char *tablename, *cp;
-
- /* Set locale via LC_ALL. */
- setlocale (LC_ALL, "");
- /* Set the text message domain. */
- textdomain (PACKAGE);
-
- /* Parse and process arguments. */
- argp_parse (&argp, argc, argv, 0, &remaining, NULL);
-
- if (remaining + 1 != argc)
- {
- error (0, 0, gettext ("wrong number of arguments"));
- argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
- exit (EXIT_FAILURE);
- }
-
- tablename = alloca (strlen (argv[1]) + 10);
- cp = stpcpy (tablename, argv[1]);
- strcpy (cp, ".org_dir");
-
- res = nis_lookup (tablename, EXPAND_NAME|FOLLOW_LINKS);
-
- if (res == NULL ||
- (res->status != NIS_SUCCESS && res->status != NIS_S_SUCCESS))
- return 0;
-
- if (NIS_NOBODY(NIS_RES_OBJECT(res)->zo_access, NIS_READ_ACC))
- return 0;
- else
- return 1;
-}
-
-/* Print the version information. */
-static void
-print_version (FILE *stream, struct argp_state *state)
-{
- fprintf (stream, "nscd_nischeck (GNU %s) %s\n", PACKAGE, VERSION);
- fprintf (stream, gettext ("\
-Copyright (C) %s Free Software Foundation, Inc.\n\
-This is free software; see the source for copying conditions. There is NO\n\
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
-"), "2004");
- fprintf (stream, gettext ("Written by %s.\n"), "Thorsten Kukuk");
-}
diff --git a/nscd/nscd_setup_thread.c b/nscd/nscd_setup_thread.c
new file mode 100644
index 0000000000..32bfe07000
--- /dev/null
+++ b/nscd/nscd_setup_thread.c
@@ -0,0 +1,26 @@
+/* Setup of nscd worker threads. Stub verison.
+ Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <nscd.h>
+
+
+void
+setup_thread (struct database_dyn *db)
+{
+ /* Nothing. */
+}
diff --git a/nscd/nscd_stat.c b/nscd/nscd_stat.c
index 9231642278..7f6bd1c83e 100644
--- a/nscd/nscd_stat.c
+++ b/nscd/nscd_stat.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1998, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (c) 1998, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
@@ -24,6 +24,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/socket.h>
#include <unistd.h>
#include <libintl.h>
@@ -75,6 +76,10 @@ struct statdata
int debug_level;
time_t runtime;
unsigned long int client_queued;
+ int nthreads;
+ int max_nthreads;
+ int paranoia;
+ time_t restart_interval;
int ndbs;
struct dbstat dbs[lastdb];
#ifdef HAVE_SELINUX
@@ -93,6 +98,10 @@ send_stats (int fd, struct database_dyn dbs[lastdb])
data.debug_level = debug_level;
data.runtime = time (NULL) - start_time;
data.client_queued = client_queued;
+ data.nthreads = nthreads;
+ data.max_nthreads = max_nthreads;
+ data.paranoia = paranoia;
+ data.restart_interval = restart_interval;
data.ndbs = lastdb;
for (cnt = 0; cnt < lastdb; ++cnt)
@@ -125,7 +134,8 @@ send_stats (int fd, struct database_dyn dbs[lastdb])
if (selinux_enabled)
nscd_avc_cache_stats (&data.cstats);
- if (TEMP_FAILURE_RETRY (write (fd, &data, sizeof (data))) != sizeof (data))
+ if (TEMP_FAILURE_RETRY (send (fd, &data, sizeof (data), MSG_NOSIGNAL))
+ != sizeof (data))
{
char buf[256];
dbg_log (_("cannot write statistics: %s"),
@@ -143,8 +153,8 @@ receive_print_stats (void)
int fd;
int i;
uid_t uid = getuid ();
- const char *yesstr = nl_langinfo (YESSTR);
- const char *nostr = nl_langinfo (NOSTR);
+ const char *yesstr = _("yes");
+ const char *nostr = _("no");
/* Find out whether there is another user but root allowed to
request statistics. */
@@ -172,7 +182,8 @@ receive_print_stats (void)
req.version = NSCD_VERSION;
req.type = GETSTAT;
req.key_len = 0;
- nbytes = TEMP_FAILURE_RETRY (write (fd, &req, sizeof (request_header)));
+ nbytes = TEMP_FAILURE_RETRY (send (fd, &req, sizeof (request_header),
+ MSG_NOSIGNAL));
if (nbytes != sizeof (request_header))
{
int err = errno;
@@ -230,8 +241,9 @@ receive_print_stats (void)
"%15lu number of times clients had to wait\n"
"%15s paranoia mode enabled\n"
"%15lu restart internal\n"),
- nthreads, max_nthreads, data.client_queued,
- paranoia ? yesstr : nostr, (unsigned long int) restart_interval);
+ data.nthreads, data.max_nthreads, data.client_queued,
+ data.paranoia ? yesstr : nostr,
+ (unsigned long int) data.restart_interval);
for (i = 0; i < lastdb; ++i)
{
diff --git a/nscd/pwdcache.c b/nscd/pwdcache.c
index e8b9578778..ae579df510 100644
--- a/nscd/pwdcache.c
+++ b/nscd/pwdcache.c
@@ -1,22 +1,20 @@
/* Cache handling for passwd lookup.
- Copyright (C) 1998-2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1998-2005, 2006, 2007 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.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
- The GNU C Library is distributed in the hope that it will be useful,
+ This program 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU 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. */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <alloca.h>
#include <assert.h>
@@ -32,10 +30,14 @@
#include <time.h>
#include <unistd.h>
#include <sys/mman.h>
+#include <sys/socket.h>
#include <stackinfo.h>
#include "nscd.h"
#include "dbg_log.h"
+#ifdef HAVE_SENDFILE
+# include <kernel-features.h>
+#endif
/* This is the standard reply in case the service is disabled. */
static const pw_response_header disabled =
@@ -114,7 +116,8 @@ cache_addpw (struct database_dyn *db, int fd, request_header *req,
written = total = sizeof (notfound);
if (fd != -1)
- written = TEMP_FAILURE_RETRY (write (fd, &notfound, total));
+ written = TEMP_FAILURE_RETRY (send (fd, &notfound, total,
+ MSG_NOSIGNAL));
dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len);
/* If we cannot permanently store the result, so be it. */
@@ -271,6 +274,7 @@ cache_addpw (struct database_dyn *db, int fd, request_header *req,
{
/* Adjust pointer into the memory block. */
cp = (char *) newp + (cp - (char *) dataset);
+ key_copy = (char *) newp + (key_copy - (char *) dataset);
dataset = memcpy (newp, dataset, total + n);
alloca_used = false;
@@ -287,7 +291,30 @@ cache_addpw (struct database_dyn *db, int fd, request_header *req,
unnecessarily let the receiver wait. */
assert (fd != -1);
- written = TEMP_FAILURE_RETRY (write (fd, &dataset->resp, total));
+#ifdef HAVE_SENDFILE
+ if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
+ {
+ assert (db->wr_fd != -1);
+ assert ((char *) &dataset->resp > (char *) db->data);
+ assert ((char *) &dataset->resp - (char *) db->head
+ + total
+ <= (sizeof (struct database_pers_head)
+ + db->head->module * sizeof (ref_t)
+ + db->head->data_size));
+ written = sendfileall (fd, db->wr_fd,
+ (char *) &dataset->resp
+ - (char *) db->head, total);
+# ifndef __ASSUME_SENDFILE
+ if (written == -1 && errno == ENOSYS)
+ goto use_write;
+# endif
+ }
+ else
+# ifndef __ASSUME_SENDFILE
+ use_write:
+# endif
+#endif
+ written = writeall (fd, &dataset->resp, total);
}
@@ -312,10 +339,10 @@ cache_addpw (struct database_dyn *db, int fd, request_header *req,
marked with FIRST first. Otherwise we end up with
dangling "pointers" in case a latter hash entry cannot be
added. */
- bool first = req->type == GETPWBYNAME;
+ bool first = true;
/* If the request was by UID, add that entry first. */
- if (req->type != GETPWBYNAME)
+ if (req->type == GETPWBYUID)
{
if (cache_add (GETPWBYUID, cp, key_offset, &dataset->head, true,
db, owner) < 0)
@@ -325,12 +352,14 @@ cache_addpw (struct database_dyn *db, int fd, request_header *req,
dataset->head.usable = false;
goto out;
}
+
+ first = false;
}
/* If the key is different from the name add a separate entry. */
else if (strcmp (key_copy, dataset->strdata) != 0)
{
if (cache_add (GETPWBYNAME, key_copy, key_len + 1,
- &dataset->head, first, db, owner) < 0)
+ &dataset->head, true, db, owner) < 0)
{
/* Could not allocate memory. Make sure the data gets
discarded. */
@@ -342,11 +371,12 @@ cache_addpw (struct database_dyn *db, int fd, request_header *req,
}
/* We have to add the value for both, byname and byuid. */
- if (__builtin_expect (cache_add (GETPWBYNAME, dataset->strdata,
- pw_name_len, &dataset->head, first,
- db, owner) == 0, 1))
+ if ((req->type == GETPWBYNAME || db->propagate)
+ && __builtin_expect (cache_add (GETPWBYNAME, dataset->strdata,
+ pw_name_len, &dataset->head,
+ first, db, owner) == 0, 1))
{
- if (req->type == GETPWBYNAME)
+ if (req->type == GETPWBYNAME && db->propagate)
(void) cache_add (GETPWBYUID, cp, key_offset, &dataset->head,
req->type != GETPWBYNAME, db, owner);
}
@@ -425,11 +455,10 @@ addpwbyX (struct database_dyn *db, int fd, request_header *req,
{
char *old_buffer = buffer;
errno = 0;
-#define INCR 1024
if (__builtin_expect (buflen > 32768, 0))
{
- buflen += INCR;
+ buflen *= 2;
buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
if (buffer == NULL)
{
@@ -450,7 +479,7 @@ addpwbyX (struct database_dyn *db, int fd, request_header *req,
else
/* Allocate a new buffer on the stack. If possible combine it
with the previously allocated buffer. */
- buffer = (char *) extend_alloca (buffer, buflen, buflen + INCR);
+ buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
}
#if 0
diff --git a/nscd/selinux.c b/nscd/selinux.c
index f57f0920ae..b826031150 100644
--- a/nscd/selinux.c
+++ b/nscd/selinux.c
@@ -1,5 +1,5 @@
/* SELinux access controls for nscd.
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Matthew Rickard <mjricka@epoch.ncsc.mil>, 2004.
@@ -18,6 +18,7 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+#include "config.h"
#include <error.h>
#include <errno.h>
#include <libintl.h>
@@ -26,10 +27,15 @@
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
+#include <unistd.h>
+#include <sys/prctl.h>
#include <selinux/av_permissions.h>
#include <selinux/avc.h>
#include <selinux/flask.h>
#include <selinux/selinux.h>
+#ifdef HAVE_LIBAUDIT
+# include <libaudit.h>
+#endif
#include "dbg_log.h"
#include "selinux.h"
@@ -66,6 +72,11 @@ static struct avc_entry_ref aeref;
/* Thread to listen for SELinux status changes via netlink. */
static pthread_t avc_notify_thread;
+#ifdef HAVE_LIBAUDIT
+/* Prototype for supporting the audit daemon */
+static void log_callback (const char *fmt, ...);
+#endif
+
/* Prototypes for AVC callback functions. */
static void *avc_create_thread (void (*run) (void));
static void avc_stop_thread (void *thread);
@@ -77,7 +88,11 @@ static void avc_free_lock (void *lock);
/* AVC callback structures for use in avc_init. */
static const struct avc_log_callback log_cb =
{
+#ifdef HAVE_LIBAUDIT
+ .func_log = log_callback,
+#else
.func_log = dbg_log,
+#endif
.func_audit = NULL
};
static const struct avc_thread_callback thread_cb =
@@ -93,6 +108,137 @@ static const struct avc_lock_callback lock_cb =
.func_free_lock = avc_free_lock
};
+#ifdef HAVE_LIBAUDIT
+/* The audit system's netlink socket descriptor */
+static int audit_fd = -1;
+
+/* When an avc denial occurs, log it to audit system */
+static void
+log_callback (const char *fmt, ...)
+{
+ if (audit_fd >= 0)
+ {
+ va_list ap;
+ va_start (ap, fmt);
+
+ char *buf;
+ int e = vasprintf (&buf, fmt, ap);
+ if (e < 0)
+ {
+ buf = alloca (BUFSIZ);
+ vsnprintf (buf, BUFSIZ, fmt, ap);
+ }
+
+ /* FIXME: need to attribute this to real user, using getuid for now */
+ audit_log_user_avc_message (audit_fd, AUDIT_USER_AVC, buf, NULL, NULL,
+ NULL, getuid ());
+
+ if (e >= 0)
+ free (buf);
+
+ va_end (ap);
+ }
+}
+
+/* Initialize the connection to the audit system */
+static void
+audit_init (void)
+{
+ audit_fd = audit_open ();
+ if (audit_fd < 0
+ /* If kernel doesn't support audit, bail out */
+ && errno != EINVAL && errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT)
+ dbg_log (_("Failed opening connection to the audit subsystem: %m"));
+}
+
+
+# ifdef HAVE_LIBCAP
+static const cap_value_t new_cap_list[] =
+ { CAP_AUDIT_WRITE };
+# define nnew_cap_list (sizeof (new_cap_list) / sizeof (new_cap_list[0]))
+static const cap_value_t tmp_cap_list[] =
+ { CAP_AUDIT_WRITE, CAP_SETUID, CAP_SETGID };
+# define ntmp_cap_list (sizeof (tmp_cap_list) / sizeof (tmp_cap_list[0]))
+
+cap_t
+preserve_capabilities (void)
+{
+ if (getuid () != 0)
+ /* Not root, then we cannot preserve anything. */
+ return NULL;
+
+ if (prctl (PR_SET_KEEPCAPS, 1) == -1)
+ {
+ dbg_log (_("Failed to set keep-capabilities"));
+ error (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed"));
+ /* NOTREACHED */
+ }
+
+ cap_t tmp_caps = cap_init ();
+ cap_t new_caps;
+ if (tmp_caps != NULL)
+ new_caps = cap_init ();
+
+ if (tmp_caps == NULL || new_caps == NULL)
+ {
+ if (tmp_caps != NULL)
+ cap_free (tmp_caps);
+
+ dbg_log (_("Failed to initialize drop of capabilities"));
+ error (EXIT_FAILURE, 0, _("cap_init failed"));
+ }
+
+ /* There is no reason why these should not work. */
+ cap_set_flag (new_caps, CAP_PERMITTED, nnew_cap_list,
+ (cap_value_t *) new_cap_list, CAP_SET);
+ cap_set_flag (new_caps, CAP_EFFECTIVE, nnew_cap_list,
+ (cap_value_t *) new_cap_list, CAP_SET);
+
+ cap_set_flag (tmp_caps, CAP_PERMITTED, ntmp_cap_list,
+ (cap_value_t *) tmp_cap_list, CAP_SET);
+ cap_set_flag (tmp_caps, CAP_EFFECTIVE, ntmp_cap_list,
+ (cap_value_t *) tmp_cap_list, CAP_SET);
+
+ int res = cap_set_proc (tmp_caps);
+
+ cap_free (tmp_caps);
+
+ if (__builtin_expect (res != 0, 0))
+ {
+ cap_free (new_caps);
+ dbg_log (_("Failed to drop capabilities\n"));
+ error (EXIT_FAILURE, 0, _("cap_set_proc failed"));
+ }
+
+ return new_caps;
+}
+
+void
+install_real_capabilities (cap_t new_caps)
+{
+ /* If we have no capabilities there is nothing to do here. */
+ if (new_caps == NULL)
+ return;
+
+ if (cap_set_proc (new_caps))
+ {
+ cap_free (new_caps);
+ dbg_log (_("Failed to drop capabilities"));
+ error (EXIT_FAILURE, 0, _("cap_set_proc failed"));
+ /* NOTREACHED */
+ }
+
+ cap_free (new_caps);
+
+ if (prctl (PR_SET_KEEPCAPS, 0) == -1)
+ {
+ dbg_log (_("Failed to unset keep-capabilities"));
+ error (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed"));
+ /* NOTREACHED */
+ }
+}
+# endif /* HAVE_LIBCAP */
+#endif /* HAVE_LIBAUDIT */
/* Determine if we are running on an SELinux kernel. Set selinux_enabled
to the result. */
@@ -182,6 +328,9 @@ nscd_avc_init (void)
error (EXIT_FAILURE, errno, _("Failed to start AVC"));
else
dbg_log (_("Access Vector Cache (AVC) started"));
+#ifdef HAVE_LIBAUDIT
+ audit_init ();
+#endif
}
@@ -262,6 +411,9 @@ void
nscd_avc_destroy (void)
{
avc_destroy ();
+#ifdef HAVE_LIBAUDIT
+ audit_close (audit_fd);
+#endif
}
#endif /* HAVE_SELINUX */
diff --git a/nscd/selinux.h b/nscd/selinux.h
index b9eb053aa0..27afcd6e86 100644
--- a/nscd/selinux.h
+++ b/nscd/selinux.h
@@ -1,5 +1,5 @@
/* Header for nscd SELinux access controls.
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2006, 2007 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Matthew Rickard <mjricka@epoch.ncsc.mil>, 2004.
@@ -22,6 +22,9 @@
#define _SELINUX_H 1
#include "nscd.h"
+#ifdef HAVE_LIBCAP
+# include <sys/capability.h>
+#endif
#ifdef HAVE_SELINUX
/* Global variable to tell if the kernel has SELinux support. */
@@ -42,6 +45,13 @@ extern int nscd_request_avc_has_perm (int fd, request_type req);
extern void nscd_avc_cache_stats (struct avc_cache_stats *cstats);
/* Display statistics on AVC usage. */
extern void nscd_avc_print_stats (struct avc_cache_stats *cstats);
+
+# ifdef HAVE_LIBCAP
+/* Preserve capabilities to connect to connnect to the audit daemon. */
+extern cap_t preserve_capabilities (void);
+/* Install final capabilities. */
+extern void install_real_capabilities (cap_t new_caps);
+# endif
#else
# define selinux_enabled 0
# define nscd_avc_init() (void) 0