summaryrefslogtreecommitdiff
path: root/nscd
diff options
context:
space:
mode:
Diffstat (limited to 'nscd')
-rw-r--r--nscd/Depend2
-rw-r--r--nscd/Makefile15
-rw-r--r--nscd/aicache.c33
-rw-r--r--nscd/cache.c46
-rw-r--r--nscd/connections.c458
-rw-r--r--nscd/dbg_log.c2
-rw-r--r--nscd/dbg_log.h2
-rw-r--r--nscd/gai.c4
-rw-r--r--nscd/getgrgid_r.c2
-rw-r--r--nscd/getgrnam_r.c2
-rw-r--r--nscd/gethstbyad_r.c2
-rw-r--r--nscd/gethstbynm3_r.c2
-rw-r--r--nscd/getpwnam_r.c2
-rw-r--r--nscd/getpwuid_r.c2
-rw-r--r--nscd/getsrvbynm_r.c2
-rw-r--r--nscd/getsrvbypt_r.c2
-rw-r--r--nscd/grpcache.c30
-rw-r--r--nscd/hstcache.c33
-rw-r--r--nscd/initgrcache.c31
-rw-r--r--nscd/mem.c18
-rw-r--r--nscd/netgroupcache.c99
-rw-r--r--nscd/nscd-client.h52
-rw-r--r--nscd/nscd.c324
-rw-r--r--nscd/nscd.h64
-rw-r--r--nscd/nscd.service5
-rw-r--r--nscd/nscd_conf.c5
-rw-r--r--nscd/nscd_getai.c6
-rw-r--r--nscd/nscd_getgr_r.c32
-rw-r--r--nscd/nscd_gethst_r.c10
-rw-r--r--nscd/nscd_getpw_r.c10
-rw-r--r--nscd/nscd_getserv_r.c8
-rw-r--r--nscd/nscd_helper.c43
-rw-r--r--nscd/nscd_initgroups.c4
-rw-r--r--nscd/nscd_netgroup.c6
-rw-r--r--nscd/nscd_proto.h2
-rw-r--r--nscd/nscd_setup_thread.c2
-rw-r--r--nscd/nscd_stat.c4
-rw-r--r--nscd/pwdcache.c30
-rw-r--r--nscd/selinux.c130
-rw-r--r--nscd/selinux.h2
-rw-r--r--nscd/servicescache.c30
41 files changed, 949 insertions, 609 deletions
diff --git a/nscd/Depend b/nscd/Depend
index fe673ba5ec..6c1aa44e6e 100644
--- a/nscd/Depend
+++ b/nscd/Depend
@@ -1 +1 @@
-linuxthreads
+nptl
diff --git a/nscd/Makefile b/nscd/Makefile
index 639d87b9f8..ede941d1b2 100644
--- a/nscd/Makefile
+++ b/nscd/Makefile
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2014 Free Software Foundation, Inc.
+# Copyright (C) 1998-2015 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
@@ -79,23 +79,22 @@ CFLAGS-nscd_gethst_r.c = -fexceptions
CFLAGS-nscd_getai.c = -fexceptions
CFLAGS-nscd_initgroups.c = -fexceptions
-CPPFLAGS-nonlib += -DIS_IN_nscd=1 -D_FORTIFY_SOURCE=2
+CPPFLAGS-nscd += -D_FORTIFY_SOURCE=2
ifeq (yesyes,$(have-fpie)$(build-shared))
-CFLAGS-nonlib += $(pie-ccflag)
+CFLAGS-nscd += $(pie-ccflag)
endif
ifeq (yes,$(have-ssp))
-CFLAGS-nonlib += -fstack-protector
+CFLAGS-nscd += -fstack-protector
endif
ifeq (yesyes,$(have-fpie)$(build-shared))
LDFLAGS-nscd = -Wl,-z,now
endif
-# This makes sure CPPFLAGS-nonlib and CFLAGS-nonlib are passed
-# for all these modules.
-cpp-srcs-left := $(nscd-modules:=.c)
-lib := nonlib
+# Set libof-nscd.
+cpp-srcs-left := $(nscd-modules)
+lib := nscd
include $(patsubst %,$(..)cppflags-iterator.mk,$(cpp-srcs-left))
$(objpfx)nscd: $(nscd-modules:%=$(objpfx)%.o)
diff --git a/nscd/aicache.c b/nscd/aicache.c
index d6b928cf2d..937cb93203 100644
--- a/nscd/aicache.c
+++ b/nscd/aicache.c
@@ -1,5 +1,5 @@
/* Cache handling for host lookup.
- Copyright (C) 2004-2014 Free Software Foundation, Inc.
+ Copyright (C) 2004-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
@@ -77,7 +77,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
char strdata[0];
} *dataset = NULL;
- if (__builtin_expect (debug_level > 0, 0))
+ if (__glibc_unlikely (debug_level > 0))
{
if (he == NULL)
dbg_log (_("Haven't found \"%s\" in hosts cache!"), (char *) key);
@@ -383,17 +383,12 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
cp = family;
}
- /* Fill in the rest of the dataset. */
- dataset->head.allocsize = total + req->key_len;
- dataset->head.recsize = total - offsetof (struct dataset, resp);
- dataset->head.notfound = false;
- dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
- dataset->head.usable = true;
-
- /* Compute the timeout time. */
- dataset->head.ttl = ttl == INT32_MAX ? db->postimeout : ttl;
- timeout = dataset->head.timeout = time (NULL) + dataset->head.ttl;
+ timeout = datahead_init_pos (&dataset->head, total + req->key_len,
+ total - offsetof (struct dataset, resp),
+ he == NULL ? 0 : dh->nreloads + 1,
+ ttl == INT32_MAX ? db->postimeout : ttl);
+ /* Fill in the rest of the dataset. */
dataset->resp.version = NSCD_VERSION;
dataset->resp.found = 1;
dataset->resp.naddrs = naddrs;
@@ -434,7 +429,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
struct dataset *newp
= (struct dataset *) mempool_alloc (db, total + req->key_len,
1);
- if (__builtin_expect (newp != NULL, 1))
+ if (__glibc_likely (newp != NULL))
{
/* Adjust pointer into the memory block. */
key_copy = (char *) newp + (key_copy - (char *) dataset);
@@ -528,15 +523,9 @@ next_nip:
else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
+ req->key_len), 1)) != NULL)
{
- dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
- dataset->head.recsize = total;
- dataset->head.notfound = true;
- dataset->head.nreloads = 0;
- dataset->head.usable = true;
-
- /* Compute the timeout time. */
- timeout = dataset->head.timeout = time (NULL) + db->negtimeout;
- dataset->head.ttl = db->negtimeout;
+ timeout = datahead_init_neg (&dataset->head,
+ sizeof (struct dataset) + req->key_len,
+ total, db->negtimeout);
/* This is the reply. */
memcpy (&dataset->resp, &notfound, total);
diff --git a/nscd/cache.c b/nscd/cache.c
index 2c35a34943..f0200c303c 100644
--- a/nscd/cache.c
+++ b/nscd/cache.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1998-2014 Free Software Foundation, Inc.
+/* Copyright (c) 1998-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
@@ -138,7 +138,7 @@ cache_add (int type, const void *key, size_t len, struct datahead *packet,
bool first, struct database_dyn *table,
uid_t owner, bool prune_wakeup)
{
- if (__builtin_expect (debug_level >= 2, 0))
+ if (__glibc_unlikely (debug_level >= 2))
{
const char *str;
char buf[INET6_ADDRSTRLEN + 1];
@@ -272,28 +272,38 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
while (runp != NULL)
{
#ifdef HAVE_INOTIFY
- if (runp->inotify_descr == -1)
+ if (runp->inotify_descr[TRACED_FILE] == -1)
#endif
{
struct stat64 st;
if (stat64 (runp->fname, &st) < 0)
{
+ /* Print a diagnostic that the traced file was missing.
+ We must not disable tracing since the file might return
+ shortly and we want to reload it at the next pruning.
+ Disabling tracing here would go against the configuration
+ as specified by the user via check-files. */
char buf[128];
- /* We cannot stat() the file, disable file checking if the
- file does not exist. */
- dbg_log (_("cannot stat() file `%s': %s"),
+ dbg_log (_("checking for monitored file `%s': %s"),
runp->fname, strerror_r (errno, buf, sizeof (buf)));
- if (errno == ENOENT)
- table->check_file = 0;
}
else
{
- if (st.st_mtime != table->file_mtime)
+ /* This must be `!=` to catch cases where users turn the
+ clocks back and we still want to detect any time difference
+ in mtime. */
+ if (st.st_mtime != runp->mtime)
{
- /* The file changed. Invalidate all entries. */
+ dbg_log (_("monitored file `%s` changed (mtime)"),
+ runp->fname);
+ /* The file changed. Invalidate all entries. */
now = LONG_MAX;
- table->file_mtime = st.st_mtime;
+ runp->mtime = st.st_mtime;
+#ifdef HAVE_INOTIFY
+ /* Attempt to install a watch on the file. */
+ install_watches (runp);
+#endif
}
}
}
@@ -311,7 +321,7 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
bool *mark;
size_t memory_needed = cnt * sizeof (bool);
bool mark_use_alloca;
- if (__builtin_expect (memory_needed <= MAX_STACK_USE, 1))
+ if (__glibc_likely (memory_needed <= MAX_STACK_USE))
{
mark = alloca (cnt * sizeof (bool));
memset (mark, '\0', memory_needed);
@@ -327,7 +337,7 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
char *const data = table->data;
bool any = false;
- if (__builtin_expect (debug_level > 2, 0))
+ if (__glibc_unlikely (debug_level > 2))
dbg_log (_("pruning %s cache; time %ld"),
dbnames[table - dbs], (long int) now);
@@ -343,7 +353,7 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
struct datahead *dh = (struct datahead *) (data + runp->packet);
/* Some debug support. */
- if (__builtin_expect (debug_level > 2, 0))
+ if (__glibc_unlikely (debug_level > 2))
{
char buf[INET6_ADDRSTRLEN];
const char *str;
@@ -422,7 +432,7 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
}
while (cnt > 0);
- if (__builtin_expect (fd != -1, 0))
+ if (__glibc_unlikely (fd != -1))
{
/* Reply to the INVALIDATE initiator that the cache has been
invalidated. */
@@ -436,7 +446,7 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
/* Now we have to get the write lock since we are about to modify
the table. */
- if (__builtin_expect (pthread_rwlock_trywrlock (&table->lock) != 0, 0))
+ if (__glibc_unlikely (pthread_rwlock_trywrlock (&table->lock) != 0))
{
++table->head->wrlockdelayed;
pthread_rwlock_wrlock (&table->lock);
@@ -492,7 +502,7 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
MS_ASYNC);
/* One extra pass if we do debugging. */
- if (__builtin_expect (debug_level > 0, 0))
+ if (__glibc_unlikely (debug_level > 0))
{
struct hashentry *runp = head;
@@ -517,7 +527,7 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
}
}
- if (__builtin_expect (! mark_use_alloca, 0))
+ if (__glibc_unlikely (! mark_use_alloca))
free (mark);
/* Run garbage collection if any entry has been removed or replaced. */
diff --git a/nscd/connections.c b/nscd/connections.c
index f3732f5ef4..cba5e6ad9d 100644
--- a/nscd/connections.c
+++ b/nscd/connections.c
@@ -1,5 +1,5 @@
/* Inner loops of cache daemon.
- Copyright (C) 1998-2014 Free Software Foundation, Inc.
+ Copyright (C) 1998-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
@@ -59,6 +59,7 @@
#include <resolv/resolv.h>
#include <kernel-features.h>
+#include <libc-internal.h>
/* Support to run nscd as an unprivileged user */
@@ -318,12 +319,6 @@ enum usekey
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,
@@ -472,16 +467,7 @@ verify_persistent_db (void *mem, struct database_pers_head *readhead, int dbnr)
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;
- }
+ goto fail;
work = here->next;
@@ -501,10 +487,6 @@ verify_persistent_db (void *mem, struct database_pers_head *readhead, int dbnr)
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;
}
@@ -649,8 +631,8 @@ cannot create read-only descriptor for \"%s\"; no mmap"),
close (fd);
}
else if (errno == EACCES)
- error (EXIT_FAILURE, 0, _("cannot access '%s'"),
- dbs[cnt].db_filename);
+ do_exit (EXIT_FAILURE, 0, _("cannot access '%s'"),
+ dbs[cnt].db_filename);
}
if (dbs[cnt].head == NULL)
@@ -699,8 +681,7 @@ cannot create read-only descriptor for \"%s\"; no mmap"),
{
dbg_log (_("database for %s corrupted or simultaneously used; remove %s manually if necessary and restart"),
dbnames[cnt], dbs[cnt].db_filename);
- // XXX Correct way to terminate?
- exit (1);
+ do_exit (1, 0, NULL);
}
if (dbs[cnt].persistent)
@@ -867,7 +848,7 @@ cannot set socket to close on exec: %s; disabling paranoia mode"),
if (sock < 0)
{
dbg_log (_("cannot open socket: %s"), strerror (errno));
- exit (errno == EACCES ? 4 : 1);
+ do_exit (errno == EACCES ? 4 : 1, 0, NULL);
}
/* Bind a name to the socket. */
struct sockaddr_un sock_addr;
@@ -876,7 +857,7 @@ cannot set socket to close on exec: %s; disabling paranoia mode"),
if (bind (sock, (struct sockaddr *) &sock_addr, sizeof (sock_addr)) < 0)
{
dbg_log ("%s: %s", _PATH_NSCDSOCKET, strerror (errno));
- exit (errno == EACCES ? 4 : 1);
+ do_exit (errno == EACCES ? 4 : 1, 0, NULL);
}
#ifndef __ASSUME_SOCK_CLOEXEC
@@ -888,7 +869,7 @@ cannot set socket to close on exec: %s; disabling paranoia mode"),
{
dbg_log (_("cannot change socket to nonblocking mode: %s"),
strerror (errno));
- exit (1);
+ do_exit (1, 0, NULL);
}
/* The descriptor needs to be closed on exec. */
@@ -896,7 +877,7 @@ cannot set socket to close on exec: %s; disabling paranoia mode"),
{
dbg_log (_("cannot set socket to close on exec: %s"),
strerror (errno));
- exit (1);
+ do_exit (1, 0, NULL);
}
}
#endif
@@ -909,7 +890,7 @@ cannot set socket to close on exec: %s; disabling paranoia mode"),
{
dbg_log (_("cannot enable socket to accept connections: %s"),
strerror (errno));
- exit (1);
+ do_exit (1, 0, NULL);
}
#ifdef HAVE_NETLINK
@@ -953,7 +934,7 @@ cannot set socket to close on exec: %s; disabling paranoia mode"),
dbg_log (_("\
cannot change socket to nonblocking mode: %s"),
strerror (errno));
- exit (1);
+ do_exit (1, 0, NULL);
}
/* The descriptor needs to be closed on exec. */
@@ -962,7 +943,7 @@ cannot change socket to nonblocking mode: %s"),
{
dbg_log (_("cannot set socket to close on exec: %s"),
strerror (errno));
- exit (1);
+ do_exit (1, 0, NULL);
}
}
# endif
@@ -976,6 +957,44 @@ cannot change socket to nonblocking mode: %s"),
finish_drop_privileges ();
}
+#ifdef HAVE_INOTIFY
+#define TRACED_FILE_MASK (IN_DELETE_SELF | IN_CLOSE_WRITE | IN_MOVE_SELF)
+#define TRACED_DIR_MASK (IN_DELETE_SELF | IN_CREATE | IN_MOVED_TO | IN_MOVE_SELF)
+void
+install_watches (struct traced_file *finfo)
+{
+ /* Use inotify support if we have it. */
+ if (finfo->inotify_descr[TRACED_FILE] < 0)
+ finfo->inotify_descr[TRACED_FILE] = inotify_add_watch (inotify_fd,
+ finfo->fname,
+ TRACED_FILE_MASK);
+ if (finfo->inotify_descr[TRACED_FILE] < 0)
+ {
+ dbg_log (_("disabled inotify-based monitoring for file `%s': %s"),
+ finfo->fname, strerror (errno));
+ return;
+ }
+ dbg_log (_("monitoring file `%s` (%d)"),
+ finfo->fname, finfo->inotify_descr[TRACED_FILE]);
+ /* Additionally listen for events in the file's parent directory.
+ We do this because the file to be watched might be
+ deleted and then added back again. When it is added back again
+ we must re-add the watch. We must also cover IN_MOVED_TO to
+ detect a file being moved into the directory. */
+ if (finfo->inotify_descr[TRACED_DIR] < 0)
+ finfo->inotify_descr[TRACED_DIR] = inotify_add_watch (inotify_fd,
+ finfo->dname,
+ TRACED_DIR_MASK);
+ if (finfo->inotify_descr[TRACED_DIR] < 0)
+ {
+ dbg_log (_("disabled inotify-based monitoring for directory `%s': %s"),
+ finfo->fname, strerror (errno));
+ return;
+ }
+ dbg_log (_("monitoring directory `%s` (%d)"),
+ finfo->dname, finfo->inotify_descr[TRACED_DIR]);
+}
+#endif
/* Register the file in FINFO as a traced file for the database DBS[DBIX].
@@ -999,31 +1018,23 @@ register_traced_file (size_t dbidx, struct traced_file *finfo)
if (! dbs[dbidx].enabled || ! dbs[dbidx].check_file)
return;
- if (__builtin_expect (debug_level > 0, 0))
- dbg_log (_("register trace file %s for database %s"),
+ if (__glibc_unlikely (debug_level > 0))
+ dbg_log (_("monitoring file %s for database %s"),
finfo->fname, dbnames[dbidx]);
#ifdef HAVE_INOTIFY
- if (inotify_fd < 0
- || (finfo->inotify_descr = inotify_add_watch (inotify_fd, finfo->fname,
- IN_DELETE_SELF
- | IN_MODIFY)) < 0)
+ install_watches (finfo);
#endif
+ struct stat64 st;
+ if (stat64 (finfo->fname, &st) < 0)
{
- /* We need the modification date of the file. */
- struct stat64 st;
-
- if (stat64 (finfo->fname, &st) < 0)
- {
- /* We cannot stat() the file, disable file checking. */
- dbg_log (_("cannot stat() file `%s': %s"),
- finfo->fname, strerror (errno));
- return;
- }
-
- finfo->inotify_descr = -1;
- finfo->mtime = st.st_mtime;
+ /* We cannot stat() the file. Set mtime to zero and try again later. */
+ dbg_log (_("stat failed for file `%s'; will try again later: %s"),
+ finfo->fname, strerror (errno));
+ finfo->mtime = 0;
}
+ else
+ finfo->mtime = st.st_mtime;
/* Queue up the file name. */
finfo->next = dbs[dbidx].traced_files;
@@ -1048,20 +1059,27 @@ invalidate_cache (char *key, int fd)
for (number = pwddb; number < lastdb; ++number)
if (strcmp (key, dbnames[number]) == 0)
{
- if (number == hstdb)
+ struct traced_file *runp = dbs[number].traced_files;
+ while (runp != NULL)
{
- struct traced_file *runp = dbs[hstdb].traced_files;
- while (runp != NULL)
- if (runp->call_res_init)
- {
- res_init ();
- break;
- }
- else
- runp = runp->next;
+ /* Make sure we reload from file when checking mtime. */
+ runp->mtime = 0;
+#ifdef HAVE_INOTIFY
+ /* During an invalidation we try to reload the traced
+ file watches. This allows the user to re-sync if
+ inotify events were lost. Similar to what we do during
+ pruning. */
+ install_watches (runp);
+#endif
+ if (runp->call_res_init)
+ {
+ res_init ();
+ break;
+ }
+ runp = runp->next;
}
break;
- }
+ }
if (number == lastdb)
{
@@ -1129,7 +1147,7 @@ send_ro_fd (struct database_dyn *db, char *key, int fd)
#endif
(void) TEMP_FAILURE_RETRY (sendmsg (fd, &msg, MSG_NOSIGNAL));
- if (__builtin_expect (debug_level > 0, 0))
+ if (__glibc_unlikely (debug_level > 0))
dbg_log (_("provide access to FD %d, for %s"), db->ro_fd, key);
}
#endif /* SCM_RIGHTS */
@@ -1201,7 +1219,7 @@ request from '%s' [%ld] not handled due to missing permission"),
}
/* Is this service enabled? */
- if (__builtin_expect (!db->enabled, 0))
+ if (__glibc_unlikely (!db->enabled))
{
/* No, sent the prepared record. */
if (TEMP_FAILURE_RETRY (send (fd, db->disabled_iov->iov_base,
@@ -1220,7 +1238,7 @@ request from '%s' [%ld] not handled due to missing permission"),
}
/* Be sure we can read the data. */
- if (__builtin_expect (pthread_rwlock_tryrdlock (&db->lock) != 0, 0))
+ if (__glibc_unlikely (pthread_rwlock_tryrdlock (&db->lock) != 0))
{
++db->head->rdlockdelayed;
pthread_rwlock_rdlock (&db->lock);
@@ -1236,7 +1254,7 @@ request from '%s' [%ld] not handled due to missing permission"),
ssize_t nwritten;
#ifdef HAVE_SENDFILE
- if (__builtin_expect (db->mmap_used, 1))
+ if (__glibc_likely (db->mmap_used))
{
assert (db->wr_fd != -1);
assert ((char *) cached->data > (char *) db->data);
@@ -1484,7 +1502,7 @@ cannot change to old UID: %s; disabling paranoia mode"),
cannot change to old GID: %s; disabling paranoia mode"),
strerror (errno));
- setuid (server_uid);
+ ignore_value (setuid (server_uid));
paranoia = 0;
return;
}
@@ -1499,8 +1517,8 @@ cannot change to old working directory: %s; disabling paranoia mode"),
if (server_user != NULL)
{
- setuid (server_uid);
- setgid (server_gid);
+ ignore_value (setuid (server_uid));
+ ignore_value (setgid (server_gid));
}
paranoia = 0;
return;
@@ -1544,8 +1562,8 @@ cannot change to old working directory: %s; disabling paranoia mode"),
if (server_user != NULL)
{
- setuid (server_uid);
- setgid (server_gid);
+ ignore_value (setuid (server_uid));
+ ignore_value (setgid (server_gid));
}
if (chdir ("/") != 0)
dbg_log (_("cannot change current working directory to \"/\": %s"),
@@ -1603,7 +1621,7 @@ nscd_run_prune (void *p)
dbs[my_number].head->timestamp = now;
struct timespec prune_ts;
- if (__builtin_expect (clock_gettime (timeout_clock, &prune_ts) == -1, 0))
+ if (__glibc_unlikely (clock_gettime (timeout_clock, &prune_ts) == -1))
/* Should never happen. */
abort ();
@@ -1656,7 +1674,7 @@ nscd_run_prune (void *p)
we need to wake up occasionally to update the timestamp.
Wait 90% of the update period. */
#define UPDATE_MAPPING_TIMEOUT (MAPPING_TIMEOUT * 9 / 10)
- if (__builtin_expect (! dont_need_update, 0))
+ if (__glibc_unlikely (! dont_need_update))
{
next_wait = MIN (UPDATE_MAPPING_TIMEOUT, next_wait);
dbs[my_number].head->timestamp = now;
@@ -1756,7 +1774,7 @@ nscd_run_worker (void *p)
#ifdef SO_PEERCRED
pid_t pid = 0;
- if (__builtin_expect (debug_level > 0, 0))
+ if (__glibc_unlikely (debug_level > 0))
{
struct ucred caller;
socklen_t optlen = sizeof (caller);
@@ -1849,7 +1867,7 @@ fd_ready (int fd)
}
bool do_signal = true;
- if (__builtin_expect (nready == 0, 0))
+ if (__glibc_unlikely (nready == 0))
{
++client_queued;
do_signal = false;
@@ -1899,11 +1917,28 @@ union __inev
char buf[sizeof (struct inotify_event) + PATH_MAX];
};
+/* Returns 0 if the file is there otherwise -1. */
+int
+check_file (struct traced_file *finfo)
+{
+ struct stat64 st;
+ /* We could check mtime and if different re-add
+ the watches, and invalidate the database, but we
+ don't because we are called from inotify_check_files
+ which should be doing that work. If sufficient inotify
+ events were lost then the next pruning or invalidation
+ will do the stat and mtime check. We don't do it here to
+ keep the logic simple. */
+ if (stat64 (finfo->fname, &st) < 0)
+ return -1;
+ return 0;
+}
+
/* Process the inotify event in INEV. If the event matches any of the files
registered with a database then mark that database as requiring its cache
to be cleared. We indicate the cache needs clearing by setting
TO_CLEAR[DBCNT] to true for the matching database. */
-static inline void
+static void
inotify_check_files (bool *to_clear, union __inev *inev)
{
/* Check which of the files changed. */
@@ -1913,16 +1948,124 @@ inotify_check_files (bool *to_clear, union __inev *inev)
while (finfo != NULL)
{
- /* Inotify event watch descriptor matches. */
- if (finfo->inotify_descr == inev->i.wd)
+ /* The configuration file was moved or deleted.
+ We stop watching it at that point, and reinitialize. */
+ if (finfo->inotify_descr[TRACED_FILE] == inev->i.wd
+ && ((inev->i.mask & IN_MOVE_SELF)
+ || (inev->i.mask & IN_DELETE_SELF)
+ || (inev->i.mask & IN_IGNORED)))
+ {
+ int ret;
+ bool moved = (inev->i.mask & IN_MOVE_SELF) != 0;
+
+ if (check_file (finfo) == 0)
+ {
+ dbg_log (_("ignored inotify event for `%s` (file exists)"),
+ finfo->fname);
+ return;
+ }
+
+ dbg_log (_("monitored file `%s` was %s, removing watch"),
+ finfo->fname, moved ? "moved" : "deleted");
+ /* File was moved out, remove the watch. Watches are
+ automatically removed when the file is deleted. */
+ if (moved)
+ {
+ ret = inotify_rm_watch (inotify_fd, inev->i.wd);
+ if (ret < 0)
+ dbg_log (_("failed to remove file watch `%s`: %s"),
+ finfo->fname, strerror (errno));
+ }
+ finfo->inotify_descr[TRACED_FILE] = -1;
+ to_clear[dbcnt] = true;
+ if (finfo->call_res_init)
+ res_init ();
+ return;
+ }
+ /* The configuration file was open for writing and has just closed.
+ We reset the cache and reinitialize. */
+ if (finfo->inotify_descr[TRACED_FILE] == inev->i.wd
+ && inev->i.mask & IN_CLOSE_WRITE)
{
/* Mark cache as needing to be cleared and reinitialize. */
+ dbg_log (_("monitored file `%s` was written to"), finfo->fname);
to_clear[dbcnt] = true;
if (finfo->call_res_init)
res_init ();
return;
}
+ /* The parent directory was moved or deleted. We trigger one last
+ invalidation. At the next pruning or invalidation we may add
+ this watch back if the file is present again. */
+ if (finfo->inotify_descr[TRACED_DIR] == inev->i.wd
+ && ((inev->i.mask & IN_DELETE_SELF)
+ || (inev->i.mask & IN_MOVE_SELF)
+ || (inev->i.mask & IN_IGNORED)))
+ {
+ bool moved = (inev->i.mask & IN_MOVE_SELF) != 0;
+ /* The directory watch may have already been removed
+ but we don't know so we just remove it again and
+ ignore the error. Then we remove the file watch.
+ Note: watches are automatically removed for deleted
+ files. */
+ if (moved)
+ inotify_rm_watch (inotify_fd, inev->i.wd);
+ if (finfo->inotify_descr[TRACED_FILE] != -1)
+ {
+ dbg_log (_("monitored parent directory `%s` was %s, removing watch on `%s`"),
+ finfo->dname, moved ? "moved" : "deleted", finfo->fname);
+ if (inotify_rm_watch (inotify_fd, finfo->inotify_descr[TRACED_FILE]) < 0)
+ dbg_log (_("failed to remove file watch `%s`: %s"),
+ finfo->dname, strerror (errno));
+ }
+ finfo->inotify_descr[TRACED_FILE] = -1;
+ finfo->inotify_descr[TRACED_DIR] = -1;
+ to_clear[dbcnt] = true;
+ if (finfo->call_res_init)
+ res_init ();
+ /* Continue to the next entry since this might be the
+ parent directory for multiple registered files and
+ we want to remove watches for all registered files. */
+ continue;
+ }
+ /* The parent directory had a create or moved to event. */
+ if (finfo->inotify_descr[TRACED_DIR] == inev->i.wd
+ && ((inev->i.mask & IN_MOVED_TO)
+ || (inev->i.mask & IN_CREATE))
+ && strcmp (inev->i.name, finfo->sfname) == 0)
+ {
+ /* We detected a directory change. We look for the creation
+ of the file we are tracking or the move of the same file
+ into the directory. */
+ int ret;
+ dbg_log (_("monitored file `%s` was %s, adding watch"),
+ finfo->fname,
+ inev->i.mask & IN_CREATE ? "created" : "moved into place");
+ /* File was moved in or created. Regenerate the watch. */
+ if (finfo->inotify_descr[TRACED_FILE] != -1)
+ inotify_rm_watch (inotify_fd,
+ finfo->inotify_descr[TRACED_FILE]);
+
+ ret = inotify_add_watch (inotify_fd,
+ finfo->fname,
+ TRACED_FILE_MASK);
+ if (ret < 0)
+ dbg_log (_("failed to add file watch `%s`: %s"),
+ finfo->fname, strerror (errno));
+
+ finfo->inotify_descr[TRACED_FILE] = ret;
+
+ /* The file is new or moved so mark cache as needing to
+ be cleared and reinitialize. */
+ to_clear[dbcnt] = true;
+ if (finfo->call_res_init)
+ res_init ();
+ /* Done re-adding the watch. Don't return, we may still
+ have other files in this same directory, same watch
+ descriptor, and need to process them. */
+ }
+ /* Other events are ignored, and we move on to the next file. */
finfo = finfo->next;
}
}
@@ -1944,6 +2087,51 @@ clear_db_cache (bool *to_clear)
}
}
+int
+handle_inotify_events (void)
+{
+ bool to_clear[lastdb] = { false, };
+ union __inev inev;
+
+ /* Read all inotify events for files registered via
+ register_traced_file(). */
+ while (1)
+ {
+ /* Potentially read multiple events into buf. */
+ ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd,
+ &inev.buf,
+ sizeof (inev)));
+ if (nb < (ssize_t) sizeof (struct inotify_event))
+ {
+ /* Not even 1 event. */
+ if (__glibc_unlikely (nb == -1 && errno != EAGAIN))
+ return -1;
+ /* Done reading events that are ready. */
+ break;
+ }
+ /* Process all events. The normal inotify interface delivers
+ complete events on a read and never a partial event. */
+ char *eptr = &inev.buf[0];
+ ssize_t count;
+ while (1)
+ {
+ /* Check which of the files changed. */
+ inotify_check_files (to_clear, &inev);
+ count = sizeof (struct inotify_event) + inev.i.len;
+ eptr += count;
+ nb -= count;
+ if (nb >= (ssize_t) sizeof (struct inotify_event))
+ memcpy (&inev, eptr, nb);
+ else
+ break;
+ }
+ continue;
+ }
+ /* Actually perform the cache clearing. */
+ clear_db_cache (to_clear);
+ return 0;
+}
+
#endif
static void
@@ -2050,42 +2238,20 @@ main_loop_poll (void)
{
if (conns[1].revents != 0)
{
- bool to_clear[lastdb] = { false, };
- union __inev inev;
-
- /* Read all inotify events for files registered via
- register_traced_file(). */
- while (1)
+ int ret;
+ ret = handle_inotify_events ();
+ if (ret == -1)
{
- ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd, &inev,
- sizeof (inev)));
- if (nb < (ssize_t) sizeof (struct inotify_event))
- {
- if (__builtin_expect (nb == -1 && errno != EAGAIN,
- 0))
- {
- /* Something went wrong when reading the inotify
- data. Better disable inotify. */
- dbg_log (_("\
-disabled inotify after read error %d"),
- errno);
- conns[1].fd = -1;
- firstfree = 1;
- if (nused == 2)
- nused = 1;
- close (inotify_fd);
- inotify_fd = -1;
- }
- break;
- }
-
- /* Check which of the files changed. */
- inotify_check_files (to_clear, &inev);
+ /* Something went wrong when reading the inotify
+ data. Better disable inotify. */
+ dbg_log (_("disabled inotify-based monitoring after read error %d"), errno);
+ conns[1].fd = -1;
+ firstfree = 1;
+ if (nused == 2)
+ nused = 1;
+ close (inotify_fd);
+ inotify_fd = -1;
}
-
- /* Actually perform the cache clearing. */
- clear_db_cache (to_clear);
-
--n;
}
@@ -2253,37 +2419,18 @@ main_loop_epoll (int efd)
# ifdef HAVE_INOTIFY
else if (revs[cnt].data.fd == inotify_fd)
{
- bool to_clear[lastdb] = { false, };
- union __inev inev;
-
- /* Read all inotify events for files registered via
- register_traced_file(). */
- while (1)
+ int ret;
+ ret = handle_inotify_events ();
+ if (ret == -1)
{
- ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd, &inev,
- sizeof (inev)));
- if (nb < (ssize_t) sizeof (struct inotify_event))
- {
- if (__builtin_expect (nb == -1 && errno != EAGAIN, 0))
- {
- /* Something went wrong when reading the inotify
- data. Better disable inotify. */
- dbg_log (_("disabled inotify after read error %d"),
- errno);
- (void) epoll_ctl (efd, EPOLL_CTL_DEL, inotify_fd,
- NULL);
- close (inotify_fd);
- inotify_fd = -1;
- }
- break;
- }
-
- /* Check which of the files changed. */
- inotify_check_files(to_clear, &inev);
+ /* Something went wrong when reading the inotify
+ data. Better disable inotify. */
+ dbg_log (_("disabled inotify-based monitoring after read error %d"), errno);
+ (void) epoll_ctl (efd, EPOLL_CTL_DEL, inotify_fd, NULL);
+ close (inotify_fd);
+ inotify_fd = -1;
+ break;
}
-
- /* Actually perform the cache clearing. */
- clear_db_cache (to_clear);
}
# endif
# ifdef HAVE_NETLINK
@@ -2320,7 +2467,9 @@ main_loop_epoll (int efd)
no reply in too long of a time. */
time_t laststart = now - ACCEPT_TIMEOUT;
assert (starttime[sock] == 0);
+# ifdef HAVE_INOTIFY
assert (inotify_fd == -1 || starttime[inotify_fd] == 0);
+# endif
assert (nl_status_fd == -1 || starttime[nl_status_fd] == 0);
for (int cnt = highest; cnt > STDERR_FILENO; --cnt)
if (starttime[cnt] != 0 && starttime[cnt] < laststart)
@@ -2392,7 +2541,7 @@ start_threads (void)
if (pthread_cond_init (&dbs[i].prune_cond, &condattr) != 0)
{
dbg_log (_("could not initialize conditional variable"));
- exit (1);
+ do_exit (1, 0, NULL);
}
pthread_t th;
@@ -2400,7 +2549,7 @@ start_threads (void)
&& pthread_create (&th, &attr, nscd_run_prune, (void *) i) != 0)
{
dbg_log (_("could not start clean-up thread; terminating"));
- exit (1);
+ do_exit (1, 0, NULL);
}
}
@@ -2414,13 +2563,17 @@ start_threads (void)
if (i == 0)
{
dbg_log (_("could not start any worker thread; terminating"));
- exit (1);
+ do_exit (1, 0, NULL);
}
break;
}
}
+ /* Now it is safe to let the parent know that we're doing fine and it can
+ exit. */
+ notify_parent (0);
+
/* Determine how much room for descriptors we should initially
allocate. This might need to change later if we cap the number
with MAXCONN. */
@@ -2465,8 +2618,8 @@ begin_drop_privileges (void)
if (pwd == NULL)
{
dbg_log (_("Failed to run nscd as user '%s'"), server_user);
- error (EXIT_FAILURE, 0, _("Failed to run nscd as user '%s'"),
- server_user);
+ do_exit (EXIT_FAILURE, 0,
+ _("Failed to run nscd as user '%s'"), server_user);
}
server_uid = pwd->pw_uid;
@@ -2483,7 +2636,8 @@ begin_drop_privileges (void)
{
/* This really must never happen. */
dbg_log (_("Failed to run nscd as user '%s'"), server_user);
- error (EXIT_FAILURE, errno, _("initial getgrouplist failed"));
+ do_exit (EXIT_FAILURE, errno,
+ _("initial getgrouplist failed"));
}
server_groups = (gid_t *) xmalloc (server_ngroups * sizeof (gid_t));
@@ -2492,7 +2646,7 @@ begin_drop_privileges (void)
== -1)
{
dbg_log (_("Failed to run nscd as user '%s'"), server_user);
- error (EXIT_FAILURE, errno, _("getgrouplist failed"));
+ do_exit (EXIT_FAILURE, errno, _("getgrouplist failed"));
}
}
@@ -2510,7 +2664,7 @@ finish_drop_privileges (void)
if (setgroups (server_ngroups, server_groups) == -1)
{
dbg_log (_("Failed to run nscd as user '%s'"), server_user);
- error (EXIT_FAILURE, errno, _("setgroups failed"));
+ do_exit (EXIT_FAILURE, errno, _("setgroups failed"));
}
int res;
@@ -2521,8 +2675,7 @@ finish_drop_privileges (void)
if (res == -1)
{
dbg_log (_("Failed to run nscd as user '%s'"), server_user);
- perror ("setgid");
- exit (4);
+ do_exit (4, errno, "setgid");
}
if (paranoia)
@@ -2532,8 +2685,7 @@ finish_drop_privileges (void)
if (res == -1)
{
dbg_log (_("Failed to run nscd as user '%s'"), server_user);
- perror ("setuid");
- exit (4);
+ do_exit (4, errno, "setuid");
}
#if defined HAVE_LIBAUDIT && defined HAVE_LIBCAP
diff --git a/nscd/dbg_log.c b/nscd/dbg_log.c
index f42d18c731..f2cd4282d2 100644
--- a/nscd/dbg_log.c
+++ b/nscd/dbg_log.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1998-2014 Free Software Foundation, Inc.
+/* Copyright (c) 1998-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
diff --git a/nscd/dbg_log.h b/nscd/dbg_log.h
index d042b1ab75..22eed37fa9 100644
--- a/nscd/dbg_log.h
+++ b/nscd/dbg_log.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 1998-2014 Free Software Foundation, Inc.
+/* Copyright (c) 1998-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
diff --git a/nscd/gai.c b/nscd/gai.c
index 47d3d402fe..9a52a97452 100644
--- a/nscd/gai.c
+++ b/nscd/gai.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004-2014 Free Software Foundation, Inc.
+/* Copyright (C) 2004-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 2004.
@@ -16,7 +16,6 @@
along with this program; if not, see <http://www.gnu.org/licenses/>. */
#include <alloca.h>
-#include <kernel-features.h>
/* This file uses the getaddrinfo code but it compiles it without NSCD
support. We just need a few symbol renames. */
@@ -29,6 +28,7 @@
#define __sendto sendto
#define __strchrnul strchrnul
#define __getline getline
+#define __qsort_r qsort_r
/* nscd uses 1MB or 2MB thread stacks. */
#define __libc_use_alloca(size) (size <= __MAX_ALLOCA_CUTOFF)
diff --git a/nscd/getgrgid_r.c b/nscd/getgrgid_r.c
index 4864c12187..fe5bda4241 100644
--- a/nscd/getgrgid_r.c
+++ b/nscd/getgrgid_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-2014 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
diff --git a/nscd/getgrnam_r.c b/nscd/getgrnam_r.c
index 6056a01d16..5ec56877f5 100644
--- a/nscd/getgrnam_r.c
+++ b/nscd/getgrnam_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-2014 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
diff --git a/nscd/gethstbyad_r.c b/nscd/gethstbyad_r.c
index ccb8775836..4964f532cf 100644
--- a/nscd/gethstbyad_r.c
+++ b/nscd/gethstbyad_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-2014 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
diff --git a/nscd/gethstbynm3_r.c b/nscd/gethstbynm3_r.c
index 8897f31a37..c5ba65e5e9 100644
--- a/nscd/gethstbynm3_r.c
+++ b/nscd/gethstbynm3_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-2014 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
diff --git a/nscd/getpwnam_r.c b/nscd/getpwnam_r.c
index 956c4e2a6b..95111173cf 100644
--- a/nscd/getpwnam_r.c
+++ b/nscd/getpwnam_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-2014 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
diff --git a/nscd/getpwuid_r.c b/nscd/getpwuid_r.c
index 3dda341a4d..40c2dcbf80 100644
--- a/nscd/getpwuid_r.c
+++ b/nscd/getpwuid_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-2014 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
diff --git a/nscd/getsrvbynm_r.c b/nscd/getsrvbynm_r.c
index d48242ec14..ce4d96df63 100644
--- a/nscd/getsrvbynm_r.c
+++ b/nscd/getsrvbynm_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-2014 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
diff --git a/nscd/getsrvbypt_r.c b/nscd/getsrvbypt_r.c
index 5c1ec3257a..fa3670b176 100644
--- a/nscd/getsrvbypt_r.c
+++ b/nscd/getsrvbypt_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-2014 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
diff --git a/nscd/grpcache.c b/nscd/grpcache.c
index 8f5d39b138..eed0e3dca8 100644
--- a/nscd/grpcache.c
+++ b/nscd/grpcache.c
@@ -1,5 +1,5 @@
/* Cache handling for group lookup.
- Copyright (C) 1998-2014 Free Software Foundation, Inc.
+ Copyright (C) 1998-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
@@ -128,14 +128,10 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req,
}
else if ((dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1)) != NULL)
{
- dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
- dataset->head.recsize = total;
- dataset->head.notfound = true;
- dataset->head.nreloads = 0;
- dataset->head.usable = true;
-
- /* Compute the timeout time. */
- timeout = dataset->head.timeout = t + db->negtimeout;
+ timeout = datahead_init_neg (&dataset->head,
+ (sizeof (struct dataset)
+ + req->key_len), total,
+ db->negtimeout);
/* This is the reply. */
memcpy (&dataset->resp, &notfound, total);
@@ -232,14 +228,10 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req,
dataset_temporary = true;
}
- dataset->head.allocsize = total + n;
- dataset->head.recsize = total - offsetof (struct dataset, resp);
- dataset->head.notfound = false;
- dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
- dataset->head.usable = true;
-
- /* Compute the timeout time. */
- timeout = dataset->head.timeout = t + db->postimeout;
+ timeout = datahead_init_pos (&dataset->head, total + n,
+ total - offsetof (struct dataset, resp),
+ he == NULL ? 0 : dh->nreloads + 1,
+ db->postimeout);
dataset->resp.version = NSCD_VERSION;
dataset->resp.found = 1;
@@ -452,7 +444,7 @@ addgrbyX (struct database_dyn *db, int fd, request_header *req,
bool use_malloc = false;
int errval = 0;
- if (__builtin_expect (debug_level > 0, 0))
+ if (__glibc_unlikely (debug_level > 0))
{
if (he == NULL)
dbg_log (_("Haven't found \"%s\" in group cache!"), keystr);
@@ -465,7 +457,7 @@ addgrbyX (struct database_dyn *db, int fd, request_header *req,
{
errno = 0;
- if (__builtin_expect (buflen > 32768, 0))
+ if (__glibc_unlikely (buflen > 32768))
{
char *old_buffer = buffer;
buflen *= 2;
diff --git a/nscd/hstcache.c b/nscd/hstcache.c
index abedf9a63e..e6db06451b 100644
--- a/nscd/hstcache.c
+++ b/nscd/hstcache.c
@@ -1,5 +1,5 @@
/* Cache handling for host lookup.
- Copyright (C) 1998-2014 Free Software Foundation, Inc.
+ Copyright (C) 1998-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
@@ -152,15 +152,11 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
+ req->key_len), 1)) != NULL)
{
- dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
- dataset->head.recsize = total;
- dataset->head.notfound = true;
- dataset->head.nreloads = 0;
- dataset->head.usable = true;
-
- /* Compute the timeout time. */
- dataset->head.ttl = ttl == INT32_MAX ? db->negtimeout : ttl;
- timeout = dataset->head.timeout = t + dataset->head.ttl;
+ timeout = datahead_init_neg (&dataset->head,
+ (sizeof (struct dataset)
+ + req->key_len), total,
+ (ttl == INT32_MAX
+ ? db->negtimeout : ttl));
/* This is the reply. */
memcpy (&dataset->resp, resp, total);
@@ -257,15 +253,10 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
alloca_used = true;
}
- dataset->head.allocsize = total + req->key_len;
- dataset->head.recsize = total - offsetof (struct dataset, resp);
- dataset->head.notfound = false;
- dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
- dataset->head.usable = true;
-
- /* Compute the timeout time. */
- dataset->head.ttl = ttl == INT32_MAX ? db->postimeout : ttl;
- timeout = dataset->head.timeout = t + dataset->head.ttl;
+ timeout = datahead_init_pos (&dataset->head, total + req->key_len,
+ total - offsetof (struct dataset, resp),
+ he == NULL ? 0 : dh->nreloads + 1,
+ ttl == INT32_MAX ? db->postimeout : ttl);
dataset->resp.version = NSCD_VERSION;
dataset->resp.found = 1;
@@ -480,7 +471,7 @@ addhstbyX (struct database_dyn *db, int fd, request_header *req,
int errval = 0;
int32_t ttl = INT32_MAX;
- if (__builtin_expect (debug_level > 0, 0))
+ if (__glibc_unlikely (debug_level > 0))
{
const char *str;
char buf[INET6_ADDRSTRLEN + 1];
@@ -502,7 +493,7 @@ addhstbyX (struct database_dyn *db, int fd, request_header *req,
{
errno = 0;
- if (__builtin_expect (buflen > 32768, 0))
+ if (__glibc_unlikely (buflen > 32768))
{
char *old_buffer = buffer;
buflen *= 2;
diff --git a/nscd/initgrcache.c b/nscd/initgrcache.c
index a727fa9c8b..e45d65c006 100644
--- a/nscd/initgrcache.c
+++ b/nscd/initgrcache.c
@@ -1,5 +1,5 @@
/* Cache handling for host lookup.
- Copyright (C) 2004-2014 Free Software Foundation, Inc.
+ Copyright (C) 2004-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
@@ -24,6 +24,7 @@
#include <time.h>
#include <unistd.h>
#include <sys/mman.h>
+#include <scratch_buffer.h>
#include "dbg_log.h"
#include "nscd.h"
@@ -71,7 +72,7 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req,
char strdata[0];
} *dataset = NULL;
- if (__builtin_expect (debug_level > 0, 0))
+ if (__glibc_unlikely (debug_level > 0))
{
if (he == NULL)
dbg_log (_("Haven't found \"%s\" in group cache!"), (char *) key);
@@ -112,7 +113,7 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req,
mempool_alloc. */
// XXX This really should use alloca. need to change the backends.
gid_t *groups = (gid_t *) malloc (size * sizeof (gid_t));
- if (__builtin_expect (groups == NULL, 0))
+ if (__glibc_unlikely (groups == NULL))
/* No more memory. */
goto out;
@@ -213,14 +214,10 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req,
else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
+ req->key_len), 1)) != NULL)
{
- dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
- dataset->head.recsize = total;
- dataset->head.notfound = true;
- dataset->head.nreloads = 0;
- dataset->head.usable = true;
-
- /* Compute the timeout time. */
- timeout = dataset->head.timeout = time (NULL) + db->negtimeout;
+ timeout = datahead_init_neg (&dataset->head,
+ (sizeof (struct dataset)
+ + req->key_len), total,
+ db->negtimeout);
/* This is the reply. */
memcpy (&dataset->resp, &notfound, total);
@@ -276,14 +273,10 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req,
alloca_used = true;
}
- dataset->head.allocsize = total + req->key_len;
- dataset->head.recsize = total - offsetof (struct dataset, resp);
- dataset->head.notfound = false;
- dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
- dataset->head.usable = true;
-
- /* Compute the timeout time. */
- timeout = dataset->head.timeout = time (NULL) + db->postimeout;
+ timeout = datahead_init_pos (&dataset->head, total + req->key_len,
+ total - offsetof (struct dataset, resp),
+ he == NULL ? 0 : dh->nreloads + 1,
+ db->postimeout);
dataset->resp.version = NSCD_VERSION;
dataset->resp.found = 1;
diff --git a/nscd/mem.c b/nscd/mem.c
index 0d09e21d5e..4a2ad4bcca 100644
--- a/nscd/mem.c
+++ b/nscd/mem.c
@@ -1,5 +1,5 @@
/* Cache memory handling.
- Copyright (C) 2004-2014 Free Software Foundation, Inc.
+ Copyright (C) 2004-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
@@ -124,11 +124,11 @@ gc (struct database_dyn *db)
/* In prune_cache we are also using a dynamically allocated array.
If the array in the caller is too large we have malloc'ed it. */
size_t stack_used = sizeof (bool) * db->head->module;
- if (__builtin_expect (stack_used > MAX_STACK_USE, 0))
+ if (__glibc_unlikely (stack_used > MAX_STACK_USE))
stack_used = 0;
size_t nmark = (db->head->first_free / BLOCK_ALIGN + BITS - 1) / BITS;
size_t memory_needed = nmark * sizeof (BITMAP_T);
- if (__builtin_expect (stack_used + memory_needed <= MAX_STACK_USE, 1))
+ if (__glibc_likely (stack_used + memory_needed <= MAX_STACK_USE))
{
mark = (BITMAP_T *) alloca_account (memory_needed, stack_used);
mark_use_malloc = false;
@@ -146,7 +146,7 @@ gc (struct database_dyn *db)
struct hashentry **he;
struct hashentry **he_data;
bool he_use_malloc;
- if (__builtin_expect (stack_used + memory_needed <= MAX_STACK_USE, 1))
+ if (__glibc_likely (stack_used + memory_needed <= MAX_STACK_USE))
{
he = alloca_account (memory_needed, stack_used);
he_use_malloc = false;
@@ -421,10 +421,10 @@ gc (struct database_dyn *db)
}
while (runp != moves->next);
- if (__builtin_expect (debug_level >= 3, 0))
+ if (__glibc_unlikely (debug_level >= 3))
dbg_log (_("freed %zu bytes in %s cache"),
- db->head->first_free
- - ((char *) moves->to + moves->size - db->data),
+ (size_t) (db->head->first_free
+ - ((char *) moves->to + moves->size - db->data)),
dbnames[db - dbs]);
/* The byte past the end of the last copied block is the next
@@ -432,7 +432,7 @@ gc (struct database_dyn *db)
db->head->first_free = (char *) moves->to + moves->size - db->data;
/* Consistency check. */
- if (__builtin_expect (debug_level >= 3, 0))
+ if (__glibc_unlikely (debug_level >= 3))
{
for (size_t idx = 0; idx < db->head->module; ++idx)
{
@@ -527,7 +527,7 @@ mempool_alloc (struct database_dyn *db, size_t len, int data_alloc)
retry:
res = db->data + db->head->first_free;
- if (__builtin_expect (db->head->first_free + len > db->head->data_size, 0))
+ if (__glibc_unlikely (db->head->first_free + len > db->head->data_size))
{
if (! tried_resize)
{
diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
index be01fe8670..b42fb11ef2 100644
--- a/nscd/netgroupcache.c
+++ b/nscd/netgroupcache.c
@@ -1,5 +1,5 @@
/* Cache handling for netgroup lookup.
- Copyright (C) 2011-2014 Free Software Foundation, Inc.
+ Copyright (C) 2011-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
@@ -21,6 +21,7 @@
#include <errno.h>
#include <libintl.h>
#include <stdbool.h>
+#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
@@ -90,15 +91,9 @@ do_notfound (struct database_dyn *db, int fd, request_header *req,
/* If we cannot permanently store the result, so be it. */
if (dataset != NULL)
{
- dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
- dataset->head.recsize = total;
- dataset->head.notfound = true;
- dataset->head.nreloads = 0;
- dataset->head.usable = true;
-
- /* Compute the timeout time. */
- timeout = dataset->head.timeout = time (NULL) + db->negtimeout;
- dataset->head.ttl = db->negtimeout;
+ timeout = datahead_init_neg (&dataset->head,
+ sizeof (struct dataset) + req->key_len,
+ total, db->negtimeout);
/* This is the reply. */
memcpy (&dataset->resp, &notfound, total);
@@ -120,7 +115,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
const char *key, uid_t uid, struct hashentry *he,
struct datahead *dh, struct dataset **resultp)
{
- if (__builtin_expect (debug_level > 0, 0))
+ if (__glibc_unlikely (debug_level > 0))
{
if (he == NULL)
dbg_log (_("Haven't found \"%s\" in netgroup cache!"), key);
@@ -142,11 +137,8 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
char *buffer = NULL;
size_t nentries = 0;
size_t group_len = strlen (key) + 1;
- union
- {
- struct name_list elem;
- char mem[sizeof (struct name_list) + group_len];
- } first_needed;
+ struct name_list *first_needed
+ = alloca (sizeof (struct name_list) + group_len);
if (netgroup_database == NULL
&& __nss_database_lookup ("netgroup", NULL, NULL, &netgroup_database))
@@ -159,9 +151,9 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
memset (&data, '\0', sizeof (data));
buffer = xmalloc (buflen);
- first_needed.elem.next = &first_needed.elem;
- memcpy (first_needed.elem.name, key, group_len);
- data.needed_groups = &first_needed.elem;
+ first_needed->next = first_needed;
+ memcpy (first_needed->name, key, group_len);
+ data.needed_groups = first_needed;
while (data.needed_groups != NULL)
{
@@ -202,12 +194,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
{
int e;
status = getfct.f (&data, buffer + buffilled,
- buflen - buffilled, &e);
- if (status == NSS_STATUS_RETURN
- || status == NSS_STATUS_NOTFOUND)
- /* This was either the last one for this group or the
- group was empty. Look at next group if available. */
- break;
+ buflen - buffilled - req->key_len, &e);
if (status == NSS_STATUS_SUCCESS)
{
if (data.type == triple_val)
@@ -216,6 +203,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
const char *nuser = data.val.triple.user;
const char *ndomain = data.val.triple.domain;
+ size_t hostlen = strlen (nhost ?: "") + 1;
+ size_t userlen = strlen (nuser ?: "") + 1;
+ size_t domainlen = strlen (ndomain ?: "") + 1;
+
if (nhost == NULL || nuser == NULL || ndomain == NULL
|| nhost > nuser || nuser > ndomain)
{
@@ -233,9 +224,6 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
: last + strlen (last) + 1 - buffer);
/* We have to make temporary copies. */
- size_t hostlen = strlen (nhost ?: "") + 1;
- size_t userlen = strlen (nuser ?: "") + 1;
- size_t domainlen = strlen (ndomain ?: "") + 1;
size_t needed = hostlen + userlen + domainlen;
if (buflen - req->key_len - bufused < needed)
@@ -269,9 +257,12 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
}
char *wp = buffer + buffilled;
- wp = stpcpy (wp, nhost) + 1;
- wp = stpcpy (wp, nuser) + 1;
- wp = stpcpy (wp, ndomain) + 1;
+ wp = memmove (wp, nhost ?: "", hostlen);
+ wp += hostlen;
+ wp = memmove (wp, nuser ?: "", userlen);
+ wp += userlen;
+ wp = memmove (wp, ndomain ?: "", domainlen);
+ wp += domainlen;
buffilled = wp - buffer;
++nentries;
}
@@ -322,11 +313,18 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
}
}
}
- else if (status == NSS_STATUS_UNAVAIL && e == ERANGE)
+ else if (status == NSS_STATUS_TRYAGAIN && e == ERANGE)
{
buflen *= 2;
buffer = xrealloc (buffer, buflen);
}
+ else if (status == NSS_STATUS_RETURN
+ || status == NSS_STATUS_NOTFOUND
+ || status == NSS_STATUS_UNAVAIL)
+ /* This was either the last one for this group or the
+ group was empty or the NSS module had an internal
+ failure. Look at next group if available. */
+ break;
}
enum nss_status (*endfct) (struct __netgrent *);
@@ -355,13 +353,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
/* Fill in the dataset. */
dataset = (struct dataset *) buffer;
- dataset->head.allocsize = total + req->key_len;
- dataset->head.recsize = total - offsetof (struct dataset, resp);
- dataset->head.notfound = false;
- dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
- dataset->head.usable = true;
- dataset->head.ttl = db->postimeout;
- timeout = dataset->head.timeout = time (NULL) + dataset->head.ttl;
+ timeout = datahead_init_pos (&dataset->head, total + req->key_len,
+ total - offsetof (struct dataset, resp),
+ he == NULL ? 0 : dh->nreloads + 1,
+ db->postimeout);
dataset->resp.version = NSCD_VERSION;
dataset->resp.found = 1;
@@ -398,7 +393,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
{
struct dataset *newp
= (struct dataset *) mempool_alloc (db, total + req->key_len, 1);
- if (__builtin_expect (newp != NULL, 1))
+ if (__glibc_likely (newp != NULL))
{
/* Adjust pointer into the memory block. */
key_copy = (char *) newp + (key_copy - buffer);
@@ -494,7 +489,7 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
key = (char *) rawmemchr (key, '\0') + 1;
const char *domain = *key++ ? key : NULL;
- if (__builtin_expect (debug_level > 0, 0))
+ if (__glibc_unlikely (debug_level > 0))
{
if (he == NULL)
dbg_log (_("Haven't found \"%s (%s,%s,%s)\" in netgroup cache!"),
@@ -531,18 +526,18 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
1);
struct indataset dataset_mem;
bool cacheable = true;
- if (__builtin_expect (dataset == NULL, 0))
+ if (__glibc_unlikely (dataset == NULL))
{
cacheable = false;
dataset = &dataset_mem;
}
- dataset->head.allocsize = sizeof (*dataset) + req->key_len;
- dataset->head.recsize = sizeof (innetgroup_response_header);
+ datahead_init_pos (&dataset->head, sizeof (*dataset) + req->key_len,
+ sizeof (innetgroup_response_header),
+ he == NULL ? 0 : dh->nreloads + 1, result->head.ttl);
+ /* Set the notfound status and timeout based on the result from
+ getnetgrent. */
dataset->head.notfound = result->head.notfound;
- dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
- dataset->head.usable = true;
- dataset->head.ttl = result->head.ttl;
dataset->head.timeout = timeout;
dataset->resp.version = NSCD_VERSION;
@@ -560,15 +555,19 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
{
bool success = true;
- if (host != NULL)
+ /* For the host, user and domain in each triplet, we assume success
+ if the value is blank because that is how the wildcard entry to
+ match anything is stored in the netgroup cache. */
+ if (host != NULL && *triplets != '\0')
success = strcmp (host, triplets) == 0;
triplets = (const char *) rawmemchr (triplets, '\0') + 1;
- if (success && user != NULL)
+ if (success && user != NULL && *triplets != '\0')
success = strcmp (user, triplets) == 0;
triplets = (const char *) rawmemchr (triplets, '\0') + 1;
- if (success && (domain == NULL || strcmp (domain, triplets) == 0))
+ if (success && (domain == NULL || *triplets == '\0'
+ || strcmp (domain, triplets) == 0))
{
dataset->resp.result = 1;
break;
diff --git a/nscd/nscd-client.h b/nscd/nscd-client.h
index b5c9f871a7..740e2f9e34 100644
--- a/nscd/nscd-client.h
+++ b/nscd/nscd-client.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 1998-2014 Free Software Foundation, Inc.
+/* Copyright (c) 1998-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
@@ -24,6 +24,8 @@
#include <stdbool.h>
#include <stdint.h>
+#include <string.h>
+#include <time.h>
#include <sys/types.h>
#include <atomic.h>
#include <nscd-types.h>
@@ -236,6 +238,48 @@ struct datahead
} data[0];
};
+static inline time_t
+datahead_init_common (struct datahead *head, nscd_ssize_t allocsize,
+ nscd_ssize_t recsize, uint32_t ttl)
+{
+ /* Initialize so that we don't write out junk in uninitialized data to the
+ cache. */
+ memset (head, 0, sizeof (*head));
+
+ head->allocsize = allocsize;
+ head->recsize = recsize;
+ head->usable = true;
+
+ head->ttl = ttl;
+
+ /* Compute and return the timeout time. */
+ return head->timeout = time (NULL) + ttl;
+}
+
+static inline time_t
+datahead_init_pos (struct datahead *head, nscd_ssize_t allocsize,
+ nscd_ssize_t recsize, uint8_t nreloads, uint32_t ttl)
+{
+ time_t ret = datahead_init_common (head, allocsize, recsize, ttl);
+
+ head->notfound = false;
+ head->nreloads = nreloads;
+
+ return ret;
+}
+
+static inline time_t
+datahead_init_neg (struct datahead *head, nscd_ssize_t allocsize,
+ nscd_ssize_t recsize, uint32_t ttl)
+{
+ time_t ret = datahead_init_common (head, allocsize, recsize, ttl);
+
+ /* We don't need to touch nreloads here since it is set to our desired value
+ (0) when we clear the structure. */
+ head->notfound = true;
+
+ return ret;
+}
/* Structure for one hash table entry. */
struct hashentry
@@ -331,10 +375,10 @@ __nscd_acquire_maplock (volatile struct locked_map_ptr *mapptr)
1, 0) != 0, 0))
{
// XXX Best number of rounds?
- if (__builtin_expect (++cnt > 5, 0))
+ if (__glibc_unlikely (++cnt > 5))
return false;
- atomic_delay ();
+ atomic_spin_nop ();
}
return true;
@@ -369,7 +413,7 @@ __nscd_drop_map_ref (struct mapped_database *map, int *gc_cycle)
if (map != NO_MAPPING)
{
int now_cycle = map->head->gc_cycle;
- if (__builtin_expect (now_cycle != *gc_cycle, 0))
+ if (__glibc_unlikely (now_cycle != *gc_cycle))
{
/* We might have read inconsistent data. */
*gc_cycle = now_cycle;
diff --git a/nscd/nscd.c b/nscd/nscd.c
index 63d9d83599..35b3a97904 100644
--- a/nscd/nscd.c
+++ b/nscd/nscd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1998-2014 Free Software Foundation, Inc.
+/* Copyright (c) 1998-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
@@ -39,6 +39,8 @@
#include <sys/stat.h>
#include <sys/uio.h>
#include <sys/un.h>
+#include <sys/wait.h>
+#include <stdarg.h>
#include "dbg_log.h"
#include "nscd.h"
@@ -48,26 +50,13 @@
#ifdef HAVE_INOTIFY
# include <sys/inotify.h>
#endif
+#include <kernel-features.h>
/* Get libc version number. */
#include <version.h>
#define PACKAGE _libc_intl_domainname
-/* Structure used by main() thread to keep track of the number of
- active threads. Used to limit how many threads it will create
- and under a shutdown condition to wait till all in-progress
- requests have finished before "turning off the lights". */
-
-typedef struct
-{
- int num_active;
- pthread_cond_t thread_exit_cv;
- pthread_mutex_t mutex;
-} thread_info_t;
-
-thread_info_t thread_info;
-
int do_shutdown;
int disabled_passwd;
int disabled_group;
@@ -101,6 +90,7 @@ gid_t old_gid;
static int check_pid (const char *file);
static int write_pid (const char *file);
+static int monitor_child (int fd);
/* Name and version of program. */
static void print_version (FILE *stream, struct argp_state *state);
@@ -142,6 +132,7 @@ static struct argp argp =
/* True if only statistics are requested. */
static bool get_stats;
+static int parent_fd = -1;
int
main (int argc, char **argv)
@@ -196,11 +187,27 @@ main (int argc, char **argv)
/* Behave like a daemon. */
if (run_mode == RUN_DAEMONIZE)
{
+ int fd[2];
+
+ if (pipe (fd) != 0)
+ error (EXIT_FAILURE, errno,
+ _("cannot create a pipe to talk to the child"));
+
pid = fork ();
if (pid == -1)
error (EXIT_FAILURE, errno, _("cannot fork"));
if (pid != 0)
- exit (0);
+ {
+ /* The parent only reads from the child. */
+ close (fd[1]);
+ exit (monitor_child (fd[0]));
+ }
+ else
+ {
+ /* The child only writes to the parent. */
+ close (fd[0]);
+ parent_fd = fd[1];
+ }
}
int nullfd = open (_PATH_DEVNULL, O_RDWR);
@@ -242,7 +249,8 @@ main (int argc, char **argv)
char *endp;
long int fdn = strtol (dirent->d_name, &endp, 10);
- if (*endp == '\0' && fdn != dfdn && fdn >= min_close_fd)
+ if (*endp == '\0' && fdn != dfdn && fdn >= min_close_fd
+ && fdn != parent_fd)
close ((int) fdn);
}
@@ -250,13 +258,14 @@ main (int argc, char **argv)
}
else
for (i = min_close_fd; i < getdtablesize (); i++)
- close (i);
+ if (i != parent_fd)
+ close (i);
setsid ();
if (chdir ("/") != 0)
- error (EXIT_FAILURE, errno,
- _("cannot change current working directory to \"/\""));
+ do_exit (EXIT_FAILURE, errno,
+ _("cannot change current working directory to \"/\""));
openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
@@ -315,6 +324,75 @@ main (int argc, char **argv)
}
+static void __attribute__ ((noreturn))
+invalidate_db (const char *dbname)
+{
+ int sock = nscd_open_socket ();
+
+ if (sock == -1)
+ exit (EXIT_FAILURE);
+
+ size_t dbname_len = strlen (dbname) + 1;
+ size_t reqlen = sizeof (request_header) + dbname_len;
+ struct
+ {
+ request_header req;
+ char dbname[];
+ } *reqdata = alloca (reqlen);
+
+ reqdata->req.key_len = dbname_len;
+ reqdata->req.version = NSCD_VERSION;
+ reqdata->req.type = INVALIDATE;
+ memcpy (reqdata->dbname, dbname, dbname_len);
+
+ ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, reqdata, reqlen,
+ MSG_NOSIGNAL));
+
+ if (nbytes != reqlen)
+ {
+ 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);
+
+ if (resp != 0)
+ error (EXIT_FAILURE, resp, _("invalidation failed"));
+
+ exit (0);
+}
+
+static void __attribute__ ((noreturn))
+send_shutdown (void)
+{
+ int sock = nscd_open_socket ();
+
+ if (sock == -1)
+ exit (EXIT_FAILURE);
+
+ request_header req;
+ req.version = NSCD_VERSION;
+ req.type = SHUTDOWN;
+ req.key_len = 0;
+
+ ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &req, sizeof req,
+ MSG_NOSIGNAL));
+ close (sock);
+ exit (nbytes != sizeof (request_header) ? EXIT_FAILURE : EXIT_SUCCESS);
+}
+
/* Handle program arguments. */
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
@@ -337,91 +415,34 @@ parse_opt (int key, char *arg, struct argp_state *state)
case 'K':
if (getuid () != 0)
error (4, 0, _("Only root is allowed to use this option!"));
- {
- int sock = nscd_open_socket ();
-
- if (sock == -1)
- exit (EXIT_FAILURE);
-
- request_header req;
- req.version = NSCD_VERSION;
- req.type = SHUTDOWN;
- req.key_len = 0;
-
- ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &req,
- sizeof (request_header),
- MSG_NOSIGNAL));
- close (sock);
- exit (nbytes != sizeof (request_header) ? EXIT_FAILURE : EXIT_SUCCESS);
- }
+ else
+ send_shutdown ();
+ break;
case 'g':
get_stats = true;
break;
case 'i':
+ {
+ /* Validate the database name. */
+
+ dbtype cnt;
+ for (cnt = pwddb; cnt < lastdb; ++cnt)
+ if (strcmp (arg, dbnames[cnt]) == 0)
+ break;
+
+ if (cnt == lastdb)
+ {
+ argp_error (state, _("'%s' is not a known database"), arg);
+ return EINVAL;
+ }
+ }
if (getuid () != 0)
error (4, 0, _("Only root is allowed to use this option!"));
else
- {
- int sock = nscd_open_socket ();
-
- if (sock == -1)
- exit (EXIT_FAILURE);
-
- dbtype cnt;
- for (cnt = pwddb; cnt < lastdb; ++cnt)
- if (strcmp (arg, dbnames[cnt]) == 0)
- break;
-
- if (cnt == lastdb)
- {
- argp_error (state, _("'%s' is not a known database"), arg);
- return EINVAL;
- }
-
- size_t arg_len = strlen (arg) + 1;
- struct
- {
- request_header req;
- char arg[arg_len];
- } reqdata;
-
- reqdata.req.key_len = strlen (arg) + 1;
- reqdata.req.version = NSCD_VERSION;
- reqdata.req.type = INVALIDATE;
- memcpy (reqdata.arg, arg, arg_len);
-
- ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &reqdata,
- sizeof (request_header)
- + arg_len,
- MSG_NOSIGNAL));
-
- if (nbytes != sizeof (request_header) + arg_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);
-
- if (resp != 0)
- error (EXIT_FAILURE, resp, _("invalidation failed"));
-
- exit (0);
- }
+ invalidate_db (arg);
+ break;
case 't':
nthreads = atol (arg);
@@ -442,33 +463,36 @@ parse_opt (int key, char *arg, struct argp_state *state)
static char *
more_help (int key, const char *text, void *input)
{
- char *tables, *tp = NULL;
-
switch (key)
{
case ARGP_KEY_HELP_EXTRA:
{
- dbtype cnt;
+ /* We print some extra information. */
- tables = xmalloc (sizeof (dbnames) + 1);
- for (cnt = 0; cnt < lastdb; cnt++)
+ char *tables = xstrdup (dbnames[0]);
+ for (dbtype i = 1; i < lastdb; ++i)
{
- strcat (tables, dbnames[cnt]);
- strcat (tables, " ");
+ char *more_tables;
+ if (asprintf (&more_tables, "%s %s", tables, dbnames[i]) < 0)
+ more_tables = NULL;
+ free (tables);
+ if (more_tables == NULL)
+ return NULL;
+ tables = more_tables;
}
- }
- /* We print some extra information. */
- if (asprintf (&tp, gettext ("\
+ char *tp;
+ if (asprintf (&tp, gettext ("\
Supported tables:\n\
%s\n\
\n\
For bug reporting instructions, please see:\n\
%s.\n\
"), tables, REPORT_BUGS_TO) < 0)
- tp = NULL;
- free (tables);
- return tp;
+ tp = NULL;
+ free (tables);
+ return tp;
+ }
default:
break;
@@ -486,7 +510,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\
-"), "2014");
+"), "2015");
fprintf (stream, gettext ("Written by %s.\n"),
"Thorsten Kukuk and Ulrich Drepper");
}
@@ -592,3 +616,83 @@ write_pid (const char *file)
return result;
}
+
+static int
+monitor_child (int fd)
+{
+ int child_ret = 0;
+ int ret = read (fd, &child_ret, sizeof (child_ret));
+
+ /* The child terminated with an error, either via exit or some other abnormal
+ method, like a segfault. */
+ if (ret <= 0 || child_ret != 0)
+ {
+ int status;
+ int err = wait (&status);
+
+ if (err < 0)
+ {
+ fprintf (stderr, _("'wait' failed\n"));
+ return 1;
+ }
+
+ if (WIFEXITED (status))
+ {
+ child_ret = WEXITSTATUS (status);
+ fprintf (stderr, _("child exited with status %d\n"), child_ret);
+ }
+ if (WIFSIGNALED (status))
+ {
+ child_ret = WTERMSIG (status);
+ fprintf (stderr, _("child terminated by signal %d\n"), child_ret);
+ }
+ }
+
+ /* We have the child status, so exit with that code. */
+ close (fd);
+
+ return child_ret;
+}
+
+void
+do_exit (int child_ret, int errnum, const char *format, ...)
+{
+ if (parent_fd != -1)
+ {
+ int ret = write (parent_fd, &child_ret, sizeof (child_ret));
+ assert (ret == sizeof (child_ret));
+ close (parent_fd);
+ }
+
+ if (format != NULL)
+ {
+ /* Emulate error() since we don't have a va_list variant for it. */
+ va_list argp;
+
+ fflush (stdout);
+
+ fprintf (stderr, "%s: ", program_invocation_name);
+
+ va_start (argp, format);
+ vfprintf (stderr, format, argp);
+ va_end (argp);
+
+ fprintf (stderr, ": %s\n", strerror (errnum));
+ fflush (stderr);
+ }
+
+ /* Finally, exit. */
+ exit (child_ret);
+}
+
+void
+notify_parent (int child_ret)
+{
+ if (parent_fd == -1)
+ return;
+
+ int ret = write (parent_fd, &child_ret, sizeof (child_ret));
+ assert (ret == sizeof (child_ret));
+ close (parent_fd);
+ parent_fd = -1;
+}
diff --git a/nscd/nscd.h b/nscd/nscd.h
index 972f4628b9..75c2eccea0 100644
--- a/nscd/nscd.h
+++ b/nscd/nscd.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 1998-2014 Free Software Foundation, Inc.
+/* Copyright (c) 1998-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
@@ -61,17 +61,67 @@ typedef enum
80% of the thread stack size. */
#define MAX_STACK_USE ((8 * NSCD_THREAD_STACKSIZE) / 10)
-
-/* Registered filename used to fill database. */
+/* Records the file registered per database that when changed
+ or modified requires invalidating the database. */
struct traced_file
{
+ /* Tracks the last modified time of the traced file. */
time_t mtime;
+ /* Support multiple registered files per database. */
struct traced_file *next;
int call_res_init;
- int inotify_descr;
+ /* Requires Inotify support to do anything useful. */
+#define TRACED_FILE 0
+#define TRACED_DIR 1
+ int inotify_descr[2];
+# ifndef PATH_MAX
+# define PATH_MAX 1024
+# endif
+ /* The parent directory is used to scan for creation/deletion. */
+ char dname[PATH_MAX];
+ /* Just the name of the file with no directory component. */
+ char *sfname;
+ /* The full-path name of the registered file. */
char fname[];
};
+/* Initialize a `struct traced_file`. As input we need the name
+ of the file, and if invalidation requires calling res_init.
+ If CRINIT is 1 then res_init will be called after invalidation
+ or if the traced file is changed in any way, otherwise it will
+ not. */
+static inline void
+init_traced_file(struct traced_file *file, const char *fname, int crinit)
+{
+ char *dname;
+ file->mtime = 0;
+ file->inotify_descr[TRACED_FILE] = -1;
+ file->inotify_descr[TRACED_DIR] = -1;
+ strcpy (file->fname, fname);
+ /* Compute the parent directory name and store a copy. The copy makes
+ it much faster to add/remove watches while nscd is running instead
+ of computing this over and over again in a temp buffer. */
+ file->dname[0] = '\0';
+ dname = strrchr (fname, '/');
+ if (dname != NULL)
+ {
+ size_t len = (size_t)(dname - fname);
+ if (len > sizeof (file->dname))
+ abort ();
+ strncpy (file->dname, file->fname, len);
+ file->dname[len] = '\0';
+ }
+ /* The basename is the name just after the last forward slash. */
+ file->sfname = &dname[1];
+ file->call_res_init = crinit;
+}
+
+#define define_traced_file(id, filename) \
+static union \
+{ \
+ struct traced_file file; \
+ char buf[sizeof (struct traced_file) + sizeof (filename)]; \
+} id##_traced_file;
/* Structure describing dynamic part of one database. */
struct database_dyn
@@ -90,7 +140,6 @@ struct database_dyn
int propagate;
struct traced_file *traced_files;
const char *db_filename;
- time_t file_mtime;
size_t suggested_module;
size_t max_db_size;
@@ -205,10 +254,15 @@ extern gid_t old_gid;
/* nscd.c */
extern void termination_handler (int signum) __attribute__ ((__noreturn__));
extern int nscd_open_socket (void);
+void notify_parent (int child_ret);
+void do_exit (int child_ret, int errnum, const char *format, ...);
/* connections.c */
extern void nscd_init (void);
extern void register_traced_file (size_t dbidx, struct traced_file *finfo);
+#ifdef HAVE_INOTIFY
+extern void install_watches (struct traced_file *finfo);
+#endif
extern void close_sockets (void);
extern void start_threads (void) __attribute__ ((__noreturn__));
diff --git a/nscd/nscd.service b/nscd/nscd.service
index 99c7563990..ab38e8f982 100644
--- a/nscd/nscd.service
+++ b/nscd/nscd.service
@@ -4,13 +4,14 @@
Description=Name Service Cache Daemon
[Service]
-Type=simple
-ExecStart=/usr/sbin/nscd --foreground
+Type=forking
+ExecStart=/usr/sbin/nscd
ExecStop=/usr/sbin/nscd --shutdown
ExecReload=/usr/sbin/nscd -i passwd
ExecReload=/usr/sbin/nscd -i group
ExecReload=/usr/sbin/nscd -i hosts
ExecReload=/usr/sbin/nscd -i services
+ExecReload=/usr/sbin/nscd -i netgroup
Restart=always
PIDFile=/run/nscd/nscd.pid
diff --git a/nscd/nscd_conf.c b/nscd/nscd_conf.c
index 7856ed9b5a..e82ba3b824 100644
--- a/nscd/nscd_conf.c
+++ b/nscd/nscd_conf.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1998-2014 Free Software Foundation, Inc.
+/* Copyright (c) 1998-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
@@ -32,9 +32,6 @@
#include "dbg_log.h"
#include "nscd.h"
-/* Wrapper functions with error checking for standard functions. */
-extern char *xstrdup (const char *s);
-
/* Names of the databases. */
const char *const dbnames[lastdb] =
diff --git a/nscd/nscd_getai.c b/nscd/nscd_getai.c
index 155cfef2eb..3d2836eb8b 100644
--- a/nscd/nscd_getai.c
+++ b/nscd/nscd_getai.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004-2014 Free Software Foundation, Inc.
+/* Copyright (C) 2004-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
@@ -42,7 +42,7 @@ extern int __nss_have_localdomain attribute_hidden;
int
__nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop)
{
- if (__builtin_expect (__nss_have_localdomain >= 0, 0))
+ if (__glibc_unlikely (__nss_have_localdomain >= 0))
{
if (__nss_have_localdomain == 0)
__nss_have_localdomain = getenv ("LOCALDOMAIN") != NULL ? 1 : -1;
@@ -171,7 +171,7 @@ __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop)
}
else
{
- if (__builtin_expect (ai_resp.found == -1, 0))
+ if (__glibc_unlikely (ai_resp.found == -1))
{
/* The daemon does not cache this database. */
__nss_not_use_nscd_hosts = 1;
diff --git a/nscd/nscd_getgr_r.c b/nscd/nscd_getgr_r.c
index ed5dc11159..d08b73f3cb 100644
--- a/nscd/nscd_getgr_r.c
+++ b/nscd/nscd_getgr_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1998-2014 Free Software Foundation, Inc.
+/* Copyright (C) 1998-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1998.
@@ -31,6 +31,7 @@
#include <sys/un.h>
#include <not-cancel.h>
#include <_itoa.h>
+#include <scratch_buffer.h>
#include "nscd-client.h"
#include "nscd_proto.h"
@@ -89,7 +90,8 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
int gc_cycle;
int nretries = 0;
const uint32_t *len = NULL;
- size_t lensize = 0;
+ struct scratch_buffer lenbuf;
+ scratch_buffer_init (&lenbuf);
/* If the mapping is available, try to search there instead of
communicating with the nscd. */
@@ -143,7 +145,7 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
/* No value found so far. */
*result = NULL;
- if (__builtin_expect (gr_resp.found == -1, 0))
+ if (__glibc_unlikely (gr_resp.found == -1))
{
/* The daemon does not cache this database. */
__nss_not_use_nscd_group = 1;
@@ -164,7 +166,7 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
& (__alignof__ (char *) - 1));
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))
+ if (__glibc_unlikely (buflen < total_len))
{
no_room:
__set_errno (ERANGE);
@@ -190,7 +192,7 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
if (gr_name == NULL)
{
/* Handle a simple, usual case: no group members. */
- if (__builtin_expect (gr_resp.gr_mem_cnt == 0, 1))
+ if (__glibc_likely (gr_resp.gr_mem_cnt == 0))
{
size_t n = gr_resp.gr_name_len + gr_resp.gr_passwd_len;
if (__builtin_expect (__readall (sock, resultbuf->gr_name, n)
@@ -200,14 +202,10 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
else
{
/* Allocate array to store lengths. */
- if (lensize == 0)
- {
- 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)
- len = extend_alloca (len, lensize,
- gr_resp.gr_mem_cnt * sizeof (uint32_t));
+ if (!scratch_buffer_set_array_size
+ (&lenbuf, gr_resp.gr_mem_cnt, sizeof (uint32_t)))
+ goto out_close;
+ len = lenbuf.data;
vec[0].iov_base = (void *) len;
vec[0].iov_len = gr_resp.gr_mem_cnt * sizeof (uint32_t);
@@ -217,7 +215,7 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
/* Get this data. */
size_t n = __readvall (sock, vec, 2);
- if (__builtin_expect (n != total_len, 0))
+ if (__glibc_unlikely (n != total_len))
goto out_close;
}
}
@@ -239,7 +237,7 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
p += len[cnt];
}
- if (__builtin_expect (gr_name + gr_name_len + total_len > recend, 0))
+ if (__glibc_unlikely (gr_name + gr_name_len + total_len > recend))
{
/* len array might contain garbage during nscd GC cycle,
retry rather than fail in that case. */
@@ -247,7 +245,7 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
retval = -2;
goto out_close;
}
- if (__builtin_expect (total_len > buflen, 0))
+ if (__glibc_unlikely (total_len > buflen))
{
/* len array might contain garbage during nscd GC cycle,
retry rather than fail in that case. */
@@ -326,5 +324,7 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type,
goto retry;
}
+ scratch_buffer_free (&lenbuf);
+
return retval;
}
diff --git a/nscd/nscd_gethst_r.c b/nscd/nscd_gethst_r.c
index 3368fc4482..7b2333eba1 100644
--- a/nscd/nscd_gethst_r.c
+++ b/nscd/nscd_gethst_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1998-2014 Free Software Foundation, Inc.
+/* Copyright (C) 1998-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
@@ -140,7 +140,7 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
struct hostent *resultbuf, char *buffer, size_t buflen,
struct hostent **result, int *h_errnop)
{
- if (__builtin_expect (__nss_have_localdomain >= 0, 0))
+ if (__glibc_unlikely (__nss_have_localdomain >= 0))
{
if (__nss_have_localdomain == 0)
__nss_have_localdomain = getenv ("LOCALDOMAIN") != NULL ? 1 : -1;
@@ -191,7 +191,7 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
goto out;
}
-#ifndef _STRING_ARCH_unaligned
+#if !_STRING_ARCH_unaligned
/* The aliases_len array in the mapped database might very
well be unaligned. We will access it word-wise so on
platforms which do not tolerate unaligned accesses we
@@ -232,7 +232,7 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
/* No value found so far. */
*result = NULL;
- if (__builtin_expect (hst_resp.found == -1, 0))
+ if (__glibc_unlikely (hst_resp.found == -1))
{
/* The daemon does not cache this database. */
__nss_not_use_nscd_hosts = 1;
@@ -377,7 +377,7 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type,
goto out_close;
}
/* See whether this would exceed the buffer capacity. */
- if (__builtin_expect (cp > buffer + buflen, 0))
+ if (__glibc_unlikely (cp > buffer + buflen))
{
/* aliases_len array might contain garbage during nscd GC cycle,
retry rather than fail in that case. */
diff --git a/nscd/nscd_getpw_r.c b/nscd/nscd_getpw_r.c
index 5454ab62ad..aeb33f817d 100644
--- a/nscd/nscd_getpw_r.c
+++ b/nscd/nscd_getpw_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1998-2014 Free Software Foundation, Inc.
+/* Copyright (C) 1998-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1998.
@@ -134,7 +134,7 @@ nscd_getpw_r (const char *key, size_t keylen, request_type type,
/* No value found so far. */
*result = NULL;
- if (__builtin_expect (pw_resp.found == -1, 0))
+ if (__glibc_unlikely (pw_resp.found == -1))
{
/* The daemon does not cache this database. */
__nss_not_use_nscd_passwd = 1;
@@ -165,9 +165,9 @@ nscd_getpw_r (const char *key, size_t keylen, request_type type,
p += pw_resp.pw_shell_len;
ssize_t total = p - buffer;
- if (__builtin_expect (pw_name + total > recend, 0))
+ if (__glibc_unlikely (pw_name + total > recend))
goto out_close;
- if (__builtin_expect (buflen < total, 0))
+ if (__glibc_unlikely (buflen < total))
{
__set_errno (ERANGE);
retval = ERANGE;
@@ -179,7 +179,7 @@ nscd_getpw_r (const char *key, size_t keylen, request_type type,
{
ssize_t nbytes = __readall (sock, buffer, total);
- if (__builtin_expect (nbytes != total, 0))
+ if (__glibc_unlikely (nbytes != total))
{
/* The `errno' to some value != ERANGE. */
__set_errno (ENOENT);
diff --git a/nscd/nscd_getserv_r.c b/nscd/nscd_getserv_r.c
index 38f159eecf..a3098bbb48 100644
--- a/nscd/nscd_getserv_r.c
+++ b/nscd/nscd_getserv_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2014 Free Software Foundation, Inc.
+/* Copyright (C) 2007-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2007.
@@ -141,7 +141,7 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto,
> recend, 0))
goto out;
-#ifndef _STRING_ARCH_unaligned
+#if !_STRING_ARCH_unaligned
/* The aliases_len array in the mapped database might very
well be unaligned. We will access it word-wise so on
platforms which do not tolerate unaligned accesses we
@@ -189,7 +189,7 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto,
/* No value found so far. */
*result = NULL;
- if (__builtin_expect (serv_resp.found == -1, 0))
+ if (__glibc_unlikely (serv_resp.found == -1))
{
/* The daemon does not cache this database. */
__nss_not_use_nscd_services = 1;
@@ -300,7 +300,7 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto,
}
/* See whether this would exceed the buffer capacity. */
- if (__builtin_expect (cp > buf + buflen, 0))
+ if (__glibc_unlikely (cp > buf + buflen))
{
/* aliases_len array might contain garbage during nscd GC cycle,
retry rather than fail in that case. */
diff --git a/nscd/nscd_helper.c b/nscd/nscd_helper.c
index e4fb2e59f8..52a5caadfa 100644
--- a/nscd/nscd_helper.c
+++ b/nscd/nscd_helper.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1998-2014 Free Software Foundation, Inc.
+/* Copyright (C) 1998-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
@@ -21,6 +21,7 @@
#include <fcntl.h>
#include <stdbool.h>
#include <stddef.h>
+#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
@@ -110,7 +111,7 @@ __readvall (int fd, const struct iovec *iov, int iovcnt)
ssize_t ret = TEMP_FAILURE_RETRY (__readv (fd, iov, iovcnt));
if (ret <= 0)
{
- if (__builtin_expect (ret == 0 || errno != EAGAIN, 1))
+ if (__glibc_likely (ret == 0 || errno != EAGAIN))
/* A genuine error or no data to read. */
return ret;
@@ -186,12 +187,12 @@ open_socket (request_type type, const char *key, size_t keylen)
if (sock < 0)
return -1;
+ size_t real_sizeof_reqdata = sizeof (request_header) + keylen;
struct
{
request_header req;
- char key[keylen];
- } reqdata;
- size_t real_sizeof_reqdata = sizeof (request_header) + keylen;
+ char key[];
+ } *reqdata = alloca (real_sizeof_reqdata);
#ifndef __ASSUME_SOCK_CLOEXEC
# ifdef SOCK_NONBLOCK
@@ -208,11 +209,11 @@ open_socket (request_type type, const char *key, size_t keylen)
&& errno != EINPROGRESS)
goto out;
- reqdata.req.version = NSCD_VERSION;
- reqdata.req.type = type;
- reqdata.req.key_len = keylen;
+ reqdata->req.version = NSCD_VERSION;
+ reqdata->req.type = type;
+ reqdata->req.key_len = keylen;
- memcpy (reqdata.key, key, keylen);
+ memcpy (reqdata->key, key, keylen);
bool first_try = true;
struct timeval tvend;
@@ -223,10 +224,10 @@ open_socket (request_type type, const char *key, size_t keylen)
#ifndef MSG_NOSIGNAL
# define MSG_NOSIGNAL 0
#endif
- ssize_t wres = TEMP_FAILURE_RETRY (__send (sock, &reqdata,
+ ssize_t wres = TEMP_FAILURE_RETRY (__send (sock, reqdata,
real_sizeof_reqdata,
MSG_NOSIGNAL));
- if (__builtin_expect (wres == (ssize_t) real_sizeof_reqdata, 1))
+ if (__glibc_likely (wres == (ssize_t) real_sizeof_reqdata))
/* We managed to send the request. */
return sock;
@@ -339,13 +340,13 @@ __nscd_get_mapping (request_type type, const char *key,
int *ip = (void *) CMSG_DATA (cmsg);
mapfd = *ip;
- if (__builtin_expect (n != keylen && n != keylen + sizeof (mapsize), 0))
+ if (__glibc_unlikely (n != keylen && n != keylen + sizeof (mapsize)))
goto out_close;
- if (__builtin_expect (strcmp (resdata, key) != 0, 0))
+ if (__glibc_unlikely (strcmp (resdata, key) != 0))
goto out_close;
- if (__builtin_expect (n == keylen, 0))
+ if (__glibc_unlikely (n == keylen))
{
struct stat64 st;
if (__builtin_expect (fstat64 (mapfd, &st) != 0, 0)
@@ -358,7 +359,7 @@ __nscd_get_mapping (request_type type, const char *key,
/* The file is large enough, map it now. */
void *mapping = __mmap (NULL, mapsize, PROT_READ, MAP_SHARED, mapfd, 0);
- if (__builtin_expect (mapping != MAP_FAILED, 1))
+ if (__glibc_likely (mapping != MAP_FAILED))
{
/* Check whether the database is correct and up-to-date. */
struct database_pers_head *head = mapping;
@@ -383,7 +384,7 @@ __nscd_get_mapping (request_type type, const char *key,
ALIGN)
+ head->data_size);
- if (__builtin_expect (mapsize < size, 0))
+ if (__glibc_unlikely (mapsize < size))
goto out_unmap;
/* Allocate a record for the mapping. */
@@ -433,7 +434,7 @@ __nscd_get_map_ref (request_type type, const char *name,
cur = mapptr->mapped;
- if (__builtin_expect (cur != NO_MAPPING, 1))
+ if (__glibc_likely (cur != NO_MAPPING))
{
/* If not mapped or timestamp not updated, request new map. */
if (cur == NULL
@@ -443,7 +444,7 @@ __nscd_get_map_ref (request_type type, const char *name,
cur = __nscd_get_mapping (type, name,
(struct mapped_database **) &mapptr->mapped);
- if (__builtin_expect (cur != NO_MAPPING, 1))
+ if (__glibc_likely (cur != NO_MAPPING))
{
if (__builtin_expect (((*gc_cyclep = cur->head->gc_cycle) & 1) != 0,
0))
@@ -490,7 +491,7 @@ __nscd_cache_search (request_type type, const char *key, size_t keylen,
struct hashentry *here = (struct hashentry *) (mapped->data + work);
ref_t here_key, here_packet;
-#ifndef _STRING_ARCH_unaligned
+#if !_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
@@ -512,7 +513,7 @@ __nscd_cache_search (request_type type, const char *key, size_t keylen,
struct datahead *dh
= (struct datahead *) (mapped->data + here_packet);
-#ifndef _STRING_ARCH_unaligned
+#if !_STRING_ARCH_unaligned
if ((uintptr_t) dh & (__alignof__ (*dh) - 1))
return NULL;
#endif
@@ -536,7 +537,7 @@ __nscd_cache_search (request_type type, const char *key, size_t keylen,
struct hashentry *trailelem;
trailelem = (struct hashentry *) (mapped->data + trail);
-#ifndef _STRING_ARCH_unaligned
+#if !_STRING_ARCH_unaligned
/* We have to redo the checks. Maybe the data changed. */
if ((uintptr_t) trailelem & (__alignof__ (*trailelem) - 1))
return NULL;
diff --git a/nscd/nscd_initgroups.c b/nscd/nscd_initgroups.c
index 8bc3e6ce3d..53c37b3022 100644
--- a/nscd/nscd_initgroups.c
+++ b/nscd/nscd_initgroups.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004-2014 Free Software Foundation, Inc.
+/* Copyright (C) 2004-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
@@ -130,7 +130,7 @@ __nscd_getgrouplist (const char *user, gid_t group, long int *size,
}
else
{
- if (__builtin_expect (initgr_resp.found == -1, 0))
+ if (__glibc_unlikely (initgr_resp.found == -1))
{
/* The daemon does not cache this database. */
__nss_not_use_nscd_group = 1;
diff --git a/nscd/nscd_netgroup.c b/nscd/nscd_netgroup.c
index 4acb0be412..011dc05629 100644
--- a/nscd/nscd_netgroup.c
+++ b/nscd/nscd_netgroup.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011-2014 Free Software Foundation, Inc.
+/* Copyright (C) 2011-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
@@ -124,7 +124,7 @@ __nscd_setnetgrent (const char *group, struct __netgrent *datap)
}
else
{
- if (__builtin_expect (netgroup_resp.found == -1, 0))
+ if (__glibc_unlikely (netgroup_resp.found == -1))
{
/* The daemon does not cache this database. */
__nss_not_use_nscd_netgroup = 1;
@@ -248,7 +248,7 @@ __nscd_innetgr (const char *netgroup, const char *host, const char *user,
retval = innetgroup_resp.result;
else
{
- if (__builtin_expect (innetgroup_resp.found == -1, 0))
+ if (__glibc_unlikely (innetgroup_resp.found == -1))
{
/* The daemon does not cache this database. */
__nss_not_use_nscd_netgroup = 1;
diff --git a/nscd/nscd_proto.h b/nscd/nscd_proto.h
index dc971c21b6..58ff9e3e40 100644
--- a/nscd/nscd_proto.h
+++ b/nscd/nscd_proto.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1998-2014 Free Software Foundation, Inc.
+/* Copyright (C) 1998-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
diff --git a/nscd/nscd_setup_thread.c b/nscd/nscd_setup_thread.c
index 989dab3352..99a0ead62c 100644
--- a/nscd/nscd_setup_thread.c
+++ b/nscd/nscd_setup_thread.c
@@ -1,5 +1,5 @@
/* Setup of nscd worker threads. Stub verison.
- Copyright (C) 2004-2014 Free Software Foundation, Inc.
+ Copyright (C) 2004-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
diff --git a/nscd/nscd_stat.c b/nscd/nscd_stat.c
index 997ff46a8e..7aaa21bb1a 100644
--- a/nscd/nscd_stat.c
+++ b/nscd/nscd_stat.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1998-2014 Free Software Foundation, Inc.
+/* Copyright (c) 1998-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
@@ -94,6 +94,8 @@ send_stats (int fd, struct database_dyn dbs[lastdb])
struct statdata data;
int cnt;
+ memset (&data, 0, sizeof (data));
+
memcpy (data.version, compilation, sizeof (compilation));
data.debug_level = debug_level;
data.runtime = time (NULL) - start_time;
diff --git a/nscd/pwdcache.c b/nscd/pwdcache.c
index 5adb8ad8e3..b12a13de35 100644
--- a/nscd/pwdcache.c
+++ b/nscd/pwdcache.c
@@ -1,5 +1,5 @@
/* Cache handling for passwd lookup.
- Copyright (C) 1998-2014 Free Software Foundation, Inc.
+ Copyright (C) 1998-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
@@ -135,14 +135,10 @@ cache_addpw (struct database_dyn *db, int fd, request_header *req,
else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
+ req->key_len), 1)) != NULL)
{
- dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
- dataset->head.recsize = total;
- dataset->head.notfound = true;
- dataset->head.nreloads = 0;
- dataset->head.usable = true;
-
- /* Compute the timeout time. */
- timeout = dataset->head.timeout = t + db->negtimeout;
+ timeout = datahead_init_neg (&dataset->head,
+ (sizeof (struct dataset)
+ + req->key_len), total,
+ db->negtimeout);
/* This is the reply. */
memcpy (&dataset->resp, &notfound, total);
@@ -215,14 +211,10 @@ cache_addpw (struct database_dyn *db, int fd, request_header *req,
alloca_used = true;
}
- dataset->head.allocsize = total + n;
- dataset->head.recsize = total - offsetof (struct dataset, resp);
- dataset->head.notfound = false;
- dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
- dataset->head.usable = true;
-
- /* Compute the timeout time. */
- timeout = dataset->head.timeout = t + db->postimeout;
+ timeout = datahead_init_pos (&dataset->head, total + n,
+ total - offsetof (struct dataset, resp),
+ he == NULL ? 0 : dh->nreloads + 1,
+ db->postimeout);
dataset->resp.version = NSCD_VERSION;
dataset->resp.found = 1;
@@ -430,7 +422,7 @@ addpwbyX (struct database_dyn *db, int fd, request_header *req,
bool use_malloc = false;
int errval = 0;
- if (__builtin_expect (debug_level > 0, 0))
+ if (__glibc_unlikely (debug_level > 0))
{
if (he == NULL)
dbg_log (_("Haven't found \"%s\" in password cache!"), keystr);
@@ -443,7 +435,7 @@ addpwbyX (struct database_dyn *db, int fd, request_header *req,
{
errno = 0;
- if (__builtin_expect (buflen > 32768, 0))
+ if (__glibc_unlikely (buflen > 32768))
{
char *old_buffer = buffer;
buflen *= 2;
diff --git a/nscd/selinux.c b/nscd/selinux.c
index c0c8e22f5c..806763f9bd 100644
--- a/nscd/selinux.c
+++ b/nscd/selinux.c
@@ -1,5 +1,5 @@
/* SELinux access controls for nscd.
- Copyright (C) 2004-2014 Free Software Foundation, Inc.
+ Copyright (C) 2004-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Matthew Rickard <mjricka@epoch.ncsc.mil>, 2004.
@@ -28,9 +28,7 @@
#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>
@@ -44,35 +42,31 @@
/* Global variable to tell if the kernel has SELinux support. */
int selinux_enabled;
-/* Define mappings of access vector permissions to request types. */
-static const access_vector_t perms[LASTREQ] =
+/* Define mappings of request type to AVC permission name. */
+static const char *perms[LASTREQ] =
{
- [GETPWBYNAME] = NSCD__GETPWD,
- [GETPWBYUID] = NSCD__GETPWD,
- [GETGRBYNAME] = NSCD__GETGRP,
- [GETGRBYGID] = NSCD__GETGRP,
- [GETHOSTBYNAME] = NSCD__GETHOST,
- [GETHOSTBYNAMEv6] = NSCD__GETHOST,
- [GETHOSTBYADDR] = NSCD__GETHOST,
- [GETHOSTBYADDRv6] = NSCD__GETHOST,
- [GETSTAT] = NSCD__GETSTAT,
- [SHUTDOWN] = NSCD__ADMIN,
- [INVALIDATE] = NSCD__ADMIN,
- [GETFDPW] = NSCD__SHMEMPWD,
- [GETFDGR] = NSCD__SHMEMGRP,
- [GETFDHST] = NSCD__SHMEMHOST,
- [GETAI] = NSCD__GETHOST,
- [INITGROUPS] = NSCD__GETGRP,
-#ifdef NSCD__GETSERV
- [GETSERVBYNAME] = NSCD__GETSERV,
- [GETSERVBYPORT] = NSCD__GETSERV,
- [GETFDSERV] = NSCD__SHMEMSERV,
-#endif
-#ifdef NSCD__GETNETGRP
- [GETNETGRENT] = NSCD__GETNETGRP,
- [INNETGR] = NSCD__GETNETGRP,
- [GETFDNETGR] = NSCD__SHMEMNETGRP,
-#endif
+ [GETPWBYNAME] = "getpwd",
+ [GETPWBYUID] = "getpwd",
+ [GETGRBYNAME] = "getgrp",
+ [GETGRBYGID] = "getgrp",
+ [GETHOSTBYNAME] = "gethost",
+ [GETHOSTBYNAMEv6] = "gethost",
+ [GETHOSTBYADDR] = "gethost",
+ [GETHOSTBYADDRv6] = "gethost",
+ [SHUTDOWN] = "admin",
+ [GETSTAT] = "getstat",
+ [INVALIDATE] = "admin",
+ [GETFDPW] = "shmempwd",
+ [GETFDGR] = "shmemgrp",
+ [GETFDHST] = "shmemhost",
+ [GETAI] = "gethost",
+ [INITGROUPS] = "getgrp",
+ [GETSERVBYNAME] = "getserv",
+ [GETSERVBYPORT] = "getserv",
+ [GETFDSERV] = "shmemserv",
+ [GETNETGRENT] = "getnetgrp",
+ [INNETGR] = "getnetgrp",
+ [GETFDNETGR] = "shmemnetgrp",
};
/* Store an entry ref to speed AVC decisions. */
@@ -179,7 +173,7 @@ preserve_capabilities (void)
if (prctl (PR_SET_KEEPCAPS, 1) == -1)
{
dbg_log (_("Failed to set keep-capabilities"));
- error (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed"));
+ do_exit (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed"));
/* NOTREACHED */
}
@@ -194,7 +188,7 @@ preserve_capabilities (void)
cap_free (tmp_caps);
dbg_log (_("Failed to initialize drop of capabilities"));
- error (EXIT_FAILURE, 0, _("cap_init failed"));
+ do_exit (EXIT_FAILURE, 0, _("cap_init failed"));
}
/* There is no reason why these should not work. */
@@ -212,11 +206,11 @@ preserve_capabilities (void)
cap_free (tmp_caps);
- if (__builtin_expect (res != 0, 0))
+ if (__glibc_unlikely (res != 0))
{
cap_free (new_caps);
dbg_log (_("Failed to drop capabilities"));
- error (EXIT_FAILURE, 0, _("cap_set_proc failed"));
+ do_exit (EXIT_FAILURE, 0, _("cap_set_proc failed"));
}
return new_caps;
@@ -233,7 +227,7 @@ install_real_capabilities (cap_t new_caps)
{
cap_free (new_caps);
dbg_log (_("Failed to drop capabilities"));
- error (EXIT_FAILURE, 0, _("cap_set_proc failed"));
+ do_exit (EXIT_FAILURE, 0, _("cap_set_proc failed"));
/* NOTREACHED */
}
@@ -242,7 +236,7 @@ install_real_capabilities (cap_t new_caps)
if (prctl (PR_SET_KEEPCAPS, 0) == -1)
{
dbg_log (_("Failed to unset keep-capabilities"));
- error (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed"));
+ do_exit (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed"));
/* NOTREACHED */
}
}
@@ -258,7 +252,7 @@ nscd_selinux_enabled (int *selinux_enabled)
if (*selinux_enabled < 0)
{
dbg_log (_("Failed to determine if kernel supports SELinux"));
- exit (EXIT_FAILURE);
+ do_exit (EXIT_FAILURE, 0, NULL);
}
}
@@ -272,7 +266,7 @@ avc_create_thread (void (*run) (void))
rc =
pthread_create (&avc_notify_thread, NULL, (void *(*) (void *)) run, NULL);
if (rc != 0)
- error (EXIT_FAILURE, rc, _("Failed to start AVC thread"));
+ do_exit (EXIT_FAILURE, rc, _("Failed to start AVC thread"));
return &avc_notify_thread;
}
@@ -294,7 +288,7 @@ avc_alloc_lock (void)
avc_mutex = malloc (sizeof (pthread_mutex_t));
if (avc_mutex == NULL)
- error (EXIT_FAILURE, errno, _("Failed to create AVC lock"));
+ do_exit (EXIT_FAILURE, errno, _("Failed to create AVC lock"));
pthread_mutex_init (avc_mutex, NULL);
return avc_mutex;
@@ -334,7 +328,7 @@ nscd_avc_init (void)
avc_entry_ref_init (&aeref);
if (avc_init ("avc", NULL, &log_cb, &thread_cb, &lock_cb) < 0)
- error (EXIT_FAILURE, errno, _("Failed to start AVC"));
+ do_exit (EXIT_FAILURE, errno, _("Failed to start AVC"));
else
dbg_log (_("Access Vector Cache (AVC) started"));
#ifdef HAVE_LIBAUDIT
@@ -344,7 +338,16 @@ nscd_avc_init (void)
/* Check the permission from the caller (via getpeercon) to nscd.
- Returns 0 if access is allowed, 1 if denied, and -1 on error. */
+ Returns 0 if access is allowed, 1 if denied, and -1 on error.
+
+ The SELinux policy, enablement, and permission bits are all dynamic and the
+ caching done by glibc is not entirely correct. This nscd support should be
+ rewritten to use selinux_check_permission. A rewrite is risky though and
+ requires some refactoring. Currently we use symbolic mappings instead of
+ compile time constants (which SELinux upstream says are going away), and we
+ use security_deny_unknown to determine what to do if selinux-policy* doesn't
+ have a definition for the the permission or object class we are looking
+ up. */
int
nscd_request_avc_has_perm (int fd, request_type req)
{
@@ -354,6 +357,33 @@ nscd_request_avc_has_perm (int fd, request_type req)
security_id_t ssid = NULL;
security_id_t tsid = NULL;
int rc = -1;
+ security_class_t sc_nscd;
+ access_vector_t perm;
+ int avc_deny_unknown;
+
+ /* Check if SELinux denys or allows unknown object classes
+ and permissions. It is 0 if they are allowed, 1 if they
+ are not allowed and -1 on error. */
+ if ((avc_deny_unknown = security_deny_unknown ()) == -1)
+ dbg_log (_("Error querying policy for undefined object classes "
+ "or permissions."));
+
+ /* Get the security class for nscd. If this fails we will likely be
+ unable to do anything unless avc_deny_unknown is 0. */
+ sc_nscd = string_to_security_class ("nscd");
+ if (sc_nscd == 0 && avc_deny_unknown == 1)
+ dbg_log (_("Error getting security class for nscd."));
+
+ /* Convert permission to AVC bits. */
+ perm = string_to_av_perm (sc_nscd, perms[req]);
+ if (perm == 0 && avc_deny_unknown == 1)
+ dbg_log (_("Error translating permission name "
+ "\"%s\" to access vector bit."), perms[req]);
+
+ /* If the nscd security class was not found or perms were not
+ found and AVC does not deny unknown values then allow it. */
+ if ((sc_nscd == 0 || perm == 0) && avc_deny_unknown == 0)
+ return 0;
if (getpeercon (fd, &scon) < 0)
{
@@ -372,15 +402,13 @@ nscd_request_avc_has_perm (int fd, request_type req)
goto out;
}
-#ifndef NSCD__GETSERV
- if (perms[req] == 0)
- {
- dbg_log (_("compile-time support for database policy missing"));
- goto out;
- }
-#endif
-
- rc = avc_has_perm (ssid, tsid, SECCLASS_NSCD, perms[req], &aeref, NULL) < 0;
+ /* The SELinux API for avc_has_perm conflates access denied and error into
+ the return code -1, while nscd_request_avs_has_perm has distinct error
+ (-1) and denied (1) return codes. We map the avc_has_perm access denied or
+ error into an access denied at the nscd interface level (we do accurately
+ report error for the getpeercon, getcon, and avc_context_to_sid interfaces
+ used above). */
+ rc = avc_has_perm (ssid, tsid, sc_nscd, perm, &aeref, NULL) < 0;
out:
if (scon)
diff --git a/nscd/selinux.h b/nscd/selinux.h
index 04f2b7e68d..34da41bf66 100644
--- a/nscd/selinux.h
+++ b/nscd/selinux.h
@@ -1,5 +1,5 @@
/* Header for nscd SELinux access controls.
- Copyright (C) 2004-2014 Free Software Foundation, Inc.
+ Copyright (C) 2004-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Matthew Rickard <mjricka@epoch.ncsc.mil>, 2004.
diff --git a/nscd/servicescache.c b/nscd/servicescache.c
index 52058a6e02..4e8ee4c019 100644
--- a/nscd/servicescache.c
+++ b/nscd/servicescache.c
@@ -1,5 +1,5 @@
/* Cache handling for services lookup.
- Copyright (C) 2007-2014 Free Software Foundation, Inc.
+ Copyright (C) 2007-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@drepper.com>, 2007.
@@ -120,14 +120,10 @@ cache_addserv (struct database_dyn *db, int fd, request_header *req,
else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
+ req->key_len), 1)) != NULL)
{
- dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
- dataset->head.recsize = total;
- dataset->head.notfound = true;
- dataset->head.nreloads = 0;
- dataset->head.usable = true;
-
- /* Compute the timeout time. */
- timeout = dataset->head.timeout = t + db->negtimeout;
+ timeout = datahead_init_neg (&dataset->head,
+ (sizeof (struct dataset)
+ + req->key_len), total,
+ db->negtimeout);
/* This is the reply. */
memcpy (&dataset->resp, &notfound, total);
@@ -207,14 +203,10 @@ cache_addserv (struct database_dyn *db, int fd, request_header *req,
alloca_used = true;
}
- dataset->head.allocsize = total + req->key_len;
- dataset->head.recsize = total - offsetof (struct dataset, resp);
- dataset->head.notfound = false;
- dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
- dataset->head.usable = true;
-
- /* Compute the timeout time. */
- timeout = dataset->head.timeout = t + db->postimeout;
+ timeout = datahead_init_pos (&dataset->head, total + req->key_len,
+ total - offsetof (struct dataset, resp),
+ he == NULL ? 0 : dh->nreloads + 1,
+ db->postimeout);
dataset->resp.version = NSCD_VERSION;
dataset->resp.found = 1;
@@ -389,7 +381,7 @@ addservbyX (struct database_dyn *db, int fd, request_header *req,
bool use_malloc = false;
int errval = 0;
- if (__builtin_expect (debug_level > 0, 0))
+ if (__glibc_unlikely (debug_level > 0))
{
if (he == NULL)
dbg_log (_("Haven't found \"%s\" in services cache!"), key);
@@ -402,7 +394,7 @@ addservbyX (struct database_dyn *db, int fd, request_header *req,
{
errno = 0;
- if (__builtin_expect (buflen > 32768, 0))
+ if (__glibc_unlikely (buflen > 32768))
{
char *old_buffer = buffer;
buflen *= 2;