aboutsummaryrefslogtreecommitdiff
path: root/nscd
diff options
context:
space:
mode:
authorZack Weinberg <zackw@panix.com>2017-06-08 15:39:03 -0400
committerZack Weinberg <zackw@panix.com>2017-06-08 15:39:03 -0400
commit5046dbb4a7eba5eccfd258f92f4735c9ffc8d069 (patch)
tree4470480d904b65cf14ca524f96f79eca818c3eaf /nscd
parent199fc19d3aaaf57944ef036e15904febe877fc93 (diff)
downloadglibc-5046dbb4a7eba5eccfd258f92f4735c9ffc8d069.tar
glibc-5046dbb4a7eba5eccfd258f92f4735c9ffc8d069.tar.gz
glibc-5046dbb4a7eba5eccfd258f92f4735c9ffc8d069.tar.bz2
glibc-5046dbb4a7eba5eccfd258f92f4735c9ffc8d069.zip
Prepare for radical source tree reorganization.zack/build-layout-experiment
All top-level files and directories are moved into a temporary storage directory, REORG.TODO, except for files that will certainly still exist in their current form at top level when we're done (COPYING, COPYING.LIB, LICENSES, NEWS, README), all old ChangeLog files (which are moved to the new directory OldChangeLogs, instead), and the generated file INSTALL (which is just deleted; in the new order, there will be no generated files checked into version control).
Diffstat (limited to 'nscd')
-rw-r--r--nscd/Depend1
-rw-r--r--nscd/Makefile103
-rw-r--r--nscd/aicache.c585
-rw-r--r--nscd/cache.c540
-rw-r--r--nscd/connections.c2558
-rw-r--r--nscd/dbg_log.c85
-rw-r--r--nscd/dbg_log.h30
-rw-r--r--nscd/gai.c48
-rw-r--r--nscd/getgrgid_r.c35
-rw-r--r--nscd/getgrnam_r.c34
-rw-r--r--nscd/gethstbyad_r.c46
-rw-r--r--nscd/gethstbynm3_r.c55
-rw-r--r--nscd/getpwnam_r.c31
-rw-r--r--nscd/getpwuid_r.c31
-rw-r--r--nscd/getsrvbynm_r.c30
-rw-r--r--nscd/getsrvbypt_r.c30
-rw-r--r--nscd/grpcache.c572
-rw-r--r--nscd/hstcache.c619
-rw-r--r--nscd/initgrcache.c438
-rw-r--r--nscd/mem.c589
-rw-r--r--nscd/netgroupcache.c699
-rw-r--r--nscd/nscd-client.h452
-rw-r--r--nscd/nscd.c700
-rw-r--r--nscd/nscd.conf88
-rw-r--r--nscd/nscd.h377
-rw-r--r--nscd/nscd.init116
-rw-r--r--nscd/nscd.service19
-rw-r--r--nscd/nscd.tmpfiles4
-rw-r--r--nscd/nscd_conf.c315
-rw-r--r--nscd/nscd_getai.c216
-rw-r--r--nscd/nscd_getgr_r.c330
-rw-r--r--nscd/nscd_gethst_r.c459
-rw-r--r--nscd/nscd_getpw_r.c241
-rw-r--r--nscd/nscd_getserv_r.c388
-rw-r--r--nscd/nscd_helper.c564
-rw-r--r--nscd/nscd_initgroups.c180
-rw-r--r--nscd/nscd_netgroup.c289
-rw-r--r--nscd/nscd_proto.h79
-rw-r--r--nscd/nscd_setup_thread.c27
-rw-r--r--nscd/nscd_stat.c318
-rw-r--r--nscd/pwdcache.c552
-rw-r--r--nscd/res_hconf.c13
-rw-r--r--nscd/selinux.c453
-rw-r--r--nscd/selinux.h61
-rw-r--r--nscd/servicescache.c474
45 files changed, 0 insertions, 13874 deletions
diff --git a/nscd/Depend b/nscd/Depend
deleted file mode 100644
index 6c1aa44e6e..0000000000
--- a/nscd/Depend
+++ /dev/null
@@ -1 +0,0 @@
-nptl
diff --git a/nscd/Makefile b/nscd/Makefile
deleted file mode 100644
index 4126996887..0000000000
--- a/nscd/Makefile
+++ /dev/null
@@ -1,103 +0,0 @@
-# Copyright (C) 1998-2017 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
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-
-# The GNU C Library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-
-# You should have received a copy of the GNU Lesser General Public
-# License along with the GNU C Library; if not, see
-# <http://www.gnu.org/licenses/>.
-
-#
-# Sub-makefile for nscd portion of the library.
-#
-subdir := nscd
-
-include ../Makeconfig
-
-ifneq ($(use-nscd),no)
-routines := nscd_getpw_r nscd_getgr_r nscd_gethst_r nscd_getai \
- nscd_initgroups nscd_getserv_r nscd_netgroup
-aux := nscd_helper
-endif
-
-# To find xmalloc.c
-vpath %.c ../locale/programs
-
-nscd-modules := nscd connections pwdcache getpwnam_r getpwuid_r grpcache \
- getgrnam_r getgrgid_r hstcache gethstbyad_r gethstbynm3_r \
- getsrvbynm_r getsrvbypt_r servicescache \
- dbg_log nscd_conf nscd_stat cache mem nscd_setup_thread \
- xmalloc xstrdup aicache initgrcache gai res_hconf \
- netgroupcache
-
-ifeq ($(build-nscd)$(have-thread-library),yesyes)
-
-others += nscd
-others-pie += nscd
-install-sbin := nscd
-
-extra-objs = $(nscd-modules:=.o)
-
-endif
-
-all-nscd-modules := $(nscd-modules) selinux
-ifeq (yes,$(have-selinux))
-ifeq (yes,$(have-libaudit))
-libaudit = -laudit
-ifeq (yes,$(have-libcap))
-libcap = -lcap
-endif
-endif
-
-nscd-modules += selinux
-selinux-LIBS := -lselinux $(libaudit) $(libcap)
-
-# The configure.ac check for libselinux and its headers did not use
-# $SYSINCLUDES. The directory specified by --with-headers usually
-# contains only the basic kernel interface headers, not something like
-# libselinux. So the simplest thing is to presume that the standard
-# system headers will be ok for this file.
-$(objpfx)nscd_stat.o: sysincludes = # nothing
-$(objpfx)selinux.o: sysincludes = # nothing
-endif
-
-LDLIBS-nscd = $(selinux-LIBS)
-
-include ../Rules
-
-CFLAGS-nscd_getpw_r.c = -fexceptions
-CFLAGS-nscd_getgr_r.c = -fexceptions
-CFLAGS-nscd_gethst_r.c = -fexceptions
-CFLAGS-nscd_getai.c = -fexceptions
-CFLAGS-nscd_initgroups.c = -fexceptions
-
-CPPFLAGS-nscd += -D_FORTIFY_SOURCE=2
-
-ifeq (yesyes,$(have-fpie)$(build-shared))
-CFLAGS-nscd += $(pie-ccflag)
-endif
-
-ifeq (yesyes,$(have-fpie)$(build-shared))
-LDFLAGS-nscd = -Wl,-z,now
-endif
-
-# Set libof-nscd.
-cpp-srcs-left := $(nscd-modules)
-lib := nscd
-include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left))
-
-$(objpfx)nscd: $(nscd-modules:%=$(objpfx)%.o)
-
-ifeq ($(build-shared),yes)
-$(objpfx)nscd: $(shared-thread-library) $(common-objpfx)nis/libnsl.so
-else
-$(objpfx)nscd: $(static-thread-library) $(common-objpfx)nis/libnsl.a
-endif
diff --git a/nscd/aicache.c b/nscd/aicache.c
deleted file mode 100644
index 7bf4131979..0000000000
--- a/nscd/aicache.c
+++ /dev/null
@@ -1,585 +0,0 @@
-/* Cache handling for host lookup.
- Copyright (C) 2004-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#include <assert.h>
-#include <errno.h>
-#include <libintl.h>
-#include <netdb.h>
-#include <nss.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <resolv/resolv-internal.h>
-#include <resolv/res_hconf.h>
-
-#include "dbg_log.h"
-#include "nscd.h"
-#ifdef HAVE_SENDFILE
-# include <kernel-features.h>
-#endif
-
-
-typedef enum nss_status (*nss_gethostbyname4_r)
- (const char *name, struct gaih_addrtuple **pat,
- char *buffer, size_t buflen, int *errnop,
- int *h_errnop, int32_t *ttlp);
-typedef enum nss_status (*nss_gethostbyname3_r)
- (const char *name, int af, struct hostent *host,
- char *buffer, size_t buflen, int *errnop,
- int *h_errnop, int32_t *, char **);
-typedef enum nss_status (*nss_getcanonname_r)
- (const char *name, char *buffer, size_t buflen, char **result,
- int *errnop, int *h_errnop);
-
-
-static const ai_response_header notfound =
-{
- .version = NSCD_VERSION,
- .found = 0,
- .naddrs = 0,
- .addrslen = 0,
- .canonlen = 0,
- .error = 0
-};
-
-
-static time_t
-addhstaiX (struct database_dyn *db, int fd, request_header *req,
- void *key, uid_t uid, struct hashentry *const he,
- struct datahead *dh)
-{
- /* Search for the entry matching the key. Please note that we don't
- look again in the table whether the dataset is now available. We
- simply insert it. It does not matter if it is in there twice. The
- pruning function only will look at the timestamp. */
-
- /* We allocate all data in one memory block: the iov vector,
- the response header and the dataset itself. */
- struct dataset
- {
- struct datahead head;
- ai_response_header resp;
- char strdata[0];
- } *dataset = NULL;
-
- if (__glibc_unlikely (debug_level > 0))
- {
- if (he == NULL)
- dbg_log (_("Haven't found \"%s\" in hosts cache!"), (char *) key);
- else
- dbg_log (_("Reloading \"%s\" in hosts cache!"), (char *) key);
- }
-
- static service_user *hosts_database;
- service_user *nip;
- int no_more;
- int rc6 = 0;
- int rc4 = 0;
- int herrno = 0;
-
- if (hosts_database == NULL)
- no_more = __nss_database_lookup ("hosts", NULL,
- "dns [!UNAVAIL=return] files",
- &hosts_database);
- else
- no_more = 0;
- nip = hosts_database;
-
- /* Initialize configurations. */
- _res_hconf_init ();
- if (__res_maybe_init (&_res, 0) == -1)
- no_more = 1;
-
- /* If we are looking for both IPv4 and IPv6 address we don't want
- the lookup functions to automatically promote IPv4 addresses to
- IPv6 addresses. Currently this is decided by setting the
- RES_USE_INET6 bit in _res.options. */
- int old_res_options = _res.options;
- _res.options &= ~DEPRECATED_RES_USE_INET6;
-
- size_t tmpbuf6len = 1024;
- char *tmpbuf6 = alloca (tmpbuf6len);
- size_t tmpbuf4len = 0;
- char *tmpbuf4 = NULL;
- int32_t ttl = INT32_MAX;
- ssize_t total = 0;
- char *key_copy = NULL;
- bool alloca_used = false;
- time_t timeout = MAX_TIMEOUT_VALUE;
-
- while (!no_more)
- {
- void *cp;
- int status[2] = { NSS_STATUS_UNAVAIL, NSS_STATUS_UNAVAIL };
- int naddrs = 0;
- size_t addrslen = 0;
- char *canon = NULL;
- size_t canonlen;
-
- nss_gethostbyname4_r fct4 = __nss_lookup_function (nip,
- "gethostbyname4_r");
- if (fct4 != NULL)
- {
- struct gaih_addrtuple atmem;
- struct gaih_addrtuple *at;
- while (1)
- {
- at = &atmem;
- rc6 = 0;
- herrno = 0;
- status[1] = DL_CALL_FCT (fct4, (key, &at, tmpbuf6, tmpbuf6len,
- &rc6, &herrno, &ttl));
- if (rc6 != ERANGE || (herrno != NETDB_INTERNAL
- && herrno != TRY_AGAIN))
- break;
- tmpbuf6 = extend_alloca (tmpbuf6, tmpbuf6len, 2 * tmpbuf6len);
- }
-
- if (rc6 != 0 && herrno == NETDB_INTERNAL)
- goto out;
-
- if (status[1] != NSS_STATUS_SUCCESS)
- goto next_nip;
-
- /* We found the data. Count the addresses and the size. */
- for (const struct gaih_addrtuple *at2 = at = &atmem; at2 != NULL;
- at2 = at2->next)
- {
- ++naddrs;
- /* We do not handle anything other than IPv4 and IPv6
- addresses. The getaddrinfo implementation does not
- either so it is not worth trying to do more. */
- if (at2->family == AF_INET)
- addrslen += INADDRSZ;
- else if (at2->family == AF_INET6)
- addrslen += IN6ADDRSZ;
- }
- canon = at->name;
- canonlen = strlen (canon) + 1;
-
- total = sizeof (*dataset) + naddrs + addrslen + canonlen;
-
- /* Now we can allocate the data structure. If the TTL of the
- entry is reported as zero do not cache the entry at all. */
- if (ttl != 0 && he == NULL)
- dataset = (struct dataset *) mempool_alloc (db, total
- + req->key_len, 1);
-
- if (dataset == NULL)
- {
- /* We cannot permanently add the result in the moment. But
- we can provide the result as is. Store the data in some
- temporary memory. */
- dataset = (struct dataset *) alloca (total + req->key_len);
-
- /* We cannot add this record to the permanent database. */
- alloca_used = true;
- }
-
- /* Fill in the address and address families. */
- char *addrs = dataset->strdata;
- uint8_t *family = (uint8_t *) (addrs + addrslen);
-
- for (const struct gaih_addrtuple *at2 = at; at2 != NULL;
- at2 = at2->next)
- {
- *family++ = at2->family;
- if (at2->family == AF_INET)
- addrs = mempcpy (addrs, at2->addr, INADDRSZ);
- else if (at2->family == AF_INET6)
- addrs = mempcpy (addrs, at2->addr, IN6ADDRSZ);
- }
-
- cp = family;
- }
- else
- {
- /* Prefer the function which also returns the TTL and
- canonical name. */
- nss_gethostbyname3_r fct = __nss_lookup_function (nip,
- "gethostbyname3_r");
- if (fct == NULL)
- fct = __nss_lookup_function (nip, "gethostbyname2_r");
-
- if (fct == NULL)
- goto next_nip;
-
- struct hostent th[2];
-
- /* Collect IPv6 information first. */
- while (1)
- {
- rc6 = 0;
- status[0] = DL_CALL_FCT (fct, (key, AF_INET6, &th[0], tmpbuf6,
- tmpbuf6len, &rc6, &herrno, &ttl,
- &canon));
- if (rc6 != ERANGE || herrno != NETDB_INTERNAL)
- break;
- tmpbuf6 = extend_alloca (tmpbuf6, tmpbuf6len, 2 * tmpbuf6len);
- }
-
- if (rc6 != 0 && herrno == NETDB_INTERNAL)
- goto out;
-
- /* If the IPv6 lookup has been successful do not use the
- buffer used in that lookup, use a new one. */
- if (status[0] == NSS_STATUS_SUCCESS && rc6 == 0)
- {
- tmpbuf4len = 512;
- tmpbuf4 = alloca (tmpbuf4len);
- }
- else
- {
- tmpbuf4len = tmpbuf6len;
- tmpbuf4 = tmpbuf6;
- }
-
- /* Next collect IPv4 information. */
- while (1)
- {
- rc4 = 0;
- status[1] = DL_CALL_FCT (fct, (key, AF_INET, &th[1], tmpbuf4,
- tmpbuf4len, &rc4, &herrno,
- ttl == INT32_MAX ? &ttl : NULL,
- canon == NULL ? &canon : NULL));
- if (rc4 != ERANGE || herrno != NETDB_INTERNAL)
- break;
- tmpbuf4 = extend_alloca (tmpbuf4, tmpbuf4len, 2 * tmpbuf4len);
- }
-
- if (rc4 != 0 && herrno == NETDB_INTERNAL)
- goto out;
-
- if (status[0] != NSS_STATUS_SUCCESS
- && status[1] != NSS_STATUS_SUCCESS)
- goto next_nip;
-
- /* We found the data. Count the addresses and the size. */
- for (int j = 0; j < 2; ++j)
- if (status[j] == NSS_STATUS_SUCCESS)
- for (int i = 0; th[j].h_addr_list[i] != NULL; ++i)
- {
- ++naddrs;
- addrslen += th[j].h_length;
- }
-
- if (canon == NULL)
- {
- /* Determine the canonical name. */
- nss_getcanonname_r cfct;
- cfct = __nss_lookup_function (nip, "getcanonname_r");
- if (cfct != NULL)
- {
- const size_t max_fqdn_len = 256;
- char *buf = alloca (max_fqdn_len);
- char *s;
- int rc;
-
- if (DL_CALL_FCT (cfct, (key, buf, max_fqdn_len, &s,
- &rc, &herrno))
- == NSS_STATUS_SUCCESS)
- canon = s;
- else
- /* Set to name now to avoid using gethostbyaddr. */
- canon = key;
- }
- else
- {
- struct hostent *hstent = NULL;
- int herrno;
- struct hostent hstent_mem;
- void *addr;
- size_t addrlen;
- int addrfamily;
-
- if (status[1] == NSS_STATUS_SUCCESS)
- {
- addr = th[1].h_addr_list[0];
- addrlen = sizeof (struct in_addr);
- addrfamily = AF_INET;
- }
- else
- {
- addr = th[0].h_addr_list[0];
- addrlen = sizeof (struct in6_addr);
- addrfamily = AF_INET6;
- }
-
- size_t tmpbuflen = 512;
- char *tmpbuf = alloca (tmpbuflen);
- int rc;
- while (1)
- {
- rc = __gethostbyaddr2_r (addr, addrlen, addrfamily,
- &hstent_mem, tmpbuf, tmpbuflen,
- &hstent, &herrno, NULL);
- if (rc != ERANGE || herrno != NETDB_INTERNAL)
- break;
- tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
- tmpbuflen * 2);
- }
-
- if (rc == 0)
- {
- if (hstent != NULL)
- canon = hstent->h_name;
- else
- canon = key;
- }
- }
- }
-
- canonlen = canon == NULL ? 0 : (strlen (canon) + 1);
-
- total = sizeof (*dataset) + naddrs + addrslen + canonlen;
-
-
- /* Now we can allocate the data structure. If the TTL of the
- entry is reported as zero do not cache the entry at all. */
- if (ttl != 0 && he == NULL)
- dataset = (struct dataset *) mempool_alloc (db, total
- + req->key_len, 1);
-
- if (dataset == NULL)
- {
- /* We cannot permanently add the result in the moment. But
- we can provide the result as is. Store the data in some
- temporary memory. */
- dataset = (struct dataset *) alloca (total + req->key_len);
-
- /* We cannot add this record to the permanent database. */
- alloca_used = true;
- }
-
- /* Fill in the address and address families. */
- char *addrs = dataset->strdata;
- uint8_t *family = (uint8_t *) (addrs + addrslen);
-
- for (int j = 0; j < 2; ++j)
- if (status[j] == NSS_STATUS_SUCCESS)
- for (int i = 0; th[j].h_addr_list[i] != NULL; ++i)
- {
- addrs = mempcpy (addrs, th[j].h_addr_list[i],
- th[j].h_length);
- *family++ = th[j].h_addrtype;
- }
-
- cp = family;
- }
-
- 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;
- dataset->resp.addrslen = addrslen;
- dataset->resp.canonlen = canonlen;
- dataset->resp.error = NETDB_SUCCESS;
-
- if (canon != NULL)
- cp = mempcpy (cp, canon, canonlen);
-
- key_copy = memcpy (cp, key, req->key_len);
-
- assert (cp == (char *) dataset + total);
-
- /* Now we can determine whether on refill we have to create a
- new record or not. */
- if (he != NULL)
- {
- assert (fd == -1);
-
- if (total + req->key_len == dh->allocsize
- && total - offsetof (struct dataset, resp) == dh->recsize
- && memcmp (&dataset->resp, dh->data,
- dh->allocsize - offsetof (struct dataset,
- resp)) == 0)
- {
- /* The data has not changed. We will just bump the
- timeout value. Note that the new record has been
- allocated on the stack and need not be freed. */
- dh->timeout = dataset->head.timeout;
- dh->ttl = dataset->head.ttl;
- ++dh->nreloads;
- }
- else
- {
- /* We have to create a new record. Just allocate
- appropriate memory and copy it. */
- struct dataset *newp
- = (struct dataset *) mempool_alloc (db, total + req->key_len,
- 1);
- if (__glibc_likely (newp != NULL))
- {
- /* Adjust pointer into the memory block. */
- key_copy = (char *) newp + (key_copy - (char *) dataset);
-
- dataset = memcpy (newp, dataset, total + req->key_len);
- alloca_used = false;
- }
-
- /* Mark the old record as obsolete. */
- dh->usable = false;
- }
- }
- else
- {
- /* We write the dataset before inserting it to the database
- since while inserting this thread might block and so
- would unnecessarily let the receiver wait. */
- assert (fd != -1);
-
-#ifdef HAVE_SENDFILE
- if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
- {
- assert (db->wr_fd != -1);
- assert ((char *) &dataset->resp > (char *) db->data);
- assert ((char *) dataset - (char *) db->head + total
- <= (sizeof (struct database_pers_head)
- + db->head->module * sizeof (ref_t)
- + db->head->data_size));
-# ifndef __ASSUME_SENDFILE
- ssize_t written;
- written =
-# endif
- sendfileall (fd, db->wr_fd, (char *) &dataset->resp
- - (char *) db->head, dataset->head.recsize);
-# ifndef __ASSUME_SENDFILE
- if (written == -1 && errno == ENOSYS)
- goto use_write;
-# endif
- }
- else
-# ifndef __ASSUME_SENDFILE
- use_write:
-# endif
-#endif
- writeall (fd, &dataset->resp, dataset->head.recsize);
- }
-
- goto out;
-
-next_nip:
- if (nss_next_action (nip, status[1]) == NSS_ACTION_RETURN)
- break;
-
- if (nip->next == NULL)
- no_more = -1;
- else
- nip = nip->next;
- }
-
- /* No result found. Create a negative result record. */
- if (he != NULL && rc4 == EAGAIN)
- {
- /* If we have an old record available but cannot find one now
- because the service is not available we keep the old record
- and make sure it does not get removed. */
- if (reload_count != UINT_MAX && dh->nreloads == reload_count)
- /* Do not reset the value if we never not reload the record. */
- dh->nreloads = reload_count - 1;
-
- /* Reload with the same time-to-live value. */
- timeout = dh->timeout = time (NULL) + dh->ttl;
- }
- else
- {
- /* We have no data. This means we send the standard reply for
- this case. */
- total = sizeof (notfound);
-
- if (fd != -1)
- TEMP_FAILURE_RETRY (send (fd, &notfound, total, MSG_NOSIGNAL));
-
- /* If we have a transient error or cannot permanently store the
- result, so be it. */
- if (rc4 == EAGAIN || __builtin_expect (db->negtimeout == 0, 0))
- {
- /* Mark the old entry as obsolete. */
- if (dh != NULL)
- dh->usable = false;
- dataset = NULL;
- }
- else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
- + req->key_len), 1)) != NULL)
- {
- timeout = datahead_init_neg (&dataset->head,
- sizeof (struct dataset) + req->key_len,
- total, db->negtimeout);
-
- /* This is the reply. */
- memcpy (&dataset->resp, &notfound, total);
-
- /* Copy the key data. */
- key_copy = memcpy (dataset->strdata, key, req->key_len);
- }
- }
-
- out:
- _res.options |= old_res_options & DEPRECATED_RES_USE_INET6;
-
- if (dataset != NULL && !alloca_used)
- {
- /* If necessary, we also propagate the data to disk. */
- if (db->persistent)
- {
- // XXX async OK?
- uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
- msync ((void *) pval,
- ((uintptr_t) dataset & pagesize_m1) + total + req->key_len,
- MS_ASYNC);
- }
-
- (void) cache_add (req->type, key_copy, req->key_len, &dataset->head,
- true, db, uid, he == NULL);
-
- pthread_rwlock_unlock (&db->lock);
-
- /* Mark the old entry as obsolete. */
- if (dh != NULL)
- dh->usable = false;
- }
-
- return timeout;
-}
-
-
-void
-addhstai (struct database_dyn *db, int fd, request_header *req, void *key,
- uid_t uid)
-{
- addhstaiX (db, fd, req, key, uid, NULL, NULL);
-}
-
-
-time_t
-readdhstai (struct database_dyn *db, struct hashentry *he, struct datahead *dh)
-{
- request_header req =
- {
- .type = GETAI,
- .key_len = he->len
- };
-
- return addhstaiX (db, -1, &req, db->data + he->key, he->owner, he, dh);
-}
diff --git a/nscd/cache.c b/nscd/cache.c
deleted file mode 100644
index b9dbc7a0bd..0000000000
--- a/nscd/cache.c
+++ /dev/null
@@ -1,540 +0,0 @@
-/* Copyright (c) 1998-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#include <assert.h>
-#include <atomic.h>
-#include <errno.h>
-#include <error.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <libintl.h>
-#include <arpa/inet.h>
-#include <rpcsvc/nis.h>
-#include <sys/mman.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
-
-#include "nscd.h"
-#include "dbg_log.h"
-
-
-/* Wrapper functions with error checking for standard functions. */
-extern void *xcalloc (size_t n, size_t s);
-
-
-/* Number of times a value is reloaded without being used. UINT_MAX
- means unlimited. */
-unsigned int reload_count = DEFAULT_RELOAD_LIMIT;
-
-
-static time_t (*const readdfcts[LASTREQ]) (struct database_dyn *,
- struct hashentry *,
- struct datahead *) =
-{
- [GETPWBYNAME] = readdpwbyname,
- [GETPWBYUID] = readdpwbyuid,
- [GETGRBYNAME] = readdgrbyname,
- [GETGRBYGID] = readdgrbygid,
- [GETHOSTBYNAME] = readdhstbyname,
- [GETHOSTBYNAMEv6] = readdhstbynamev6,
- [GETHOSTBYADDR] = readdhstbyaddr,
- [GETHOSTBYADDRv6] = readdhstbyaddrv6,
- [GETAI] = readdhstai,
- [INITGROUPS] = readdinitgroups,
- [GETSERVBYNAME] = readdservbyname,
- [GETSERVBYPORT] = readdservbyport,
- [GETNETGRENT] = readdgetnetgrent,
- [INNETGR] = readdinnetgr
-};
-
-
-/* Search the cache for a matching entry and return it when found. If
- this fails search the negative cache and return (void *) -1 if this
- search was successful. Otherwise return NULL.
-
- This function must be called with the read-lock held. */
-struct datahead *
-cache_search (request_type type, const void *key, size_t len,
- struct database_dyn *table, uid_t owner)
-{
- unsigned long int hash = __nis_hash (key, len) % table->head->module;
-
- unsigned long int nsearched = 0;
- struct datahead *result = NULL;
-
- ref_t work = table->head->array[hash];
- while (work != ENDREF)
- {
- ++nsearched;
-
- struct hashentry *here = (struct hashentry *) (table->data + work);
-
- if (type == here->type && len == here->len
- && memcmp (key, table->data + here->key, len) == 0
- && here->owner == owner)
- {
- /* We found the entry. Increment the appropriate counter. */
- struct datahead *dh
- = (struct datahead *) (table->data + here->packet);
-
- /* See whether we must ignore the entry. */
- if (dh->usable)
- {
- /* We do not synchronize the memory here. The statistics
- data is not crucial, we synchronize only once in a while
- in the cleanup threads. */
- if (dh->notfound)
- ++table->head->neghit;
- else
- {
- ++table->head->poshit;
-
- if (dh->nreloads != 0)
- dh->nreloads = 0;
- }
-
- result = dh;
- break;
- }
- }
-
- work = here->next;
- }
-
- if (nsearched > table->head->maxnsearched)
- table->head->maxnsearched = nsearched;
-
- return result;
-}
-
-/* Add a new entry to the cache. The return value is zero if the function
- call was successful.
-
- This function must be called with the read-lock held.
-
- We modify the table but we nevertheless only acquire a read-lock.
- This is ok since we use operations which would be safe even without
- locking, given that the `prune_cache' function never runs. Using
- the readlock reduces the chance of conflicts. */
-int
-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 (__glibc_unlikely (debug_level >= 2))
- {
- const char *str;
- char buf[INET6_ADDRSTRLEN + 1];
- if (type == GETHOSTBYADDR || type == GETHOSTBYADDRv6)
- str = inet_ntop (type == GETHOSTBYADDR ? AF_INET : AF_INET6,
- key, buf, sizeof (buf));
- else
- str = key;
-
- dbg_log (_("add new entry \"%s\" of type %s for %s to cache%s"),
- str, serv2str[type], dbnames[table - dbs],
- first ? _(" (first)") : "");
- }
-
- unsigned long int hash = __nis_hash (key, len) % table->head->module;
- struct hashentry *newp;
-
- newp = mempool_alloc (table, sizeof (struct hashentry), 0);
- /* If we cannot allocate memory, just do not do anything. */
- if (newp == NULL)
- {
- /* If necessary mark the entry as unusable so that lookups will
- not use it. */
- if (first)
- packet->usable = false;
-
- return -1;
- }
-
- newp->type = type;
- newp->first = first;
- newp->len = len;
- newp->key = (char *) key - table->data;
- assert (newp->key + newp->len <= table->head->first_free);
- newp->owner = owner;
- newp->packet = (char *) packet - table->data;
- assert ((newp->packet & BLOCK_ALIGN_M1) == 0);
-
- /* Put the new entry in the first position. */
- /* TODO Review concurrency. Use atomic_exchange_release. */
- newp->next = atomic_load_relaxed (&table->head->array[hash]);
- while (!atomic_compare_exchange_weak_release (&table->head->array[hash],
- (ref_t *) &newp->next,
- (ref_t) ((char *) newp
- - table->data)));
-
- /* Update the statistics. */
- if (packet->notfound)
- ++table->head->negmiss;
- else if (first)
- ++table->head->posmiss;
-
- /* We depend on this value being correct and at least as high as the
- real number of entries. */
- atomic_increment (&table->head->nentries);
-
- /* It does not matter that we are not loading the just increment
- value, this is just for statistics. */
- unsigned long int nentries = table->head->nentries;
- if (nentries > table->head->maxnentries)
- table->head->maxnentries = nentries;
-
- if (table->persistent)
- // XXX async OK?
- msync ((void *) table->head,
- (char *) &table->head->array[hash] - (char *) table->head
- + sizeof (ref_t), MS_ASYNC);
-
- /* We do not have to worry about the pruning thread if we are
- re-adding the data since this is done by the pruning thread. We
- also do not have to do anything in case this is not the first
- time the data is entered since different data heads all have the
- same timeout. */
- if (first && prune_wakeup)
- {
- /* Perhaps the prune thread for the table is not running in a long
- time. Wake it if necessary. */
- pthread_mutex_lock (&table->prune_lock);
- time_t next_wakeup = table->wakeup_time;
- bool do_wakeup = false;
- if (next_wakeup > packet->timeout + CACHE_PRUNE_INTERVAL)
- {
- table->wakeup_time = packet->timeout;
- do_wakeup = true;
- }
- pthread_mutex_unlock (&table->prune_lock);
- if (do_wakeup)
- pthread_cond_signal (&table->prune_cond);
- }
-
- return 0;
-}
-
-/* Walk through the table and remove all entries which lifetime ended.
-
- We have a problem here. To actually remove the entries we must get
- the write-lock. But since we want to keep the time we have the
- lock as short as possible we cannot simply acquire the lock when we
- start looking for timedout entries.
-
- Therefore we do it in two stages: first we look for entries which
- must be invalidated and remember them. Then we get the lock and
- actually remove them. This is complicated by the way we have to
- free the data structures since some hash table entries share the same
- data. */
-time_t
-prune_cache (struct database_dyn *table, time_t now, int fd)
-{
- size_t cnt = table->head->module;
-
- /* If this table is not actually used don't do anything. */
- if (cnt == 0)
- {
- if (fd != -1)
- {
- /* Reply to the INVALIDATE initiator. */
- int32_t resp = 0;
- writeall (fd, &resp, sizeof (resp));
- }
-
- /* No need to do this again anytime soon. */
- return 24 * 60 * 60;
- }
-
- /* If we check for the modification of the underlying file we invalidate
- the entries also in this case. */
- if (table->check_file && now != LONG_MAX)
- {
- struct traced_file *runp = table->traced_files;
-
- while (runp != NULL)
- {
-#ifdef HAVE_INOTIFY
- 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];
- dbg_log (_("checking for monitored file `%s': %s"),
- runp->fname, strerror_r (errno, buf, sizeof (buf)));
- }
- else
- {
- /* 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)
- {
- dbg_log (_("monitored file `%s` changed (mtime)"),
- runp->fname);
- /* The file changed. Invalidate all entries. */
- now = LONG_MAX;
- runp->mtime = st.st_mtime;
-#ifdef HAVE_INOTIFY
- /* Attempt to install a watch on the file. */
- install_watches (runp);
-#endif
- }
- }
- }
-
- runp = runp->next;
- }
- }
-
- /* We run through the table and find values which are not valid anymore.
-
- Note that for the initial step, finding the entries to be removed,
- we don't need to get any lock. It is at all timed assured that the
- linked lists are set up correctly and that no second thread prunes
- the cache. */
- bool *mark;
- size_t memory_needed = cnt * sizeof (bool);
- bool mark_use_alloca;
- if (__glibc_likely (memory_needed <= MAX_STACK_USE))
- {
- mark = alloca (cnt * sizeof (bool));
- memset (mark, '\0', memory_needed);
- mark_use_alloca = true;
- }
- else
- {
- mark = xcalloc (1, memory_needed);
- mark_use_alloca = false;
- }
- size_t first = cnt + 1;
- size_t last = 0;
- char *const data = table->data;
- bool any = false;
-
- if (__glibc_unlikely (debug_level > 2))
- dbg_log (_("pruning %s cache; time %ld"),
- dbnames[table - dbs], (long int) now);
-
-#define NO_TIMEOUT LONG_MAX
- time_t next_timeout = NO_TIMEOUT;
- do
- {
- ref_t run = table->head->array[--cnt];
-
- while (run != ENDREF)
- {
- struct hashentry *runp = (struct hashentry *) (data + run);
- struct datahead *dh = (struct datahead *) (data + runp->packet);
-
- /* Some debug support. */
- if (__glibc_unlikely (debug_level > 2))
- {
- char buf[INET6_ADDRSTRLEN];
- const char *str;
-
- if (runp->type == GETHOSTBYADDR || runp->type == GETHOSTBYADDRv6)
- {
- inet_ntop (runp->type == GETHOSTBYADDR ? AF_INET : AF_INET6,
- data + runp->key, buf, sizeof (buf));
- str = buf;
- }
- else
- str = data + runp->key;
-
- dbg_log (_("considering %s entry \"%s\", timeout %" PRIu64),
- serv2str[runp->type], str, dh->timeout);
- }
-
- /* Check whether the entry timed out. */
- if (dh->timeout < now)
- {
- /* This hash bucket could contain entries which need to
- be looked at. */
- mark[cnt] = true;
-
- first = MIN (first, cnt);
- last = MAX (last, cnt);
-
- /* We only have to look at the data of the first entries
- since the count information is kept in the data part
- which is shared. */
- if (runp->first)
- {
-
- /* At this point there are two choices: we reload the
- value or we discard it. Do not change NRELOADS if
- we never not reload the record. */
- if ((reload_count != UINT_MAX
- && __builtin_expect (dh->nreloads >= reload_count, 0))
- /* We always remove negative entries. */
- || dh->notfound
- /* Discard everything if the user explicitly
- requests it. */
- || now == LONG_MAX)
- {
- /* Remove the value. */
- dh->usable = false;
-
- /* We definitely have some garbage entries now. */
- any = true;
- }
- else
- {
- /* Reload the value. We do this only for the
- initially used key, not the additionally
- added derived value. */
- assert (runp->type < LASTREQ
- && readdfcts[runp->type] != NULL);
-
- time_t timeout = readdfcts[runp->type] (table, runp, dh);
- next_timeout = MIN (next_timeout, timeout);
-
- /* If the entry has been replaced, we might need
- cleanup. */
- any |= !dh->usable;
- }
- }
- }
- else
- {
- assert (dh->usable);
- next_timeout = MIN (next_timeout, dh->timeout);
- }
-
- run = runp->next;
- }
- }
- while (cnt > 0);
-
- if (__glibc_unlikely (fd != -1))
- {
- /* Reply to the INVALIDATE initiator that the cache has been
- invalidated. */
- int32_t resp = 0;
- writeall (fd, &resp, sizeof (resp));
- }
-
- if (first <= last)
- {
- struct hashentry *head = NULL;
-
- /* Now we have to get the write lock since we are about to modify
- the table. */
- if (__glibc_unlikely (pthread_rwlock_trywrlock (&table->lock) != 0))
- {
- ++table->head->wrlockdelayed;
- pthread_rwlock_wrlock (&table->lock);
- }
-
- while (first <= last)
- {
- if (mark[first])
- {
- ref_t *old = &table->head->array[first];
- ref_t run = table->head->array[first];
-
- assert (run != ENDREF);
- do
- {
- struct hashentry *runp = (struct hashentry *) (data + run);
- struct datahead *dh
- = (struct datahead *) (data + runp->packet);
-
- if (! dh->usable)
- {
- /* We need the list only for debugging but it is
- more costly to avoid creating the list than
- doing it. */
- runp->dellist = head;
- head = runp;
-
- /* No need for an atomic operation, we have the
- write lock. */
- --table->head->nentries;
-
- run = *old = runp->next;
- }
- else
- {
- old = &runp->next;
- run = runp->next;
- }
- }
- while (run != ENDREF);
- }
-
- ++first;
- }
-
- /* It's all done. */
- pthread_rwlock_unlock (&table->lock);
-
- /* Make sure the data is saved to disk. */
- if (table->persistent)
- msync (table->head,
- data + table->head->first_free - (char *) table->head,
- MS_ASYNC);
-
- /* One extra pass if we do debugging. */
- if (__glibc_unlikely (debug_level > 0))
- {
- struct hashentry *runp = head;
-
- while (runp != NULL)
- {
- char buf[INET6_ADDRSTRLEN];
- const char *str;
-
- if (runp->type == GETHOSTBYADDR || runp->type == GETHOSTBYADDRv6)
- {
- inet_ntop (runp->type == GETHOSTBYADDR ? AF_INET : AF_INET6,
- data + runp->key, buf, sizeof (buf));
- str = buf;
- }
- else
- str = data + runp->key;
-
- dbg_log ("remove %s entry \"%s\"", serv2str[runp->type], str);
-
- runp = runp->dellist;
- }
- }
- }
-
- if (__glibc_unlikely (! mark_use_alloca))
- free (mark);
-
- /* Run garbage collection if any entry has been removed or replaced. */
- if (any)
- gc (table);
-
- /* If there is no entry in the database and we therefore have no new
- timeout value, tell the caller to wake up in 24 hours. */
- return next_timeout == NO_TIMEOUT ? 24 * 60 * 60 : next_timeout - now;
-}
diff --git a/nscd/connections.c b/nscd/connections.c
deleted file mode 100644
index cc1ed72077..0000000000
--- a/nscd/connections.c
+++ /dev/null
@@ -1,2558 +0,0 @@
-/* Inner loops of cache daemon.
- Copyright (C) 1998-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#include <alloca.h>
-#include <assert.h>
-#include <atomic.h>
-#include <error.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <grp.h>
-#include <ifaddrs.h>
-#include <libintl.h>
-#include <pthread.h>
-#include <pwd.h>
-#include <resolv.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <arpa/inet.h>
-#ifdef HAVE_NETLINK
-# include <linux/netlink.h>
-# include <linux/rtnetlink.h>
-#endif
-#ifdef HAVE_EPOLL
-# include <sys/epoll.h>
-#endif
-#ifdef HAVE_INOTIFY
-# include <sys/inotify.h>
-#endif
-#include <sys/mman.h>
-#include <sys/param.h>
-#include <sys/poll.h>
-#ifdef HAVE_SENDFILE
-# include <sys/sendfile.h>
-#endif
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/un.h>
-
-#include "nscd.h"
-#include "dbg_log.h"
-#include "selinux.h"
-#include <resolv/resolv.h>
-
-#include <kernel-features.h>
-#include <libc-diag.h>
-
-
-/* Support to run nscd as an unprivileged user */
-const char *server_user;
-static uid_t server_uid;
-static gid_t server_gid;
-const char *stat_user;
-uid_t stat_uid;
-static gid_t *server_groups;
-#ifndef NGROUPS
-# define NGROUPS 32
-#endif
-static int server_ngroups;
-
-static pthread_attr_t attr;
-
-static void begin_drop_privileges (void);
-static void finish_drop_privileges (void);
-
-/* Map request type to a string. */
-const char *const serv2str[LASTREQ] =
-{
- [GETPWBYNAME] = "GETPWBYNAME",
- [GETPWBYUID] = "GETPWBYUID",
- [GETGRBYNAME] = "GETGRBYNAME",
- [GETGRBYGID] = "GETGRBYGID",
- [GETHOSTBYNAME] = "GETHOSTBYNAME",
- [GETHOSTBYNAMEv6] = "GETHOSTBYNAMEv6",
- [GETHOSTBYADDR] = "GETHOSTBYADDR",
- [GETHOSTBYADDRv6] = "GETHOSTBYADDRv6",
- [SHUTDOWN] = "SHUTDOWN",
- [GETSTAT] = "GETSTAT",
- [INVALIDATE] = "INVALIDATE",
- [GETFDPW] = "GETFDPW",
- [GETFDGR] = "GETFDGR",
- [GETFDHST] = "GETFDHST",
- [GETAI] = "GETAI",
- [INITGROUPS] = "INITGROUPS",
- [GETSERVBYNAME] = "GETSERVBYNAME",
- [GETSERVBYPORT] = "GETSERVBYPORT",
- [GETFDSERV] = "GETFDSERV",
- [GETNETGRENT] = "GETNETGRENT",
- [INNETGR] = "INNETGR",
- [GETFDNETGR] = "GETFDNETGR"
-};
-
-/* The control data structures for the services. */
-struct database_dyn dbs[lastdb] =
-{
- [pwddb] = {
- .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
- .prune_lock = PTHREAD_MUTEX_INITIALIZER,
- .prune_run_lock = PTHREAD_MUTEX_INITIALIZER,
- .enabled = 0,
- .check_file = 1,
- .persistent = 0,
- .propagate = 1,
- .shared = 0,
- .max_db_size = DEFAULT_MAX_DB_SIZE,
- .suggested_module = DEFAULT_SUGGESTED_MODULE,
- .db_filename = _PATH_NSCD_PASSWD_DB,
- .disabled_iov = &pwd_iov_disabled,
- .postimeout = 3600,
- .negtimeout = 20,
- .wr_fd = -1,
- .ro_fd = -1,
- .mmap_used = false
- },
- [grpdb] = {
- .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
- .prune_lock = PTHREAD_MUTEX_INITIALIZER,
- .prune_run_lock = PTHREAD_MUTEX_INITIALIZER,
- .enabled = 0,
- .check_file = 1,
- .persistent = 0,
- .propagate = 1,
- .shared = 0,
- .max_db_size = DEFAULT_MAX_DB_SIZE,
- .suggested_module = DEFAULT_SUGGESTED_MODULE,
- .db_filename = _PATH_NSCD_GROUP_DB,
- .disabled_iov = &grp_iov_disabled,
- .postimeout = 3600,
- .negtimeout = 60,
- .wr_fd = -1,
- .ro_fd = -1,
- .mmap_used = false
- },
- [hstdb] = {
- .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
- .prune_lock = PTHREAD_MUTEX_INITIALIZER,
- .prune_run_lock = PTHREAD_MUTEX_INITIALIZER,
- .enabled = 0,
- .check_file = 1,
- .persistent = 0,
- .propagate = 0, /* Not used. */
- .shared = 0,
- .max_db_size = DEFAULT_MAX_DB_SIZE,
- .suggested_module = DEFAULT_SUGGESTED_MODULE,
- .db_filename = _PATH_NSCD_HOSTS_DB,
- .disabled_iov = &hst_iov_disabled,
- .postimeout = 3600,
- .negtimeout = 20,
- .wr_fd = -1,
- .ro_fd = -1,
- .mmap_used = false
- },
- [servdb] = {
- .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
- .prune_lock = PTHREAD_MUTEX_INITIALIZER,
- .prune_run_lock = PTHREAD_MUTEX_INITIALIZER,
- .enabled = 0,
- .check_file = 1,
- .persistent = 0,
- .propagate = 0, /* Not used. */
- .shared = 0,
- .max_db_size = DEFAULT_MAX_DB_SIZE,
- .suggested_module = DEFAULT_SUGGESTED_MODULE,
- .db_filename = _PATH_NSCD_SERVICES_DB,
- .disabled_iov = &serv_iov_disabled,
- .postimeout = 28800,
- .negtimeout = 20,
- .wr_fd = -1,
- .ro_fd = -1,
- .mmap_used = false
- },
- [netgrdb] = {
- .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
- .prune_lock = PTHREAD_MUTEX_INITIALIZER,
- .prune_run_lock = PTHREAD_MUTEX_INITIALIZER,
- .enabled = 0,
- .check_file = 1,
- .persistent = 0,
- .propagate = 0, /* Not used. */
- .shared = 0,
- .max_db_size = DEFAULT_MAX_DB_SIZE,
- .suggested_module = DEFAULT_SUGGESTED_MODULE,
- .db_filename = _PATH_NSCD_NETGROUP_DB,
- .disabled_iov = &netgroup_iov_disabled,
- .postimeout = 28800,
- .negtimeout = 20,
- .wr_fd = -1,
- .ro_fd = -1,
- .mmap_used = false
- }
-};
-
-
-/* Mapping of request type to database. */
-static struct
-{
- bool data_request;
- struct database_dyn *db;
-} const reqinfo[LASTREQ] =
-{
- [GETPWBYNAME] = { true, &dbs[pwddb] },
- [GETPWBYUID] = { true, &dbs[pwddb] },
- [GETGRBYNAME] = { true, &dbs[grpdb] },
- [GETGRBYGID] = { true, &dbs[grpdb] },
- [GETHOSTBYNAME] = { true, &dbs[hstdb] },
- [GETHOSTBYNAMEv6] = { true, &dbs[hstdb] },
- [GETHOSTBYADDR] = { true, &dbs[hstdb] },
- [GETHOSTBYADDRv6] = { true, &dbs[hstdb] },
- [SHUTDOWN] = { false, NULL },
- [GETSTAT] = { false, NULL },
- [SHUTDOWN] = { false, NULL },
- [GETFDPW] = { false, &dbs[pwddb] },
- [GETFDGR] = { false, &dbs[grpdb] },
- [GETFDHST] = { false, &dbs[hstdb] },
- [GETAI] = { true, &dbs[hstdb] },
- [INITGROUPS] = { true, &dbs[grpdb] },
- [GETSERVBYNAME] = { true, &dbs[servdb] },
- [GETSERVBYPORT] = { true, &dbs[servdb] },
- [GETFDSERV] = { false, &dbs[servdb] },
- [GETNETGRENT] = { true, &dbs[netgrdb] },
- [INNETGR] = { true, &dbs[netgrdb] },
- [GETFDNETGR] = { false, &dbs[netgrdb] }
-};
-
-
-/* Initial number of threads to use. */
-int nthreads = -1;
-/* Maximum number of threads to use. */
-int max_nthreads = 32;
-
-/* Socket for incoming connections. */
-static int sock;
-
-#ifdef HAVE_INOTIFY
-/* Inotify descriptor. */
-int inotify_fd = -1;
-#endif
-
-#ifdef HAVE_NETLINK
-/* Descriptor for netlink status updates. */
-static int nl_status_fd = -1;
-#endif
-
-/* Number of times clients had to wait. */
-unsigned long int client_queued;
-
-
-ssize_t
-writeall (int fd, const void *buf, size_t len)
-{
- size_t n = len;
- ssize_t ret;
- do
- {
- ret = TEMP_FAILURE_RETRY (send (fd, buf, n, MSG_NOSIGNAL));
- if (ret <= 0)
- break;
- buf = (const char *) buf + ret;
- n -= ret;
- }
- while (n > 0);
- return ret < 0 ? ret : len - n;
-}
-
-
-#ifdef HAVE_SENDFILE
-ssize_t
-sendfileall (int tofd, int fromfd, off_t off, size_t len)
-{
- ssize_t n = len;
- ssize_t ret;
-
- do
- {
- ret = TEMP_FAILURE_RETRY (sendfile (tofd, fromfd, &off, n));
- if (ret <= 0)
- break;
- n -= ret;
- }
- while (n > 0);
- return ret < 0 ? ret : len - n;
-}
-#endif
-
-
-enum usekey
- {
- use_not = 0,
- /* The following three are not really used, they are symbolic constants. */
- use_first = 16,
- use_begin = 32,
- use_end = 64,
-
- use_he = 1,
- use_he_begin = use_he | use_begin,
- use_he_end = use_he | use_end,
- use_data = 3,
- use_data_begin = use_data | use_begin,
- use_data_end = use_data | use_end,
- use_data_first = use_data_begin | use_first
- };
-
-
-static int
-check_use (const char *data, nscd_ssize_t first_free, uint8_t *usemap,
- enum usekey use, ref_t start, size_t len)
-{
- assert (len >= 2);
-
- if (start > first_free || start + len > first_free
- || (start & BLOCK_ALIGN_M1))
- return 0;
-
- if (usemap[start] == use_not)
- {
- /* Add the start marker. */
- usemap[start] = use | use_begin;
- use &= ~use_first;
-
- while (--len > 0)
- if (usemap[++start] != use_not)
- return 0;
- else
- usemap[start] = use;
-
- /* Add the end marker. */
- usemap[start] = use | use_end;
- }
- else if ((usemap[start] & ~use_first) == ((use | use_begin) & ~use_first))
- {
- /* Hash entries can't be shared. */
- if (use == use_he)
- return 0;
-
- usemap[start] |= (use & use_first);
- use &= ~use_first;
-
- while (--len > 1)
- if (usemap[++start] != use)
- return 0;
-
- if (usemap[++start] != (use | use_end))
- return 0;
- }
- else
- /* Points to a wrong object or somewhere in the middle. */
- return 0;
-
- return 1;
-}
-
-
-/* Verify data in persistent database. */
-static int
-verify_persistent_db (void *mem, struct database_pers_head *readhead, int dbnr)
-{
- assert (dbnr == pwddb || dbnr == grpdb || dbnr == hstdb || dbnr == servdb
- || dbnr == netgrdb);
-
- time_t now = time (NULL);
-
- struct database_pers_head *head = mem;
- struct database_pers_head head_copy = *head;
-
- /* Check that the header that was read matches the head in the database. */
- if (memcmp (head, readhead, sizeof (*head)) != 0)
- return 0;
-
- /* First some easy tests: make sure the database header is sane. */
- if (head->version != DB_VERSION
- || head->header_size != sizeof (*head)
- /* We allow a timestamp to be one hour ahead of the current time.
- This should cover daylight saving time changes. */
- || head->timestamp > now + 60 * 60 + 60
- || (head->gc_cycle & 1)
- || head->module == 0
- || (size_t) head->module > INT32_MAX / sizeof (ref_t)
- || (size_t) head->data_size > INT32_MAX - head->module * sizeof (ref_t)
- || head->first_free < 0
- || head->first_free > head->data_size
- || (head->first_free & BLOCK_ALIGN_M1) != 0
- || head->maxnentries < 0
- || head->maxnsearched < 0)
- return 0;
-
- uint8_t *usemap = calloc (head->first_free, 1);
- if (usemap == NULL)
- return 0;
-
- const char *data = (char *) &head->array[roundup (head->module,
- ALIGN / sizeof (ref_t))];
-
- nscd_ssize_t he_cnt = 0;
- for (nscd_ssize_t cnt = 0; cnt < head->module; ++cnt)
- {
- ref_t trail = head->array[cnt];
- ref_t work = trail;
- int tick = 0;
-
- while (work != ENDREF)
- {
- if (! check_use (data, head->first_free, usemap, use_he, work,
- sizeof (struct hashentry)))
- goto fail;
-
- /* Now we know we can dereference the record. */
- struct hashentry *here = (struct hashentry *) (data + work);
-
- ++he_cnt;
-
- /* Make sure the record is for this type of service. */
- if (here->type >= LASTREQ
- || reqinfo[here->type].db != &dbs[dbnr])
- goto fail;
-
- /* Validate boolean field value. */
- if (here->first != false && here->first != true)
- goto fail;
-
- if (here->len < 0)
- goto fail;
-
- /* Now the data. */
- if (here->packet < 0
- || here->packet > head->first_free
- || here->packet + sizeof (struct datahead) > head->first_free)
- goto fail;
-
- struct datahead *dh = (struct datahead *) (data + here->packet);
-
- if (! check_use (data, head->first_free, usemap,
- use_data | (here->first ? use_first : 0),
- here->packet, dh->allocsize))
- goto fail;
-
- if (dh->allocsize < sizeof (struct datahead)
- || dh->recsize > dh->allocsize
- || (dh->notfound != false && dh->notfound != true)
- || (dh->usable != false && dh->usable != true))
- goto fail;
-
- if (here->key < here->packet + sizeof (struct datahead)
- || here->key > here->packet + dh->allocsize
- || here->key + here->len > here->packet + dh->allocsize)
- goto fail;
-
- work = here->next;
-
- if (work == trail)
- /* A circular list, this must not happen. */
- goto fail;
- if (tick)
- trail = ((struct hashentry *) (data + trail))->next;
- tick = 1 - tick;
- }
- }
-
- if (he_cnt != head->nentries)
- goto fail;
-
- /* See if all data and keys had at least one reference from
- he->first == true hashentry. */
- for (ref_t idx = 0; idx < head->first_free; ++idx)
- {
- if (usemap[idx] == use_data_begin)
- goto fail;
- }
-
- /* Finally, make sure the database hasn't changed since the first test. */
- if (memcmp (mem, &head_copy, sizeof (*head)) != 0)
- goto fail;
-
- free (usemap);
- return 1;
-
-fail:
- free (usemap);
- return 0;
-}
-
-
-/* Initialize database information structures. */
-void
-nscd_init (void)
-{
- /* Look up unprivileged uid/gid/groups before we start listening on the
- socket */
- if (server_user != NULL)
- begin_drop_privileges ();
-
- if (nthreads == -1)
- /* No configuration for this value, assume a default. */
- nthreads = 4;
-
- for (size_t cnt = 0; cnt < lastdb; ++cnt)
- if (dbs[cnt].enabled)
- {
- pthread_rwlock_init (&dbs[cnt].lock, NULL);
- pthread_mutex_init (&dbs[cnt].memlock, NULL);
-
- if (dbs[cnt].persistent)
- {
- /* Try to open the appropriate file on disk. */
- int fd = open (dbs[cnt].db_filename, O_RDWR | O_CLOEXEC);
- if (fd != -1)
- {
- char *msg = NULL;
- struct stat64 st;
- void *mem;
- size_t total;
- struct database_pers_head head;
- ssize_t n = TEMP_FAILURE_RETRY (read (fd, &head,
- sizeof (head)));
- if (n != sizeof (head) || fstat64 (fd, &st) != 0)
- {
- fail_db_errno:
- /* The code is single-threaded at this point so
- using strerror is just fine. */
- msg = strerror (errno);
- fail_db:
- dbg_log (_("invalid persistent database file \"%s\": %s"),
- dbs[cnt].db_filename, msg);
- unlink (dbs[cnt].db_filename);
- }
- else if (head.module == 0 && head.data_size == 0)
- {
- /* The file has been created, but the head has not
- been initialized yet. */
- msg = _("uninitialized header");
- goto fail_db;
- }
- else if (head.header_size != (int) sizeof (head))
- {
- msg = _("header size does not match");
- goto fail_db;
- }
- else if ((total = (sizeof (head)
- + roundup (head.module * sizeof (ref_t),
- ALIGN)
- + head.data_size))
- > st.st_size
- || total < sizeof (head))
- {
- msg = _("file size does not match");
- goto fail_db;
- }
- /* Note we map with the maximum size allowed for the
- database. This is likely much larger than the
- actual file size. This is OK on most OSes since
- extensions of the underlying file will
- automatically translate more pages available for
- memory access. */
- else if ((mem = mmap (NULL, dbs[cnt].max_db_size,
- PROT_READ | PROT_WRITE,
- MAP_SHARED, fd, 0))
- == MAP_FAILED)
- goto fail_db_errno;
- else if (!verify_persistent_db (mem, &head, cnt))
- {
- munmap (mem, total);
- msg = _("verification failed");
- goto fail_db;
- }
- else
- {
- /* Success. We have the database. */
- dbs[cnt].head = mem;
- dbs[cnt].memsize = total;
- dbs[cnt].data = (char *)
- &dbs[cnt].head->array[roundup (dbs[cnt].head->module,
- ALIGN / sizeof (ref_t))];
- dbs[cnt].mmap_used = true;
-
- if (dbs[cnt].suggested_module > head.module)
- dbg_log (_("suggested size of table for database %s larger than the persistent database's table"),
- dbnames[cnt]);
-
- dbs[cnt].wr_fd = fd;
- fd = -1;
- /* We also need a read-only descriptor. */
- if (dbs[cnt].shared)
- {
- dbs[cnt].ro_fd = open (dbs[cnt].db_filename,
- O_RDONLY | O_CLOEXEC);
- if (dbs[cnt].ro_fd == -1)
- dbg_log (_("\
-cannot create read-only descriptor for \"%s\"; no mmap"),
- dbs[cnt].db_filename);
- }
-
- // XXX Shall we test whether the descriptors actually
- // XXX point to the same file?
- }
-
- /* Close the file descriptors in case something went
- wrong in which case the variable have not been
- assigned -1. */
- if (fd != -1)
- close (fd);
- }
- else if (errno == EACCES)
- do_exit (EXIT_FAILURE, 0, _("cannot access '%s'"),
- dbs[cnt].db_filename);
- }
-
- if (dbs[cnt].head == NULL)
- {
- /* No database loaded. Allocate the data structure,
- possibly on disk. */
- struct database_pers_head head;
- size_t total = (sizeof (head)
- + roundup (dbs[cnt].suggested_module
- * sizeof (ref_t), ALIGN)
- + (dbs[cnt].suggested_module
- * DEFAULT_DATASIZE_PER_BUCKET));
-
- /* Try to create the database. If we do not need a
- persistent database create a temporary file. */
- int fd;
- int ro_fd = -1;
- if (dbs[cnt].persistent)
- {
- fd = open (dbs[cnt].db_filename,
- O_RDWR | O_CREAT | O_EXCL | O_TRUNC | O_CLOEXEC,
- S_IRUSR | S_IWUSR);
- if (fd != -1 && dbs[cnt].shared)
- ro_fd = open (dbs[cnt].db_filename,
- O_RDONLY | O_CLOEXEC);
- }
- else
- {
- char fname[] = _PATH_NSCD_XYZ_DB_TMP;
- fd = mkostemp (fname, O_CLOEXEC);
-
- /* We do not need the file name anymore after we
- opened another file descriptor in read-only mode. */
- if (fd != -1)
- {
- if (dbs[cnt].shared)
- ro_fd = open (fname, O_RDONLY | O_CLOEXEC);
-
- unlink (fname);
- }
- }
-
- if (fd == -1)
- {
- if (errno == EEXIST)
- {
- dbg_log (_("database for %s corrupted or simultaneously used; remove %s manually if necessary and restart"),
- dbnames[cnt], dbs[cnt].db_filename);
- do_exit (1, 0, NULL);
- }
-
- if (dbs[cnt].persistent)
- dbg_log (_("cannot create %s; no persistent database used"),
- dbs[cnt].db_filename);
- else
- dbg_log (_("cannot create %s; no sharing possible"),
- dbs[cnt].db_filename);
-
- dbs[cnt].persistent = 0;
- // XXX remember: no mmap
- }
- else
- {
- /* Tell the user if we could not create the read-only
- descriptor. */
- if (ro_fd == -1 && dbs[cnt].shared)
- dbg_log (_("\
-cannot create read-only descriptor for \"%s\"; no mmap"),
- dbs[cnt].db_filename);
-
- /* Before we create the header, initialize the hash
- table. That way if we get interrupted while writing
- the header we can recognize a partially initialized
- database. */
- size_t ps = sysconf (_SC_PAGESIZE);
- char tmpbuf[ps];
- assert (~ENDREF == 0);
- memset (tmpbuf, '\xff', ps);
-
- size_t remaining = dbs[cnt].suggested_module * sizeof (ref_t);
- off_t offset = sizeof (head);
-
- size_t towrite;
- if (offset % ps != 0)
- {
- towrite = MIN (remaining, ps - (offset % ps));
- if (pwrite (fd, tmpbuf, towrite, offset) != towrite)
- goto write_fail;
- offset += towrite;
- remaining -= towrite;
- }
-
- while (remaining > ps)
- {
- if (pwrite (fd, tmpbuf, ps, offset) == -1)
- goto write_fail;
- offset += ps;
- remaining -= ps;
- }
-
- if (remaining > 0
- && pwrite (fd, tmpbuf, remaining, offset) != remaining)
- goto write_fail;
-
- /* Create the header of the file. */
- struct database_pers_head head =
- {
- .version = DB_VERSION,
- .header_size = sizeof (head),
- .module = dbs[cnt].suggested_module,
- .data_size = (dbs[cnt].suggested_module
- * DEFAULT_DATASIZE_PER_BUCKET),
- .first_free = 0
- };
- void *mem;
-
- if ((TEMP_FAILURE_RETRY (write (fd, &head, sizeof (head)))
- != sizeof (head))
- || (TEMP_FAILURE_RETRY_VAL (posix_fallocate (fd, 0, total))
- != 0)
- || (mem = mmap (NULL, dbs[cnt].max_db_size,
- PROT_READ | PROT_WRITE,
- MAP_SHARED, fd, 0)) == MAP_FAILED)
- {
- write_fail:
- unlink (dbs[cnt].db_filename);
- dbg_log (_("cannot write to database file %s: %s"),
- dbs[cnt].db_filename, strerror (errno));
- dbs[cnt].persistent = 0;
- }
- else
- {
- /* Success. */
- dbs[cnt].head = mem;
- dbs[cnt].data = (char *)
- &dbs[cnt].head->array[roundup (dbs[cnt].head->module,
- ALIGN / sizeof (ref_t))];
- dbs[cnt].memsize = total;
- dbs[cnt].mmap_used = true;
-
- /* Remember the descriptors. */
- dbs[cnt].wr_fd = fd;
- dbs[cnt].ro_fd = ro_fd;
- fd = -1;
- ro_fd = -1;
- }
-
- if (fd != -1)
- close (fd);
- if (ro_fd != -1)
- close (ro_fd);
- }
- }
-
- if (dbs[cnt].head == NULL)
- {
- /* We do not use the persistent database. Just
- create an in-memory data structure. */
- assert (! dbs[cnt].persistent);
-
- dbs[cnt].head = xmalloc (sizeof (struct database_pers_head)
- + (dbs[cnt].suggested_module
- * sizeof (ref_t)));
- memset (dbs[cnt].head, '\0', sizeof (struct database_pers_head));
- assert (~ENDREF == 0);
- memset (dbs[cnt].head->array, '\xff',
- dbs[cnt].suggested_module * sizeof (ref_t));
- dbs[cnt].head->module = dbs[cnt].suggested_module;
- dbs[cnt].head->data_size = (DEFAULT_DATASIZE_PER_BUCKET
- * dbs[cnt].head->module);
- dbs[cnt].data = xmalloc (dbs[cnt].head->data_size);
- dbs[cnt].head->first_free = 0;
-
- dbs[cnt].shared = 0;
- assert (dbs[cnt].ro_fd == -1);
- }
- }
-
- /* Create the socket. */
- sock = socket (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
- if (sock < 0)
- {
- dbg_log (_("cannot open socket: %s"), strerror (errno));
- do_exit (errno == EACCES ? 4 : 1, 0, NULL);
- }
- /* Bind a name to the socket. */
- struct sockaddr_un sock_addr;
- sock_addr.sun_family = AF_UNIX;
- strcpy (sock_addr.sun_path, _PATH_NSCDSOCKET);
- if (bind (sock, (struct sockaddr *) &sock_addr, sizeof (sock_addr)) < 0)
- {
- dbg_log ("%s: %s", _PATH_NSCDSOCKET, strerror (errno));
- do_exit (errno == EACCES ? 4 : 1, 0, NULL);
- }
-
- /* Set permissions for the socket. */
- chmod (_PATH_NSCDSOCKET, DEFFILEMODE);
-
- /* Set the socket up to accept connections. */
- if (listen (sock, SOMAXCONN) < 0)
- {
- dbg_log (_("cannot enable socket to accept connections: %s"),
- strerror (errno));
- do_exit (1, 0, NULL);
- }
-
-#ifdef HAVE_NETLINK
- if (dbs[hstdb].enabled)
- {
- /* Try to open netlink socket to monitor network setting changes. */
- nl_status_fd = socket (AF_NETLINK,
- SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
- NETLINK_ROUTE);
- if (nl_status_fd != -1)
- {
- struct sockaddr_nl snl;
- memset (&snl, '\0', sizeof (snl));
- snl.nl_family = AF_NETLINK;
- /* XXX Is this the best set to use? */
- snl.nl_groups = (RTMGRP_IPV4_IFADDR | RTMGRP_TC | RTMGRP_IPV4_MROUTE
- | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_RULE
- | RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_MROUTE
- | RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFINFO
- | RTMGRP_IPV6_PREFIX);
-
- if (bind (nl_status_fd, (struct sockaddr *) &snl, sizeof (snl)) != 0)
- {
- close (nl_status_fd);
- nl_status_fd = -1;
- }
- else
- {
- /* Start the timestamp process. */
- dbs[hstdb].head->extra_data[NSCD_HST_IDX_CONF_TIMESTAMP]
- = __bump_nl_timestamp ();
- }
- }
- }
-#endif
-
- /* Change to unprivileged uid/gid/groups if specified in config file */
- if (server_user != NULL)
- 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].
-
- We support registering multiple files per database. Each call to
- register_traced_file adds to the list of registered files.
-
- When we prune the database, either through timeout or a request to
- invalidate, we will check to see if any of the registered files has changed.
- When we accept new connections to handle a cache request we will also
- check to see if any of the registered files has changed.
-
- If we have inotify support then we install an inotify fd to notify us of
- file deletion or modification, both of which will require we invalidate
- the cache for the database. Without inotify support we stat the file and
- store st_mtime to determine if the file has been modified. */
-void
-register_traced_file (size_t dbidx, struct traced_file *finfo)
-{
- /* If the database is disabled or file checking is disabled
- then ignore the registration. */
- if (! dbs[dbidx].enabled || ! dbs[dbidx].check_file)
- return;
-
- if (__glibc_unlikely (debug_level > 0))
- dbg_log (_("monitoring file %s for database %s"),
- finfo->fname, dbnames[dbidx]);
-
-#ifdef HAVE_INOTIFY
- install_watches (finfo);
-#endif
- struct stat64 st;
- if (stat64 (finfo->fname, &st) < 0)
- {
- /* 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;
- dbs[dbidx].traced_files = finfo;
-}
-
-
-/* Close the connections. */
-void
-close_sockets (void)
-{
- close (sock);
-}
-
-
-static void
-invalidate_cache (char *key, int fd)
-{
- dbtype number;
- int32_t resp;
-
- for (number = pwddb; number < lastdb; ++number)
- if (strcmp (key, dbnames[number]) == 0)
- {
- struct traced_file *runp = dbs[number].traced_files;
- while (runp != NULL)
- {
- /* 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)
- {
- resp = EINVAL;
- writeall (fd, &resp, sizeof (resp));
- return;
- }
-
- if (dbs[number].enabled)
- {
- pthread_mutex_lock (&dbs[number].prune_run_lock);
- prune_cache (&dbs[number], LONG_MAX, fd);
- pthread_mutex_unlock (&dbs[number].prune_run_lock);
- }
- else
- {
- resp = 0;
- writeall (fd, &resp, sizeof (resp));
- }
-}
-
-
-#ifdef SCM_RIGHTS
-static void
-send_ro_fd (struct database_dyn *db, char *key, int fd)
-{
- /* If we do not have an read-only file descriptor do nothing. */
- if (db->ro_fd == -1)
- return;
-
- /* We need to send some data along with the descriptor. */
- uint64_t mapsize = (db->head->data_size
- + roundup (db->head->module * sizeof (ref_t), ALIGN)
- + sizeof (struct database_pers_head));
- struct iovec iov[2];
- iov[0].iov_base = key;
- iov[0].iov_len = strlen (key) + 1;
- iov[1].iov_base = &mapsize;
- iov[1].iov_len = sizeof (mapsize);
-
- /* Prepare the control message to transfer the descriptor. */
- union
- {
- struct cmsghdr hdr;
- char bytes[CMSG_SPACE (sizeof (int))];
- } buf;
- struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 2,
- .msg_control = buf.bytes,
- .msg_controllen = sizeof (buf) };
- struct cmsghdr *cmsg = CMSG_FIRSTHDR (&msg);
-
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN (sizeof (int));
-
- int *ip = (int *) CMSG_DATA (cmsg);
- *ip = db->ro_fd;
-
- msg.msg_controllen = cmsg->cmsg_len;
-
- /* Send the control message. We repeat when we are interrupted but
- everything else is ignored. */
-#ifndef MSG_NOSIGNAL
-# define MSG_NOSIGNAL 0
-#endif
- (void) TEMP_FAILURE_RETRY (sendmsg (fd, &msg, MSG_NOSIGNAL));
-
- if (__glibc_unlikely (debug_level > 0))
- dbg_log (_("provide access to FD %d, for %s"), db->ro_fd, key);
-}
-#endif /* SCM_RIGHTS */
-
-
-/* Handle new request. */
-static void
-handle_request (int fd, request_header *req, void *key, uid_t uid, pid_t pid)
-{
- if (__builtin_expect (req->version, NSCD_VERSION) != NSCD_VERSION)
- {
- if (debug_level > 0)
- dbg_log (_("\
-cannot handle old request version %d; current version is %d"),
- req->version, NSCD_VERSION);
- return;
- }
-
- /* Perform the SELinux check before we go on to the standard checks. */
- if (selinux_enabled && nscd_request_avc_has_perm (fd, req->type) != 0)
- {
- if (debug_level > 0)
- {
-#ifdef SO_PEERCRED
-# ifdef PATH_MAX
- char buf[PATH_MAX];
-# else
- char buf[4096];
-# endif
-
- snprintf (buf, sizeof (buf), "/proc/%ld/exe", (long int) pid);
- ssize_t n = readlink (buf, buf, sizeof (buf) - 1);
-
- if (n <= 0)
- dbg_log (_("\
-request from %ld not handled due to missing permission"), (long int) pid);
- else
- {
- buf[n] = '\0';
- dbg_log (_("\
-request from '%s' [%ld] not handled due to missing permission"),
- buf, (long int) pid);
- }
-#else
- dbg_log (_("request not handled due to missing permission"));
-#endif
- }
- return;
- }
-
- struct database_dyn *db = reqinfo[req->type].db;
-
- /* See whether we can service the request from the cache. */
- if (__builtin_expect (reqinfo[req->type].data_request, true))
- {
- if (__builtin_expect (debug_level, 0) > 0)
- {
- if (req->type == GETHOSTBYADDR || req->type == GETHOSTBYADDRv6)
- {
- char buf[INET6_ADDRSTRLEN];
-
- dbg_log ("\t%s (%s)", serv2str[req->type],
- inet_ntop (req->type == GETHOSTBYADDR
- ? AF_INET : AF_INET6,
- key, buf, sizeof (buf)));
- }
- else
- dbg_log ("\t%s (%s)", serv2str[req->type], (char *) key);
- }
-
- /* Is this service enabled? */
- if (__glibc_unlikely (!db->enabled))
- {
- /* No, sent the prepared record. */
- if (TEMP_FAILURE_RETRY (send (fd, db->disabled_iov->iov_base,
- db->disabled_iov->iov_len,
- MSG_NOSIGNAL))
- != (ssize_t) db->disabled_iov->iov_len
- && __builtin_expect (debug_level, 0) > 0)
- {
- /* We have problems sending the result. */
- char buf[256];
- dbg_log (_("cannot write result: %s"),
- strerror_r (errno, buf, sizeof (buf)));
- }
-
- return;
- }
-
- /* Be sure we can read the data. */
- if (__glibc_unlikely (pthread_rwlock_tryrdlock (&db->lock) != 0))
- {
- ++db->head->rdlockdelayed;
- pthread_rwlock_rdlock (&db->lock);
- }
-
- /* See whether we can handle it from the cache. */
- struct datahead *cached;
- cached = (struct datahead *) cache_search (req->type, key, req->key_len,
- db, uid);
- if (cached != NULL)
- {
- /* Hurray it's in the cache. */
- ssize_t nwritten;
-
-#ifdef HAVE_SENDFILE
- if (__glibc_likely (db->mmap_used))
- {
- assert (db->wr_fd != -1);
- assert ((char *) cached->data > (char *) db->data);
- assert ((char *) cached->data - (char *) db->head
- + cached->recsize
- <= (sizeof (struct database_pers_head)
- + db->head->module * sizeof (ref_t)
- + db->head->data_size));
- nwritten = sendfileall (fd, db->wr_fd,
- (char *) cached->data
- - (char *) db->head, cached->recsize);
-# ifndef __ASSUME_SENDFILE
- if (nwritten == -1 && errno == ENOSYS)
- goto use_write;
-# endif
- }
- else
-# ifndef __ASSUME_SENDFILE
- use_write:
-# endif
-#endif
- nwritten = writeall (fd, cached->data, cached->recsize);
-
- if (nwritten != cached->recsize
- && __builtin_expect (debug_level, 0) > 0)
- {
- /* We have problems sending the result. */
- char buf[256];
- dbg_log (_("cannot write result: %s"),
- strerror_r (errno, buf, sizeof (buf)));
- }
-
- pthread_rwlock_unlock (&db->lock);
-
- return;
- }
-
- pthread_rwlock_unlock (&db->lock);
- }
- else if (__builtin_expect (debug_level, 0) > 0)
- {
- if (req->type == INVALIDATE)
- dbg_log ("\t%s (%s)", serv2str[req->type], (char *) key);
- else
- dbg_log ("\t%s", serv2str[req->type]);
- }
-
- /* Handle the request. */
- switch (req->type)
- {
- case GETPWBYNAME:
- addpwbyname (db, fd, req, key, uid);
- break;
-
- case GETPWBYUID:
- addpwbyuid (db, fd, req, key, uid);
- break;
-
- case GETGRBYNAME:
- addgrbyname (db, fd, req, key, uid);
- break;
-
- case GETGRBYGID:
- addgrbygid (db, fd, req, key, uid);
- break;
-
- case GETHOSTBYNAME:
- addhstbyname (db, fd, req, key, uid);
- break;
-
- case GETHOSTBYNAMEv6:
- addhstbynamev6 (db, fd, req, key, uid);
- break;
-
- case GETHOSTBYADDR:
- addhstbyaddr (db, fd, req, key, uid);
- break;
-
- case GETHOSTBYADDRv6:
- addhstbyaddrv6 (db, fd, req, key, uid);
- break;
-
- case GETAI:
- addhstai (db, fd, req, key, uid);
- break;
-
- case INITGROUPS:
- addinitgroups (db, fd, req, key, uid);
- break;
-
- case GETSERVBYNAME:
- addservbyname (db, fd, req, key, uid);
- break;
-
- case GETSERVBYPORT:
- addservbyport (db, fd, req, key, uid);
- break;
-
- case GETNETGRENT:
- addgetnetgrent (db, fd, req, key, uid);
- break;
-
- case INNETGR:
- addinnetgr (db, fd, req, key, uid);
- break;
-
- case GETSTAT:
- case SHUTDOWN:
- case INVALIDATE:
- {
- /* Get the callers credentials. */
-#ifdef SO_PEERCRED
- struct ucred caller;
- socklen_t optlen = sizeof (caller);
-
- if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
- {
- char buf[256];
-
- dbg_log (_("error getting caller's id: %s"),
- strerror_r (errno, buf, sizeof (buf)));
- break;
- }
-
- uid = caller.uid;
-#else
- /* Some systems have no SO_PEERCRED implementation. They don't
- care about security so we don't as well. */
- uid = 0;
-#endif
- }
-
- /* Accept shutdown, getstat and invalidate only from root. For
- the stat call also allow the user specified in the config file. */
- if (req->type == GETSTAT)
- {
- if (uid == 0 || uid == stat_uid)
- send_stats (fd, dbs);
- }
- else if (uid == 0)
- {
- if (req->type == INVALIDATE)
- invalidate_cache (key, fd);
- else
- termination_handler (0);
- }
- break;
-
- case GETFDPW:
- case GETFDGR:
- case GETFDHST:
- case GETFDSERV:
- case GETFDNETGR:
-#ifdef SCM_RIGHTS
- send_ro_fd (reqinfo[req->type].db, key, fd);
-#endif
- break;
-
- default:
- /* Ignore the command, it's nothing we know. */
- break;
- }
-}
-
-
-/* Restart the process. */
-static void
-restart (void)
-{
- /* First determine the parameters. We do not use the parameters
- passed to main() since in case nscd is started by running the
- dynamic linker this will not work. Yes, this is not the usual
- case but nscd is part of glibc and we occasionally do this. */
- size_t buflen = 1024;
- char *buf = alloca (buflen);
- size_t readlen = 0;
- int fd = open ("/proc/self/cmdline", O_RDONLY);
- if (fd == -1)
- {
- dbg_log (_("\
-cannot open /proc/self/cmdline: %s; disabling paranoia mode"),
- strerror (errno));
-
- paranoia = 0;
- return;
- }
-
- while (1)
- {
- ssize_t n = TEMP_FAILURE_RETRY (read (fd, buf + readlen,
- buflen - readlen));
- if (n == -1)
- {
- dbg_log (_("\
-cannot read /proc/self/cmdline: %s; disabling paranoia mode"),
- strerror (errno));
-
- close (fd);
- paranoia = 0;
- return;
- }
-
- readlen += n;
-
- if (readlen < buflen)
- break;
-
- /* We might have to extend the buffer. */
- size_t old_buflen = buflen;
- char *newp = extend_alloca (buf, buflen, 2 * buflen);
- buf = memmove (newp, buf, old_buflen);
- }
-
- close (fd);
-
- /* Parse the command line. Worst case scenario: every two
- characters form one parameter (one character plus NUL). */
- char **argv = alloca ((readlen / 2 + 1) * sizeof (argv[0]));
- int argc = 0;
-
- char *cp = buf;
- while (cp < buf + readlen)
- {
- argv[argc++] = cp;
- cp = (char *) rawmemchr (cp, '\0') + 1;
- }
- argv[argc] = NULL;
-
- /* Second, change back to the old user if we changed it. */
- if (server_user != NULL)
- {
- if (setresuid (old_uid, old_uid, old_uid) != 0)
- {
- dbg_log (_("\
-cannot change to old UID: %s; disabling paranoia mode"),
- strerror (errno));
-
- paranoia = 0;
- return;
- }
-
- if (setresgid (old_gid, old_gid, old_gid) != 0)
- {
- dbg_log (_("\
-cannot change to old GID: %s; disabling paranoia mode"),
- strerror (errno));
-
- ignore_value (setuid (server_uid));
- paranoia = 0;
- return;
- }
- }
-
- /* Next change back to the old working directory. */
- if (chdir (oldcwd) == -1)
- {
- dbg_log (_("\
-cannot change to old working directory: %s; disabling paranoia mode"),
- strerror (errno));
-
- if (server_user != NULL)
- {
- ignore_value (setuid (server_uid));
- ignore_value (setgid (server_gid));
- }
- paranoia = 0;
- return;
- }
-
- /* Synchronize memory. */
- int32_t certainly[lastdb];
- for (int cnt = 0; cnt < lastdb; ++cnt)
- if (dbs[cnt].enabled)
- {
- /* Make sure nobody keeps using the database. */
- dbs[cnt].head->timestamp = 0;
- certainly[cnt] = dbs[cnt].head->nscd_certainly_running;
- dbs[cnt].head->nscd_certainly_running = 0;
-
- if (dbs[cnt].persistent)
- // XXX async OK?
- msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
- }
-
- /* The preparations are done. */
-#ifdef PATH_MAX
- char pathbuf[PATH_MAX];
-#else
- char pathbuf[256];
-#endif
- /* Try to exec the real nscd program so the process name (as reported
- in /proc/PID/status) will be 'nscd', but fall back to /proc/self/exe
- if readlink or the exec with the result of the readlink call fails. */
- ssize_t n = readlink ("/proc/self/exe", pathbuf, sizeof (pathbuf) - 1);
- if (n != -1)
- {
- pathbuf[n] = '\0';
- execv (pathbuf, argv);
- }
- execv ("/proc/self/exe", argv);
-
- /* If we come here, we will never be able to re-exec. */
- dbg_log (_("re-exec failed: %s; disabling paranoia mode"),
- strerror (errno));
-
- if (server_user != NULL)
- {
- ignore_value (setuid (server_uid));
- ignore_value (setgid (server_gid));
- }
- if (chdir ("/") != 0)
- dbg_log (_("cannot change current working directory to \"/\": %s"),
- strerror (errno));
- paranoia = 0;
-
- /* Reenable the databases. */
- time_t now = time (NULL);
- for (int cnt = 0; cnt < lastdb; ++cnt)
- if (dbs[cnt].enabled)
- {
- dbs[cnt].head->timestamp = now;
- dbs[cnt].head->nscd_certainly_running = certainly[cnt];
- }
-}
-
-
-/* List of file descriptors. */
-struct fdlist
-{
- int fd;
- struct fdlist *next;
-};
-/* Memory allocated for the list. */
-static struct fdlist *fdlist;
-/* List of currently ready-to-read file descriptors. */
-static struct fdlist *readylist;
-
-/* Conditional variable and mutex to signal availability of entries in
- READYLIST. The condvar is initialized dynamically since we might
- use a different clock depending on availability. */
-static pthread_cond_t readylist_cond = PTHREAD_COND_INITIALIZER;
-static pthread_mutex_t readylist_lock = PTHREAD_MUTEX_INITIALIZER;
-
-/* The clock to use with the condvar. */
-static clockid_t timeout_clock = CLOCK_REALTIME;
-
-/* Number of threads ready to handle the READYLIST. */
-static unsigned long int nready;
-
-
-/* Function for the clean-up threads. */
-static void *
-__attribute__ ((__noreturn__))
-nscd_run_prune (void *p)
-{
- const long int my_number = (long int) p;
- assert (dbs[my_number].enabled);
-
- int dont_need_update = setup_thread (&dbs[my_number]);
-
- time_t now = time (NULL);
-
- /* We are running. */
- dbs[my_number].head->timestamp = now;
-
- struct timespec prune_ts;
- if (__glibc_unlikely (clock_gettime (timeout_clock, &prune_ts) == -1))
- /* Should never happen. */
- abort ();
-
- /* Compute the initial timeout time. Prevent all the timers to go
- off at the same time by adding a db-based value. */
- prune_ts.tv_sec += CACHE_PRUNE_INTERVAL + my_number;
- dbs[my_number].wakeup_time = now + CACHE_PRUNE_INTERVAL + my_number;
-
- pthread_mutex_t *prune_lock = &dbs[my_number].prune_lock;
- pthread_mutex_t *prune_run_lock = &dbs[my_number].prune_run_lock;
- pthread_cond_t *prune_cond = &dbs[my_number].prune_cond;
-
- pthread_mutex_lock (prune_lock);
- while (1)
- {
- /* Wait, but not forever. */
- int e = 0;
- if (! dbs[my_number].clear_cache)
- e = pthread_cond_timedwait (prune_cond, prune_lock, &prune_ts);
- assert (__builtin_expect (e == 0 || e == ETIMEDOUT, 1));
-
- time_t next_wait;
- now = time (NULL);
- if (e == ETIMEDOUT || now >= dbs[my_number].wakeup_time
- || dbs[my_number].clear_cache)
- {
- /* We will determine the new timout values based on the
- cache content. Should there be concurrent additions to
- the cache which are not accounted for in the cache
- pruning we want to know about it. Therefore set the
- timeout to the maximum. It will be descreased when adding
- new entries to the cache, if necessary. */
- dbs[my_number].wakeup_time = MAX_TIMEOUT_VALUE;
-
- /* Unconditionally reset the flag. */
- time_t prune_now = dbs[my_number].clear_cache ? LONG_MAX : now;
- dbs[my_number].clear_cache = 0;
-
- pthread_mutex_unlock (prune_lock);
-
- /* We use a separate lock for running the prune function (instead
- of keeping prune_lock locked) because this enables concurrent
- invocations of cache_add which might modify the timeout value. */
- pthread_mutex_lock (prune_run_lock);
- next_wait = prune_cache (&dbs[my_number], prune_now, -1);
- pthread_mutex_unlock (prune_run_lock);
-
- next_wait = MAX (next_wait, CACHE_PRUNE_INTERVAL);
- /* If clients cannot determine for sure whether nscd is running
- 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 (__glibc_unlikely (! dont_need_update))
- {
- next_wait = MIN (UPDATE_MAPPING_TIMEOUT, next_wait);
- dbs[my_number].head->timestamp = now;
- }
-
- pthread_mutex_lock (prune_lock);
-
- /* Make it known when we will wake up again. */
- if (now + next_wait < dbs[my_number].wakeup_time)
- dbs[my_number].wakeup_time = now + next_wait;
- else
- next_wait = dbs[my_number].wakeup_time - now;
- }
- else
- /* The cache was just pruned. Do not do it again now. Just
- use the new timeout value. */
- next_wait = dbs[my_number].wakeup_time - now;
-
- if (clock_gettime (timeout_clock, &prune_ts) == -1)
- /* Should never happen. */
- abort ();
-
- /* Compute next timeout time. */
- prune_ts.tv_sec += next_wait;
- }
-}
-
-
-/* This is the main loop. It is replicated in different threads but
- the use of the ready list makes sure only one thread handles an
- incoming connection. */
-static void *
-__attribute__ ((__noreturn__))
-nscd_run_worker (void *p)
-{
- char buf[256];
-
- /* Initial locking. */
- pthread_mutex_lock (&readylist_lock);
-
- /* One more thread available. */
- ++nready;
-
- while (1)
- {
- while (readylist == NULL)
- pthread_cond_wait (&readylist_cond, &readylist_lock);
-
- struct fdlist *it = readylist->next;
- if (readylist->next == readylist)
- /* Just one entry on the list. */
- readylist = NULL;
- else
- readylist->next = it->next;
-
- /* Extract the information and mark the record ready to be used
- again. */
- int fd = it->fd;
- it->next = NULL;
-
- /* One more thread available. */
- --nready;
-
- /* We are done with the list. */
- pthread_mutex_unlock (&readylist_lock);
-
- /* Now read the request. */
- request_header req;
- if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, &req, sizeof (req)))
- != sizeof (req), 0))
- {
- /* We failed to read data. Note that this also might mean we
- failed because we would have blocked. */
- if (debug_level > 0)
- dbg_log (_("short read while reading request: %s"),
- strerror_r (errno, buf, sizeof (buf)));
- goto close_and_out;
- }
-
- /* Check whether this is a valid request type. */
- if (req.type < GETPWBYNAME || req.type >= LASTREQ)
- goto close_and_out;
-
- /* Some systems have no SO_PEERCRED implementation. They don't
- care about security so we don't as well. */
- uid_t uid = -1;
-#ifdef SO_PEERCRED
- pid_t pid = 0;
-
- if (__glibc_unlikely (debug_level > 0))
- {
- struct ucred caller;
- socklen_t optlen = sizeof (caller);
-
- if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) == 0)
- pid = caller.pid;
- }
-#else
- const pid_t pid = 0;
-#endif
-
- /* It should not be possible to crash the nscd with a silly
- request (i.e., a terribly large key). We limit the size to 1kb. */
- if (__builtin_expect (req.key_len, 1) < 0
- || __builtin_expect (req.key_len, 1) > MAXKEYLEN)
- {
- if (debug_level > 0)
- dbg_log (_("key length in request too long: %d"), req.key_len);
- }
- else
- {
- /* Get the key. */
- char keybuf[MAXKEYLEN + 1];
-
- if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, keybuf,
- req.key_len))
- != req.key_len, 0))
- {
- /* Again, this can also mean we would have blocked. */
- if (debug_level > 0)
- dbg_log (_("short read while reading request key: %s"),
- strerror_r (errno, buf, sizeof (buf)));
- goto close_and_out;
- }
- keybuf[req.key_len] = '\0';
-
- if (__builtin_expect (debug_level, 0) > 0)
- {
-#ifdef SO_PEERCRED
- if (pid != 0)
- dbg_log (_("\
-handle_request: request received (Version = %d) from PID %ld"),
- req.version, (long int) pid);
- else
-#endif
- dbg_log (_("\
-handle_request: request received (Version = %d)"), req.version);
- }
-
- /* Phew, we got all the data, now process it. */
- handle_request (fd, &req, keybuf, uid, pid);
- }
-
- close_and_out:
- /* We are done. */
- close (fd);
-
- /* Re-locking. */
- pthread_mutex_lock (&readylist_lock);
-
- /* One more thread available. */
- ++nready;
- }
- /* NOTREACHED */
-}
-
-
-static unsigned int nconns;
-
-static void
-fd_ready (int fd)
-{
- pthread_mutex_lock (&readylist_lock);
-
- /* Find an empty entry in FDLIST. */
- size_t inner;
- for (inner = 0; inner < nconns; ++inner)
- if (fdlist[inner].next == NULL)
- break;
- assert (inner < nconns);
-
- fdlist[inner].fd = fd;
-
- if (readylist == NULL)
- readylist = fdlist[inner].next = &fdlist[inner];
- else
- {
- fdlist[inner].next = readylist->next;
- readylist = readylist->next = &fdlist[inner];
- }
-
- bool do_signal = true;
- if (__glibc_unlikely (nready == 0))
- {
- ++client_queued;
- do_signal = false;
-
- /* Try to start another thread to help out. */
- pthread_t th;
- if (nthreads < max_nthreads
- && pthread_create (&th, &attr, nscd_run_worker,
- (void *) (long int) nthreads) == 0)
- {
- /* We got another thread. */
- ++nthreads;
- /* The new thread might need a kick. */
- do_signal = true;
- }
-
- }
-
- pthread_mutex_unlock (&readylist_lock);
-
- /* Tell one of the worker threads there is work to do. */
- if (do_signal)
- pthread_cond_signal (&readylist_cond);
-}
-
-
-/* Check whether restarting should happen. */
-static bool
-restart_p (time_t now)
-{
- return (paranoia && readylist == NULL && nready == nthreads
- && now >= restart_time);
-}
-
-
-/* Array for times a connection was accepted. */
-static time_t *starttime;
-
-#ifdef HAVE_INOTIFY
-/* Inotify event for changed file. */
-union __inev
-{
- struct inotify_event i;
-# ifndef PATH_MAX
-# define PATH_MAX 1024
-# endif
- 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 void
-inotify_check_files (bool *to_clear, union __inev *inev)
-{
- /* Check which of the files changed. */
- for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
- {
- struct traced_file *finfo = dbs[dbcnt].traced_files;
-
- while (finfo != NULL)
- {
- /* 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;
- }
- }
-}
-
-/* If an entry in the array of booleans TO_CLEAR is TRUE then clear the cache
- for the associated database, otherwise do nothing. The TO_CLEAR array must
- have LASTDB entries. */
-static inline void
-clear_db_cache (bool *to_clear)
-{
- for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
- if (to_clear[dbcnt])
- {
- pthread_mutex_lock (&dbs[dbcnt].prune_lock);
- dbs[dbcnt].clear_cache = 1;
- pthread_mutex_unlock (&dbs[dbcnt].prune_lock);
- pthread_cond_signal (&dbs[dbcnt].prune_cond);
- }
-}
-
-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
-__attribute__ ((__noreturn__))
-main_loop_poll (void)
-{
- struct pollfd *conns = (struct pollfd *) xmalloc (nconns
- * sizeof (conns[0]));
-
- conns[0].fd = sock;
- conns[0].events = POLLRDNORM;
- size_t nused = 1;
- size_t firstfree = 1;
-
-#ifdef HAVE_INOTIFY
- if (inotify_fd != -1)
- {
- conns[1].fd = inotify_fd;
- conns[1].events = POLLRDNORM;
- nused = 2;
- firstfree = 2;
- }
-#endif
-
-#ifdef HAVE_NETLINK
- size_t idx_nl_status_fd = 0;
- if (nl_status_fd != -1)
- {
- idx_nl_status_fd = nused;
- conns[nused].fd = nl_status_fd;
- conns[nused].events = POLLRDNORM;
- ++nused;
- firstfree = nused;
- }
-#endif
-
- while (1)
- {
- /* Wait for any event. We wait at most a couple of seconds so
- that we can check whether we should close any of the accepted
- connections since we have not received a request. */
-#define MAX_ACCEPT_TIMEOUT 30
-#define MIN_ACCEPT_TIMEOUT 5
-#define MAIN_THREAD_TIMEOUT \
- (MAX_ACCEPT_TIMEOUT * 1000 \
- - ((MAX_ACCEPT_TIMEOUT - MIN_ACCEPT_TIMEOUT) * 1000 * nused) / (2 * nconns))
-
- int n = poll (conns, nused, MAIN_THREAD_TIMEOUT);
-
- time_t now = time (NULL);
-
- /* If there is a descriptor ready for reading or there is a new
- connection, process this now. */
- if (n > 0)
- {
- if (conns[0].revents != 0)
- {
- /* We have a new incoming connection. Accept the connection. */
- int fd = TEMP_FAILURE_RETRY (accept4 (sock, NULL, NULL,
- SOCK_NONBLOCK));
-
- /* Use the descriptor if we have not reached the limit. */
- if (fd >= 0)
- {
- if (firstfree < nconns)
- {
- conns[firstfree].fd = fd;
- conns[firstfree].events = POLLRDNORM;
- starttime[firstfree] = now;
- if (firstfree >= nused)
- nused = firstfree + 1;
-
- do
- ++firstfree;
- while (firstfree < nused && conns[firstfree].fd != -1);
- }
- else
- /* We cannot use the connection so close it. */
- close (fd);
- }
-
- --n;
- }
-
- size_t first = 1;
-#ifdef HAVE_INOTIFY
- if (inotify_fd != -1 && conns[1].fd == inotify_fd)
- {
- if (conns[1].revents != 0)
- {
- int ret;
- ret = handle_inotify_events ();
- if (ret == -1)
- {
- /* 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;
- }
- --n;
- }
-
- first = 2;
- }
-#endif
-
-#ifdef HAVE_NETLINK
- if (idx_nl_status_fd != 0 && conns[idx_nl_status_fd].revents != 0)
- {
- char buf[4096];
- /* Read all the data. We do not interpret it here. */
- while (TEMP_FAILURE_RETRY (read (nl_status_fd, buf,
- sizeof (buf))) != -1)
- ;
-
- dbs[hstdb].head->extra_data[NSCD_HST_IDX_CONF_TIMESTAMP]
- = __bump_nl_timestamp ();
- }
-#endif
-
- for (size_t cnt = first; cnt < nused && n > 0; ++cnt)
- if (conns[cnt].revents != 0)
- {
- fd_ready (conns[cnt].fd);
-
- /* Clean up the CONNS array. */
- conns[cnt].fd = -1;
- if (cnt < firstfree)
- firstfree = cnt;
- if (cnt == nused - 1)
- do
- --nused;
- while (conns[nused - 1].fd == -1);
-
- --n;
- }
- }
-
- /* Now find entries which have timed out. */
- assert (nused > 0);
-
- /* We make the timeout length depend on the number of file
- descriptors currently used. */
-#define ACCEPT_TIMEOUT \
- (MAX_ACCEPT_TIMEOUT \
- - ((MAX_ACCEPT_TIMEOUT - MIN_ACCEPT_TIMEOUT) * nused) / nconns)
- time_t laststart = now - ACCEPT_TIMEOUT;
-
- for (size_t cnt = nused - 1; cnt > 0; --cnt)
- {
- if (conns[cnt].fd != -1 && starttime[cnt] < laststart)
- {
- /* Remove the entry, it timed out. */
- (void) close (conns[cnt].fd);
- conns[cnt].fd = -1;
-
- if (cnt < firstfree)
- firstfree = cnt;
- if (cnt == nused - 1)
- do
- --nused;
- while (conns[nused - 1].fd == -1);
- }
- }
-
- if (restart_p (now))
- restart ();
- }
-}
-
-
-#ifdef HAVE_EPOLL
-static void
-main_loop_epoll (int efd)
-{
- struct epoll_event ev = { 0, };
- int nused = 1;
- size_t highest = 0;
-
- /* Add the socket. */
- ev.events = EPOLLRDNORM;
- ev.data.fd = sock;
- if (epoll_ctl (efd, EPOLL_CTL_ADD, sock, &ev) == -1)
- /* We cannot use epoll. */
- return;
-
-# ifdef HAVE_INOTIFY
- if (inotify_fd != -1)
- {
- ev.events = EPOLLRDNORM;
- ev.data.fd = inotify_fd;
- if (epoll_ctl (efd, EPOLL_CTL_ADD, inotify_fd, &ev) == -1)
- /* We cannot use epoll. */
- return;
- nused = 2;
- }
-# endif
-
-# ifdef HAVE_NETLINK
- if (nl_status_fd != -1)
- {
- ev.events = EPOLLRDNORM;
- ev.data.fd = nl_status_fd;
- if (epoll_ctl (efd, EPOLL_CTL_ADD, nl_status_fd, &ev) == -1)
- /* We cannot use epoll. */
- return;
- }
-# endif
-
- while (1)
- {
- struct epoll_event revs[100];
-# define nrevs (sizeof (revs) / sizeof (revs[0]))
-
- int n = epoll_wait (efd, revs, nrevs, MAIN_THREAD_TIMEOUT);
-
- time_t now = time (NULL);
-
- for (int cnt = 0; cnt < n; ++cnt)
- if (revs[cnt].data.fd == sock)
- {
- /* A new connection. */
- int fd = TEMP_FAILURE_RETRY (accept4 (sock, NULL, NULL,
- SOCK_NONBLOCK));
-
- /* Use the descriptor if we have not reached the limit. */
- if (fd >= 0)
- {
- /* Try to add the new descriptor. */
- ev.data.fd = fd;
- if (fd >= nconns
- || epoll_ctl (efd, EPOLL_CTL_ADD, fd, &ev) == -1)
- /* The descriptor is too large or something went
- wrong. Close the descriptor. */
- close (fd);
- else
- {
- /* Remember when we accepted the connection. */
- starttime[fd] = now;
-
- if (fd > highest)
- highest = fd;
-
- ++nused;
- }
- }
- }
-# ifdef HAVE_INOTIFY
- else if (revs[cnt].data.fd == inotify_fd)
- {
- int ret;
- ret = handle_inotify_events ();
- if (ret == -1)
- {
- /* 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;
- }
- }
-# endif
-# ifdef HAVE_NETLINK
- else if (revs[cnt].data.fd == nl_status_fd)
- {
- char buf[4096];
- /* Read all the data. We do not interpret it here. */
- while (TEMP_FAILURE_RETRY (read (nl_status_fd, buf,
- sizeof (buf))) != -1)
- ;
-
- __bump_nl_timestamp ();
- }
-# endif
- else
- {
- /* Remove the descriptor from the epoll descriptor. */
- (void) epoll_ctl (efd, EPOLL_CTL_DEL, revs[cnt].data.fd, NULL);
-
- /* Get a worker to handle the request. */
- fd_ready (revs[cnt].data.fd);
-
- /* Reset the time. */
- starttime[revs[cnt].data.fd] = 0;
- if (revs[cnt].data.fd == highest)
- do
- --highest;
- while (highest > 0 && starttime[highest] == 0);
-
- --nused;
- }
-
- /* Now look for descriptors for accepted connections which have
- 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)
- {
- /* We are waiting for this one for too long. Close it. */
- (void) epoll_ctl (efd, EPOLL_CTL_DEL, cnt, NULL);
-
- (void) close (cnt);
-
- starttime[cnt] = 0;
- if (cnt == highest)
- --highest;
- }
- else if (cnt != sock && starttime[cnt] == 0 && cnt == highest)
- --highest;
-
- if (restart_p (now))
- restart ();
- }
-}
-#endif
-
-
-/* Start all the threads we want. The initial process is thread no. 1. */
-void
-start_threads (void)
-{
- /* Initialize the conditional variable we will use. The only
- non-standard attribute we might use is the clock selection. */
- pthread_condattr_t condattr;
- pthread_condattr_init (&condattr);
-
-#if defined _POSIX_CLOCK_SELECTION && _POSIX_CLOCK_SELECTION >= 0 \
- && defined _POSIX_MONOTONIC_CLOCK && _POSIX_MONOTONIC_CLOCK >= 0
- /* Determine whether the monotonous clock is available. */
- struct timespec dummy;
-# if _POSIX_MONOTONIC_CLOCK == 0
- if (sysconf (_SC_MONOTONIC_CLOCK) > 0)
-# endif
-# if _POSIX_CLOCK_SELECTION == 0
- if (sysconf (_SC_CLOCK_SELECTION) > 0)
-# endif
- if (clock_getres (CLOCK_MONOTONIC, &dummy) == 0
- && pthread_condattr_setclock (&condattr, CLOCK_MONOTONIC) == 0)
- timeout_clock = CLOCK_MONOTONIC;
-#endif
-
- /* Create the attribute for the threads. They are all created
- detached. */
- pthread_attr_init (&attr);
- pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
- /* Use 1MB stacks, twice as much for 64-bit architectures. */
- pthread_attr_setstacksize (&attr, NSCD_THREAD_STACKSIZE);
-
- /* We allow less than LASTDB threads only for debugging. */
- if (debug_level == 0)
- nthreads = MAX (nthreads, lastdb);
-
- /* Create the threads which prune the databases. */
- // XXX Ideally this work would be done by some of the worker threads.
- // XXX But this is problematic since we would need to be able to wake
- // XXX them up explicitly as well as part of the group handling the
- // XXX ready-list. This requires an operation where we can wait on
- // XXX two conditional variables at the same time. This operation
- // XXX does not exist (yet).
- for (long int i = 0; i < lastdb; ++i)
- {
- /* Initialize the conditional variable. */
- if (pthread_cond_init (&dbs[i].prune_cond, &condattr) != 0)
- {
- dbg_log (_("could not initialize conditional variable"));
- do_exit (1, 0, NULL);
- }
-
- pthread_t th;
- if (dbs[i].enabled
- && pthread_create (&th, &attr, nscd_run_prune, (void *) i) != 0)
- {
- dbg_log (_("could not start clean-up thread; terminating"));
- do_exit (1, 0, NULL);
- }
- }
-
- pthread_condattr_destroy (&condattr);
-
- for (long int i = 0; i < nthreads; ++i)
- {
- pthread_t th;
- if (pthread_create (&th, &attr, nscd_run_worker, NULL) != 0)
- {
- if (i == 0)
- {
- dbg_log (_("could not start any worker thread; terminating"));
- 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. */
- const long int nfds = sysconf (_SC_OPEN_MAX);
-#define MINCONN 32
-#define MAXCONN 16384
- if (nfds == -1 || nfds > MAXCONN)
- nconns = MAXCONN;
- else if (nfds < MINCONN)
- nconns = MINCONN;
- else
- nconns = nfds;
-
- /* We need memory to pass descriptors on to the worker threads. */
- fdlist = (struct fdlist *) xcalloc (nconns, sizeof (fdlist[0]));
- /* Array to keep track when connection was accepted. */
- starttime = (time_t *) xcalloc (nconns, sizeof (starttime[0]));
-
- /* In the main thread we execute the loop which handles incoming
- connections. */
-#ifdef HAVE_EPOLL
- int efd = epoll_create (100);
- if (efd != -1)
- {
- main_loop_epoll (efd);
- close (efd);
- }
-#endif
-
- main_loop_poll ();
-}
-
-
-/* Look up the uid, gid, and supplementary groups to run nscd as. When
- this function is called, we are not listening on the nscd socket yet so
- we can just use the ordinary lookup functions without causing a lockup */
-static void
-begin_drop_privileges (void)
-{
- struct passwd *pwd = getpwnam (server_user);
-
- if (pwd == NULL)
- {
- dbg_log (_("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;
- server_gid = pwd->pw_gid;
-
- /* Save the old UID/GID if we have to change back. */
- if (paranoia)
- {
- old_uid = getuid ();
- old_gid = getgid ();
- }
-
- if (getgrouplist (server_user, server_gid, NULL, &server_ngroups) == 0)
- {
- /* This really must never happen. */
- dbg_log (_("Failed to run nscd as user '%s'"), server_user);
- do_exit (EXIT_FAILURE, errno,
- _("initial getgrouplist failed"));
- }
-
- server_groups = (gid_t *) xmalloc (server_ngroups * sizeof (gid_t));
-
- if (getgrouplist (server_user, server_gid, server_groups, &server_ngroups)
- == -1)
- {
- dbg_log (_("Failed to run nscd as user '%s'"), server_user);
- do_exit (EXIT_FAILURE, errno, _("getgrouplist failed"));
- }
-}
-
-
-/* Call setgroups(), setgid(), and setuid() to drop root privileges and
- run nscd as the user specified in the configuration file. */
-static void
-finish_drop_privileges (void)
-{
-#if defined HAVE_LIBAUDIT && defined HAVE_LIBCAP
- /* We need to preserve the capabilities to connect to the audit daemon. */
- cap_t new_caps = preserve_capabilities ();
-#endif
-
- if (setgroups (server_ngroups, server_groups) == -1)
- {
- dbg_log (_("Failed to run nscd as user '%s'"), server_user);
- do_exit (EXIT_FAILURE, errno, _("setgroups failed"));
- }
-
- int res;
- if (paranoia)
- res = setresgid (server_gid, server_gid, old_gid);
- else
- res = setgid (server_gid);
- if (res == -1)
- {
- dbg_log (_("Failed to run nscd as user '%s'"), server_user);
- do_exit (4, errno, "setgid");
- }
-
- if (paranoia)
- res = setresuid (server_uid, server_uid, old_uid);
- else
- res = setuid (server_uid);
- if (res == -1)
- {
- dbg_log (_("Failed to run nscd as user '%s'"), server_user);
- do_exit (4, errno, "setuid");
- }
-
-#if defined HAVE_LIBAUDIT && defined HAVE_LIBCAP
- /* Remove the temporary capabilities. */
- install_real_capabilities (new_caps);
-#endif
-}
diff --git a/nscd/dbg_log.c b/nscd/dbg_log.c
deleted file mode 100644
index d4b19acc0c..0000000000
--- a/nscd/dbg_log.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/* Copyright (c) 1998-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-#include "dbg_log.h"
-#include "nscd.h"
-
-/* if in debug mode and we have a debug file, we write the messages to it,
- if in debug mode and no debug file, we write the messages to stderr,
- else to syslog. */
-
-static char *logfilename;
-FILE *dbgout;
-int debug_level;
-
-void
-set_logfile (const char *logfile)
-{
- logfilename = strdup (logfile);
-}
-
-int
-init_logfile (void)
-{
- if (logfilename)
- {
- dbgout = fopen64 (logfilename, "a");
- return dbgout == NULL ? 0 : 1;
- }
- return 1;
-}
-
-void
-dbg_log (const char *fmt,...)
-{
- va_list ap;
- char msg2[512];
-
- va_start (ap, fmt);
- vsnprintf (msg2, sizeof (msg2), fmt, ap);
-
- if (debug_level > 0)
- {
- time_t t = time (NULL);
-
- struct tm now;
- localtime_r (&t, &now);
-
- char buf[256];
- strftime (buf, sizeof (buf), "%c", &now);
-
- char msg[512];
- snprintf (msg, sizeof (msg), "%s - %d: %s%s", buf, getpid (), msg2,
- msg2[strlen (msg2) - 1] == '\n' ? "" : "\n");
- if (dbgout)
- {
- fputs (msg, dbgout);
- fflush (dbgout);
- }
- else
- fputs (msg, stderr);
- }
- else
- syslog (LOG_NOTICE, "%d %s", getpid (), msg2);
-
- va_end (ap);
-}
diff --git a/nscd/dbg_log.h b/nscd/dbg_log.h
deleted file mode 100644
index 158bfb39aa..0000000000
--- a/nscd/dbg_log.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (c) 1998-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-#ifndef _DBG_LOG_H
-#define _DBG_LOG_H 1
-
-extern int debug_level;
-
-extern void dbg_log (const char *str, ...)
- __attribute__ ((__format__ (__printf__, 1, 2)));;
-
-extern void set_logfile (const char *logfile);
-extern int init_logfile (void);
-
-#endif
diff --git a/nscd/gai.c b/nscd/gai.c
deleted file mode 100644
index a1aeadadc3..0000000000
--- a/nscd/gai.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/* Copyright (C) 2004-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@cygnus.com>, 2004.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#include <alloca.h>
-
-/* This file uses the getaddrinfo code but it compiles it without NSCD
- support. We just need a few symbol renames. */
-#define __inet_aton inet_aton
-#define __ioctl ioctl
-#define __getsockname getsockname
-#define __socket socket
-#define __recvmsg recvmsg
-#define __bind bind
-#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)
-
-/* We are nscd, so we don't want to be talking to ourselves. */
-#undef USE_NSCD
-
-#include <getaddrinfo.c>
-
-/* Support code. */
-#include <check_pf.c>
-#include <check_native.c>
-#ifdef HAVE_LIBIDN
-# include <libidn/idn-stub.c>
-#endif
-
-/* Some variables normally defined in libc. */
-service_user *__nss_hosts_database;
diff --git a/nscd/getgrgid_r.c b/nscd/getgrgid_r.c
deleted file mode 100644
index 0e7fd21be7..0000000000
--- a/nscd/getgrgid_r.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright (C) 1996-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#include <grp.h>
-
-#include <grp-merge.h>
-
-#define LOOKUP_TYPE struct group
-#define FUNCTION_NAME getgrgid
-#define DATABASE_NAME group
-#define ADD_PARAMS gid_t gid
-#define ADD_VARIABLES gid
-#define BUFLEN NSS_BUFLEN_GROUP
-
-#define DEEPCOPY_FN __copy_grp
-#define MERGE_FN __merge_grp
-
-/* We are nscd, so we don't want to be talking to ourselves. */
-#undef USE_NSCD
-
-#include <nss/getXXbyYY_r.c>
diff --git a/nscd/getgrnam_r.c b/nscd/getgrnam_r.c
deleted file mode 100644
index 80cb441888..0000000000
--- a/nscd/getgrnam_r.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Copyright (C) 1996-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#include <grp.h>
-
-#include <grp-merge.h>
-
-#define LOOKUP_TYPE struct group
-#define FUNCTION_NAME getgrnam
-#define DATABASE_NAME group
-#define ADD_PARAMS const char *name
-#define ADD_VARIABLES name
-
-#define DEEPCOPY_FN __copy_grp
-#define MERGE_FN __merge_grp
-
-/* We are nscd, so we don't want to be talking to ourselves. */
-#undef USE_NSCD
-
-#include <nss/getXXbyYY_r.c>
diff --git a/nscd/gethstbyad_r.c b/nscd/gethstbyad_r.c
deleted file mode 100644
index b17f0d2b51..0000000000
--- a/nscd/gethstbyad_r.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/* Copyright (C) 1996-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#include <netdb.h>
-
-
-#define LOOKUP_TYPE struct hostent
-#define FUNCTION_NAME gethostbyaddr2
-#define FUNCTION2_NAME gethostbyaddr
-#define DATABASE_NAME hosts
-#define ADD_PARAMS const void *addr, socklen_t len, int type
-#define EXTRA_PARAMS , int32_t *ttlp
-#define ADD_VARIABLES addr, len, type
-#define EXTRA_VARIABLES , ttlp
-#define NEED_H_ERRNO 1
-#define NEED__RES 1
-#define NEED__RES_HCONF 1
-
-/* We are nscd, so we don't want to be talking to ourselves. */
-#undef USE_NSCD
-
-#include "../nss/getXXbyYY_r.c"
-
-
-int
-__gethostbyaddr_r (const void *addr, socklen_t len, int type,
- struct hostent *result_buf, char *buf, size_t buflen,
- struct hostent **result, int *h_errnop)
-{
- return __gethostbyaddr2_r (addr, len, type, result_buf, buf, buflen,
- result, h_errnop, NULL);
-}
diff --git a/nscd/gethstbynm3_r.c b/nscd/gethstbynm3_r.c
deleted file mode 100644
index 41bb26845d..0000000000
--- a/nscd/gethstbynm3_r.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/* Copyright (C) 1996-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#include <ctype.h>
-#include <errno.h>
-#include <netdb.h>
-#include <string.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-
-
-#define LOOKUP_TYPE struct hostent
-#define FUNCTION_NAME gethostbyname3
-#define FUNCTION2_NAME gethostbyname2
-#define DATABASE_NAME hosts
-#define ADD_PARAMS const char *name, int af
-#define EXTRA_PARAMS , int32_t *ttlp, char **canonp
-#define ADD_VARIABLES name, af
-#define EXTRA_VARIABLES , ttlp, canonp
-#define NEED_H_ERRNO 1
-#define NEED__RES_HCONF 1
-
-#define HANDLE_DIGITS_DOTS 1
-#define HAVE_LOOKUP_BUFFER 1
-#define HAVE_AF 1
-
-#define __inet_aton inet_aton
-
-/* We are nscd, so we don't want to be talking to ourselves. */
-#undef USE_NSCD
-
-#include "../nss/getXXbyYY_r.c"
-
-
-int
-__gethostbyname2_r (const char *name, int af, struct hostent *ret, char *buf,
- size_t buflen, struct hostent **result, int *h_errnop)
-{
- return __gethostbyname3_r (name, af, ret, buf, buflen, result, h_errnop,
- NULL, NULL);
-}
diff --git a/nscd/getpwnam_r.c b/nscd/getpwnam_r.c
deleted file mode 100644
index 9af95b6c01..0000000000
--- a/nscd/getpwnam_r.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/* Copyright (C) 1996-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#include <pwd.h>
-
-
-#define LOOKUP_TYPE struct passwd
-#define FUNCTION_NAME getpwnam
-#define DATABASE_NAME passwd
-#define ADD_PARAMS const char *name
-#define ADD_VARIABLES name
-#define BUFLEN NSS_BUFLEN_PASSWD
-
-/* We are nscd, so we don't want to be talking to ourselves. */
-#undef USE_NSCD
-
-#include <nss/getXXbyYY_r.c>
diff --git a/nscd/getpwuid_r.c b/nscd/getpwuid_r.c
deleted file mode 100644
index fae2a141be..0000000000
--- a/nscd/getpwuid_r.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/* Copyright (C) 1996-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#include <pwd.h>
-
-
-#define LOOKUP_TYPE struct passwd
-#define FUNCTION_NAME getpwuid
-#define DATABASE_NAME passwd
-#define ADD_PARAMS uid_t uid
-#define ADD_VARIABLES uid
-#define BUFLEN NSS_BUFLEN_PASSWD
-
-/* We are nscd, so we don't want to be talking to ourselves. */
-#undef USE_NSCD
-
-#include <nss/getXXbyYY_r.c>
diff --git a/nscd/getsrvbynm_r.c b/nscd/getsrvbynm_r.c
deleted file mode 100644
index ef6eac0358..0000000000
--- a/nscd/getsrvbynm_r.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 1996-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#include <netdb.h>
-
-
-#define LOOKUP_TYPE struct servent
-#define FUNCTION_NAME getservbyname
-#define DATABASE_NAME services
-#define ADD_PARAMS const char *name, const char *proto
-#define ADD_VARIABLES name, proto
-
-/* We are nscd, so we don't want to be talking to ourselves. */
-#undef USE_NSCD
-
-#include "../nss/getXXbyYY_r.c"
diff --git a/nscd/getsrvbypt_r.c b/nscd/getsrvbypt_r.c
deleted file mode 100644
index 10a3d57ab4..0000000000
--- a/nscd/getsrvbypt_r.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 1996-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#include <netdb.h>
-
-
-#define LOOKUP_TYPE struct servent
-#define FUNCTION_NAME getservbyport
-#define DATABASE_NAME services
-#define ADD_PARAMS int port, const char *proto
-#define ADD_VARIABLES port, proto
-
-/* We are nscd, so we don't want to be talking to ourselves. */
-#undef USE_NSCD
-
-#include "../nss/getXXbyYY_r.c"
diff --git a/nscd/grpcache.c b/nscd/grpcache.c
deleted file mode 100644
index d2ad53509d..0000000000
--- a/nscd/grpcache.c
+++ /dev/null
@@ -1,572 +0,0 @@
-/* Cache handling for group lookup.
- Copyright (C) 1998-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#include <alloca.h>
-#include <assert.h>
-#include <errno.h>
-#include <error.h>
-#include <grp.h>
-#include <libintl.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/socket.h>
-#include <stackinfo.h>
-
-#include "nscd.h"
-#include "dbg_log.h"
-#ifdef HAVE_SENDFILE
-# include <kernel-features.h>
-#endif
-
-/* This is the standard reply in case the service is disabled. */
-static const gr_response_header disabled =
-{
- .version = NSCD_VERSION,
- .found = -1,
- .gr_name_len = 0,
- .gr_passwd_len = 0,
- .gr_gid = -1,
- .gr_mem_cnt = 0,
-};
-
-/* This is the struct describing how to write this record. */
-const struct iovec grp_iov_disabled =
-{
- .iov_base = (void *) &disabled,
- .iov_len = sizeof (disabled)
-};
-
-
-/* This is the standard reply in case we haven't found the dataset. */
-static const gr_response_header notfound =
-{
- .version = NSCD_VERSION,
- .found = 0,
- .gr_name_len = 0,
- .gr_passwd_len = 0,
- .gr_gid = -1,
- .gr_mem_cnt = 0,
-};
-
-
-static time_t
-cache_addgr (struct database_dyn *db, int fd, request_header *req,
- const void *key, struct group *grp, uid_t owner,
- struct hashentry *const he, struct datahead *dh, int errval)
-{
- bool all_written = true;
- ssize_t total;
- time_t t = time (NULL);
-
- /* We allocate all data in one memory block: the iov vector,
- the response header and the dataset itself. */
- struct dataset
- {
- struct datahead head;
- gr_response_header resp;
- char strdata[0];
- } *dataset;
-
- assert (offsetof (struct dataset, resp) == offsetof (struct datahead, data));
-
- time_t timeout = MAX_TIMEOUT_VALUE;
- if (grp == NULL)
- {
- if (he != NULL && errval == EAGAIN)
- {
- /* If we have an old record available but cannot find one
- now because the service is not available we keep the old
- record and make sure it does not get removed. */
- if (reload_count != UINT_MAX)
- /* Do not reset the value if we never not reload the record. */
- dh->nreloads = reload_count - 1;
-
- /* Reload with the same time-to-live value. */
- timeout = dh->timeout = t + db->postimeout;
-
- total = 0;
- }
- else
- {
- /* We have no data. This means we send the standard reply for this
- case. */
- total = sizeof (notfound);
-
- if (fd != -1
- && TEMP_FAILURE_RETRY (send (fd, &notfound, total,
- MSG_NOSIGNAL)) != total)
- all_written = false;
-
- /* If we have a transient error or cannot permanently store
- the result, so be it. */
- if (errno == EAGAIN || __builtin_expect (db->negtimeout == 0, 0))
- {
- /* Mark the old entry as obsolete. */
- if (dh != NULL)
- dh->usable = false;
- }
- else if ((dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1)) != NULL)
- {
- timeout = datahead_init_neg (&dataset->head,
- (sizeof (struct dataset)
- + req->key_len), total,
- db->negtimeout);
-
- /* This is the reply. */
- memcpy (&dataset->resp, &notfound, total);
-
- /* Copy the key data. */
- memcpy (dataset->strdata, key, req->key_len);
-
- /* If necessary, we also propagate the data to disk. */
- if (db->persistent)
- {
- // XXX async OK?
- uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
- msync ((void *) pval,
- ((uintptr_t) dataset & pagesize_m1)
- + sizeof (struct dataset) + req->key_len, MS_ASYNC);
- }
-
- (void) cache_add (req->type, &dataset->strdata, req->key_len,
- &dataset->head, true, db, owner, he == NULL);
-
- pthread_rwlock_unlock (&db->lock);
-
- /* Mark the old entry as obsolete. */
- if (dh != NULL)
- dh->usable = false;
- }
- }
- }
- else
- {
- /* Determine the I/O structure. */
- size_t gr_name_len = strlen (grp->gr_name) + 1;
- size_t gr_passwd_len = strlen (grp->gr_passwd) + 1;
- size_t gr_mem_cnt = 0;
- uint32_t *gr_mem_len;
- size_t gr_mem_len_total = 0;
- char *gr_name;
- char *cp;
- const size_t key_len = strlen (key);
- const size_t buf_len = 3 * sizeof (grp->gr_gid) + key_len + 1;
- size_t alloca_used = 0;
- char *buf = alloca_account (buf_len, alloca_used);
- ssize_t n;
- size_t cnt;
-
- /* We need this to insert the `bygid' entry. */
- int key_offset;
- n = snprintf (buf, buf_len, "%d%c%n%s", grp->gr_gid, '\0',
- &key_offset, (char *) key) + 1;
-
- /* Determine the length of all members. */
- while (grp->gr_mem[gr_mem_cnt])
- ++gr_mem_cnt;
- gr_mem_len = alloca_account (gr_mem_cnt * sizeof (uint32_t), alloca_used);
- for (gr_mem_cnt = 0; grp->gr_mem[gr_mem_cnt]; ++gr_mem_cnt)
- {
- gr_mem_len[gr_mem_cnt] = strlen (grp->gr_mem[gr_mem_cnt]) + 1;
- gr_mem_len_total += gr_mem_len[gr_mem_cnt];
- }
-
- total = (offsetof (struct dataset, strdata)
- + gr_mem_cnt * sizeof (uint32_t)
- + gr_name_len + gr_passwd_len + gr_mem_len_total);
-
- /* If we refill the cache, first assume the reconrd did not
- change. Allocate memory on the cache since it is likely
- discarded anyway. If it turns out to be necessary to have a
- new record we can still allocate real memory. */
- bool dataset_temporary = false;
- bool dataset_malloced = false;
- dataset = NULL;
-
- if (he == NULL)
- {
- /* Prevent an INVALIDATE request from pruning the data between
- the two calls to cache_add. */
- if (db->propagate)
- pthread_mutex_lock (&db->prune_run_lock);
- dataset = (struct dataset *) mempool_alloc (db, total + n, 1);
- }
-
- if (dataset == NULL)
- {
- if (he == NULL && db->propagate)
- pthread_mutex_unlock (&db->prune_run_lock);
-
- /* We cannot permanently add the result in the moment. But
- we can provide the result as is. Store the data in some
- temporary memory. */
- if (! __libc_use_alloca (alloca_used + total + n))
- {
- dataset = malloc (total + n);
- /* Perhaps we should log a message that we were unable
- to allocate memory for a large request. */
- if (dataset == NULL)
- goto out;
- dataset_malloced = true;
- }
- else
- dataset = alloca_account (total + n, alloca_used);
-
- /* We cannot add this record to the permanent database. */
- dataset_temporary = true;
- }
-
- 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;
- dataset->resp.gr_name_len = gr_name_len;
- dataset->resp.gr_passwd_len = gr_passwd_len;
- dataset->resp.gr_gid = grp->gr_gid;
- dataset->resp.gr_mem_cnt = gr_mem_cnt;
-
- cp = dataset->strdata;
-
- /* This is the member string length array. */
- cp = mempcpy (cp, gr_mem_len, gr_mem_cnt * sizeof (uint32_t));
- gr_name = cp;
- cp = mempcpy (cp, grp->gr_name, gr_name_len);
- cp = mempcpy (cp, grp->gr_passwd, gr_passwd_len);
-
- for (cnt = 0; cnt < gr_mem_cnt; ++cnt)
- cp = mempcpy (cp, grp->gr_mem[cnt], gr_mem_len[cnt]);
-
- /* Finally the stringified GID value. */
- memcpy (cp, buf, n);
- char *key_copy = cp + key_offset;
- assert (key_copy == (char *) rawmemchr (cp, '\0') + 1);
-
- assert (cp == dataset->strdata + total - offsetof (struct dataset,
- strdata));
-
- /* Now we can determine whether on refill we have to create a new
- record or not. */
- if (he != NULL)
- {
- assert (fd == -1);
-
- if (total + n == dh->allocsize
- && total - offsetof (struct dataset, resp) == dh->recsize
- && memcmp (&dataset->resp, dh->data,
- dh->allocsize - offsetof (struct dataset, resp)) == 0)
- {
- /* The data has not changed. We will just bump the
- timeout value. Note that the new record has been
- allocated on the stack and need not be freed. */
- dh->timeout = dataset->head.timeout;
- ++dh->nreloads;
-
- /* If the new record was allocated via malloc, then we must free
- it here. */
- if (dataset_malloced)
- free (dataset);
- }
- else
- {
- /* We have to create a new record. Just allocate
- appropriate memory and copy it. */
- struct dataset *newp
- = (struct dataset *) mempool_alloc (db, total + n, 1);
- if (newp != NULL)
- {
- /* Adjust pointers into the memory block. */
- gr_name = (char *) newp + (gr_name - (char *) dataset);
- cp = (char *) newp + (cp - (char *) dataset);
- key_copy = (char *) newp + (key_copy - (char *) dataset);
-
- dataset = memcpy (newp, dataset, total + n);
- dataset_temporary = false;
- }
-
- /* Mark the old record as obsolete. */
- dh->usable = false;
- }
- }
- else
- {
- /* We write the dataset before inserting it to the database
- since while inserting this thread might block and so would
- unnecessarily let the receiver wait. */
- assert (fd != -1);
-
-#ifdef HAVE_SENDFILE
- if (__builtin_expect (db->mmap_used, 1) && ! dataset_temporary)
- {
- assert (db->wr_fd != -1);
- assert ((char *) &dataset->resp > (char *) db->data);
- assert ((char *) dataset - (char *) db->head
- + total
- <= (sizeof (struct database_pers_head)
- + db->head->module * sizeof (ref_t)
- + db->head->data_size));
- ssize_t written = sendfileall (fd, db->wr_fd,
- (char *) &dataset->resp
- - (char *) db->head,
- dataset->head.recsize);
- if (written != dataset->head.recsize)
- {
-# ifndef __ASSUME_SENDFILE
- if (written == -1 && errno == ENOSYS)
- goto use_write;
-# endif
- all_written = false;
- }
- }
- else
-# ifndef __ASSUME_SENDFILE
- use_write:
-# endif
-#endif
- if (writeall (fd, &dataset->resp, dataset->head.recsize)
- != dataset->head.recsize)
- all_written = false;
- }
-
- /* Add the record to the database. But only if it has not been
- stored on the stack. */
- if (! dataset_temporary)
- {
- /* If necessary, we also propagate the data to disk. */
- if (db->persistent)
- {
- // XXX async OK?
- uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
- msync ((void *) pval,
- ((uintptr_t) dataset & pagesize_m1) + total + n,
- MS_ASYNC);
- }
-
- /* NB: in the following code we always must add the entry
- marked with FIRST first. Otherwise we end up with
- dangling "pointers" in case a latter hash entry cannot be
- added. */
- bool first = true;
-
- /* If the request was by GID, add that entry first. */
- if (req->type == GETGRBYGID)
- {
- if (cache_add (GETGRBYGID, cp, key_offset, &dataset->head, true,
- db, owner, he == NULL) < 0)
- goto out;
-
- first = false;
- }
- /* If the key is different from the name add a separate entry. */
- else if (strcmp (key_copy, gr_name) != 0)
- {
- if (cache_add (GETGRBYNAME, key_copy, key_len + 1,
- &dataset->head, true, db, owner, he == NULL) < 0)
- goto out;
-
- first = false;
- }
-
- /* We have to add the value for both, byname and byuid. */
- if ((req->type == GETGRBYNAME || db->propagate)
- && __builtin_expect (cache_add (GETGRBYNAME, gr_name,
- gr_name_len,
- &dataset->head, first, db, owner,
- he == NULL)
- == 0, 1))
- {
- if (req->type == GETGRBYNAME && db->propagate)
- (void) cache_add (GETGRBYGID, cp, key_offset, &dataset->head,
- false, db, owner, false);
- }
-
- out:
- pthread_rwlock_unlock (&db->lock);
- if (he == NULL && db->propagate)
- pthread_mutex_unlock (&db->prune_run_lock);
- }
- }
-
- if (__builtin_expect (!all_written, 0) && debug_level > 0)
- {
- char buf[256];
- dbg_log (_("short write in %s: %s"), __FUNCTION__,
- strerror_r (errno, buf, sizeof (buf)));
- }
-
- return timeout;
-}
-
-
-union keytype
-{
- void *v;
- gid_t g;
-};
-
-
-static int
-lookup (int type, union keytype key, struct group *resultbufp, char *buffer,
- size_t buflen, struct group **grp)
-{
- if (type == GETGRBYNAME)
- return __getgrnam_r (key.v, resultbufp, buffer, buflen, grp);
- else
- return __getgrgid_r (key.g, resultbufp, buffer, buflen, grp);
-}
-
-
-static time_t
-addgrbyX (struct database_dyn *db, int fd, request_header *req,
- union keytype key, const char *keystr, uid_t uid,
- struct hashentry *he, struct datahead *dh)
-{
- /* Search for the entry matching the key. Please note that we don't
- look again in the table whether the dataset is now available. We
- simply insert it. It does not matter if it is in there twice. The
- pruning function only will look at the timestamp. */
- size_t buflen = 1024;
- char *buffer = (char *) alloca (buflen);
- struct group resultbuf;
- struct group *grp;
- bool use_malloc = false;
- int errval = 0;
-
- if (__glibc_unlikely (debug_level > 0))
- {
- if (he == NULL)
- dbg_log (_("Haven't found \"%s\" in group cache!"), keystr);
- else
- dbg_log (_("Reloading \"%s\" in group cache!"), keystr);
- }
-
- while (lookup (req->type, key, &resultbuf, buffer, buflen, &grp) != 0
- && (errval = errno) == ERANGE)
- {
- errno = 0;
-
- if (__glibc_unlikely (buflen > 32768))
- {
- char *old_buffer = buffer;
- buflen *= 2;
- buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
- if (buffer == NULL)
- {
- /* We ran out of memory. We cannot do anything but
- sending a negative response. In reality this should
- never happen. */
- grp = NULL;
- buffer = old_buffer;
-
- /* We set the error to indicate this is (possibly) a
- temporary error and that it does not mean the entry
- is not available at all. */
- errval = EAGAIN;
- break;
- }
- use_malloc = true;
- }
- else
- /* Allocate a new buffer on the stack. If possible combine it
- with the previously allocated buffer. */
- buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
- }
-
- time_t timeout = cache_addgr (db, fd, req, keystr, grp, uid, he, dh, errval);
-
- if (use_malloc)
- free (buffer);
-
- return timeout;
-}
-
-
-void
-addgrbyname (struct database_dyn *db, int fd, request_header *req,
- void *key, uid_t uid)
-{
- union keytype u = { .v = key };
-
- addgrbyX (db, fd, req, u, key, uid, NULL, NULL);
-}
-
-
-time_t
-readdgrbyname (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh)
-{
- request_header req =
- {
- .type = GETGRBYNAME,
- .key_len = he->len
- };
- union keytype u = { .v = db->data + he->key };
-
- return addgrbyX (db, -1, &req, u, db->data + he->key, he->owner, he, dh);
-}
-
-
-void
-addgrbygid (struct database_dyn *db, int fd, request_header *req,
- void *key, uid_t uid)
-{
- char *ep;
- gid_t gid = strtoul ((char *) key, &ep, 10);
-
- if (*(char *) key == '\0' || *ep != '\0') /* invalid numeric uid */
- {
- if (debug_level > 0)
- dbg_log (_("Invalid numeric gid \"%s\"!"), (char *) key);
-
- errno = EINVAL;
- return;
- }
-
- union keytype u = { .g = gid };
-
- addgrbyX (db, fd, req, u, key, uid, NULL, NULL);
-}
-
-
-time_t
-readdgrbygid (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh)
-{
- char *ep;
- gid_t gid = strtoul (db->data + he->key, &ep, 10);
-
- /* Since the key has been added before it must be OK. */
- assert (*(db->data + he->key) != '\0' && *ep == '\0');
-
- request_header req =
- {
- .type = GETGRBYGID,
- .key_len = he->len
- };
- union keytype u = { .g = gid };
-
- return addgrbyX (db, -1, &req, u, db->data + he->key, he->owner, he, dh);
-}
diff --git a/nscd/hstcache.c b/nscd/hstcache.c
deleted file mode 100644
index 9f6ce979ac..0000000000
--- a/nscd/hstcache.c
+++ /dev/null
@@ -1,619 +0,0 @@
-/* Cache handling for host lookup.
- Copyright (C) 1998-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#include <alloca.h>
-#include <assert.h>
-#include <errno.h>
-#include <error.h>
-#include <libintl.h>
-#include <netdb.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <arpa/inet.h>
-#include <arpa/nameser.h>
-#include <sys/mman.h>
-#include <stackinfo.h>
-
-#include "nscd.h"
-#include "dbg_log.h"
-#ifdef HAVE_SENDFILE
-# include <kernel-features.h>
-#endif
-
-
-/* This is the standard reply in case the service is disabled. */
-static const hst_response_header disabled =
-{
- .version = NSCD_VERSION,
- .found = -1,
- .h_name_len = 0,
- .h_aliases_cnt = 0,
- .h_addrtype = -1,
- .h_length = -1,
- .h_addr_list_cnt = 0,
- .error = NETDB_INTERNAL
-};
-
-/* This is the struct describing how to write this record. */
-const struct iovec hst_iov_disabled =
-{
- .iov_base = (void *) &disabled,
- .iov_len = sizeof (disabled)
-};
-
-
-/* This is the standard reply in case we haven't found the dataset. */
-static const hst_response_header notfound =
-{
- .version = NSCD_VERSION,
- .found = 0,
- .h_name_len = 0,
- .h_aliases_cnt = 0,
- .h_addrtype = -1,
- .h_length = -1,
- .h_addr_list_cnt = 0,
- .error = HOST_NOT_FOUND
-};
-
-
-/* This is the standard reply in case there are temporary problems. */
-static const hst_response_header tryagain =
-{
- .version = NSCD_VERSION,
- .found = 0,
- .h_name_len = 0,
- .h_aliases_cnt = 0,
- .h_addrtype = -1,
- .h_length = -1,
- .h_addr_list_cnt = 0,
- .error = TRY_AGAIN
-};
-
-
-static time_t
-cache_addhst (struct database_dyn *db, int fd, request_header *req,
- const void *key, struct hostent *hst, uid_t owner,
- struct hashentry *const he, struct datahead *dh, int errval,
- int32_t ttl)
-{
- bool all_written = true;
- time_t t = time (NULL);
-
- /* We allocate all data in one memory block: the iov vector,
- the response header and the dataset itself. */
- struct dataset
- {
- struct datahead head;
- hst_response_header resp;
- char strdata[0];
- } *dataset;
-
- assert (offsetof (struct dataset, resp) == offsetof (struct datahead, data));
-
- time_t timeout = MAX_TIMEOUT_VALUE;
- if (hst == NULL)
- {
- if (he != NULL && errval == EAGAIN)
- {
- /* If we have an old record available but cannot find one
- now because the service is not available we keep the old
- record and make sure it does not get removed. */
- if (reload_count != UINT_MAX)
- /* Do not reset the value if we never not reload the record. */
- dh->nreloads = reload_count - 1;
-
- /* Reload with the same time-to-live value. */
- timeout = dh->timeout = t + dh->ttl;
- }
- else
- {
- /* We have no data. This means we send the standard reply for this
- case. Possibly this is only temporary. */
- ssize_t total = sizeof (notfound);
- assert (sizeof (notfound) == sizeof (tryagain));
-
- const hst_response_header *resp = (errval == EAGAIN
- ? &tryagain : &notfound);
-
- if (fd != -1 &&
- TEMP_FAILURE_RETRY (send (fd, resp, total,
- MSG_NOSIGNAL)) != total)
- all_written = false;
-
- /* If we have a transient error or cannot permanently store
- the result, so be it. */
- if (errval == EAGAIN || __builtin_expect (db->negtimeout == 0, 0))
- {
- /* Mark the old entry as obsolete. */
- if (dh != NULL)
- dh->usable = false;
- }
- else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
- + req->key_len), 1)) != NULL)
- {
- 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);
-
- /* Copy the key data. */
- memcpy (dataset->strdata, key, req->key_len);
-
- /* If necessary, we also propagate the data to disk. */
- if (db->persistent)
- {
- // XXX async OK?
- uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
- msync ((void *) pval,
- ((uintptr_t) dataset & pagesize_m1)
- + sizeof (struct dataset) + req->key_len, MS_ASYNC);
- }
-
- (void) cache_add (req->type, &dataset->strdata, req->key_len,
- &dataset->head, true, db, owner, he == NULL);
-
- pthread_rwlock_unlock (&db->lock);
-
- /* Mark the old entry as obsolete. */
- if (dh != NULL)
- dh->usable = false;
- }
- }
- }
- else
- {
- /* Determine the I/O structure. */
- size_t h_name_len = strlen (hst->h_name) + 1;
- size_t h_aliases_cnt;
- uint32_t *h_aliases_len;
- size_t h_addr_list_cnt;
- char *addresses;
- char *aliases;
- char *key_copy = NULL;
- char *cp;
- size_t cnt;
- ssize_t total;
-
- /* Determine the number of aliases. */
- h_aliases_cnt = 0;
- for (cnt = 0; hst->h_aliases[cnt] != NULL; ++cnt)
- ++h_aliases_cnt;
- /* Determine the length of all aliases. */
- h_aliases_len = (uint32_t *) alloca (h_aliases_cnt * sizeof (uint32_t));
- total = 0;
- for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
- {
- h_aliases_len[cnt] = strlen (hst->h_aliases[cnt]) + 1;
- total += h_aliases_len[cnt];
- }
-
- /* Determine the number of addresses. */
- h_addr_list_cnt = 0;
- while (hst->h_addr_list[h_addr_list_cnt] != NULL)
- ++h_addr_list_cnt;
-
- if (h_addr_list_cnt == 0)
- /* Invalid entry. */
- return MAX_TIMEOUT_VALUE;
-
- total += (sizeof (struct dataset)
- + h_name_len
- + h_aliases_cnt * sizeof (uint32_t)
- + h_addr_list_cnt * hst->h_length);
-
- /* If we refill the cache, first assume the reconrd did not
- change. Allocate memory on the cache since it is likely
- discarded anyway. If it turns out to be necessary to have a
- new record we can still allocate real memory. */
- bool alloca_used = false;
- dataset = NULL;
-
- /* If the record contains more than one IP address (used for
- load balancing etc) don't cache the entry. This is something
- the current cache handling cannot handle and it is more than
- questionable whether it is worthwhile complicating the cache
- handling just for handling such a special case. */
- if (he == NULL && h_addr_list_cnt == 1)
- dataset = (struct dataset *) mempool_alloc (db, total + req->key_len,
- 1);
-
- if (dataset == NULL)
- {
- /* We cannot permanently add the result in the moment. But
- we can provide the result as is. Store the data in some
- temporary memory. */
- dataset = (struct dataset *) alloca (total + req->key_len);
-
- /* We cannot add this record to the permanent database. */
- alloca_used = true;
- }
-
- 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;
- dataset->resp.h_name_len = h_name_len;
- dataset->resp.h_aliases_cnt = h_aliases_cnt;
- dataset->resp.h_addrtype = hst->h_addrtype;
- dataset->resp.h_length = hst->h_length;
- dataset->resp.h_addr_list_cnt = h_addr_list_cnt;
- dataset->resp.error = NETDB_SUCCESS;
-
- /* Make sure there is no gap. */
- assert ((char *) (&dataset->resp.error + 1) == dataset->strdata);
-
- cp = dataset->strdata;
-
- cp = mempcpy (cp, hst->h_name, h_name_len);
- cp = mempcpy (cp, h_aliases_len, h_aliases_cnt * sizeof (uint32_t));
-
- /* The normal addresses first. */
- addresses = cp;
- for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
- cp = mempcpy (cp, hst->h_addr_list[cnt], hst->h_length);
-
- /* Then the aliases. */
- aliases = cp;
- for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
- cp = mempcpy (cp, hst->h_aliases[cnt], h_aliases_len[cnt]);
-
- assert (cp
- == dataset->strdata + total - offsetof (struct dataset,
- strdata));
-
- /* If we are adding a GETHOSTBYNAME{,v6} entry we must be prepared
- that the answer we get from the NSS does not contain the key
- itself. This is the case if the resolver is used and the name
- is extended by the domainnames from /etc/resolv.conf. Therefore
- we explicitly add the name here. */
- key_copy = memcpy (cp, key, req->key_len);
-
- assert ((char *) &dataset->resp + dataset->head.recsize == cp);
-
- /* Now we can determine whether on refill we have to create a new
- record or not. */
- if (he != NULL)
- {
- assert (fd == -1);
-
- if (total + req->key_len == dh->allocsize
- && total - offsetof (struct dataset, resp) == dh->recsize
- && memcmp (&dataset->resp, dh->data,
- dh->allocsize - offsetof (struct dataset, resp)) == 0)
- {
- /* The data has not changed. We will just bump the
- timeout value. Note that the new record has been
- allocated on the stack and need not be freed. */
- assert (h_addr_list_cnt == 1);
- dh->ttl = dataset->head.ttl;
- dh->timeout = dataset->head.timeout;
- ++dh->nreloads;
- }
- else
- {
- if (h_addr_list_cnt == 1)
- {
- /* We have to create a new record. Just allocate
- appropriate memory and copy it. */
- struct dataset *newp
- = (struct dataset *) mempool_alloc (db,
- total + req->key_len,
- 1);
- if (newp != NULL)
- {
- /* Adjust pointers into the memory block. */
- addresses = (char *) newp + (addresses
- - (char *) dataset);
- aliases = (char *) newp + (aliases - (char *) dataset);
- assert (key_copy != NULL);
- key_copy = (char *) newp + (key_copy - (char *) dataset);
-
- dataset = memcpy (newp, dataset, total + req->key_len);
- alloca_used = false;
- }
- }
-
- /* Mark the old record as obsolete. */
- dh->usable = false;
- }
- }
- else
- {
- /* We write the dataset before inserting it to the database
- since while inserting this thread might block and so would
- unnecessarily keep the receiver waiting. */
- assert (fd != -1);
-
-#ifdef HAVE_SENDFILE
- if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
- {
- assert (db->wr_fd != -1);
- assert ((char *) &dataset->resp > (char *) db->data);
- assert ((char *) dataset - (char *) db->head
- + total
- <= (sizeof (struct database_pers_head)
- + db->head->module * sizeof (ref_t)
- + db->head->data_size));
- ssize_t written = sendfileall (fd, db->wr_fd,
- (char *) &dataset->resp
- - (char *) db->head,
- dataset->head.recsize);
- if (written != dataset->head.recsize)
- {
-# ifndef __ASSUME_SENDFILE
- if (written == -1 && errno == ENOSYS)
- goto use_write;
-# endif
- all_written = false;
- }
- }
- else
-# ifndef __ASSUME_SENDFILE
- use_write:
-# endif
-#endif
- if (writeall (fd, &dataset->resp, dataset->head.recsize)
- != dataset->head.recsize)
- all_written = false;
- }
-
- /* Add the record to the database. But only if it has not been
- stored on the stack.
-
- If the record contains more than one IP address (used for
- load balancing etc) don't cache the entry. This is something
- the current cache handling cannot handle and it is more than
- questionable whether it is worthwhile complicating the cache
- handling just for handling such a special case. */
- if (! alloca_used)
- {
- /* If necessary, we also propagate the data to disk. */
- if (db->persistent)
- {
- // XXX async OK?
- uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
- msync ((void *) pval,
- ((uintptr_t) dataset & pagesize_m1)
- + total + req->key_len, MS_ASYNC);
- }
-
- /* NB: the following code is really complicated. It has
- seemlingly duplicated code paths which do the same. The
- problem is that we always must add the hash table entry
- with the FIRST flag set first. Otherwise we get dangling
- pointers in case memory allocation fails. */
- assert (hst->h_addr_list[1] == NULL);
-
- /* Avoid adding names if more than one address is available. See
- above for more info. */
- assert (req->type == GETHOSTBYNAME
- || req->type == GETHOSTBYNAMEv6
- || req->type == GETHOSTBYADDR
- || req->type == GETHOSTBYADDRv6);
-
- (void) cache_add (req->type, key_copy, req->key_len,
- &dataset->head, true, db, owner, he == NULL);
-
- pthread_rwlock_unlock (&db->lock);
- }
- }
-
- if (__builtin_expect (!all_written, 0) && debug_level > 0)
- {
- char buf[256];
- dbg_log (_("short write in %s: %s"), __FUNCTION__,
- strerror_r (errno, buf, sizeof (buf)));
- }
-
- return timeout;
-}
-
-
-static int
-lookup (int type, void *key, struct hostent *resultbufp, char *buffer,
- size_t buflen, struct hostent **hst, int32_t *ttlp)
-{
- if (type == GETHOSTBYNAME)
- return __gethostbyname3_r (key, AF_INET, resultbufp, buffer, buflen, hst,
- &h_errno, ttlp, NULL);
- if (type == GETHOSTBYNAMEv6)
- return __gethostbyname3_r (key, AF_INET6, resultbufp, buffer, buflen, hst,
- &h_errno, ttlp, NULL);
- if (type == GETHOSTBYADDR)
- return __gethostbyaddr2_r (key, NS_INADDRSZ, AF_INET, resultbufp, buffer,
- buflen, hst, &h_errno, ttlp);
- return __gethostbyaddr2_r (key, NS_IN6ADDRSZ, AF_INET6, resultbufp, buffer,
- buflen, hst, &h_errno, ttlp);
-}
-
-
-static time_t
-addhstbyX (struct database_dyn *db, int fd, request_header *req,
- void *key, uid_t uid, struct hashentry *he, struct datahead *dh)
-{
- /* Search for the entry matching the key. Please note that we don't
- look again in the table whether the dataset is now available. We
- simply insert it. It does not matter if it is in there twice. The
- pruning function only will look at the timestamp. */
- int buflen = 1024;
- char *buffer = (char *) alloca (buflen);
- struct hostent resultbuf;
- struct hostent *hst;
- bool use_malloc = false;
- int errval = 0;
- int32_t ttl = INT32_MAX;
-
- if (__glibc_unlikely (debug_level > 0))
- {
- const char *str;
- char buf[INET6_ADDRSTRLEN + 1];
- if (req->type == GETHOSTBYNAME || req->type == GETHOSTBYNAMEv6)
- str = key;
- else
- str = inet_ntop (req->type == GETHOSTBYADDR ? AF_INET : AF_INET6,
- key, buf, sizeof (buf));
-
- if (he == NULL)
- dbg_log (_("Haven't found \"%s\" in hosts cache!"), (char *) str);
- else
- dbg_log (_("Reloading \"%s\" in hosts cache!"), (char *) str);
- }
-
- while (lookup (req->type, key, &resultbuf, buffer, buflen, &hst, &ttl) != 0
- && h_errno == NETDB_INTERNAL
- && (errval = errno) == ERANGE)
- {
- errno = 0;
-
- if (__glibc_unlikely (buflen > 32768))
- {
- char *old_buffer = buffer;
- buflen *= 2;
- buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
- if (buffer == NULL)
- {
- /* We ran out of memory. We cannot do anything but
- sending a negative response. In reality this should
- never happen. */
- hst = NULL;
- buffer = old_buffer;
-
- /* We set the error to indicate this is (possibly) a
- temporary error and that it does not mean the entry
- is not available at all. */
- h_errno = TRY_AGAIN;
- errval = EAGAIN;
- break;
- }
- use_malloc = true;
- }
- else
- /* Allocate a new buffer on the stack. If possible combine it
- with the previously allocated buffer. */
- buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
- }
-
- time_t timeout = cache_addhst (db, fd, req, key, hst, uid, he, dh,
- h_errno == TRY_AGAIN ? errval : 0, ttl);
-
- if (use_malloc)
- free (buffer);
-
- return timeout;
-}
-
-
-void
-addhstbyname (struct database_dyn *db, int fd, request_header *req,
- void *key, uid_t uid)
-{
- addhstbyX (db, fd, req, key, uid, NULL, NULL);
-}
-
-
-time_t
-readdhstbyname (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh)
-{
- request_header req =
- {
- .type = GETHOSTBYNAME,
- .key_len = he->len
- };
-
- return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
-}
-
-
-void
-addhstbyaddr (struct database_dyn *db, int fd, request_header *req,
- void *key, uid_t uid)
-{
- addhstbyX (db, fd, req, key, uid, NULL, NULL);
-}
-
-
-time_t
-readdhstbyaddr (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh)
-{
- request_header req =
- {
- .type = GETHOSTBYADDR,
- .key_len = he->len
- };
-
- return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
-}
-
-
-void
-addhstbynamev6 (struct database_dyn *db, int fd, request_header *req,
- void *key, uid_t uid)
-{
- addhstbyX (db, fd, req, key, uid, NULL, NULL);
-}
-
-
-time_t
-readdhstbynamev6 (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh)
-{
- request_header req =
- {
- .type = GETHOSTBYNAMEv6,
- .key_len = he->len
- };
-
- return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
-}
-
-
-void
-addhstbyaddrv6 (struct database_dyn *db, int fd, request_header *req,
- void *key, uid_t uid)
-{
- addhstbyX (db, fd, req, key, uid, NULL, NULL);
-}
-
-
-time_t
-readdhstbyaddrv6 (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh)
-{
- request_header req =
- {
- .type = GETHOSTBYADDRv6,
- .key_len = he->len
- };
-
- return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
-}
diff --git a/nscd/initgrcache.c b/nscd/initgrcache.c
deleted file mode 100644
index 4deb483fbb..0000000000
--- a/nscd/initgrcache.c
+++ /dev/null
@@ -1,438 +0,0 @@
-/* Cache handling for host lookup.
- Copyright (C) 2004-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#include <assert.h>
-#include <errno.h>
-#include <grp.h>
-#include <libintl.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <scratch_buffer.h>
-
-#include "dbg_log.h"
-#include "nscd.h"
-#ifdef HAVE_SENDFILE
-# include <kernel-features.h>
-#endif
-
-#include "../nss/nsswitch.h"
-
-
-/* Type of the lookup function. */
-typedef enum nss_status (*initgroups_dyn_function) (const char *, gid_t,
- long int *, long int *,
- gid_t **, long int, int *);
-
-
-static const initgr_response_header notfound =
-{
- .version = NSCD_VERSION,
- .found = 0,
- .ngrps = 0
-};
-
-
-#include "../grp/compat-initgroups.c"
-
-
-static time_t
-addinitgroupsX (struct database_dyn *db, int fd, request_header *req,
- void *key, uid_t uid, struct hashentry *const he,
- struct datahead *dh)
-{
- /* Search for the entry matching the key. Please note that we don't
- look again in the table whether the dataset is now available. We
- simply insert it. It does not matter if it is in there twice. The
- pruning function only will look at the timestamp. */
-
-
- /* We allocate all data in one memory block: the iov vector,
- the response header and the dataset itself. */
- struct dataset
- {
- struct datahead head;
- initgr_response_header resp;
- char strdata[0];
- } *dataset = NULL;
-
- if (__glibc_unlikely (debug_level > 0))
- {
- if (he == NULL)
- dbg_log (_("Haven't found \"%s\" in group cache!"), (char *) key);
- else
- dbg_log (_("Reloading \"%s\" in group cache!"), (char *) key);
- }
-
- static service_user *group_database;
- service_user *nip;
- int no_more;
-
- if (group_database == NULL)
- no_more = __nss_database_lookup ("group", NULL,
- "compat [NOTFOUND=return] files",
- &group_database);
- else
- no_more = 0;
- nip = group_database;
-
- /* We always use sysconf even if NGROUPS_MAX is defined. That way, the
- limit can be raised in the kernel configuration without having to
- recompile libc. */
- long int limit = __sysconf (_SC_NGROUPS_MAX);
-
- long int size;
- if (limit > 0)
- /* We limit the size of the intially allocated array. */
- size = MIN (limit, 64);
- else
- /* No fixed limit on groups. Pick a starting buffer size. */
- size = 16;
-
- long int start = 0;
- bool all_tryagain = true;
- bool any_success = false;
-
- /* This is temporary memory, we need not (and must not) call
- mempool_alloc. */
- // XXX This really should use alloca. need to change the backends.
- gid_t *groups = (gid_t *) malloc (size * sizeof (gid_t));
- if (__glibc_unlikely (groups == NULL))
- /* No more memory. */
- goto out;
-
- /* Nothing added yet. */
- while (! no_more)
- {
- long int prev_start = start;
- enum nss_status status;
- initgroups_dyn_function fct;
- fct = __nss_lookup_function (nip, "initgroups_dyn");
-
- if (fct == NULL)
- {
- status = compat_call (nip, key, -1, &start, &size, &groups,
- limit, &errno);
-
- if (nss_next_action (nip, NSS_STATUS_UNAVAIL) != NSS_ACTION_CONTINUE)
- break;
- }
- else
- status = DL_CALL_FCT (fct, (key, -1, &start, &size, &groups,
- limit, &errno));
-
- /* Remove duplicates. */
- long int cnt = prev_start;
- while (cnt < start)
- {
- long int inner;
- for (inner = 0; inner < prev_start; ++inner)
- if (groups[inner] == groups[cnt])
- break;
-
- if (inner < prev_start)
- groups[cnt] = groups[--start];
- else
- ++cnt;
- }
-
- if (status != NSS_STATUS_TRYAGAIN)
- all_tryagain = false;
-
- /* This is really only for debugging. */
- if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN)
- __libc_fatal ("illegal status in internal_getgrouplist");
-
- any_success |= status == NSS_STATUS_SUCCESS;
-
- if (status != NSS_STATUS_SUCCESS
- && nss_next_action (nip, status) == NSS_ACTION_RETURN)
- break;
-
- if (nip->next == NULL)
- no_more = -1;
- else
- nip = nip->next;
- }
-
- bool all_written;
- ssize_t total;
- time_t timeout;
- out:
- all_written = true;
- timeout = MAX_TIMEOUT_VALUE;
- if (!any_success)
- {
- /* Nothing found. Create a negative result record. */
- total = sizeof (notfound);
-
- if (he != NULL && all_tryagain)
- {
- /* If we have an old record available but cannot find one now
- because the service is not available we keep the old record
- and make sure it does not get removed. */
- if (reload_count != UINT_MAX && dh->nreloads == reload_count)
- /* Do not reset the value if we never not reload the record. */
- dh->nreloads = reload_count - 1;
-
- /* Reload with the same time-to-live value. */
- timeout = dh->timeout = time (NULL) + db->postimeout;
- }
- else
- {
- /* We have no data. This means we send the standard reply for this
- case. */
- if (fd != -1
- && TEMP_FAILURE_RETRY (send (fd, &notfound, total,
- MSG_NOSIGNAL)) != total)
- all_written = false;
-
- /* If we have a transient error or cannot permanently store
- the result, so be it. */
- if (all_tryagain || __builtin_expect (db->negtimeout == 0, 0))
- {
- /* Mark the old entry as obsolete. */
- if (dh != NULL)
- dh->usable = false;
- }
- else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
- + req->key_len), 1)) != NULL)
- {
- timeout = datahead_init_neg (&dataset->head,
- (sizeof (struct dataset)
- + req->key_len), total,
- db->negtimeout);
-
- /* This is the reply. */
- memcpy (&dataset->resp, &notfound, total);
-
- /* Copy the key data. */
- char *key_copy = memcpy (dataset->strdata, key, req->key_len);
-
- /* If necessary, we also propagate the data to disk. */
- if (db->persistent)
- {
- // XXX async OK?
- uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
- msync ((void *) pval,
- ((uintptr_t) dataset & pagesize_m1)
- + sizeof (struct dataset) + req->key_len, MS_ASYNC);
- }
-
- (void) cache_add (req->type, key_copy, req->key_len,
- &dataset->head, true, db, uid, he == NULL);
-
- pthread_rwlock_unlock (&db->lock);
-
- /* Mark the old entry as obsolete. */
- if (dh != NULL)
- dh->usable = false;
- }
- }
- }
- else
- {
-
- total = offsetof (struct dataset, strdata) + start * sizeof (int32_t);
-
- /* If we refill the cache, first assume the reconrd did not
- change. Allocate memory on the cache since it is likely
- discarded anyway. If it turns out to be necessary to have a
- new record we can still allocate real memory. */
- bool alloca_used = false;
- dataset = NULL;
-
- if (he == NULL)
- dataset = (struct dataset *) mempool_alloc (db, total + req->key_len,
- 1);
-
- if (dataset == NULL)
- {
- /* We cannot permanently add the result in the moment. But
- we can provide the result as is. Store the data in some
- temporary memory. */
- dataset = (struct dataset *) alloca (total + req->key_len);
-
- /* We cannot add this record to the permanent database. */
- alloca_used = true;
- }
-
- 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;
- dataset->resp.ngrps = start;
-
- char *cp = dataset->strdata;
-
- /* Copy the GID values. If the size of the types match this is
- very simple. */
- if (sizeof (gid_t) == sizeof (int32_t))
- cp = mempcpy (cp, groups, start * sizeof (gid_t));
- else
- {
- gid_t *gcp = (gid_t *) cp;
-
- for (int i = 0; i < start; ++i)
- *gcp++ = groups[i];
-
- cp = (char *) gcp;
- }
-
- /* Finally the user name. */
- memcpy (cp, key, req->key_len);
-
- assert (cp == dataset->strdata + total - offsetof (struct dataset,
- strdata));
-
- /* Now we can determine whether on refill we have to create a new
- record or not. */
- if (he != NULL)
- {
- assert (fd == -1);
-
- if (total + req->key_len == dh->allocsize
- && total - offsetof (struct dataset, resp) == dh->recsize
- && memcmp (&dataset->resp, dh->data,
- dh->allocsize - offsetof (struct dataset, resp)) == 0)
- {
- /* The data has not changed. We will just bump the
- timeout value. Note that the new record has been
- allocated on the stack and need not be freed. */
- dh->timeout = dataset->head.timeout;
- ++dh->nreloads;
- }
- else
- {
- /* We have to create a new record. Just allocate
- appropriate memory and copy it. */
- struct dataset *newp
- = (struct dataset *) mempool_alloc (db, total + req->key_len,
- 1);
- if (newp != NULL)
- {
- /* Adjust pointer into the memory block. */
- cp = (char *) newp + (cp - (char *) dataset);
-
- dataset = memcpy (newp, dataset, total + req->key_len);
- alloca_used = false;
- }
-
- /* Mark the old record as obsolete. */
- dh->usable = false;
- }
- }
- else
- {
- /* We write the dataset before inserting it to the database
- since while inserting this thread might block and so would
- unnecessarily let the receiver wait. */
- assert (fd != -1);
-
-#ifdef HAVE_SENDFILE
- if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
- {
- assert (db->wr_fd != -1);
- assert ((char *) &dataset->resp > (char *) db->data);
- assert ((char *) dataset - (char *) db->head
- + total
- <= (sizeof (struct database_pers_head)
- + db->head->module * sizeof (ref_t)
- + db->head->data_size));
- ssize_t written = sendfileall (fd, db->wr_fd,
- (char *) &dataset->resp
- - (char *) db->head,
- dataset->head.recsize);
- if (written != dataset->head.recsize)
- {
-# ifndef __ASSUME_SENDFILE
- if (written == -1 && errno == ENOSYS)
- goto use_write;
-# endif
- all_written = false;
- }
- }
- else
-# ifndef __ASSUME_SENDFILE
- use_write:
-# endif
-#endif
- if (writeall (fd, &dataset->resp, dataset->head.recsize)
- != dataset->head.recsize)
- all_written = false;
- }
-
-
- /* Add the record to the database. But only if it has not been
- stored on the stack. */
- if (! alloca_used)
- {
- /* If necessary, we also propagate the data to disk. */
- if (db->persistent)
- {
- // XXX async OK?
- uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
- msync ((void *) pval,
- ((uintptr_t) dataset & pagesize_m1) + total +
- req->key_len, MS_ASYNC);
- }
-
- (void) cache_add (INITGROUPS, cp, req->key_len, &dataset->head, true,
- db, uid, he == NULL);
-
- pthread_rwlock_unlock (&db->lock);
- }
- }
-
- free (groups);
-
- if (__builtin_expect (!all_written, 0) && debug_level > 0)
- {
- char buf[256];
- dbg_log (_("short write in %s: %s"), __FUNCTION__,
- strerror_r (errno, buf, sizeof (buf)));
- }
-
- return timeout;
-}
-
-
-void
-addinitgroups (struct database_dyn *db, int fd, request_header *req, void *key,
- uid_t uid)
-{
- addinitgroupsX (db, fd, req, key, uid, NULL, NULL);
-}
-
-
-time_t
-readdinitgroups (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh)
-{
- request_header req =
- {
- .type = INITGROUPS,
- .key_len = he->len
- };
-
- return addinitgroupsX (db, -1, &req, db->data + he->key, he->owner, he, dh);
-}
diff --git a/nscd/mem.c b/nscd/mem.c
deleted file mode 100644
index 092f3ae7c1..0000000000
--- a/nscd/mem.c
+++ /dev/null
@@ -1,589 +0,0 @@
-/* Cache memory handling.
- Copyright (C) 2004-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#include <assert.h>
-#include <errno.h>
-#include <error.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <libintl.h>
-#include <limits.h>
-#include <obstack.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/param.h>
-
-#include "dbg_log.h"
-#include "nscd.h"
-
-
-static int
-sort_he (const void *p1, const void *p2)
-{
- struct hashentry *h1 = *(struct hashentry **) p1;
- struct hashentry *h2 = *(struct hashentry **) p2;
-
- if (h1 < h2)
- return -1;
- if (h1 > h2)
- return 1;
- return 0;
-}
-
-
-static int
-sort_he_data (const void *p1, const void *p2)
-{
- struct hashentry *h1 = *(struct hashentry **) p1;
- struct hashentry *h2 = *(struct hashentry **) p2;
-
- if (h1->packet < h2->packet)
- return -1;
- if (h1->packet > h2->packet)
- return 1;
- return 0;
-}
-
-
-/* Basic definitions for the bitmap implementation. Only BITMAP_T
- needs to be changed to choose a different word size. */
-#define BITMAP_T uint8_t
-#define BITS (CHAR_BIT * sizeof (BITMAP_T))
-#define ALLBITS ((((BITMAP_T) 1) << BITS) - 1)
-#define HIGHBIT (((BITMAP_T) 1) << (BITS - 1))
-
-
-static void
-markrange (BITMAP_T *mark, ref_t start, size_t len)
-{
- /* Adjust parameters for block alignment. */
- assert ((start & BLOCK_ALIGN_M1) == 0);
- start /= BLOCK_ALIGN;
- len = (len + BLOCK_ALIGN_M1) / BLOCK_ALIGN;
-
- size_t elem = start / BITS;
-
- if (start % BITS != 0)
- {
- if (start % BITS + len <= BITS)
- {
- /* All fits in the partial byte. */
- mark[elem] |= (ALLBITS >> (BITS - len)) << (start % BITS);
- return;
- }
-
- mark[elem++] |= ALLBITS << (start % BITS);
- len -= BITS - (start % BITS);
- }
-
- while (len >= BITS)
- {
- mark[elem++] = ALLBITS;
- len -= BITS;
- }
-
- if (len > 0)
- mark[elem] |= ALLBITS >> (BITS - len);
-}
-
-
-void
-gc (struct database_dyn *db)
-{
- /* We need write access. */
- pthread_rwlock_wrlock (&db->lock);
-
- /* And the memory handling lock. */
- pthread_mutex_lock (&db->memlock);
-
- /* We need an array representing the data area. All memory
- allocation is BLOCK_ALIGN aligned so this is the level at which
- we have to look at the memory. We use a mark and sweep algorithm
- where the marks are placed in this array. */
- assert (db->head->first_free % BLOCK_ALIGN == 0);
-
- BITMAP_T *mark;
- bool mark_use_malloc;
- /* 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 (__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 (__glibc_likely (stack_used + memory_needed <= MAX_STACK_USE))
- {
- mark = (BITMAP_T *) alloca_account (memory_needed, stack_used);
- mark_use_malloc = false;
- memset (mark, '\0', memory_needed);
- }
- else
- {
- mark = (BITMAP_T *) xcalloc (1, memory_needed);
- mark_use_malloc = true;
- }
-
- /* Create an array which can hold pointer to all the entries in hash
- entries. */
- memory_needed = 2 * db->head->nentries * sizeof (struct hashentry *);
- struct hashentry **he;
- struct hashentry **he_data;
- bool he_use_malloc;
- if (__glibc_likely (stack_used + memory_needed <= MAX_STACK_USE))
- {
- he = alloca_account (memory_needed, stack_used);
- he_use_malloc = false;
- }
- else
- {
- he = xmalloc (memory_needed);
- he_use_malloc = true;
- }
- he_data = &he[db->head->nentries];
-
- size_t cnt = 0;
- for (size_t idx = 0; idx < db->head->module; ++idx)
- {
- ref_t *prevp = &db->head->array[idx];
- ref_t run = *prevp;
-
- while (run != ENDREF)
- {
- assert (cnt < db->head->nentries);
- he[cnt] = (struct hashentry *) (db->data + run);
-
- he[cnt]->prevp = prevp;
- prevp = &he[cnt]->next;
-
- /* This is the hash entry itself. */
- markrange (mark, run, sizeof (struct hashentry));
-
- /* Add the information for the data itself. We do this
- only for the one special entry marked with FIRST. */
- if (he[cnt]->first)
- {
- struct datahead *dh
- = (struct datahead *) (db->data + he[cnt]->packet);
- markrange (mark, he[cnt]->packet, dh->allocsize);
- }
-
- run = he[cnt]->next;
-
- ++cnt;
- }
- }
- assert (cnt == db->head->nentries);
-
- /* Sort the entries by the addresses of the referenced data. All
- the entries pointing to the same DATAHEAD object will have the
- same key. Stability of the sorting is unimportant. */
- memcpy (he_data, he, cnt * sizeof (struct hashentry *));
- qsort (he_data, cnt, sizeof (struct hashentry *), sort_he_data);
-
- /* Sort the entries by their address. */
- qsort (he, cnt, sizeof (struct hashentry *), sort_he);
-
-#define obstack_chunk_alloc xmalloc
-#define obstack_chunk_free free
- struct obstack ob;
- obstack_init (&ob);
-
- /* Determine the highest used address. */
- size_t high = nmark;
- while (high > 0 && mark[high - 1] == 0)
- --high;
-
- /* No memory used. */
- if (high == 0)
- {
- db->head->first_free = 0;
- goto out;
- }
-
- /* Determine the highest offset. */
- BITMAP_T mask = HIGHBIT;
- ref_t highref = (high * BITS - 1) * BLOCK_ALIGN;
- while ((mark[high - 1] & mask) == 0)
- {
- mask >>= 1;
- highref -= BLOCK_ALIGN;
- }
-
- /* Now we can iterate over the MARK array and find bits which are not
- set. These represent memory which can be recovered. */
- size_t byte = 0;
- /* Find the first gap. */
- while (byte < high && mark[byte] == ALLBITS)
- ++byte;
-
- if (byte == high
- || (byte == high - 1 && (mark[byte] & ~(mask | (mask - 1))) == 0))
- /* No gap. */
- goto out;
-
- mask = 1;
- cnt = 0;
- while ((mark[byte] & mask) != 0)
- {
- ++cnt;
- mask <<= 1;
- }
- ref_t off_free = (byte * BITS + cnt) * BLOCK_ALIGN;
- assert (off_free <= db->head->first_free);
-
- struct hashentry **next_hash = he;
- struct hashentry **next_data = he_data;
-
- /* Skip over the hash entries in the first block which does not get
- moved. */
- while (next_hash < &he[db->head->nentries]
- && *next_hash < (struct hashentry *) (db->data + off_free))
- ++next_hash;
-
- while (next_data < &he_data[db->head->nentries]
- && (*next_data)->packet < off_free)
- ++next_data;
-
-
- /* Now we start modifying the data. Make sure all readers of the
- data are aware of this and temporarily don't use the data. */
- ++db->head->gc_cycle;
- assert ((db->head->gc_cycle & 1) == 1);
-
-
- /* We do not perform the move operations right away since the
- he_data array is not sorted by the address of the data. */
- struct moveinfo
- {
- void *from;
- void *to;
- size_t size;
- struct moveinfo *next;
- } *moves = NULL;
-
- while (byte < high)
- {
- /* Search for the next filled block. BYTE is the index of the
- entry in MARK, MASK is the bit, and CNT is the bit number.
- OFF_FILLED is the corresponding offset. */
- if ((mark[byte] & ~(mask - 1)) == 0)
- {
- /* No other bit set in the same element of MARK. Search in the
- following memory. */
- do
- ++byte;
- while (byte < high && mark[byte] == 0);
-
- if (byte == high)
- /* That was it. */
- break;
-
- mask = 1;
- cnt = 0;
- }
- /* Find the exact bit. */
- while ((mark[byte] & mask) == 0)
- {
- ++cnt;
- mask <<= 1;
- }
-
- ref_t off_alloc = (byte * BITS + cnt) * BLOCK_ALIGN;
- assert (off_alloc <= db->head->first_free);
-
- /* Find the end of the used area. */
- if ((mark[byte] & ~(mask - 1)) == (BITMAP_T) ~(mask - 1))
- {
- /* All other bits set. Search the next bytes in MARK. */
- do
- ++byte;
- while (byte < high && mark[byte] == ALLBITS);
-
- mask = 1;
- cnt = 0;
- }
- if (byte < high)
- {
- /* Find the exact bit. */
- while ((mark[byte] & mask) != 0)
- {
- ++cnt;
- mask <<= 1;
- }
- }
-
- ref_t off_allocend = (byte * BITS + cnt) * BLOCK_ALIGN;
- assert (off_allocend <= db->head->first_free);
- /* Now we know that we can copy the area from OFF_ALLOC to
- OFF_ALLOCEND (not included) to the memory starting at
- OFF_FREE. First fix up all the entries for the
- displacement. */
- ref_t disp = off_alloc - off_free;
-
- struct moveinfo *new_move;
- if (__builtin_expect (stack_used + sizeof (*new_move) <= MAX_STACK_USE,
- 1))
- new_move = alloca_account (sizeof (*new_move), stack_used);
- else
- new_move = obstack_alloc (&ob, sizeof (*new_move));
- new_move->from = db->data + off_alloc;
- new_move->to = db->data + off_free;
- new_move->size = off_allocend - off_alloc;
- /* Create a circular list to be always able to append at the end. */
- if (moves == NULL)
- moves = new_move->next = new_move;
- else
- {
- new_move->next = moves->next;
- moves = moves->next = new_move;
- }
-
- /* The following loop will prepare to move this much data. */
- off_free += off_allocend - off_alloc;
-
- while (off_alloc < off_allocend)
- {
- /* Determine whether the next entry is for a hash entry or
- the data. */
- if ((struct hashentry *) (db->data + off_alloc) == *next_hash)
- {
- /* Just correct the forward reference. */
- *(*next_hash++)->prevp -= disp;
-
- off_alloc += ((sizeof (struct hashentry) + BLOCK_ALIGN_M1)
- & ~BLOCK_ALIGN_M1);
- }
- else
- {
- assert (next_data < &he_data[db->head->nentries]);
- assert ((*next_data)->packet == off_alloc);
-
- struct datahead *dh = (struct datahead *) (db->data + off_alloc);
- do
- {
- assert ((*next_data)->key >= (*next_data)->packet);
- assert ((*next_data)->key + (*next_data)->len
- <= (*next_data)->packet + dh->allocsize);
-
- (*next_data)->packet -= disp;
- (*next_data)->key -= disp;
- ++next_data;
- }
- while (next_data < &he_data[db->head->nentries]
- && (*next_data)->packet == off_alloc);
-
- off_alloc += (dh->allocsize + BLOCK_ALIGN_M1) & ~BLOCK_ALIGN_M1;
- }
- }
- assert (off_alloc == off_allocend);
-
- assert (off_alloc <= db->head->first_free);
- if (off_alloc == db->head->first_free)
- /* We are done, that was the last block. */
- break;
- }
- assert (next_hash == &he[db->head->nentries]);
- assert (next_data == &he_data[db->head->nentries]);
-
- /* Now perform the actual moves. */
- if (moves != NULL)
- {
- struct moveinfo *runp = moves->next;
- do
- {
- assert ((char *) runp->to >= db->data);
- assert ((char *) runp->to + runp->size
- <= db->data + db->head->first_free);
- assert ((char *) runp->from >= db->data);
- assert ((char *) runp->from + runp->size
- <= db->data + db->head->first_free);
-
- /* The regions may overlap. */
- memmove (runp->to, runp->from, runp->size);
- runp = runp->next;
- }
- while (runp != moves->next);
-
- if (__glibc_unlikely (debug_level >= 3))
- dbg_log (_("freed %zu bytes in %s cache"),
- (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
- available byte. */
- db->head->first_free = (char *) moves->to + moves->size - db->data;
-
- /* Consistency check. */
- if (__glibc_unlikely (debug_level >= 3))
- {
- for (size_t idx = 0; idx < db->head->module; ++idx)
- {
- ref_t run = db->head->array[idx];
- size_t cnt = 0;
-
- while (run != ENDREF)
- {
- if (run + sizeof (struct hashentry) > db->head->first_free)
- {
- dbg_log ("entry %zu in hash bucket %zu out of bounds: "
- "%" PRIu32 "+%zu > %zu\n",
- cnt, idx, run, sizeof (struct hashentry),
- (size_t) db->head->first_free);
- break;
- }
-
- struct hashentry *he = (struct hashentry *) (db->data + run);
-
- if (he->key + he->len > db->head->first_free)
- dbg_log ("key of entry %zu in hash bucket %zu out of "
- "bounds: %" PRIu32 "+%zu > %zu\n",
- cnt, idx, he->key, (size_t) he->len,
- (size_t) db->head->first_free);
-
- if (he->packet + sizeof (struct datahead)
- > db->head->first_free)
- dbg_log ("packet of entry %zu in hash bucket %zu out of "
- "bounds: %" PRIu32 "+%zu > %zu\n",
- cnt, idx, he->packet, sizeof (struct datahead),
- (size_t) db->head->first_free);
- else
- {
- struct datahead *dh = (struct datahead *) (db->data
- + he->packet);
- if (he->packet + dh->allocsize
- > db->head->first_free)
- dbg_log ("full key of entry %zu in hash bucket %zu "
- "out of bounds: %" PRIu32 "+%zu > %zu",
- cnt, idx, he->packet, (size_t) dh->allocsize,
- (size_t) db->head->first_free);
- }
-
- run = he->next;
- ++cnt;
- }
- }
- }
- }
-
- /* Make sure the data on disk is updated. */
- if (db->persistent)
- msync (db->head, db->data + db->head->first_free - (char *) db->head,
- MS_ASYNC);
-
-
- /* Now we are done modifying the data. */
- ++db->head->gc_cycle;
- assert ((db->head->gc_cycle & 1) == 0);
-
- /* We are done. */
- out:
- pthread_mutex_unlock (&db->memlock);
- pthread_rwlock_unlock (&db->lock);
-
- if (he_use_malloc)
- free (he);
- if (mark_use_malloc)
- free (mark);
-
- obstack_free (&ob, NULL);
-}
-
-
-void *
-mempool_alloc (struct database_dyn *db, size_t len, int data_alloc)
-{
- /* Make sure LEN is a multiple of our maximum alignment so we can
- keep track of used memory is multiples of this alignment value. */
- if ((len & BLOCK_ALIGN_M1) != 0)
- len += BLOCK_ALIGN - (len & BLOCK_ALIGN_M1);
-
- if (data_alloc)
- pthread_rwlock_rdlock (&db->lock);
-
- pthread_mutex_lock (&db->memlock);
-
- assert ((db->head->first_free & BLOCK_ALIGN_M1) == 0);
-
- bool tried_resize = false;
- void *res;
- retry:
- res = db->data + db->head->first_free;
-
- if (__glibc_unlikely (db->head->first_free + len > db->head->data_size))
- {
- if (! tried_resize)
- {
- /* Try to resize the database. Grow size of 1/8th. */
- size_t oldtotal = (sizeof (struct database_pers_head)
- + roundup (db->head->module * sizeof (ref_t),
- ALIGN)
- + db->head->data_size);
- size_t new_data_size = (db->head->data_size
- + MAX (2 * len, db->head->data_size / 8));
- size_t newtotal = (sizeof (struct database_pers_head)
- + roundup (db->head->module * sizeof (ref_t), ALIGN)
- + new_data_size);
- if (newtotal > db->max_db_size)
- {
- new_data_size -= newtotal - db->max_db_size;
- newtotal = db->max_db_size;
- }
-
- if (db->mmap_used && newtotal > oldtotal
- /* We only have to adjust the file size. The new pages
- become magically available. */
- && TEMP_FAILURE_RETRY_VAL (posix_fallocate (db->wr_fd, oldtotal,
- newtotal
- - oldtotal)) == 0)
- {
- db->head->data_size = new_data_size;
- tried_resize = true;
- goto retry;
- }
- }
-
- if (data_alloc)
- pthread_rwlock_unlock (&db->lock);
-
- if (! db->last_alloc_failed)
- {
- dbg_log (_("no more memory for database '%s'"), dbnames[db - dbs]);
-
- db->last_alloc_failed = true;
- }
-
- ++db->head->addfailed;
-
- /* No luck. */
- res = NULL;
- }
- else
- {
- db->head->first_free += len;
-
- db->last_alloc_failed = false;
-
- }
-
- pthread_mutex_unlock (&db->memlock);
-
- return res;
-}
diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
deleted file mode 100644
index cd0c3ea19b..0000000000
--- a/nscd/netgroupcache.c
+++ /dev/null
@@ -1,699 +0,0 @@
-/* Cache handling for netgroup lookup.
- Copyright (C) 2011-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#include <alloca.h>
-#include <assert.h>
-#include <errno.h>
-#include <libintl.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/mman.h>
-
-#include "../inet/netgroup.h"
-#include "nscd.h"
-#include "dbg_log.h"
-
-#include <kernel-features.h>
-
-
-/* This is the standard reply in case the service is disabled. */
-static const netgroup_response_header disabled =
-{
- .version = NSCD_VERSION,
- .found = -1,
- .nresults = 0,
- .result_len = 0
-};
-
-/* This is the struct describing how to write this record. */
-const struct iovec netgroup_iov_disabled =
-{
- .iov_base = (void *) &disabled,
- .iov_len = sizeof (disabled)
-};
-
-
-/* This is the standard reply in case we haven't found the dataset. */
-static const netgroup_response_header notfound =
-{
- .version = NSCD_VERSION,
- .found = 0,
- .nresults = 0,
- .result_len = 0
-};
-
-
-struct dataset
-{
- struct datahead head;
- netgroup_response_header resp;
- char strdata[0];
-};
-
-/* Sends a notfound message and prepares a notfound dataset to write to the
- cache. Returns true if there was enough memory to allocate the dataset and
- returns the dataset in DATASETP, total bytes to write in TOTALP and the
- timeout in TIMEOUTP. KEY_COPY is set to point to the copy of the key in the
- dataset. */
-static bool
-do_notfound (struct database_dyn *db, int fd, request_header *req,
- const char *key, struct dataset **datasetp, ssize_t *totalp,
- time_t *timeoutp, char **key_copy)
-{
- struct dataset *dataset;
- ssize_t total;
- time_t timeout;
- bool cacheable = false;
-
- total = sizeof (notfound);
- timeout = time (NULL) + db->negtimeout;
-
- if (fd != -1)
- TEMP_FAILURE_RETRY (send (fd, &notfound, total, MSG_NOSIGNAL));
-
- dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1);
- /* If we cannot permanently store the result, so be it. */
- if (dataset != NULL)
- {
- timeout = datahead_init_neg (&dataset->head,
- sizeof (struct dataset) + req->key_len,
- total, db->negtimeout);
-
- /* This is the reply. */
- memcpy (&dataset->resp, &notfound, total);
-
- /* Copy the key data. */
- memcpy (dataset->strdata, key, req->key_len);
- *key_copy = dataset->strdata;
-
- cacheable = true;
- }
- *timeoutp = timeout;
- *totalp = total;
- *datasetp = dataset;
- return cacheable;
-}
-
-static time_t
-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 (__glibc_unlikely (debug_level > 0))
- {
- if (he == NULL)
- dbg_log (_("Haven't found \"%s\" in netgroup cache!"), key);
- else
- dbg_log (_("Reloading \"%s\" in netgroup cache!"), key);
- }
-
- static service_user *netgroup_database;
- time_t timeout;
- struct dataset *dataset;
- bool cacheable = false;
- ssize_t total;
- bool found = false;
-
- char *key_copy = NULL;
- struct __netgrent data;
- size_t buflen = MAX (1024, sizeof (*dataset) + req->key_len);
- size_t buffilled = sizeof (*dataset);
- char *buffer = NULL;
- size_t nentries = 0;
- size_t group_len = strlen (key) + 1;
- struct name_list *first_needed
- = alloca (sizeof (struct name_list) + group_len);
-
- if (netgroup_database == NULL
- && __nss_database_lookup ("netgroup", NULL, NULL, &netgroup_database))
- {
- /* No such service. */
- cacheable = do_notfound (db, fd, req, key, &dataset, &total, &timeout,
- &key_copy);
- goto writeout;
- }
-
- memset (&data, '\0', sizeof (data));
- buffer = xmalloc (buflen);
- first_needed->next = first_needed;
- memcpy (first_needed->name, key, group_len);
- data.needed_groups = first_needed;
-
- while (data.needed_groups != NULL)
- {
- /* Add the next group to the list of those which are known. */
- struct name_list *this_group = data.needed_groups->next;
- if (this_group == data.needed_groups)
- data.needed_groups = NULL;
- else
- data.needed_groups->next = this_group->next;
- this_group->next = data.known_groups;
- data.known_groups = this_group;
-
- union
- {
- enum nss_status (*f) (const char *, struct __netgrent *);
- void *ptr;
- } setfct;
-
- service_user *nip = netgroup_database;
- int no_more = __nss_lookup (&nip, "setnetgrent", NULL, &setfct.ptr);
- while (!no_more)
- {
- enum nss_status status
- = DL_CALL_FCT (*setfct.f, (data.known_groups->name, &data));
-
- if (status == NSS_STATUS_SUCCESS)
- {
- found = true;
- union
- {
- enum nss_status (*f) (struct __netgrent *, char *, size_t,
- int *);
- void *ptr;
- } getfct;
- getfct.ptr = __nss_lookup_function (nip, "getnetgrent_r");
- if (getfct.f != NULL)
- while (1)
- {
- int e;
- status = getfct.f (&data, buffer + buffilled,
- buflen - buffilled - req->key_len, &e);
- if (status == NSS_STATUS_SUCCESS)
- {
- if (data.type == triple_val)
- {
- const char *nhost = data.val.triple.host;
- 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)
- {
- const char *last = nhost;
- if (last == NULL
- || (nuser != NULL && nuser > last))
- last = nuser;
- if (last == NULL
- || (ndomain != NULL && ndomain > last))
- last = ndomain;
-
- size_t bufused
- = (last == NULL
- ? buffilled
- : last + strlen (last) + 1 - buffer);
-
- /* We have to make temporary copies. */
- size_t needed = hostlen + userlen + domainlen;
-
- if (buflen - req->key_len - bufused < needed)
- {
- buflen += MAX (buflen, 2 * needed);
- /* Save offset in the old buffer. We don't
- bother with the NULL check here since
- we'll do that later anyway. */
- size_t nhostdiff = nhost - buffer;
- size_t nuserdiff = nuser - buffer;
- size_t ndomaindiff = ndomain - buffer;
-
- char *newbuf = xrealloc (buffer, buflen);
- /* Fix up the triplet pointers into the new
- buffer. */
- nhost = (nhost ? newbuf + nhostdiff
- : NULL);
- nuser = (nuser ? newbuf + nuserdiff
- : NULL);
- ndomain = (ndomain ? newbuf + ndomaindiff
- : NULL);
- buffer = newbuf;
- }
-
- nhost = memcpy (buffer + bufused,
- nhost ?: "", hostlen);
- nuser = memcpy ((char *) nhost + hostlen,
- nuser ?: "", userlen);
- ndomain = memcpy ((char *) nuser + userlen,
- ndomain ?: "", domainlen);
- }
-
- char *wp = buffer + buffilled;
- 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;
- }
- else
- {
- /* Check that the group has not been
- requested before. */
- struct name_list *runp = data.needed_groups;
- if (runp != NULL)
- while (1)
- {
- if (strcmp (runp->name, data.val.group) == 0)
- break;
-
- runp = runp->next;
- if (runp == data.needed_groups)
- {
- runp = NULL;
- break;
- }
- }
-
- if (runp == NULL)
- {
- runp = data.known_groups;
- while (runp != NULL)
- if (strcmp (runp->name, data.val.group) == 0)
- break;
- else
- runp = runp->next;
- }
-
- if (runp == NULL)
- {
- /* A new group is requested. */
- size_t namelen = strlen (data.val.group) + 1;
- struct name_list *newg = alloca (sizeof (*newg)
- + namelen);
- memcpy (newg->name, data.val.group, namelen);
- if (data.needed_groups == NULL)
- data.needed_groups = newg->next = newg;
- else
- {
- newg->next = data.needed_groups->next;
- data.needed_groups->next = newg;
- data.needed_groups = newg;
- }
- }
- }
- }
- 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 *);
- endfct = __nss_lookup_function (nip, "endnetgrent");
- if (endfct != NULL)
- (void) DL_CALL_FCT (*endfct, (&data));
-
- break;
- }
-
- no_more = __nss_next2 (&nip, "setnetgrent", NULL, &setfct.ptr,
- status, 0);
- }
- }
-
- /* No results. Return a failure and write out a notfound record in the
- cache. */
- if (!found)
- {
- cacheable = do_notfound (db, fd, req, key, &dataset, &total, &timeout,
- &key_copy);
- goto writeout;
- }
-
- total = buffilled;
-
- /* Fill in the dataset. */
- dataset = (struct dataset *) buffer;
- 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;
- dataset->resp.nresults = nentries;
- dataset->resp.result_len = buffilled - sizeof (*dataset);
-
- assert (buflen - buffilled >= req->key_len);
- key_copy = memcpy (buffer + buffilled, key, req->key_len);
- buffilled += req->key_len;
-
- /* Now we can determine whether on refill we have to create a new
- record or not. */
- if (he != NULL)
- {
- assert (fd == -1);
-
- if (dataset->head.allocsize == dh->allocsize
- && dataset->head.recsize == dh->recsize
- && memcmp (&dataset->resp, dh->data,
- dh->allocsize - offsetof (struct dataset, resp)) == 0)
- {
- /* The data has not changed. We will just bump the timeout
- value. Note that the new record has been allocated on
- the stack and need not be freed. */
- dh->timeout = dataset->head.timeout;
- dh->ttl = dataset->head.ttl;
- ++dh->nreloads;
- dataset = (struct dataset *) dh;
-
- goto out;
- }
- }
-
- {
- struct dataset *newp
- = (struct dataset *) mempool_alloc (db, total + req->key_len, 1);
- if (__glibc_likely (newp != NULL))
- {
- /* Adjust pointer into the memory block. */
- key_copy = (char *) newp + (key_copy - buffer);
-
- dataset = memcpy (newp, dataset, total + req->key_len);
- cacheable = true;
-
- if (he != NULL)
- /* Mark the old record as obsolete. */
- dh->usable = false;
- }
- }
-
- if (he == NULL && fd != -1)
- {
- /* We write the dataset before inserting it to the database
- since while inserting this thread might block and so would
- unnecessarily let the receiver wait. */
- writeout:
-#ifdef HAVE_SENDFILE
- if (__builtin_expect (db->mmap_used, 1) && cacheable)
- {
- assert (db->wr_fd != -1);
- assert ((char *) &dataset->resp > (char *) db->data);
- assert ((char *) dataset - (char *) db->head + total
- <= (sizeof (struct database_pers_head)
- + db->head->module * sizeof (ref_t)
- + db->head->data_size));
-# ifndef __ASSUME_SENDFILE
- ssize_t written =
-# endif
- sendfileall (fd, db->wr_fd, (char *) &dataset->resp
- - (char *) db->head, dataset->head.recsize);
-# ifndef __ASSUME_SENDFILE
- if (written == -1 && errno == ENOSYS)
- goto use_write;
-# endif
- }
- else
-#endif
- {
-#if defined HAVE_SENDFILE && !defined __ASSUME_SENDFILE
- use_write:
-#endif
- writeall (fd, &dataset->resp, dataset->head.recsize);
- }
- }
-
- if (cacheable)
- {
- /* If necessary, we also propagate the data to disk. */
- if (db->persistent)
- {
- // XXX async OK?
- uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
- msync ((void *) pval,
- ((uintptr_t) dataset & pagesize_m1) + total + req->key_len,
- MS_ASYNC);
- }
-
- (void) cache_add (req->type, key_copy, req->key_len, &dataset->head,
- true, db, uid, he == NULL);
-
- pthread_rwlock_unlock (&db->lock);
-
- /* Mark the old entry as obsolete. */
- if (dh != NULL)
- dh->usable = false;
- }
-
- out:
- free (buffer);
-
- *resultp = dataset;
-
- return timeout;
-}
-
-
-static time_t
-addinnetgrX (struct database_dyn *db, int fd, request_header *req,
- char *key, uid_t uid, struct hashentry *he,
- struct datahead *dh)
-{
- const char *group = key;
- key = (char *) rawmemchr (key, '\0') + 1;
- size_t group_len = key - group - 1;
- const char *host = *key++ ? key : NULL;
- if (host != NULL)
- key = (char *) rawmemchr (key, '\0') + 1;
- const char *user = *key++ ? key : NULL;
- if (user != NULL)
- key = (char *) rawmemchr (key, '\0') + 1;
- const char *domain = *key++ ? key : NULL;
-
- if (__glibc_unlikely (debug_level > 0))
- {
- if (he == NULL)
- dbg_log (_("Haven't found \"%s (%s,%s,%s)\" in netgroup cache!"),
- group, host ?: "", user ?: "", domain ?: "");
- else
- dbg_log (_("Reloading \"%s (%s,%s,%s)\" in netgroup cache!"),
- group, host ?: "", user ?: "", domain ?: "");
- }
-
- struct dataset *result = (struct dataset *) cache_search (GETNETGRENT,
- group, group_len,
- db, uid);
- time_t timeout;
- if (result != NULL)
- timeout = result->head.timeout;
- else
- {
- request_header req_get =
- {
- .type = GETNETGRENT,
- .key_len = group_len
- };
- timeout = addgetnetgrentX (db, -1, &req_get, group, uid, NULL, NULL,
- &result);
- }
-
- struct indataset
- {
- struct datahead head;
- innetgroup_response_header resp;
- } *dataset
- = (struct indataset *) mempool_alloc (db,
- sizeof (*dataset) + req->key_len,
- 1);
- struct indataset dataset_mem;
- bool cacheable = true;
- if (__glibc_unlikely (dataset == NULL))
- {
- cacheable = false;
- dataset = &dataset_mem;
- }
-
- 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.timeout = timeout;
-
- dataset->resp.version = NSCD_VERSION;
- dataset->resp.found = result->resp.found;
- /* Until we find a matching entry the result is 0. */
- dataset->resp.result = 0;
-
- char *key_copy = memcpy ((char *) (dataset + 1), group, req->key_len);
-
- if (dataset->resp.found)
- {
- const char *triplets = (const char *) (&result->resp + 1);
-
- for (nscd_ssize_t i = result->resp.nresults; i > 0; --i)
- {
- bool success = true;
-
- /* 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 && *triplets != '\0')
- success = strcmp (user, triplets) == 0;
- triplets = (const char *) rawmemchr (triplets, '\0') + 1;
-
- if (success && (domain == NULL || *triplets == '\0'
- || strcmp (domain, triplets) == 0))
- {
- dataset->resp.result = 1;
- break;
- }
- triplets = (const char *) rawmemchr (triplets, '\0') + 1;
- }
- }
-
- if (he != NULL && dh->data[0].innetgroupdata.result == dataset->resp.result)
- {
- /* The data has not changed. We will just bump the timeout
- value. Note that the new record has been allocated on
- the stack and need not be freed. */
- dh->timeout = timeout;
- dh->ttl = dataset->head.ttl;
- ++dh->nreloads;
- return timeout;
- }
-
- if (he == NULL)
- {
- /* We write the dataset before inserting it to the database
- since while inserting this thread might block and so would
- unnecessarily let the receiver wait. */
- assert (fd != -1);
-
-#ifdef HAVE_SENDFILE
- if (__builtin_expect (db->mmap_used, 1) && cacheable)
- {
- assert (db->wr_fd != -1);
- assert ((char *) &dataset->resp > (char *) db->data);
- assert ((char *) dataset - (char *) db->head + sizeof (*dataset)
- <= (sizeof (struct database_pers_head)
- + db->head->module * sizeof (ref_t)
- + db->head->data_size));
-# ifndef __ASSUME_SENDFILE
- ssize_t written =
-# endif
- sendfileall (fd, db->wr_fd,
- (char *) &dataset->resp - (char *) db->head,
- sizeof (innetgroup_response_header));
-# ifndef __ASSUME_SENDFILE
- if (written == -1 && errno == ENOSYS)
- goto use_write;
-# endif
- }
- else
-#endif
- {
-#if defined HAVE_SENDFILE && !defined __ASSUME_SENDFILE
- use_write:
-#endif
- writeall (fd, &dataset->resp, sizeof (innetgroup_response_header));
- }
- }
-
- if (cacheable)
- {
- /* If necessary, we also propagate the data to disk. */
- if (db->persistent)
- {
- // XXX async OK?
- uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
- msync ((void *) pval,
- ((uintptr_t) dataset & pagesize_m1) + sizeof (*dataset)
- + req->key_len,
- MS_ASYNC);
- }
-
- (void) cache_add (req->type, key_copy, req->key_len, &dataset->head,
- true, db, uid, he == NULL);
-
- pthread_rwlock_unlock (&db->lock);
-
- /* Mark the old entry as obsolete. */
- if (dh != NULL)
- dh->usable = false;
- }
-
- return timeout;
-}
-
-
-void
-addgetnetgrent (struct database_dyn *db, int fd, request_header *req,
- void *key, uid_t uid)
-{
- struct dataset *ignore;
-
- addgetnetgrentX (db, fd, req, key, uid, NULL, NULL, &ignore);
-}
-
-
-time_t
-readdgetnetgrent (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh)
-{
- request_header req =
- {
- .type = GETNETGRENT,
- .key_len = he->len
- };
- struct dataset *ignore;
-
- return addgetnetgrentX (db, -1, &req, db->data + he->key, he->owner, he, dh,
- &ignore);
-}
-
-
-void
-addinnetgr (struct database_dyn *db, int fd, request_header *req,
- void *key, uid_t uid)
-{
- addinnetgrX (db, fd, req, key, uid, NULL, NULL);
-}
-
-
-time_t
-readdinnetgr (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh)
-{
- request_header req =
- {
- .type = INNETGR,
- .key_len = he->len
- };
-
- return addinnetgrX (db, -1, &req, db->data + he->key, he->owner, he, dh);
-}
diff --git a/nscd/nscd-client.h b/nscd/nscd-client.h
deleted file mode 100644
index 96170bff1b..0000000000
--- a/nscd/nscd-client.h
+++ /dev/null
@@ -1,452 +0,0 @@
-/* Copyright (c) 1998-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-/* This file defines everything that client code should need to
- know to talk to the nscd daemon. */
-
-#ifndef _NSCD_CLIENT_H
-#define _NSCD_CLIENT_H 1
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <string.h>
-#include <time.h>
-#include <sys/types.h>
-#include <atomic.h>
-#include <nscd-types.h>
-#include <sys/uio.h>
-
-
-/* Version number of the daemon interface */
-#define NSCD_VERSION 2
-
-/* Path of the file where the PID of the running system is stored. */
-#define _PATH_NSCDPID "/var/run/nscd/nscd.pid"
-
-/* Path for the Unix domain socket. */
-#define _PATH_NSCDSOCKET "/var/run/nscd/socket"
-
-/* Path for the configuration file. */
-#define _PATH_NSCDCONF "/etc/nscd.conf"
-
-/* Maximum allowed length for the key. */
-#define MAXKEYLEN 1024
-
-
-/* Available services. */
-typedef enum
-{
- GETPWBYNAME,
- GETPWBYUID,
- GETGRBYNAME,
- GETGRBYGID,
- GETHOSTBYNAME,
- GETHOSTBYNAMEv6,
- GETHOSTBYADDR,
- GETHOSTBYADDRv6,
- SHUTDOWN, /* Shut the server down. */
- GETSTAT, /* Get the server statistic. */
- INVALIDATE, /* Invalidate one special cache. */
- GETFDPW,
- GETFDGR,
- GETFDHST,
- GETAI,
- INITGROUPS,
- GETSERVBYNAME,
- GETSERVBYPORT,
- GETFDSERV,
- GETNETGRENT,
- INNETGR,
- GETFDNETGR,
- LASTREQ
-} request_type;
-
-
-/* Header common to all requests */
-typedef struct
-{
- int32_t version; /* Version number of the daemon interface. */
- request_type type; /* Service requested. */
- int32_t key_len; /* Key length. */
-} request_header;
-
-
-/* Structure sent in reply to password query. Note that this struct is
- sent also if the service is disabled or there is no record found. */
-typedef struct
-{
- int32_t version;
- int32_t found;
- nscd_ssize_t pw_name_len;
- nscd_ssize_t pw_passwd_len;
- uid_t pw_uid;
- gid_t pw_gid;
- nscd_ssize_t pw_gecos_len;
- nscd_ssize_t pw_dir_len;
- nscd_ssize_t pw_shell_len;
-} pw_response_header;
-
-
-/* Structure sent in reply to group query. Note that this struct is
- sent also if the service is disabled or there is no record found. */
-typedef struct
-{
- int32_t version;
- int32_t found;
- nscd_ssize_t gr_name_len;
- nscd_ssize_t gr_passwd_len;
- gid_t gr_gid;
- nscd_ssize_t gr_mem_cnt;
-} gr_response_header;
-
-
-/* Structure sent in reply to host query. Note that this struct is
- sent also if the service is disabled or there is no record found. */
-typedef struct
-{
- int32_t version;
- int32_t found;
- nscd_ssize_t h_name_len;
- nscd_ssize_t h_aliases_cnt;
- int32_t h_addrtype;
- int32_t h_length;
- nscd_ssize_t h_addr_list_cnt;
- int32_t error;
-} hst_response_header;
-
-
-/* Structure sent in reply to addrinfo query. Note that this struct is
- sent also if the service is disabled or there is no record found. */
-typedef struct
-{
- int32_t version;
- int32_t found;
- nscd_ssize_t naddrs;
- nscd_ssize_t addrslen;
- nscd_ssize_t canonlen;
- int32_t error;
-} ai_response_header;
-
-/* Structure filled in by __nscd_getai. */
-struct nscd_ai_result
-{
- int naddrs;
- char *canon;
- uint8_t *family;
- char *addrs;
-};
-
-/* Structure sent in reply to initgroups query. Note that this struct is
- sent also if the service is disabled or there is no record found. */
-typedef struct
-{
- int32_t version;
- int32_t found;
- nscd_ssize_t ngrps;
-} initgr_response_header;
-
-
-/* Structure sent in reply to services query. Note that this struct is
- sent also if the service is disabled or there is no record found. */
-typedef struct
-{
- int32_t version;
- int32_t found;
- nscd_ssize_t s_name_len;
- nscd_ssize_t s_proto_len;
- nscd_ssize_t s_aliases_cnt;
- int32_t s_port;
-} serv_response_header;
-
-
-/* Structure send in reply to netgroup query. Note that this struct is
- sent also if the service is disabled or there is no record found. */
-typedef struct
-{
- int32_t version;
- int32_t found;
- nscd_ssize_t nresults;
- nscd_ssize_t result_len;
-} netgroup_response_header;
-
-typedef struct
-{
- int32_t version;
- int32_t found;
- int32_t result;
-} innetgroup_response_header;
-
-
-/* Type for offsets in data part of database. */
-typedef uint32_t ref_t;
-/* Value for invalid/no reference. */
-#define ENDREF UINT32_MAX
-
-/* Timestamp type. */
-typedef uint64_t nscd_time_t;
-
-/* Maximum timestamp. */
-#define MAX_TIMEOUT_VALUE \
- (sizeof (time_t) == sizeof (long int) ? LONG_MAX : INT_MAX)
-
-/* Alignment requirement of the beginning of the data region. */
-#define ALIGN 16
-
-
-/* Head of record in data part of database. */
-struct datahead
-{
- nscd_ssize_t allocsize; /* Allocated Bytes. */
- nscd_ssize_t recsize; /* Size of the record. */
- nscd_time_t timeout; /* Time when this entry becomes invalid. */
- uint8_t notfound; /* Nonzero if data has not been found. */
- uint8_t nreloads; /* Reloads without use. */
- uint8_t usable; /* False if the entry must be ignored. */
- uint8_t unused; /* Unused. */
- uint32_t ttl; /* TTL value used. */
-
- /* We need to have the following element aligned for the response
- header data types and their use in the 'struct dataset' types
- defined in the XXXcache.c files. */
- union
- {
- pw_response_header pwdata;
- gr_response_header grdata;
- hst_response_header hstdata;
- ai_response_header aidata;
- initgr_response_header initgrdata;
- serv_response_header servdata;
- netgroup_response_header netgroupdata;
- innetgroup_response_header innetgroupdata;
- nscd_ssize_t align1;
- nscd_time_t align2;
- } 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
-{
- request_type type:8; /* Which type of dataset. */
- bool first; /* True if this was the original key. */
- nscd_ssize_t len; /* Length of key. */
- ref_t key; /* Pointer to key. */
- int32_t owner; /* If secure table, this is the owner. */
- ref_t next; /* Next entry in this hash bucket list. */
- ref_t packet; /* Records for the result. */
- union
- {
- struct hashentry *dellist; /* Next record to be deleted. This can be a
- pointer since only nscd uses this field. */
- ref_t *prevp; /* Pointer to field containing forward
- reference. */
- };
-};
-
-
-/* Current persistent database version. */
-#define DB_VERSION 2
-
-/* Maximum time allowed between updates of the timestamp. */
-#define MAPPING_TIMEOUT (5 * 60)
-
-
-/* Used indices for the EXTRA_DATA element of 'database_pers_head'.
- Each database has its own indices. */
-#define NSCD_HST_IDX_CONF_TIMESTAMP 0
-
-
-/* Header of persistent database file. */
-struct database_pers_head
-{
- int32_t version;
- int32_t header_size;
- volatile int32_t gc_cycle;
- volatile int32_t nscd_certainly_running;
- volatile nscd_time_t timestamp;
- /* Room for extensions. */
- volatile uint32_t extra_data[4];
-
- nscd_ssize_t module;
- nscd_ssize_t data_size;
-
- nscd_ssize_t first_free; /* Offset of first free byte in data area. */
-
- nscd_ssize_t nentries;
- nscd_ssize_t maxnentries;
- nscd_ssize_t maxnsearched;
-
- uint64_t poshit;
- uint64_t neghit;
- uint64_t posmiss;
- uint64_t negmiss;
-
- uint64_t rdlockdelayed;
- uint64_t wrlockdelayed;
-
- uint64_t addfailed;
-
- ref_t array[0];
-};
-
-
-/* Mapped database record. */
-struct mapped_database
-{
- const struct database_pers_head *head;
- const char *data;
- size_t mapsize;
- int counter; /* > 0 indicates it is usable. */
- size_t datasize;
-};
-#define NO_MAPPING ((struct mapped_database *) -1l)
-
-struct locked_map_ptr
-{
- int lock;
- struct mapped_database *mapped;
-};
-#define libc_locked_map_ptr(class, name) class struct locked_map_ptr name
-
-/* Try acquiring lock for mapptr, returns true if it succeeds, false
- if not. */
-static inline bool
-__nscd_acquire_maplock (volatile struct locked_map_ptr *mapptr)
-{
- int cnt = 0;
- while (__builtin_expect (atomic_compare_and_exchange_val_acq (&mapptr->lock,
- 1, 0) != 0, 0))
- {
- // XXX Best number of rounds?
- if (__glibc_unlikely (++cnt > 5))
- return false;
-
- atomic_spin_nop ();
- }
-
- return true;
-}
-
-
-/* Open socket connection to nscd server. */
-extern int __nscd_open_socket (const char *key, size_t keylen,
- request_type type, void *response,
- size_t responselen) attribute_hidden;
-
-/* Try to get a file descriptor for the shared meory segment
- containing the database. */
-extern struct mapped_database *__nscd_get_mapping (request_type type,
- const char *key,
- struct mapped_database **mappedp) attribute_hidden;
-
-/* Get reference of mapping. */
-extern struct mapped_database *__nscd_get_map_ref (request_type type,
- const char *name,
- volatile struct locked_map_ptr *mapptr,
- int *gc_cyclep);
-
-/* Unmap database. */
-extern void __nscd_unmap (struct mapped_database *mapped);
-
-/* Drop reference of mapping. */
-static int
-__attribute__ ((unused))
-__nscd_drop_map_ref (struct mapped_database *map, int *gc_cycle)
-{
- if (map != NO_MAPPING)
- {
- int now_cycle = map->head->gc_cycle;
- if (__glibc_unlikely (now_cycle != *gc_cycle))
- {
- /* We might have read inconsistent data. */
- *gc_cycle = now_cycle;
- return -1;
- }
-
- if (atomic_decrement_val (&map->counter) == 0)
- __nscd_unmap (map);
- }
-
- return 0;
-}
-
-
-/* Search the mapped database. */
-extern struct datahead *__nscd_cache_search (request_type type,
- const char *key,
- size_t keylen,
- const struct mapped_database *mapped,
- size_t datalen);
-
-/* Wrappers around read, readv and write that only read/write less than LEN
- bytes on error or EOF. */
-extern ssize_t __readall (int fd, void *buf, size_t len)
- attribute_hidden;
-extern ssize_t __readvall (int fd, const struct iovec *iov, int iovcnt)
- attribute_hidden;
-extern ssize_t writeall (int fd, const void *buf, size_t len)
- attribute_hidden;
-extern ssize_t sendfileall (int tofd, int fromfd, off_t off, size_t len)
- attribute_hidden;
-
-/* Get netlink timestamp counter from mapped area or zero. */
-extern uint32_t __nscd_get_nl_timestamp (void);
-
-#endif /* nscd.h */
diff --git a/nscd/nscd.c b/nscd/nscd.c
deleted file mode 100644
index 69ef41366c..0000000000
--- a/nscd/nscd.c
+++ /dev/null
@@ -1,700 +0,0 @@
-/* Copyright (c) 1998-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-/* nscd - Name Service Cache Daemon. Caches passwd, group, and hosts. */
-
-#include <argp.h>
-#include <assert.h>
-#include <dirent.h>
-#include <errno.h>
-#include <error.h>
-#include <fcntl.h>
-#include <libintl.h>
-#include <locale.h>
-#include <paths.h>
-#include <pthread.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/socket.h>
-#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"
-#include "selinux.h"
-#include "../nss/nsswitch.h"
-#include <device-nrs.h>
-#ifdef HAVE_INOTIFY
-# include <sys/inotify.h>
-#endif
-#include <kernel-features.h>
-
-/* Get libc version number. */
-#include <version.h>
-
-#define PACKAGE _libc_intl_domainname
-
-int do_shutdown;
-int disabled_passwd;
-int disabled_group;
-
-typedef enum
-{
- /* Running in background as daemon. */
- RUN_DAEMONIZE,
- /* Running in foreground but otherwise behave like a daemon,
- i.e., detach from terminal and use syslog. This allows
- better integration with services like systemd. */
- RUN_FOREGROUND,
- /* Run in foreground in debug mode. */
- RUN_DEBUG
-} run_modes;
-
-static run_modes run_mode = RUN_DAEMONIZE;
-
-static const char *conffile = _PATH_NSCDCONF;
-
-time_t start_time;
-
-uintptr_t pagesize_m1;
-
-int paranoia;
-time_t restart_time;
-time_t restart_interval = RESTART_INTERVAL;
-const char *oldcwd;
-uid_t old_uid;
-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);
-void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
-
-/* Function to print some extra text in the help message. */
-static char *more_help (int key, const char *text, void *input);
-
-/* Definitions of arguments for argp functions. */
-static const struct argp_option options[] =
-{
- { "config-file", 'f', N_("NAME"), 0,
- N_("Read configuration data from NAME") },
- { "debug", 'd', NULL, 0,
- N_("Do not fork and display messages on the current tty") },
- { "foreground", 'F', NULL, 0,
- N_("Do not fork, but otherwise behave like a daemon") },
- { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
- { "shutdown", 'K', NULL, 0, N_("Shut the server down") },
- { "statistics", 'g', NULL, 0, N_("Print current configuration statistics") },
- { "invalidate", 'i', N_("TABLE"), 0,
- N_("Invalidate the specified cache") },
- { "secure", 'S', N_("TABLE,yes"), OPTION_HIDDEN,
- N_("Use separate cache for each user")},
- { NULL, 0, NULL, 0, NULL }
-};
-
-/* Short description of program. */
-static const char doc[] = N_("Name Service Cache Daemon.");
-
-/* Prototype for option handler. */
-static error_t parse_opt (int key, char *arg, struct argp_state *state);
-
-/* Data structure to communicate with argp functions. */
-static struct argp argp =
-{
- options, parse_opt, NULL, doc, NULL, more_help
-};
-
-/* True if only statistics are requested. */
-static bool get_stats;
-static int parent_fd = -1;
-
-int
-main (int argc, char **argv)
-{
- int remaining;
-
- /* Set locale via LC_ALL. */
- setlocale (LC_ALL, "");
- /* Set the text message domain. */
- textdomain (PACKAGE);
-
- /* Determine if the kernel has SELinux support. */
- nscd_selinux_enabled (&selinux_enabled);
-
- /* Parse and process arguments. */
- argp_parse (&argp, argc, argv, 0, &remaining, NULL);
-
- if (remaining != argc)
- {
- error (0, 0, gettext ("wrong number of arguments"));
- argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
- exit (1);
- }
-
- /* Read the configuration file. */
- if (nscd_parse_file (conffile, dbs) != 0)
- /* We couldn't read the configuration file. We don't start the
- server. */
- error (EXIT_FAILURE, 0,
- _("failure while reading configuration file; this is fatal"));
-
- /* Do we only get statistics? */
- if (get_stats)
- /* Does not return. */
- receive_print_stats ();
-
- /* Check if we are already running. */
- if (check_pid (_PATH_NSCDPID))
- error (EXIT_FAILURE, 0, _("already running"));
-
- /* Remember when we started. */
- start_time = time (NULL);
-
- /* Determine page size. */
- pagesize_m1 = getpagesize () - 1;
-
- if (run_mode == RUN_DAEMONIZE || run_mode == RUN_FOREGROUND)
- {
- int i;
- pid_t pid;
-
- /* 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)
- {
- /* 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);
- if (nullfd != -1)
- {
- struct stat64 st;
-
- if (fstat64 (nullfd, &st) == 0 && S_ISCHR (st.st_mode) != 0
-#if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
- && st.st_rdev == makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR)
-#endif
- )
- {
- /* It is the /dev/null special device alright. */
- (void) dup2 (nullfd, STDIN_FILENO);
- (void) dup2 (nullfd, STDOUT_FILENO);
- (void) dup2 (nullfd, STDERR_FILENO);
-
- if (nullfd > 2)
- close (nullfd);
- }
- else
- {
- /* Ugh, somebody is trying to play a trick on us. */
- close (nullfd);
- nullfd = -1;
- }
- }
- int min_close_fd = nullfd == -1 ? 0 : STDERR_FILENO + 1;
-
- DIR *d = opendir ("/proc/self/fd");
- if (d != NULL)
- {
- struct dirent64 *dirent;
- int dfdn = dirfd (d);
-
- while ((dirent = readdir64 (d)) != NULL)
- {
- char *endp;
- long int fdn = strtol (dirent->d_name, &endp, 10);
-
- if (*endp == '\0' && fdn != dfdn && fdn >= min_close_fd
- && fdn != parent_fd)
- close ((int) fdn);
- }
-
- closedir (d);
- }
- else
- for (i = min_close_fd; i < getdtablesize (); i++)
- if (i != parent_fd)
- close (i);
-
- setsid ();
-
- if (chdir ("/") != 0)
- do_exit (EXIT_FAILURE, errno,
- _("cannot change current working directory to \"/\""));
-
- openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
-
- if (write_pid (_PATH_NSCDPID) < 0)
- dbg_log ("%s: %s", _PATH_NSCDPID, strerror (errno));
-
- if (!init_logfile ())
- dbg_log (_("Could not create log file"));
-
- /* Ignore job control signals. */
- signal (SIGTTOU, SIG_IGN);
- signal (SIGTTIN, SIG_IGN);
- signal (SIGTSTP, SIG_IGN);
- }
- else
- /* In debug mode we are not paranoid. */
- paranoia = 0;
-
- signal (SIGINT, termination_handler);
- signal (SIGQUIT, termination_handler);
- signal (SIGTERM, termination_handler);
- signal (SIGPIPE, SIG_IGN);
-
- /* Cleanup files created by a previous 'bind'. */
- unlink (_PATH_NSCDSOCKET);
-
-#ifdef HAVE_INOTIFY
- /* Use inotify to recognize changed files. */
- inotify_fd = inotify_init1 (IN_NONBLOCK);
-# ifndef __ASSUME_IN_NONBLOCK
- if (inotify_fd == -1 && errno == ENOSYS)
- {
- inotify_fd = inotify_init ();
- if (inotify_fd != -1)
- fcntl (inotify_fd, F_SETFL, O_RDONLY | O_NONBLOCK);
- }
-# endif
-#endif
-
-#ifdef USE_NSCD
- /* Make sure we do not get recursive calls. */
- __nss_disable_nscd (register_traced_file);
-#endif
-
- /* Init databases. */
- nscd_init ();
-
- /* Start the SELinux AVC. */
- if (selinux_enabled)
- nscd_avc_init ();
-
- /* Handle incoming requests */
- start_threads ();
-
- return 0;
-}
-
-
-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)
-{
- switch (key)
- {
- case 'd':
- ++debug_level;
- run_mode = RUN_DEBUG;
- break;
-
- case 'F':
- run_mode = RUN_FOREGROUND;
- break;
-
- case 'f':
- conffile = arg;
- break;
-
- case 'K':
- if (getuid () != 0)
- error (4, 0, _("Only root is allowed to use this option!"));
- 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
- invalidate_db (arg);
- break;
-
- case 't':
- nthreads = atol (arg);
- break;
-
- case 'S':
- error (0, 0, _("secure services not implemented anymore"));
- break;
-
- default:
- return ARGP_ERR_UNKNOWN;
- }
-
- return 0;
-}
-
-/* Print bug-reporting information in the help message. */
-static char *
-more_help (int key, const char *text, void *input)
-{
- switch (key)
- {
- case ARGP_KEY_HELP_EXTRA:
- {
- /* We print some extra information. */
-
- char *tables = xstrdup (dbnames[0]);
- for (dbtype i = 1; i < lastdb; ++i)
- {
- 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;
- }
-
- 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;
- }
-
- default:
- break;
- }
-
- return (char *) text;
-}
-
-/* Print the version information. */
-static void
-print_version (FILE *stream, struct argp_state *state)
-{
- fprintf (stream, "nscd %s%s\n", PKGVERSION, VERSION);
- fprintf (stream, gettext ("\
-Copyright (C) %s Free Software Foundation, Inc.\n\
-This is free software; see the source for copying conditions. There is NO\n\
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
-"), "2017");
- fprintf (stream, gettext ("Written by %s.\n"),
- "Thorsten Kukuk and Ulrich Drepper");
-}
-
-
-/* Create a socket connected to a name. */
-int
-nscd_open_socket (void)
-{
- struct sockaddr_un addr;
- int sock;
-
- sock = socket (PF_UNIX, SOCK_STREAM, 0);
- if (sock < 0)
- return -1;
-
- addr.sun_family = AF_UNIX;
- assert (sizeof (addr.sun_path) >= sizeof (_PATH_NSCDSOCKET));
- strcpy (addr.sun_path, _PATH_NSCDSOCKET);
- if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
- {
- close (sock);
- return -1;
- }
-
- return sock;
-}
-
-
-/* Cleanup. */
-void
-termination_handler (int signum)
-{
- close_sockets ();
-
- /* Clean up the file created by 'bind'. */
- unlink (_PATH_NSCDSOCKET);
-
- /* Clean up pid file. */
- unlink (_PATH_NSCDPID);
-
- // XXX Terminate threads.
-
- /* Synchronize memory. */
- for (int cnt = 0; cnt < lastdb; ++cnt)
- {
- if (!dbs[cnt].enabled || dbs[cnt].head == NULL)
- continue;
-
- /* Make sure nobody keeps using the database. */
- dbs[cnt].head->timestamp = 0;
-
- if (dbs[cnt].persistent)
- // XXX async OK?
- msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
- }
-
- _exit (EXIT_SUCCESS);
-}
-
-/* Returns 1 if the process in pid file FILE is running, 0 if not. */
-static int
-check_pid (const char *file)
-{
- FILE *fp;
-
- fp = fopen (file, "r");
- if (fp)
- {
- pid_t pid;
- int n;
-
- n = fscanf (fp, "%d", &pid);
- fclose (fp);
-
- /* If we cannot parse the file default to assuming nscd runs.
- If the PID is alive, assume it is running. That all unless
- the PID is the same as the current process' since tha latter
- can mean we re-exec. */
- if ((n != 1 || kill (pid, 0) == 0) && pid != getpid ())
- return 1;
- }
-
- return 0;
-}
-
-/* Write the current process id to the file FILE.
- Returns 0 if successful, -1 if not. */
-static int
-write_pid (const char *file)
-{
- FILE *fp;
-
- fp = fopen (file, "w");
- if (fp == NULL)
- return -1;
-
- fprintf (fp, "%d\n", getpid ());
-
- int result = fflush (fp) || ferror (fp) ? -1 : 0;
-
- fclose (fp);
-
- 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 __attribute__ ((unused));
- 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 __attribute__ ((unused));
- 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.conf b/nscd/nscd.conf
deleted file mode 100644
index 39b875912d..0000000000
--- a/nscd/nscd.conf
+++ /dev/null
@@ -1,88 +0,0 @@
-#
-# /etc/nscd.conf
-#
-# An example Name Service Cache config file. This file is needed by nscd.
-#
-# Legal entries are:
-#
-# logfile <file>
-# debug-level <level>
-# threads <initial #threads to use>
-# max-threads <maximum #threads to use>
-# server-user <user to run server as instead of root>
-# server-user is ignored if nscd is started with -S parameters
-# stat-user <user who is allowed to request statistics>
-# reload-count unlimited|<number>
-# paranoia <yes|no>
-# restart-interval <time in seconds>
-#
-# enable-cache <service> <yes|no>
-# positive-time-to-live <service> <time in seconds>
-# negative-time-to-live <service> <time in seconds>
-# suggested-size <service> <prime number>
-# check-files <service> <yes|no>
-# persistent <service> <yes|no>
-# shared <service> <yes|no>
-# max-db-size <service> <number bytes>
-# auto-propagate <service> <yes|no>
-#
-# Currently supported cache names (services): passwd, group, hosts, services
-#
-
-
-# logfile /var/log/nscd.log
-# threads 4
-# max-threads 32
-# server-user nobody
-# stat-user somebody
- debug-level 0
-# reload-count 5
- paranoia no
-# restart-interval 3600
-
- enable-cache passwd yes
- positive-time-to-live passwd 600
- negative-time-to-live passwd 20
- suggested-size passwd 211
- check-files passwd yes
- persistent passwd yes
- shared passwd yes
- max-db-size passwd 33554432
- auto-propagate passwd yes
-
- enable-cache group yes
- positive-time-to-live group 3600
- negative-time-to-live group 60
- suggested-size group 211
- check-files group yes
- persistent group yes
- shared group yes
- max-db-size group 33554432
- auto-propagate group yes
-
- enable-cache hosts yes
- positive-time-to-live hosts 3600
- negative-time-to-live hosts 20
- suggested-size hosts 211
- check-files hosts yes
- persistent hosts yes
- shared hosts yes
- max-db-size hosts 33554432
-
- enable-cache services yes
- positive-time-to-live services 28800
- negative-time-to-live services 20
- suggested-size services 211
- check-files services yes
- persistent services yes
- shared services yes
- max-db-size services 33554432
-
- enable-cache netgroup yes
- positive-time-to-live netgroup 28800
- negative-time-to-live netgroup 20
- suggested-size netgroup 211
- check-files netgroup yes
- persistent netgroup yes
- shared netgroup yes
- max-db-size netgroup 33554432
diff --git a/nscd/nscd.h b/nscd/nscd.h
deleted file mode 100644
index c6b0a3c836..0000000000
--- a/nscd/nscd.h
+++ /dev/null
@@ -1,377 +0,0 @@
-/* Copyright (c) 1998-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-#ifndef _NSCD_H
-#define _NSCD_H 1
-
-#include <pthread.h>
-#include <stdbool.h>
-#include <time.h>
-#include <sys/uio.h>
-
-/* The declarations for the request and response types are in the file
- "nscd-client.h", which should contain everything needed by client
- functions. */
-#include "nscd-client.h"
-
-
-/* Handle databases. */
-typedef enum
-{
- pwddb,
- grpdb,
- hstdb,
- servdb,
- netgrdb,
- lastdb
-} dbtype;
-
-
-/* Default limit on the number of times a value gets reloaded without
- being used in the meantime. NSCD does not throw a value out as
- soon as it times out. It tries to reload the value from the
- server. Only if the value has not been used for so many rounds it
- is removed. */
-#define DEFAULT_RELOAD_LIMIT 5
-
-
-/* Time before restarting the process in paranoia mode. */
-#define RESTART_INTERVAL (60 * 60)
-
-
-/* Stack size for worker threads. */
-#define NSCD_THREAD_STACKSIZE 1024 * 1024 * (sizeof (void *) / 4)
-
-/* Maximum size of stack frames we allow the thread to use. We use
- 80% of the thread stack size. */
-#define MAX_STACK_USE ((8 * NSCD_THREAD_STACKSIZE) / 10)
-
-/* 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;
- /* 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
-{
- pthread_rwlock_t lock;
- pthread_cond_t prune_cond;
- pthread_mutex_t prune_lock;
- pthread_mutex_t prune_run_lock;
- time_t wakeup_time;
-
- int enabled;
- int check_file;
- int clear_cache;
- int persistent;
- int shared;
- int propagate;
- struct traced_file *traced_files;
- const char *db_filename;
- size_t suggested_module;
- size_t max_db_size;
-
- unsigned long int postimeout; /* In seconds. */
- unsigned long int negtimeout; /* In seconds. */
-
- int wr_fd; /* Writable file descriptor. */
- int ro_fd; /* Unwritable file descriptor. */
-
- const struct iovec *disabled_iov;
-
- struct database_pers_head *head;
- char *data;
- size_t memsize;
- pthread_mutex_t memlock;
- bool mmap_used;
- bool last_alloc_failed;
-};
-
-
-/* Paths of the file for the persistent storage. */
-#define _PATH_NSCD_PASSWD_DB "/var/db/nscd/passwd"
-#define _PATH_NSCD_GROUP_DB "/var/db/nscd/group"
-#define _PATH_NSCD_HOSTS_DB "/var/db/nscd/hosts"
-#define _PATH_NSCD_SERVICES_DB "/var/db/nscd/services"
-#define _PATH_NSCD_NETGROUP_DB "/var/db/nscd/netgroup"
-
-/* Path used when not using persistent storage. */
-#define _PATH_NSCD_XYZ_DB_TMP "/var/run/nscd/dbXXXXXX"
-
-/* Maximum alignment requirement we will encounter. */
-#define BLOCK_ALIGN_LOG 3
-#define BLOCK_ALIGN (1 << BLOCK_ALIGN_LOG)
-#define BLOCK_ALIGN_M1 (BLOCK_ALIGN - 1)
-
-/* Default value for the maximum size of the database files. */
-#define DEFAULT_MAX_DB_SIZE (32 * 1024 * 1024)
-
-/* Number of bytes of data we initially reserve for each hash table bucket. */
-#define DEFAULT_DATASIZE_PER_BUCKET 1024
-
-/* Default module of hash table. */
-#define DEFAULT_SUGGESTED_MODULE 211
-
-
-/* Number of seconds between two cache pruning runs if we do not have
- better information when it is really needed. */
-#define CACHE_PRUNE_INTERVAL 15
-
-
-/* Global variables. */
-extern struct database_dyn dbs[lastdb] attribute_hidden;
-extern const char *const dbnames[lastdb];
-extern const char *const serv2str[LASTREQ];
-
-extern const struct iovec pwd_iov_disabled;
-extern const struct iovec grp_iov_disabled;
-extern const struct iovec hst_iov_disabled;
-extern const struct iovec serv_iov_disabled;
-extern const struct iovec netgroup_iov_disabled;
-
-
-/* Initial number of threads to run. */
-extern int nthreads;
-/* Maximum number of threads to use. */
-extern int max_nthreads;
-
-/* Inotify descriptor. */
-extern int inotify_fd;
-
-/* User name to run server processes as. */
-extern const char *server_user;
-
-/* Name and UID of user who is allowed to request statistics. */
-extern const char *stat_user;
-extern uid_t stat_uid;
-
-/* Time the server was started. */
-extern time_t start_time;
-
-/* Number of times clients had to wait. */
-extern unsigned long int client_queued;
-
-/* Maximum needed alignment. */
-extern const size_t block_align;
-
-/* Number of times a value is reloaded without being used. UINT_MAX
- means unlimited. */
-extern unsigned int reload_count;
-
-/* Pagesize minus one. */
-extern uintptr_t pagesize_m1;
-
-/* Nonzero if paranoia mode is enabled. */
-extern int paranoia;
-/* Time after which the process restarts. */
-extern time_t restart_time;
-/* How much time between restarts. */
-extern time_t restart_interval;
-/* Old current working directory. */
-extern const char *oldcwd;
-/* Old user and group ID. */
-extern uid_t old_uid;
-extern gid_t old_gid;
-
-
-/* Prototypes for global functions. */
-
-/* Wrapper functions with error checking for standard functions. */
-#include <programs/xmalloc.h>
-
-/* 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__));
-
-/* nscd_conf.c */
-extern int nscd_parse_file (const char *fname,
- struct database_dyn dbs[lastdb]);
-
-/* nscd_stat.c */
-extern void send_stats (int fd, struct database_dyn dbs[lastdb]);
-extern int receive_print_stats (void) __attribute__ ((__noreturn__));
-
-/* cache.c */
-extern struct datahead *cache_search (request_type, const void *key,
- size_t len, struct database_dyn *table,
- uid_t owner);
-extern int 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);
-extern time_t prune_cache (struct database_dyn *table, time_t now, int fd);
-
-/* pwdcache.c */
-extern void addpwbyname (struct database_dyn *db, int fd, request_header *req,
- void *key, uid_t uid);
-extern void addpwbyuid (struct database_dyn *db, int fd, request_header *req,
- void *key, uid_t uid);
-extern time_t readdpwbyname (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh);
-extern time_t readdpwbyuid (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh);
-
-/* grpcache.c */
-extern void addgrbyname (struct database_dyn *db, int fd, request_header *req,
- void *key, uid_t uid);
-extern void addgrbygid (struct database_dyn *db, int fd, request_header *req,
- void *key, uid_t uid);
-extern time_t readdgrbyname (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh);
-extern time_t readdgrbygid (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh);
-
-/* hstcache.c */
-extern void addhstbyname (struct database_dyn *db, int fd, request_header *req,
- void *key, uid_t uid);
-extern void addhstbyaddr (struct database_dyn *db, int fd, request_header *req,
- void *key, uid_t uid);
-extern void addhstbynamev6 (struct database_dyn *db, int fd,
- request_header *req, void *key, uid_t uid);
-extern void addhstbyaddrv6 (struct database_dyn *db, int fd,
- request_header *req, void *key, uid_t uid);
-extern time_t readdhstbyname (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh);
-extern time_t readdhstbyaddr (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh);
-extern time_t readdhstbynamev6 (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh);
-extern time_t readdhstbyaddrv6 (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh);
-
-/* aicache.c */
-extern void addhstai (struct database_dyn *db, int fd, request_header *req,
- void *key, uid_t uid);
-extern time_t readdhstai (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh);
-
-
-/* initgrcache.c */
-extern void addinitgroups (struct database_dyn *db, int fd,
- request_header *req, void *key, uid_t uid);
-extern time_t readdinitgroups (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh);
-
-/* servicecache.c */
-extern void addservbyname (struct database_dyn *db, int fd,
- request_header *req, void *key, uid_t uid);
-extern time_t readdservbyname (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh);
-extern void addservbyport (struct database_dyn *db, int fd,
- request_header *req, void *key, uid_t uid);
-extern time_t readdservbyport (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh);
-
-/* netgroupcache.c */
-extern void addinnetgr (struct database_dyn *db, int fd, request_header *req,
- void *key, uid_t uid);
-extern time_t readdinnetgr (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh);
-extern void addgetnetgrent (struct database_dyn *db, int fd,
- request_header *req, void *key, uid_t uid);
-extern time_t readdgetnetgrent (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh);
-
-/* mem.c */
-extern void *mempool_alloc (struct database_dyn *db, size_t len,
- int data_alloc);
-extern void gc (struct database_dyn *db);
-
-
-/* nscd_setup_thread.c */
-extern int setup_thread (struct database_dyn *db);
-
-
-/* Special version of TEMP_FAILURE_RETRY for functions returning error
- values. */
-#define TEMP_FAILURE_RETRY_VAL(expression) \
- (__extension__ \
- ({ long int __result; \
- do __result = (long int) (expression); \
- while (__result == EINTR); \
- __result; }))
-
-#endif /* nscd.h */
diff --git a/nscd/nscd.init b/nscd/nscd.init
deleted file mode 100644
index a882da7d8b..0000000000
--- a/nscd/nscd.init
+++ /dev/null
@@ -1,116 +0,0 @@
-#!/bin/bash
-#
-# nscd: Starts the Name Switch Cache Daemon
-#
-# chkconfig: - 30 74
-# description: This is a daemon which handles passwd and group lookups \
-# for running programs and cache the results for the next \
-# query. You should start this daemon if you use \
-# slow naming services like NIS, NIS+, LDAP, or hesiod.
-# processname: /usr/sbin/nscd
-# config: /etc/nscd.conf
-#
-### BEGIN INIT INFO
-# Provides: nscd
-# Required-Start: $syslog
-# Default-Stop: 0 1 6
-# Short-Description: Starts the Name Switch Cache Daemon
-# Description: This is a daemon which handles passwd and group lookups \
-# for running programs and cache the results for the next \
-# query. You should start this daemon if you use \
-# slow naming services like NIS, NIS+, LDAP, or hesiod.
-### END INIT INFO
-
-# Sanity checks.
-[ -f /etc/nscd.conf ] || exit 0
-[ -x /usr/sbin/nscd ] || exit 0
-
-# Source function library.
-. /etc/init.d/functions
-
-# nscd does not run on any kernel lower than 2.2.0 because of threading
-# problems, so we require that in first place.
-case $(uname -r) in
- 2.[2-9].*)
- # this is okay
- ;;
- [3-9]*)
- # these are of course also okay
- ;;
- *)
- #this is not
- exit 1
- ;;
-esac
-
-RETVAL=0
-prog=nscd
-
-start () {
- [ -d /var/run/nscd ] || mkdir /var/run/nscd
- [ -d /var/db/nscd ] || mkdir /var/db/nscd
- echo -n $"Starting $prog: "
- daemon /usr/sbin/nscd
- RETVAL=$?
- echo
- [ $RETVAL -eq 0 ] && touch /var/lock/subsys/nscd
- return $RETVAL
-}
-
-stop () {
- echo -n $"Stopping $prog: "
- /usr/sbin/nscd -K
- RETVAL=$?
- if [ $RETVAL -eq 0 ]; then
- rm -f /var/lock/subsys/nscd
- # nscd won't be able to remove these if it is running as
- # a non-privileged user
- rm -f /var/run/nscd/nscd.pid
- rm -f /var/run/nscd/socket
- success $"$prog shutdown"
- else
- failure $"$prog shutdown"
- fi
- echo
- return $RETVAL
-}
-
-restart() {
- stop
- start
-}
-
-# See how we were called.
-case "$1" in
- start)
- start
- RETVAL=$?
- ;;
- stop)
- stop
- RETVAL=$?
- ;;
- status)
- status nscd
- RETVAL=$?
- ;;
- restart)
- restart
- RETVAL=$?
- ;;
- try-restart | condrestart)
- [ -e /var/lock/subsys/nscd ] && restart
- RETVAL=$?
- ;;
- force-reload | reload)
- echo -n $"Reloading $prog: "
- killproc /usr/sbin/nscd -HUP
- RETVAL=$?
- echo
- ;;
- *)
- echo $"Usage: $0 {start|stop|status|restart|reload|condrestart}"
- RETVAL=1
- ;;
-esac
-exit $RETVAL
diff --git a/nscd/nscd.service b/nscd/nscd.service
deleted file mode 100644
index ab38e8f982..0000000000
--- a/nscd/nscd.service
+++ /dev/null
@@ -1,19 +0,0 @@
-# systemd service file for nscd
-
-[Unit]
-Description=Name Service Cache Daemon
-
-[Service]
-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
-
-[Install]
-WantedBy=multi-user.target
diff --git a/nscd/nscd.tmpfiles b/nscd/nscd.tmpfiles
deleted file mode 100644
index 52edbba673..0000000000
--- a/nscd/nscd.tmpfiles
+++ /dev/null
@@ -1,4 +0,0 @@
-# Configuration to create /run/nscd directory
-# Used as part of systemd's tmpfiles
-
-d /run/nscd 0755 root root
diff --git a/nscd/nscd_conf.c b/nscd/nscd_conf.c
deleted file mode 100644
index 9c301ad73d..0000000000
--- a/nscd/nscd_conf.c
+++ /dev/null
@@ -1,315 +0,0 @@
-/* Copyright (c) 1998-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#include <ctype.h>
-#include <errno.h>
-#include <error.h>
-#include <libintl.h>
-#include <malloc.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdio_ext.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/param.h>
-#include <sys/types.h>
-
-#include "dbg_log.h"
-#include "nscd.h"
-
-
-/* Names of the databases. */
-const char *const dbnames[lastdb] =
-{
- [pwddb] = "passwd",
- [grpdb] = "group",
- [hstdb] = "hosts",
- [servdb] = "services",
- [netgrdb] = "netgroup"
-};
-
-
-static int
-find_db (const char *name)
-{
- for (int cnt = 0; cnt < lastdb; ++cnt)
- if (strcmp (name, dbnames[cnt]) == 0)
- return cnt;
-
- error (0, 0, _("database %s is not supported"), name);
- return -1;
-}
-
-int
-nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb])
-{
- FILE *fp;
- char *line, *cp, *entry, *arg1, *arg2;
- size_t len;
- int cnt;
- const unsigned int initial_error_message_count = error_message_count;
-
- /* Open the configuration file. */
- fp = fopen (fname, "r");
- if (fp == NULL)
- return -1;
-
- /* The stream is not used by more than one thread. */
- (void) __fsetlocking (fp, FSETLOCKING_BYCALLER);
-
- line = NULL;
- len = 0;
-
- do
- {
- ssize_t n = getline (&line, &len, fp);
- if (n < 0)
- break;
- if (line[n - 1] == '\n')
- line[n - 1] = '\0';
-
- /* Because the file format does not know any form of quoting we
- can search forward for the next '#' character and if found
- make it terminating the line. */
- *strchrnul (line, '#') = '\0';
-
- /* If the line is blank it is ignored. */
- if (line[0] == '\0')
- continue;
-
- entry = line;
- while (isspace (*entry) && *entry != '\0')
- ++entry;
- cp = entry;
- while (!isspace (*cp) && *cp != '\0')
- ++cp;
- arg1 = cp;
- ++arg1;
- *cp = '\0';
- if (strlen (entry) == 0)
- error (0, 0, _("Parse error: %s"), line);
- while (isspace (*arg1) && *arg1 != '\0')
- ++arg1;
- cp = arg1;
- while (!isspace (*cp) && *cp != '\0')
- ++cp;
- arg2 = cp;
- ++arg2;
- *cp = '\0';
- if (strlen (arg2) > 0)
- {
- while (isspace (*arg2) && *arg2 != '\0')
- ++arg2;
- cp = arg2;
- while (!isspace (*cp) && *cp != '\0')
- ++cp;
- *cp = '\0';
- }
-
- if (strcmp (entry, "positive-time-to-live") == 0)
- {
- int idx = find_db (arg1);
- if (idx >= 0)
- dbs[idx].postimeout = atol (arg2);
- }
- else if (strcmp (entry, "negative-time-to-live") == 0)
- {
- int idx = find_db (arg1);
- if (idx >= 0)
- dbs[idx].negtimeout = atol (arg2);
- }
- else if (strcmp (entry, "suggested-size") == 0)
- {
- int idx = find_db (arg1);
- if (idx >= 0)
- dbs[idx].suggested_module
- = atol (arg2) ?: DEFAULT_SUGGESTED_MODULE;
- }
- else if (strcmp (entry, "enable-cache") == 0)
- {
- int idx = find_db (arg1);
- if (idx >= 0)
- {
- if (strcmp (arg2, "no") == 0)
- dbs[idx].enabled = 0;
- else if (strcmp (arg2, "yes") == 0)
- dbs[idx].enabled = 1;
- }
- }
- else if (strcmp (entry, "check-files") == 0)
- {
- int idx = find_db (arg1);
- if (idx >= 0)
- {
- if (strcmp (arg2, "no") == 0)
- dbs[idx].check_file = 0;
- else if (strcmp (arg2, "yes") == 0)
- dbs[idx].check_file = 1;
- }
- }
- else if (strcmp (entry, "max-db-size") == 0)
- {
- int idx = find_db (arg1);
- if (idx >= 0)
- dbs[idx].max_db_size = atol (arg2) ?: DEFAULT_MAX_DB_SIZE;
- }
- else if (strcmp (entry, "logfile") == 0)
- set_logfile (arg1);
- else if (strcmp (entry, "debug-level") == 0)
- {
- int level = atoi (arg1);
- if (level > 0)
- debug_level = level;
- }
- else if (strcmp (entry, "threads") == 0)
- {
- if (nthreads == -1)
- nthreads = MAX (atol (arg1), lastdb);
- }
- else if (strcmp (entry, "max-threads") == 0)
- {
- max_nthreads = MAX (atol (arg1), lastdb);
- }
- else if (strcmp (entry, "server-user") == 0)
- {
- if (!arg1)
- error (0, 0, _("Must specify user name for server-user option"));
- else
- server_user = xstrdup (arg1);
- }
- else if (strcmp (entry, "stat-user") == 0)
- {
- if (arg1 == NULL)
- error (0, 0, _("Must specify user name for stat-user option"));
- else
- {
- stat_user = xstrdup (arg1);
-
- struct passwd *pw = getpwnam (stat_user);
- if (pw != NULL)
- stat_uid = pw->pw_uid;
- }
- }
- else if (strcmp (entry, "persistent") == 0)
- {
- int idx = find_db (arg1);
- if (idx >= 0)
- {
- if (strcmp (arg2, "no") == 0)
- dbs[idx].persistent = 0;
- else if (strcmp (arg2, "yes") == 0)
- dbs[idx].persistent = 1;
- }
- }
- else if (strcmp (entry, "shared") == 0)
- {
- int idx = find_db (arg1);
- if (idx >= 0)
- {
- if (strcmp (arg2, "no") == 0)
- dbs[idx].shared = 0;
- else if (strcmp (arg2, "yes") == 0)
- dbs[idx].shared = 1;
- }
- }
- else if (strcmp (entry, "reload-count") == 0)
- {
- if (strcasecmp (arg1, "unlimited") == 0)
- reload_count = UINT_MAX;
- else
- {
- unsigned long int count = strtoul (arg1, NULL, 0);
- if (count > UINT8_MAX - 1)
- reload_count = UINT_MAX;
- else
- reload_count = count;
- }
- }
- else if (strcmp (entry, "paranoia") == 0)
- {
- if (strcmp (arg1, "no") == 0)
- paranoia = 0;
- else if (strcmp (arg1, "yes") == 0)
- paranoia = 1;
- }
- else if (strcmp (entry, "restart-interval") == 0)
- {
- if (arg1 != NULL)
- restart_interval = atol (arg1);
- else
- error (0, 0, _("Must specify value for restart-interval option"));
- }
- else if (strcmp (entry, "auto-propagate") == 0)
- {
- int idx = find_db (arg1);
- if (idx >= 0)
- {
- if (strcmp (arg2, "no") == 0)
- dbs[idx].propagate = 0;
- else if (strcmp (arg2, "yes") == 0)
- dbs[idx].propagate = 1;
- }
- }
- else
- error (0, 0, _("Unknown option: %s %s %s"), entry, arg1, arg2);
- }
- while (!feof_unlocked (fp));
-
- if (paranoia)
- {
- restart_time = time (NULL) + restart_interval;
-
- /* Save the old current workding directory if we are in paranoia
- mode. We have to change back to it. */
- oldcwd = get_current_dir_name ();
- if (oldcwd == NULL)
- {
- error (0, 0, _("\
-cannot get current working directory: %s; disabling paranoia mode"),
- strerror (errno));
- paranoia = 0;
- }
- }
-
- /* Enforce sanity. */
- if (max_nthreads < nthreads)
- max_nthreads = nthreads;
-
- for (cnt = 0; cnt < lastdb; ++cnt)
- {
- size_t datasize = (sizeof (struct database_pers_head)
- + roundup (dbs[cnt].suggested_module
- * sizeof (ref_t), ALIGN)
- + (dbs[cnt].suggested_module
- * DEFAULT_DATASIZE_PER_BUCKET));
- if (datasize > dbs[cnt].max_db_size)
- {
- error (0, 0, _("maximum file size for %s database too small"),
- dbnames[cnt]);
- dbs[cnt].max_db_size = datasize;
- }
-
- }
-
- /* Free the buffer. */
- free (line);
- /* Close configuration file. */
- fclose (fp);
-
- return error_message_count != initial_error_message_count;
-}
diff --git a/nscd/nscd_getai.c b/nscd/nscd_getai.c
deleted file mode 100644
index daaf6d68b2..0000000000
--- a/nscd/nscd_getai.c
+++ /dev/null
@@ -1,216 +0,0 @@
-/* Copyright (C) 2004-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-#include <assert.h>
-#include <errno.h>
-#include <netdb.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <not-cancel.h>
-
-#include "nscd-client.h"
-#include "nscd_proto.h"
-
-
-/* Define in nscd_gethst_r.c. */
-extern int __nss_not_use_nscd_hosts;
-
-
-/* We use the mapping from nscd_gethst. */
-libc_locked_map_ptr (extern, __hst_map_handle) attribute_hidden;
-
-/* Defined in nscd_gethst_r.c. */
-extern int __nss_have_localdomain attribute_hidden;
-
-
-int
-__nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop)
-{
- if (__glibc_unlikely (__nss_have_localdomain >= 0))
- {
- if (__nss_have_localdomain == 0)
- __nss_have_localdomain = getenv ("LOCALDOMAIN") != NULL ? 1 : -1;
- if (__nss_have_localdomain > 0)
- {
- __nss_not_use_nscd_hosts = 1;
- return -1;
- }
- }
-
- size_t keylen = strlen (key) + 1;
- int gc_cycle;
- int nretries = 0;
-
- /* If the mapping is available, try to search there instead of
- communicating with the nscd. */
- struct mapped_database *mapped;
- mapped = __nscd_get_map_ref (GETFDHST, "hosts", &__hst_map_handle,
- &gc_cycle);
-
- retry:;
- struct nscd_ai_result *resultbuf = NULL;
- const char *recend = (const char *) ~UINTMAX_C (0);
- char *respdata = NULL;
- int retval = -1;
- int sock = -1;
- ai_response_header ai_resp;
-
- if (mapped != NO_MAPPING)
- {
- struct datahead *found = __nscd_cache_search (GETAI, key, keylen,
- mapped, sizeof ai_resp);
- if (found != NULL)
- {
- respdata = (char *) (&found->data[0].aidata + 1);
- ai_resp = found->data[0].aidata;
- recend = (const char *) found->data + found->recsize;
- /* Now check if we can trust ai_resp fields. If GC is
- in progress, it can contain anything. */
- if (mapped->head->gc_cycle != gc_cycle)
- {
- retval = -2;
- goto out;
- }
- }
- }
-
- /* If we do not have the cache mapped, try to get the data over the
- socket. */
- if (respdata == NULL)
- {
- sock = __nscd_open_socket (key, keylen, GETAI, &ai_resp,
- sizeof (ai_resp));
- if (sock == -1)
- {
- /* nscd not running or wrong version. */
- __nss_not_use_nscd_hosts = 1;
- goto out;
- }
- }
-
- if (ai_resp.found == 1)
- {
- size_t datalen = ai_resp.naddrs + ai_resp.addrslen + ai_resp.canonlen;
-
- /* This check really only affects the case where the data
- comes from the mapped cache. */
- if (respdata + datalen > recend)
- {
- assert (sock == -1);
- goto out;
- }
-
- /* Create result. */
- resultbuf = (struct nscd_ai_result *) malloc (sizeof (*resultbuf)
- + datalen);
- if (resultbuf == NULL)
- {
- *h_errnop = NETDB_INTERNAL;
- goto out_close;
- }
-
- /* Set up the data structure, including pointers. */
- resultbuf->naddrs = ai_resp.naddrs;
- resultbuf->addrs = (char *) (resultbuf + 1);
- resultbuf->family = (uint8_t *) (resultbuf->addrs + ai_resp.addrslen);
- if (ai_resp.canonlen != 0)
- resultbuf->canon = (char *) (resultbuf->family + resultbuf->naddrs);
- else
- resultbuf->canon = NULL;
-
- if (respdata == NULL)
- {
- /* Read the data from the socket. */
- if ((size_t) __readall (sock, resultbuf + 1, datalen) == datalen)
- {
- retval = 0;
- *result = resultbuf;
- }
- else
- {
- free (resultbuf);
- *h_errnop = NETDB_INTERNAL;
- }
- }
- else
- {
- /* Copy the data in the block. */
- memcpy (resultbuf + 1, respdata, datalen);
-
- /* Try to detect corrupt databases. */
- if (resultbuf->canon != NULL
- && resultbuf->canon[ai_resp.canonlen - 1] != '\0')
- /* We cannot use the database. */
- {
- if (mapped->head->gc_cycle != gc_cycle)
- retval = -2;
- else
- free (resultbuf);
- goto out_close;
- }
-
- retval = 0;
- *result = resultbuf;
- }
- }
- else
- {
- if (__glibc_unlikely (ai_resp.found == -1))
- {
- /* The daemon does not cache this database. */
- __nss_not_use_nscd_hosts = 1;
- goto out_close;
- }
-
- /* Store the error number. */
- *h_errnop = ai_resp.error;
-
- /* Set errno to 0 to indicate no error, just no found record. */
- __set_errno (0);
- /* Even though we have not found anything, the result is zero. */
- retval = 0;
- }
-
- out_close:
- if (sock != -1)
- close_not_cancel_no_status (sock);
- out:
- if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
- {
- /* When we come here this means there has been a GC cycle while we
- were looking for the data. This means the data might have been
- inconsistent. Retry if possible. */
- if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
- {
- /* nscd is just running gc now. Disable using the mapping. */
- if (atomic_decrement_val (&mapped->counter) == 0)
- __nscd_unmap (mapped);
- mapped = NO_MAPPING;
- }
-
- if (retval != -1)
- {
- *result = NULL;
- free (resultbuf);
- goto retry;
- }
- }
-
- return retval;
-}
diff --git a/nscd/nscd_getgr_r.c b/nscd/nscd_getgr_r.c
deleted file mode 100644
index 87b4552197..0000000000
--- a/nscd/nscd_getgr_r.c
+++ /dev/null
@@ -1,330 +0,0 @@
-/* Copyright (C) 1998-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1998.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-#include <alloca.h>
-#include <assert.h>
-#include <errno.h>
-#include <grp.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-#include <sys/un.h>
-#include <not-cancel.h>
-#include <_itoa.h>
-#include <scratch_buffer.h>
-
-#include "nscd-client.h"
-#include "nscd_proto.h"
-
-int __nss_not_use_nscd_group;
-
-static int nscd_getgr_r (const char *key, size_t keylen, request_type type,
- struct group *resultbuf, char *buffer,
- size_t buflen, struct group **result)
- internal_function;
-
-
-int
-__nscd_getgrnam_r (const char *name, struct group *resultbuf, char *buffer,
- size_t buflen, struct group **result)
-{
- return nscd_getgr_r (name, strlen (name) + 1, GETGRBYNAME, resultbuf,
- buffer, buflen, result);
-}
-
-
-int
-__nscd_getgrgid_r (gid_t gid, struct group *resultbuf, char *buffer,
- size_t buflen, struct group **result)
-{
- char buf[3 * sizeof (gid_t)];
- buf[sizeof (buf) - 1] = '\0';
- char *cp = _itoa_word (gid, buf + sizeof (buf) - 1, 10, 0);
-
- return nscd_getgr_r (cp, buf + sizeof (buf) - cp, GETGRBYGID, resultbuf,
- buffer, buflen, result);
-}
-
-
-libc_locked_map_ptr (,__gr_map_handle) attribute_hidden;
-/* Note that we only free the structure if necessary. The memory
- mapping is not removed since it is not visible to the malloc
- handling. */
-libc_freeres_fn (gr_map_free)
-{
- if (__gr_map_handle.mapped != NO_MAPPING)
- {
- void *p = __gr_map_handle.mapped;
- __gr_map_handle.mapped = NO_MAPPING;
- free (p);
- }
-}
-
-
-static int
-internal_function
-nscd_getgr_r (const char *key, size_t keylen, request_type type,
- struct group *resultbuf, char *buffer, size_t buflen,
- struct group **result)
-{
- int gc_cycle;
- int nretries = 0;
- const uint32_t *len = NULL;
- struct scratch_buffer lenbuf;
- scratch_buffer_init (&lenbuf);
-
- /* If the mapping is available, try to search there instead of
- communicating with the nscd. */
- struct mapped_database *mapped = __nscd_get_map_ref (GETFDGR, "group",
- &__gr_map_handle,
- &gc_cycle);
- retry:;
- const char *gr_name = NULL;
- size_t gr_name_len = 0;
- int retval = -1;
- const char *recend = (const char *) ~UINTMAX_C (0);
- gr_response_header gr_resp;
-
- if (mapped != NO_MAPPING)
- {
- struct datahead *found = __nscd_cache_search (type, key, keylen, mapped,
- sizeof gr_resp);
- if (found != NULL)
- {
- len = (const uint32_t *) (&found->data[0].grdata + 1);
- gr_resp = found->data[0].grdata;
- gr_name = ((const char *) len
- + gr_resp.gr_mem_cnt * sizeof (uint32_t));
- gr_name_len = gr_resp.gr_name_len + gr_resp.gr_passwd_len;
- recend = (const char *) found->data + found->recsize;
- /* Now check if we can trust gr_resp fields. If GC is
- in progress, it can contain anything. */
- if (mapped->head->gc_cycle != gc_cycle)
- {
- retval = -2;
- goto out;
- }
-
- /* The alignment is always sufficient, unless GC is in progress. */
- assert (((uintptr_t) len & (__alignof__ (*len) - 1)) == 0);
- }
- }
-
- int sock = -1;
- if (gr_name == NULL)
- {
- sock = __nscd_open_socket (key, keylen, type, &gr_resp,
- sizeof (gr_resp));
- if (sock == -1)
- {
- __nss_not_use_nscd_group = 1;
- goto out;
- }
- }
-
- /* No value found so far. */
- *result = NULL;
-
- if (__glibc_unlikely (gr_resp.found == -1))
- {
- /* The daemon does not cache this database. */
- __nss_not_use_nscd_group = 1;
- goto out_close;
- }
-
- if (gr_resp.found == 1)
- {
- struct iovec vec[2];
- char *p = buffer;
- size_t total_len;
- uintptr_t align;
- nscd_ssize_t cnt;
-
- /* Now allocate the buffer the array for the group members. We must
- align the pointer. */
- align = ((__alignof__ (char *) - (p - ((char *) 0)))
- & (__alignof__ (char *) - 1));
- total_len = (align + (1 + gr_resp.gr_mem_cnt) * sizeof (char *)
- + gr_resp.gr_name_len + gr_resp.gr_passwd_len);
- if (__glibc_unlikely (buflen < total_len))
- {
- no_room:
- __set_errno (ERANGE);
- retval = ERANGE;
- goto out_close;
- }
- buflen -= total_len;
-
- p += align;
- resultbuf->gr_mem = (char **) p;
- p += (1 + gr_resp.gr_mem_cnt) * sizeof (char *);
-
- /* Set pointers for strings. */
- resultbuf->gr_name = p;
- p += gr_resp.gr_name_len;
- resultbuf->gr_passwd = p;
- p += gr_resp.gr_passwd_len;
-
- /* Fill in what we know now. */
- resultbuf->gr_gid = gr_resp.gr_gid;
-
- /* Read the length information, group name, and password. */
- if (gr_name == NULL)
- {
- /* Handle a simple, usual case: no group members. */
- 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)
- != (ssize_t) n, 0))
- goto out_close;
- }
- else
- {
- /* Allocate array to store lengths. */
- 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);
- vec[1].iov_base = resultbuf->gr_name;
- vec[1].iov_len = gr_resp.gr_name_len + gr_resp.gr_passwd_len;
- total_len = vec[0].iov_len + vec[1].iov_len;
-
- /* Get this data. */
- size_t n = __readvall (sock, vec, 2);
- if (__glibc_unlikely (n != total_len))
- goto out_close;
- }
- }
- else
- /* We already have the data. Just copy the group name and
- password. */
- memcpy (resultbuf->gr_name, gr_name,
- gr_resp.gr_name_len + gr_resp.gr_passwd_len);
-
- /* Clear the terminating entry. */
- resultbuf->gr_mem[gr_resp.gr_mem_cnt] = NULL;
-
- /* Prepare reading the group members. */
- total_len = 0;
- for (cnt = 0; cnt < gr_resp.gr_mem_cnt; ++cnt)
- {
- resultbuf->gr_mem[cnt] = p;
- total_len += len[cnt];
- p += len[cnt];
- }
-
- 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. */
- if (gr_name != NULL && mapped->head->gc_cycle != gc_cycle)
- retval = -2;
- goto out_close;
- }
- if (__glibc_unlikely (total_len > buflen))
- {
- /* len array might contain garbage during nscd GC cycle,
- retry rather than fail in that case. */
- if (gr_name != NULL && mapped->head->gc_cycle != gc_cycle)
- {
- retval = -2;
- goto out_close;
- }
- else
- goto no_room;
- }
-
- retval = 0;
-
- /* If there are no group members TOTAL_LEN is zero. */
- if (gr_name == NULL)
- {
- if (total_len > 0
- && __builtin_expect (__readall (sock, resultbuf->gr_mem[0],
- total_len) != total_len, 0))
- {
- /* The `errno' to some value != ERANGE. */
- __set_errno (ENOENT);
- retval = ENOENT;
- }
- else
- *result = resultbuf;
- }
- else
- {
- /* Copy the group member names. */
- memcpy (resultbuf->gr_mem[0], gr_name + gr_name_len, total_len);
-
- /* Try to detect corrupt databases. */
- if (resultbuf->gr_name[gr_name_len - 1] != '\0'
- || resultbuf->gr_passwd[gr_resp.gr_passwd_len - 1] != '\0'
- || ({for (cnt = 0; cnt < gr_resp.gr_mem_cnt; ++cnt)
- if (resultbuf->gr_mem[cnt][len[cnt] - 1] != '\0')
- break;
- cnt < gr_resp.gr_mem_cnt; }))
- {
- /* We cannot use the database. */
- retval = mapped->head->gc_cycle != gc_cycle ? -2 : -1;
- goto out_close;
- }
-
- *result = resultbuf;
- }
- }
- else
- {
- /* Set errno to 0 to indicate no error, just no found record. */
- __set_errno (0);
- /* Even though we have not found anything, the result is zero. */
- retval = 0;
- }
-
- out_close:
- if (sock != -1)
- close_not_cancel_no_status (sock);
- out:
- if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
- {
- /* When we come here this means there has been a GC cycle while we
- were looking for the data. This means the data might have been
- inconsistent. Retry if possible. */
- if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
- {
- /* nscd is just running gc now. Disable using the mapping. */
- if (atomic_decrement_val (&mapped->counter) == 0)
- __nscd_unmap (mapped);
- mapped = NO_MAPPING;
- }
-
- if (retval != -1)
- goto retry;
- }
-
- scratch_buffer_free (&lenbuf);
-
- return retval;
-}
diff --git a/nscd/nscd_gethst_r.c b/nscd/nscd_gethst_r.c
deleted file mode 100644
index daa708b3d3..0000000000
--- a/nscd/nscd_gethst_r.c
+++ /dev/null
@@ -1,459 +0,0 @@
-/* Copyright (C) 1998-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-#include <errno.h>
-#include <resolv/resolv-internal.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <arpa/nameser.h>
-#include <not-cancel.h>
-
-#include "nscd-client.h"
-#include "nscd_proto.h"
-
-int __nss_not_use_nscd_hosts;
-
-static int 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) internal_function;
-
-
-int
-__nscd_gethostbyname_r (const char *name, struct hostent *resultbuf,
- char *buffer, size_t buflen, struct hostent **result,
- int *h_errnop)
-{
- request_type reqtype;
-
- reqtype = res_use_inet6 () ? GETHOSTBYNAMEv6 : GETHOSTBYNAME;
-
- return nscd_gethst_r (name, strlen (name) + 1, reqtype, resultbuf,
- buffer, buflen, result, h_errnop);
-}
-
-
-int
-__nscd_gethostbyname2_r (const char *name, int af, struct hostent *resultbuf,
- char *buffer, size_t buflen, struct hostent **result,
- int *h_errnop)
-{
- request_type reqtype;
-
- reqtype = af == AF_INET6 ? GETHOSTBYNAMEv6 : GETHOSTBYNAME;
-
- return nscd_gethst_r (name, strlen (name) + 1, reqtype, resultbuf,
- buffer, buflen, result, h_errnop);
-}
-
-
-int
-__nscd_gethostbyaddr_r (const void *addr, socklen_t len, int type,
- struct hostent *resultbuf, char *buffer, size_t buflen,
- struct hostent **result, int *h_errnop)
-{
- request_type reqtype;
-
- if (!((len == INADDRSZ && type == AF_INET)
- || (len == IN6ADDRSZ && type == AF_INET6)))
- /* LEN and TYPE do not match. */
- return -1;
-
- reqtype = type == AF_INET6 ? GETHOSTBYADDRv6 : GETHOSTBYADDR;
-
- return nscd_gethst_r (addr, len, reqtype, resultbuf, buffer, buflen, result,
- h_errnop);
-}
-
-
-libc_locked_map_ptr (, __hst_map_handle) attribute_hidden;
-/* Note that we only free the structure if necessary. The memory
- mapping is not removed since it is not visible to the malloc
- handling. */
-libc_freeres_fn (hst_map_free)
-{
- if (__hst_map_handle.mapped != NO_MAPPING)
- {
- void *p = __hst_map_handle.mapped;
- __hst_map_handle.mapped = NO_MAPPING;
- free (p);
- }
-}
-
-
-uint32_t
-__nscd_get_nl_timestamp (void)
-{
- uint32_t retval;
- if (__nss_not_use_nscd_hosts != 0)
- return 0;
-
- /* __nscd_get_mapping can change hst_map_handle.mapped to NO_MAPPING.
- However, __nscd_get_mapping assumes the prior value was not NO_MAPPING.
- Thus we have to acquire the lock to prevent this thread from changing
- hst_map_handle.mapped to NO_MAPPING while another thread is inside
- __nscd_get_mapping. */
- if (!__nscd_acquire_maplock (&__hst_map_handle))
- return 0;
-
- struct mapped_database *map = __hst_map_handle.mapped;
-
- if (map == NULL
- || (map != NO_MAPPING
- && map->head->nscd_certainly_running == 0
- && map->head->timestamp + MAPPING_TIMEOUT < time (NULL)))
- map = __nscd_get_mapping (GETFDHST, "hosts", &__hst_map_handle.mapped);
-
- if (map == NO_MAPPING)
- retval = 0;
- else
- retval = map->head->extra_data[NSCD_HST_IDX_CONF_TIMESTAMP];
-
- /* Release the lock. */
- __hst_map_handle.lock = 0;
-
- return retval;
-}
-
-
-int __nss_have_localdomain attribute_hidden;
-
-static int
-internal_function
-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 (__glibc_unlikely (__nss_have_localdomain >= 0))
- {
- if (__nss_have_localdomain == 0)
- __nss_have_localdomain = getenv ("LOCALDOMAIN") != NULL ? 1 : -1;
- if (__nss_have_localdomain > 0)
- {
- __nss_not_use_nscd_hosts = 1;
- return -1;
- }
- }
-
- int gc_cycle;
- int nretries = 0;
-
- /* If the mapping is available, try to search there instead of
- communicating with the nscd. */
- struct mapped_database *mapped;
- mapped = __nscd_get_map_ref (GETFDHST, "hosts", &__hst_map_handle,
- &gc_cycle);
-
- retry:;
- const char *h_name = NULL;
- const uint32_t *aliases_len = NULL;
- const char *addr_list = NULL;
- size_t addr_list_len = 0;
- int retval = -1;
- const char *recend = (const char *) ~UINTMAX_C (0);
- int sock = -1;
- hst_response_header hst_resp;
- if (mapped != NO_MAPPING)
- {
- /* No const qualifier, as it can change during garbage collection. */
- struct datahead *found = __nscd_cache_search (type, key, keylen, mapped,
- sizeof hst_resp);
- if (found != NULL)
- {
- h_name = (char *) (&found->data[0].hstdata + 1);
- hst_resp = found->data[0].hstdata;
- aliases_len = (uint32_t *) (h_name + hst_resp.h_name_len);
- addr_list = ((char *) aliases_len
- + hst_resp.h_aliases_cnt * sizeof (uint32_t));
- addr_list_len = hst_resp.h_addr_list_cnt * INADDRSZ;
- recend = (const char *) found->data + found->recsize;
- /* Now check if we can trust hst_resp fields. If GC is
- in progress, it can contain anything. */
- if (mapped->head->gc_cycle != gc_cycle)
- {
- retval = -2;
- goto out;
- }
-
-#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
- need to make an aligned copy. */
- if (((uintptr_t) aliases_len & (__alignof__ (*aliases_len) - 1))
- != 0)
- {
- uint32_t *tmp = alloca (hst_resp.h_aliases_cnt
- * sizeof (uint32_t));
- aliases_len = memcpy (tmp, aliases_len,
- hst_resp.h_aliases_cnt
- * sizeof (uint32_t));
- }
-#endif
- if (type != GETHOSTBYADDR && type != GETHOSTBYNAME)
- {
- if (hst_resp.h_length == INADDRSZ)
- addr_list += addr_list_len;
- addr_list_len = hst_resp.h_addr_list_cnt * IN6ADDRSZ;
- }
- if (__builtin_expect ((const char *) addr_list + addr_list_len
- > recend, 0))
- goto out;
- }
- }
-
- if (h_name == NULL)
- {
- sock = __nscd_open_socket (key, keylen, type, &hst_resp,
- sizeof (hst_resp));
- if (sock == -1)
- {
- __nss_not_use_nscd_hosts = 1;
- goto out;
- }
- }
-
- /* No value found so far. */
- *result = NULL;
-
- if (__glibc_unlikely (hst_resp.found == -1))
- {
- /* The daemon does not cache this database. */
- __nss_not_use_nscd_hosts = 1;
- goto out_close;
- }
-
- if (hst_resp.found == 1)
- {
- char *cp = buffer;
- uintptr_t align1;
- uintptr_t align2;
- size_t total_len;
- ssize_t cnt;
- char *ignore;
- int n;
-
- /* A first check whether the buffer is sufficiently large is possible. */
- /* Now allocate the buffer the array for the group members. We must
- align the pointer and the base of the h_addr_list pointers. */
- align1 = ((__alignof__ (char *) - (cp - ((char *) 0)))
- & (__alignof__ (char *) - 1));
- align2 = ((__alignof__ (char *) - ((cp + align1 + hst_resp.h_name_len)
- - ((char *) 0)))
- & (__alignof__ (char *) - 1));
- if (buflen < (align1 + hst_resp.h_name_len + align2
- + ((hst_resp.h_aliases_cnt + hst_resp.h_addr_list_cnt
- + 2)
- * sizeof (char *))
- + hst_resp.h_addr_list_cnt * (type == AF_INET
- ? INADDRSZ : IN6ADDRSZ)))
- {
- no_room:
- *h_errnop = NETDB_INTERNAL;
- __set_errno (ERANGE);
- retval = ERANGE;
- goto out_close;
- }
- cp += align1;
-
- /* Prepare the result as far as we can. */
- resultbuf->h_aliases = (char **) cp;
- cp += (hst_resp.h_aliases_cnt + 1) * sizeof (char *);
- resultbuf->h_addr_list = (char **) cp;
- cp += (hst_resp.h_addr_list_cnt + 1) * sizeof (char *);
-
- resultbuf->h_name = cp;
- cp += hst_resp.h_name_len + align2;
-
- if (type == GETHOSTBYADDR || type == GETHOSTBYNAME)
- {
- resultbuf->h_addrtype = AF_INET;
- resultbuf->h_length = INADDRSZ;
- }
- else
- {
- resultbuf->h_addrtype = AF_INET6;
- resultbuf->h_length = IN6ADDRSZ;
- }
- for (cnt = 0; cnt < hst_resp.h_addr_list_cnt; ++cnt)
- {
- resultbuf->h_addr_list[cnt] = cp;
- cp += resultbuf->h_length;
- }
- resultbuf->h_addr_list[cnt] = NULL;
-
- if (h_name == NULL)
- {
- struct iovec vec[4];
-
- vec[0].iov_base = resultbuf->h_name;
- vec[0].iov_len = hst_resp.h_name_len;
- total_len = hst_resp.h_name_len;
- n = 1;
-
- if (hst_resp.h_aliases_cnt > 0)
- {
- aliases_len = alloca (hst_resp.h_aliases_cnt
- * sizeof (uint32_t));
- vec[n].iov_base = (void *) aliases_len;
- vec[n].iov_len = hst_resp.h_aliases_cnt * sizeof (uint32_t);
-
- total_len += hst_resp.h_aliases_cnt * sizeof (uint32_t);
- ++n;
- }
-
- if (type == GETHOSTBYADDR || type == GETHOSTBYNAME)
- {
- vec[n].iov_base = resultbuf->h_addr_list[0];
- vec[n].iov_len = hst_resp.h_addr_list_cnt * INADDRSZ;
-
- total_len += hst_resp.h_addr_list_cnt * INADDRSZ;
-
- ++n;
- }
- else
- {
- if (hst_resp.h_length == INADDRSZ)
- {
- ignore = alloca (hst_resp.h_addr_list_cnt * INADDRSZ);
- vec[n].iov_base = ignore;
- vec[n].iov_len = hst_resp.h_addr_list_cnt * INADDRSZ;
-
- total_len += hst_resp.h_addr_list_cnt * INADDRSZ;
-
- ++n;
- }
-
- vec[n].iov_base = resultbuf->h_addr_list[0];
- vec[n].iov_len = hst_resp.h_addr_list_cnt * IN6ADDRSZ;
-
- total_len += hst_resp.h_addr_list_cnt * IN6ADDRSZ;
-
- ++n;
- }
-
- if ((size_t) __readvall (sock, vec, n) != total_len)
- goto out_close;
- }
- else
- {
- memcpy (resultbuf->h_name, h_name, hst_resp.h_name_len);
- memcpy (resultbuf->h_addr_list[0], addr_list, addr_list_len);
- }
-
- /* Now we also can read the aliases. */
- total_len = 0;
- for (cnt = 0; cnt < hst_resp.h_aliases_cnt; ++cnt)
- {
- resultbuf->h_aliases[cnt] = cp;
- cp += aliases_len[cnt];
- total_len += aliases_len[cnt];
- }
- resultbuf->h_aliases[cnt] = NULL;
-
- if (__builtin_expect ((const char *) addr_list + addr_list_len
- + total_len > recend, 0))
- {
- /* aliases_len array might contain garbage during nscd GC cycle,
- retry rather than fail in that case. */
- if (addr_list != NULL && mapped->head->gc_cycle != gc_cycle)
- retval = -2;
- goto out_close;
- }
- /* See whether this would exceed the buffer capacity. */
- if (__glibc_unlikely (cp > buffer + buflen))
- {
- /* aliases_len array might contain garbage during nscd GC cycle,
- retry rather than fail in that case. */
- if (addr_list != NULL && mapped->head->gc_cycle != gc_cycle)
- {
- retval = -2;
- goto out_close;
- }
- goto no_room;
- }
-
- /* And finally read the aliases. */
- if (addr_list == NULL)
- {
- if (total_len == 0
- || ((size_t) __readall (sock, resultbuf->h_aliases[0], total_len)
- == total_len))
- {
- retval = 0;
- *result = resultbuf;
- }
- }
- else
- {
- memcpy (resultbuf->h_aliases[0],
- (const char *) addr_list + addr_list_len, total_len);
-
- /* Try to detect corrupt databases. */
- if (resultbuf->h_name[hst_resp.h_name_len - 1] != '\0'
- || ({for (cnt = 0; cnt < hst_resp.h_aliases_cnt; ++cnt)
- if (resultbuf->h_aliases[cnt][aliases_len[cnt] - 1]
- != '\0')
- break;
- cnt < hst_resp.h_aliases_cnt; }))
- {
- /* We cannot use the database. */
- if (mapped->head->gc_cycle != gc_cycle)
- retval = -2;
- goto out_close;
- }
-
- retval = 0;
- *result = resultbuf;
- }
- }
- else
- {
- /* Store the error number. */
- *h_errnop = hst_resp.error;
-
- /* Set errno to 0 to indicate no error, just no found record. */
- __set_errno (0);
- /* Even though we have not found anything, the result is zero. */
- retval = 0;
- }
-
- out_close:
- if (sock != -1)
- close_not_cancel_no_status (sock);
- out:
- if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
- {
- /* When we come here this means there has been a GC cycle while we
- were looking for the data. This means the data might have been
- inconsistent. Retry if possible. */
- if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
- {
- /* nscd is just running gc now. Disable using the mapping. */
- if (atomic_decrement_val (&mapped->counter) == 0)
- __nscd_unmap (mapped);
- mapped = NO_MAPPING;
- }
-
- if (retval != -1)
- goto retry;
- }
-
- return retval;
-}
diff --git a/nscd/nscd_getpw_r.c b/nscd/nscd_getpw_r.c
deleted file mode 100644
index b291d2fa44..0000000000
--- a/nscd/nscd_getpw_r.c
+++ /dev/null
@@ -1,241 +0,0 @@
-/* Copyright (C) 1998-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1998.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-#include <assert.h>
-#include <errno.h>
-#include <pwd.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-#include <sys/un.h>
-#include <not-cancel.h>
-#include <_itoa.h>
-
-#include "nscd-client.h"
-#include "nscd_proto.h"
-
-int __nss_not_use_nscd_passwd;
-
-static int nscd_getpw_r (const char *key, size_t keylen, request_type type,
- struct passwd *resultbuf, char *buffer,
- size_t buflen, struct passwd **result)
- internal_function;
-
-int
-__nscd_getpwnam_r (const char *name, struct passwd *resultbuf, char *buffer,
- size_t buflen, struct passwd **result)
-{
- if (name == NULL)
- return -1;
-
- return nscd_getpw_r (name, strlen (name) + 1, GETPWBYNAME, resultbuf,
- buffer, buflen, result);
-}
-
-int
-__nscd_getpwuid_r (uid_t uid, struct passwd *resultbuf, char *buffer,
- size_t buflen, struct passwd **result)
-{
- char buf[3 * sizeof (uid_t)];
- buf[sizeof (buf) - 1] = '\0';
- char *cp = _itoa_word (uid, buf + sizeof (buf) - 1, 10, 0);
-
- return nscd_getpw_r (cp, buf + sizeof (buf) - cp, GETPWBYUID, resultbuf,
- buffer, buflen, result);
-}
-
-
-libc_locked_map_ptr (static, map_handle);
-/* Note that we only free the structure if necessary. The memory
- mapping is not removed since it is not visible to the malloc
- handling. */
-libc_freeres_fn (pw_map_free)
-{
- if (map_handle.mapped != NO_MAPPING)
- {
- void *p = map_handle.mapped;
- map_handle.mapped = NO_MAPPING;
- free (p);
- }
-}
-
-
-static int
-internal_function
-nscd_getpw_r (const char *key, size_t keylen, request_type type,
- struct passwd *resultbuf, char *buffer, size_t buflen,
- struct passwd **result)
-{
- int gc_cycle;
- int nretries = 0;
-
- /* If the mapping is available, try to search there instead of
- communicating with the nscd. */
- struct mapped_database *mapped;
- mapped = __nscd_get_map_ref (GETFDPW, "passwd", &map_handle, &gc_cycle);
-
- retry:;
- const char *pw_name = NULL;
- int retval = -1;
- const char *recend = (const char *) ~UINTMAX_C (0);
- pw_response_header pw_resp;
-
- if (mapped != NO_MAPPING)
- {
- struct datahead *found = __nscd_cache_search (type, key, keylen, mapped,
- sizeof pw_resp);
- if (found != NULL)
- {
- pw_name = (const char *) (&found->data[0].pwdata + 1);
- pw_resp = found->data[0].pwdata;
- recend = (const char *) found->data + found->recsize;
- /* Now check if we can trust pw_resp fields. If GC is
- in progress, it can contain anything. */
- if (mapped->head->gc_cycle != gc_cycle)
- {
- retval = -2;
- goto out;
- }
- }
- }
-
- int sock = -1;
- if (pw_name == NULL)
- {
- sock = __nscd_open_socket (key, keylen, type, &pw_resp,
- sizeof (pw_resp));
- if (sock == -1)
- {
- __nss_not_use_nscd_passwd = 1;
- goto out;
- }
- }
-
- /* No value found so far. */
- *result = NULL;
-
- if (__glibc_unlikely (pw_resp.found == -1))
- {
- /* The daemon does not cache this database. */
- __nss_not_use_nscd_passwd = 1;
- goto out_close;
- }
-
- if (pw_resp.found == 1)
- {
- /* Set the information we already have. */
- resultbuf->pw_uid = pw_resp.pw_uid;
- resultbuf->pw_gid = pw_resp.pw_gid;
-
- char *p = buffer;
- /* get pw_name */
- resultbuf->pw_name = p;
- p += pw_resp.pw_name_len;
- /* get pw_passwd */
- resultbuf->pw_passwd = p;
- p += pw_resp.pw_passwd_len;
- /* get pw_gecos */
- resultbuf->pw_gecos = p;
- p += pw_resp.pw_gecos_len;
- /* get pw_dir */
- resultbuf->pw_dir = p;
- p += pw_resp.pw_dir_len;
- /* get pw_pshell */
- resultbuf->pw_shell = p;
- p += pw_resp.pw_shell_len;
-
- ssize_t total = p - buffer;
- if (__glibc_unlikely (pw_name + total > recend))
- goto out_close;
- if (__glibc_unlikely (buflen < total))
- {
- __set_errno (ERANGE);
- retval = ERANGE;
- goto out_close;
- }
-
- retval = 0;
- if (pw_name == NULL)
- {
- ssize_t nbytes = __readall (sock, buffer, total);
-
- if (__glibc_unlikely (nbytes != total))
- {
- /* The `errno' to some value != ERANGE. */
- __set_errno (ENOENT);
- retval = ENOENT;
- }
- else
- *result = resultbuf;
- }
- else
- {
- /* Copy the various strings. */
- memcpy (resultbuf->pw_name, pw_name, total);
-
- /* Try to detect corrupt databases. */
- if (resultbuf->pw_name[pw_resp.pw_name_len - 1] != '\0'
- || resultbuf->pw_passwd[pw_resp.pw_passwd_len - 1] != '\0'
- || resultbuf->pw_gecos[pw_resp.pw_gecos_len - 1] != '\0'
- || resultbuf->pw_dir[pw_resp.pw_dir_len - 1] != '\0'
- || resultbuf->pw_shell[pw_resp.pw_shell_len - 1] != '\0')
- {
- /* We cannot use the database. */
- retval = mapped->head->gc_cycle != gc_cycle ? -2 : -1;
- goto out_close;
- }
-
- *result = resultbuf;
- }
- }
- else
- {
- /* Set errno to 0 to indicate no error, just no found record. */
- __set_errno (0);
- /* Even though we have not found anything, the result is zero. */
- retval = 0;
- }
-
- out_close:
- if (sock != -1)
- close_not_cancel_no_status (sock);
- out:
- if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
- {
- /* When we come here this means there has been a GC cycle while we
- were looking for the data. This means the data might have been
- inconsistent. Retry if possible. */
- if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
- {
- /* nscd is just running gc now. Disable using the mapping. */
- if (atomic_decrement_val (&mapped->counter) == 0)
- __nscd_unmap (mapped);
- mapped = NO_MAPPING;
- }
-
- if (retval != -1)
- goto retry;
- }
-
- return retval;
-}
diff --git a/nscd/nscd_getserv_r.c b/nscd/nscd_getserv_r.c
deleted file mode 100644
index 7dfb1c828d..0000000000
--- a/nscd/nscd_getserv_r.c
+++ /dev/null
@@ -1,388 +0,0 @@
-/* Copyright (C) 2007-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@redhat.com>, 2007.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-#include <assert.h>
-#include <errno.h>
-#include <string.h>
-#include <not-cancel.h>
-#include <_itoa.h>
-#include <stdint.h>
-
-#include "nscd-client.h"
-#include "nscd_proto.h"
-
-
-int __nss_not_use_nscd_services;
-
-
-static int nscd_getserv_r (const char *crit, size_t critlen, const char *proto,
- request_type type, struct servent *resultbuf,
- char *buf, size_t buflen, struct servent **result);
-
-
-int
-__nscd_getservbyname_r (const char *name, const char *proto,
- struct servent *result_buf, char *buf, size_t buflen,
- struct servent **result)
-{
- return nscd_getserv_r (name, strlen (name), proto, GETSERVBYNAME, result_buf,
- buf, buflen, result);
-}
-
-
-int
-__nscd_getservbyport_r (int port, const char *proto,
- struct servent *result_buf, char *buf, size_t buflen,
- struct servent **result)
-{
- char portstr[3 * sizeof (int) + 2];
- portstr[sizeof (portstr) - 1] = '\0';
- char *cp = _itoa_word (port, portstr + sizeof (portstr) - 1, 10, 0);
-
- return nscd_getserv_r (cp, portstr + sizeof (portstr) - 1 - cp, proto,
- GETSERVBYPORT, result_buf, buf, buflen, result);
-}
-
-
-libc_locked_map_ptr (, __serv_map_handle) attribute_hidden;
-/* Note that we only free the structure if necessary. The memory
- mapping is not removed since it is not visible to the malloc
- handling. */
-libc_freeres_fn (serv_map_free)
-{
- if (__serv_map_handle.mapped != NO_MAPPING)
- {
- void *p = __serv_map_handle.mapped;
- __serv_map_handle.mapped = NO_MAPPING;
- free (p);
- }
-}
-
-
-static int
-nscd_getserv_r (const char *crit, size_t critlen, const char *proto,
- request_type type, struct servent *resultbuf,
- char *buf, size_t buflen, struct servent **result)
-{
- int gc_cycle;
- int nretries = 0;
- size_t alloca_used = 0;
-
- /* If the mapping is available, try to search there instead of
- communicating with the nscd. */
- struct mapped_database *mapped;
- mapped = __nscd_get_map_ref (GETFDSERV, "services", &__serv_map_handle,
- &gc_cycle);
- size_t protolen = proto == NULL ? 0 : strlen (proto);
- size_t keylen = critlen + 1 + protolen + 1;
- int alloca_key = __libc_use_alloca (keylen);
- char *key;
- if (alloca_key)
- key = alloca_account (keylen, alloca_used);
- else
- {
- key = malloc (keylen);
- if (key == NULL)
- return -1;
- }
- memcpy (__mempcpy (__mempcpy (key, crit, critlen),
- "/", 1), proto ?: "", protolen + 1);
-
- retry:;
- const char *s_name = NULL;
- const char *s_proto = NULL;
- int alloca_aliases_len = 0;
- const uint32_t *aliases_len = NULL;
- const char *aliases_list = NULL;
- int retval = -1;
- const char *recend = (const char *) ~UINTMAX_C (0);
- int sock = -1;
- serv_response_header serv_resp;
-
- if (mapped != NO_MAPPING)
- {
- struct datahead *found = __nscd_cache_search (type, key, keylen, mapped,
- sizeof serv_resp);
-
- if (found != NULL)
- {
- s_name = (char *) (&found->data[0].servdata + 1);
- serv_resp = found->data[0].servdata;
- s_proto = s_name + serv_resp.s_name_len;
- alloca_aliases_len = 1;
- aliases_len = (uint32_t *) (s_proto + serv_resp.s_proto_len);
- aliases_list = ((char *) aliases_len
- + serv_resp.s_aliases_cnt * sizeof (uint32_t));
- recend = (const char *) found->data + found->recsize;
- /* Now check if we can trust serv_resp fields. If GC is
- in progress, it can contain anything. */
- if (mapped->head->gc_cycle != gc_cycle)
- {
- retval = -2;
- goto out;
- }
- if (__builtin_expect ((const char *) aliases_len
- + serv_resp.s_aliases_cnt * sizeof (uint32_t)
- > recend, 0))
- goto out;
-
-#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
- need to make an aligned copy. */
- if (((uintptr_t) aliases_len & (__alignof__ (*aliases_len) - 1))
- != 0)
- {
- uint32_t *tmp;
- alloca_aliases_len
- = __libc_use_alloca (alloca_used
- + (serv_resp.s_aliases_cnt
- * sizeof (uint32_t)));
- if (alloca_aliases_len)
- tmp = alloca_account (serv_resp.s_aliases_cnt
- * sizeof (uint32_t),
- alloca_used);
- else
- {
- tmp = malloc (serv_resp.s_aliases_cnt * sizeof (uint32_t));
- if (tmp == NULL)
- {
- retval = ENOMEM;
- goto out;
- }
- }
- aliases_len = memcpy (tmp, aliases_len,
- serv_resp.s_aliases_cnt
- * sizeof (uint32_t));
- }
-#endif
- }
- }
-
- if (s_name == NULL)
- {
- sock = __nscd_open_socket (key, keylen, type, &serv_resp,
- sizeof (serv_resp));
- if (sock == -1)
- {
- __nss_not_use_nscd_services = 1;
- goto out;
- }
- }
-
- /* No value found so far. */
- *result = NULL;
-
- if (__glibc_unlikely (serv_resp.found == -1))
- {
- /* The daemon does not cache this database. */
- __nss_not_use_nscd_services = 1;
- goto out_close;
- }
-
- if (serv_resp.found == 1)
- {
- char *cp = buf;
- uintptr_t align1;
- uintptr_t align2;
- size_t total_len;
- ssize_t cnt;
- int n;
-
- /* A first check whether the buffer is sufficiently large is possible. */
- /* Now allocate the buffer the array for the group members. We must
- align the pointer and the base of the h_addr_list pointers. */
- align1 = ((__alignof__ (char *) - (cp - ((char *) 0)))
- & (__alignof__ (char *) - 1));
- align2 = ((__alignof__ (char *) - ((cp + align1 + serv_resp.s_name_len
- + serv_resp.s_proto_len)
- - ((char *) 0)))
- & (__alignof__ (char *) - 1));
- if (buflen < (align1 + serv_resp.s_name_len + serv_resp.s_proto_len
- + align2
- + (serv_resp.s_aliases_cnt + 1) * sizeof (char *)))
- {
- no_room:
- __set_errno (ERANGE);
- retval = ERANGE;
- goto out_close;
- }
- cp += align1;
-
- /* Prepare the result as far as we can. */
- resultbuf->s_aliases = (char **) cp;
- cp += (serv_resp.s_aliases_cnt + 1) * sizeof (char *);
-
- resultbuf->s_name = cp;
- cp += serv_resp.s_name_len;
- resultbuf->s_proto = cp;
- cp += serv_resp.s_proto_len + align2;
- resultbuf->s_port = serv_resp.s_port;
-
- if (s_name == NULL)
- {
- struct iovec vec[2];
-
- vec[0].iov_base = resultbuf->s_name;
- vec[0].iov_len = serv_resp.s_name_len + serv_resp.s_proto_len;
- total_len = vec[0].iov_len;
- n = 1;
-
- if (serv_resp.s_aliases_cnt > 0)
- {
- assert (alloca_aliases_len == 0);
- alloca_aliases_len
- = __libc_use_alloca (alloca_used
- + (serv_resp.s_aliases_cnt
- * sizeof (uint32_t)));
- if (alloca_aliases_len)
- aliases_len = alloca_account (serv_resp.s_aliases_cnt
- * sizeof (uint32_t),
- alloca_used);
- else
- {
- aliases_len = malloc (serv_resp.s_aliases_cnt
- * sizeof (uint32_t));
- if (aliases_len == NULL)
- {
- retval = ENOMEM;
- goto out_close;
- }
- }
- vec[n].iov_base = (void *) aliases_len;
- vec[n].iov_len = serv_resp.s_aliases_cnt * sizeof (uint32_t);
-
- total_len += serv_resp.s_aliases_cnt * sizeof (uint32_t);
- ++n;
- }
-
- if ((size_t) __readvall (sock, vec, n) != total_len)
- goto out_close;
- }
- else
- memcpy (resultbuf->s_name, s_name,
- serv_resp.s_name_len + serv_resp.s_proto_len);
-
- /* Now we also can read the aliases. */
- total_len = 0;
- for (cnt = 0; cnt < serv_resp.s_aliases_cnt; ++cnt)
- {
- resultbuf->s_aliases[cnt] = cp;
- cp += aliases_len[cnt];
- total_len += aliases_len[cnt];
- }
- resultbuf->s_aliases[cnt] = NULL;
-
- if (__builtin_expect ((const char *) aliases_list + total_len > recend,
- 0))
- {
- /* aliases_len array might contain garbage during nscd GC cycle,
- retry rather than fail in that case. */
- if (aliases_list != NULL && mapped->head->gc_cycle != gc_cycle)
- retval = -2;
- goto out_close;
- }
-
- /* See whether this would exceed the buffer capacity. */
- if (__glibc_unlikely (cp > buf + buflen))
- {
- /* aliases_len array might contain garbage during nscd GC cycle,
- retry rather than fail in that case. */
- if (aliases_list != NULL && mapped->head->gc_cycle != gc_cycle)
- {
- retval = -2;
- goto out_close;
- }
- goto no_room;
- }
-
- /* And finally read the aliases. */
- if (aliases_list == NULL)
- {
- if (total_len == 0
- || ((size_t) __readall (sock, resultbuf->s_aliases[0], total_len)
- == total_len))
- {
- retval = 0;
- *result = resultbuf;
- }
- }
- else
- {
- memcpy (resultbuf->s_aliases[0], aliases_list, total_len);
-
- /* Try to detect corrupt databases. */
- if (resultbuf->s_name[serv_resp.s_name_len - 1] != '\0'
- || resultbuf->s_proto[serv_resp.s_proto_len - 1] != '\0'
- || ({for (cnt = 0; cnt < serv_resp.s_aliases_cnt; ++cnt)
- if (resultbuf->s_aliases[cnt][aliases_len[cnt] - 1]
- != '\0')
- break;
- cnt < serv_resp.s_aliases_cnt; }))
- {
- /* We cannot use the database. */
- if (mapped->head->gc_cycle != gc_cycle)
- retval = -2;
- goto out_close;
- }
-
- retval = 0;
- *result = resultbuf;
- }
- }
- else
- {
- /* Set errno to 0 to indicate no error, just no found record. */
- __set_errno (0);
- /* Even though we have not found anything, the result is zero. */
- retval = 0;
- }
-
- out_close:
- if (sock != -1)
- close_not_cancel_no_status (sock);
- out:
- if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
- {
- /* When we come here this means there has been a GC cycle while we
- were looking for the data. This means the data might have been
- inconsistent. Retry if possible. */
- if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
- {
- /* nscd is just running gc now. Disable using the mapping. */
- if (atomic_decrement_val (&mapped->counter) == 0)
- __nscd_unmap (mapped);
- mapped = NO_MAPPING;
- }
-
- if (retval != -1)
- {
- if (!alloca_aliases_len)
- free ((void *) aliases_len);
- goto retry;
- }
- }
-
- if (!alloca_aliases_len)
- free ((void *) aliases_len);
- if (!alloca_key)
- free (key);
-
- return retval;
-}
diff --git a/nscd/nscd_helper.c b/nscd/nscd_helper.c
deleted file mode 100644
index 22905d0b83..0000000000
--- a/nscd/nscd_helper.c
+++ /dev/null
@@ -1,564 +0,0 @@
-/* Copyright (C) 1998-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <sys/mman.h>
-#include <sys/poll.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/uio.h>
-#include <sys/un.h>
-#include <not-cancel.h>
-#include <nis/rpcsvc/nis.h>
-#include <kernel-features.h>
-
-#include "nscd-client.h"
-
-
-/* Extra time we wait if the socket is still receiving data. This
- value is in milliseconds. Note that the other side is nscd on the
- local machine and it is already transmitting data. So the wait
- time need not be long. */
-#define EXTRA_RECEIVE_TIME 200
-
-
-static int
-wait_on_socket (int sock, long int usectmo)
-{
- struct pollfd fds[1];
- fds[0].fd = sock;
- fds[0].events = POLLIN | POLLERR | POLLHUP;
- int n = __poll (fds, 1, usectmo);
- if (n == -1 && __builtin_expect (errno == EINTR, 0))
- {
- /* Handle the case where the poll() call is interrupted by a
- signal. We cannot just use TEMP_FAILURE_RETRY since it might
- lead to infinite loops. */
- struct timeval now;
- (void) __gettimeofday (&now, NULL);
- long int end = now.tv_sec * 1000 + usectmo + (now.tv_usec + 500) / 1000;
- long int timeout = usectmo;
- while (1)
- {
- n = __poll (fds, 1, timeout);
- if (n != -1 || errno != EINTR)
- break;
-
- /* Recompute the timeout time. */
- (void) __gettimeofday (&now, NULL);
- timeout = end - (now.tv_sec * 1000 + (now.tv_usec + 500) / 1000);
- }
- }
-
- return n;
-}
-
-
-ssize_t
-__readall (int fd, void *buf, size_t len)
-{
- size_t n = len;
- ssize_t ret;
- do
- {
- again:
- ret = TEMP_FAILURE_RETRY (__read (fd, buf, n));
- if (ret <= 0)
- {
- if (__builtin_expect (ret < 0 && errno == EAGAIN, 0)
- /* The socket is still receiving data. Wait a bit more. */
- && wait_on_socket (fd, EXTRA_RECEIVE_TIME) > 0)
- goto again;
-
- break;
- }
- buf = (char *) buf + ret;
- n -= ret;
- }
- while (n > 0);
- return ret < 0 ? ret : len - n;
-}
-
-
-ssize_t
-__readvall (int fd, const struct iovec *iov, int iovcnt)
-{
- ssize_t ret = TEMP_FAILURE_RETRY (__readv (fd, iov, iovcnt));
- if (ret <= 0)
- {
- if (__glibc_likely (ret == 0 || errno != EAGAIN))
- /* A genuine error or no data to read. */
- return ret;
-
- /* The data has not all yet been received. Do as if we have not
- read anything yet. */
- ret = 0;
- }
-
- size_t total = 0;
- for (int i = 0; i < iovcnt; ++i)
- total += iov[i].iov_len;
-
- if (ret < total)
- {
- struct iovec iov_buf[iovcnt];
- ssize_t r = ret;
-
- struct iovec *iovp = memcpy (iov_buf, iov, iovcnt * sizeof (*iov));
- do
- {
- while (iovp->iov_len <= r)
- {
- r -= iovp->iov_len;
- --iovcnt;
- ++iovp;
- }
- iovp->iov_base = (char *) iovp->iov_base + r;
- iovp->iov_len -= r;
- again:
- r = TEMP_FAILURE_RETRY (__readv (fd, iovp, iovcnt));
- if (r <= 0)
- {
- if (__builtin_expect (r < 0 && errno == EAGAIN, 0)
- /* The socket is still receiving data. Wait a bit more. */
- && wait_on_socket (fd, EXTRA_RECEIVE_TIME) > 0)
- goto again;
-
- break;
- }
- ret += r;
- }
- while (ret < total);
- if (r < 0)
- ret = r;
- }
- return ret;
-}
-
-
-static int
-open_socket (request_type type, const char *key, size_t keylen)
-{
- int sock;
-
- sock = __socket (PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
- if (sock < 0)
- return -1;
-
- size_t real_sizeof_reqdata = sizeof (request_header) + keylen;
- struct
- {
- request_header req;
- char key[];
- } *reqdata = alloca (real_sizeof_reqdata);
-
- struct sockaddr_un sun;
- sun.sun_family = AF_UNIX;
- strcpy (sun.sun_path, _PATH_NSCDSOCKET);
- if (__connect (sock, (struct sockaddr *) &sun, sizeof (sun)) < 0
- && errno != EINPROGRESS)
- goto out;
-
- reqdata->req.version = NSCD_VERSION;
- reqdata->req.type = type;
- reqdata->req.key_len = keylen;
-
- memcpy (reqdata->key, key, keylen);
-
- bool first_try = true;
- struct timeval tvend;
- /* Fake initializing tvend. */
- asm ("" : "=m" (tvend));
- while (1)
- {
-#ifndef MSG_NOSIGNAL
-# define MSG_NOSIGNAL 0
-#endif
- ssize_t wres = TEMP_FAILURE_RETRY (__send (sock, reqdata,
- real_sizeof_reqdata,
- MSG_NOSIGNAL));
- if (__glibc_likely (wres == (ssize_t) real_sizeof_reqdata))
- /* We managed to send the request. */
- return sock;
-
- if (wres != -1 || errno != EAGAIN)
- /* Something is really wrong, no chance to continue. */
- break;
-
- /* The daemon is busy wait for it. */
- int to;
- struct timeval now;
- (void) __gettimeofday (&now, NULL);
- if (first_try)
- {
- tvend.tv_usec = now.tv_usec;
- tvend.tv_sec = now.tv_sec + 5;
- to = 5 * 1000;
- first_try = false;
- }
- else
- to = ((tvend.tv_sec - now.tv_sec) * 1000
- + (tvend.tv_usec - now.tv_usec) / 1000);
-
- struct pollfd fds[1];
- fds[0].fd = sock;
- fds[0].events = POLLOUT | POLLERR | POLLHUP;
- if (__poll (fds, 1, to) <= 0)
- /* The connection timed out or broke down. */
- break;
-
- /* We try to write again. */
- }
-
- out:
- close_not_cancel_no_status (sock);
-
- return -1;
-}
-
-
-void
-__nscd_unmap (struct mapped_database *mapped)
-{
- assert (mapped->counter == 0);
- __munmap ((void *) mapped->head, mapped->mapsize);
- free (mapped);
-}
-
-
-/* Try to get a file descriptor for the shared meory segment
- containing the database. */
-struct mapped_database *
-__nscd_get_mapping (request_type type, const char *key,
- struct mapped_database **mappedp)
-{
- struct mapped_database *result = NO_MAPPING;
-#ifdef SCM_RIGHTS
- const size_t keylen = strlen (key) + 1;
- int saved_errno = errno;
-
- int mapfd = -1;
- char resdata[keylen];
-
- /* Open a socket and send the request. */
- int sock = open_socket (type, key, keylen);
- if (sock < 0)
- goto out;
-
- /* Room for the data sent along with the file descriptor. We expect
- the key name back. */
- uint64_t mapsize;
- struct iovec iov[2];
- iov[0].iov_base = resdata;
- iov[0].iov_len = keylen;
- iov[1].iov_base = &mapsize;
- iov[1].iov_len = sizeof (mapsize);
-
- union
- {
- struct cmsghdr hdr;
- char bytes[CMSG_SPACE (sizeof (int))];
- } buf;
- struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 2,
- .msg_control = buf.bytes,
- .msg_controllen = sizeof (buf) };
- struct cmsghdr *cmsg = CMSG_FIRSTHDR (&msg);
-
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN (sizeof (int));
-
- /* This access is well-aligned since BUF is correctly aligned for an
- int and CMSG_DATA preserves this alignment. */
- memset (CMSG_DATA (cmsg), '\xff', sizeof (int));
-
- msg.msg_controllen = cmsg->cmsg_len;
-
- if (wait_on_socket (sock, 5 * 1000) <= 0)
- goto out_close2;
-
-# ifndef MSG_CMSG_CLOEXEC
-# define MSG_CMSG_CLOEXEC 0
-# endif
- ssize_t n = TEMP_FAILURE_RETRY (__recvmsg (sock, &msg, MSG_CMSG_CLOEXEC));
-
- if (__builtin_expect (CMSG_FIRSTHDR (&msg) == NULL
- || (CMSG_FIRSTHDR (&msg)->cmsg_len
- != CMSG_LEN (sizeof (int))), 0))
- goto out_close2;
-
- int *ip = (void *) CMSG_DATA (cmsg);
- mapfd = *ip;
-
- if (__glibc_unlikely (n != keylen && n != keylen + sizeof (mapsize)))
- goto out_close;
-
- if (__glibc_unlikely (strcmp (resdata, key) != 0))
- goto out_close;
-
- if (__glibc_unlikely (n == keylen))
- {
- struct stat64 st;
- if (__builtin_expect (fstat64 (mapfd, &st) != 0, 0)
- || __builtin_expect (st.st_size < sizeof (struct database_pers_head),
- 0))
- goto out_close;
-
- mapsize = st.st_size;
- }
-
- /* The file is large enough, map it now. */
- void *mapping = __mmap (NULL, mapsize, PROT_READ, MAP_SHARED, mapfd, 0);
- if (__glibc_likely (mapping != MAP_FAILED))
- {
- /* Check whether the database is correct and up-to-date. */
- struct database_pers_head *head = mapping;
-
- if (__builtin_expect (head->version != DB_VERSION, 0)
- || __builtin_expect (head->header_size != sizeof (*head), 0)
- /* Catch some misconfiguration. The server should catch
- them now but some older versions did not. */
- || __builtin_expect (head->module == 0, 0)
- /* This really should not happen but who knows, maybe the update
- thread got stuck. */
- || __builtin_expect (! head->nscd_certainly_running
- && (head->timestamp + MAPPING_TIMEOUT
- < time (NULL)), 0))
- {
- out_unmap:
- __munmap (mapping, mapsize);
- goto out_close;
- }
-
- size_t size = (sizeof (*head) + roundup (head->module * sizeof (ref_t),
- ALIGN)
- + head->data_size);
-
- if (__glibc_unlikely (mapsize < size))
- goto out_unmap;
-
- /* Allocate a record for the mapping. */
- struct mapped_database *newp = malloc (sizeof (*newp));
- if (newp == NULL)
- /* Ugh, after all we went through the memory allocation failed. */
- goto out_unmap;
-
- newp->head = mapping;
- newp->data = ((char *) mapping + head->header_size
- + roundup (head->module * sizeof (ref_t), ALIGN));
- newp->mapsize = size;
- newp->datasize = head->data_size;
- /* Set counter to 1 to show it is usable. */
- newp->counter = 1;
-
- result = newp;
- }
-
- out_close:
- __close (mapfd);
- out_close2:
- __close (sock);
- out:
- __set_errno (saved_errno);
-#endif /* SCM_RIGHTS */
-
- struct mapped_database *oldval = *mappedp;
- *mappedp = result;
-
- if (oldval != NULL && atomic_decrement_val (&oldval->counter) == 0)
- __nscd_unmap (oldval);
-
- return result;
-}
-
-struct mapped_database *
-__nscd_get_map_ref (request_type type, const char *name,
- volatile struct locked_map_ptr *mapptr, int *gc_cyclep)
-{
- struct mapped_database *cur = mapptr->mapped;
- if (cur == NO_MAPPING)
- return cur;
-
- if (!__nscd_acquire_maplock (mapptr))
- return NO_MAPPING;
-
- cur = mapptr->mapped;
-
- if (__glibc_likely (cur != NO_MAPPING))
- {
- /* If not mapped or timestamp not updated, request new map. */
- if (cur == NULL
- || (cur->head->nscd_certainly_running == 0
- && cur->head->timestamp + MAPPING_TIMEOUT < time (NULL))
- || cur->head->data_size > cur->datasize)
- cur = __nscd_get_mapping (type, name,
- (struct mapped_database **) &mapptr->mapped);
-
- if (__glibc_likely (cur != NO_MAPPING))
- {
- if (__builtin_expect (((*gc_cyclep = cur->head->gc_cycle) & 1) != 0,
- 0))
- cur = NO_MAPPING;
- else
- atomic_increment (&cur->counter);
- }
- }
-
- mapptr->lock = 0;
-
- return cur;
-}
-
-
-/* Using sizeof (hashentry) is not always correct to determine the size of
- the data structure as found in the nscd cache. The program could be
- a 64-bit process and nscd could be a 32-bit process. In this case
- sizeof (hashentry) would overestimate the size. The following is
- the minimum size of such an entry, good enough for our tests here. */
-#define MINIMUM_HASHENTRY_SIZE \
- (offsetof (struct hashentry, dellist) + sizeof (int32_t))
-
-
-/* Don't return const struct datahead *, as eventhough the record
- is normally constant, it can change arbitrarily during nscd
- garbage collection. */
-struct datahead *
-__nscd_cache_search (request_type type, const char *key, size_t keylen,
- const struct mapped_database *mapped, size_t datalen)
-{
- unsigned long int hash = __nis_hash (key, keylen) % mapped->head->module;
- size_t datasize = mapped->datasize;
-
- ref_t trail = mapped->head->array[hash];
- trail = atomic_forced_read (trail);
- ref_t work = trail;
- size_t loop_cnt = datasize / (MINIMUM_HASHENTRY_SIZE
- + offsetof (struct datahead, data) / 2);
- int tick = 0;
-
- while (work != ENDREF && work + MINIMUM_HASHENTRY_SIZE <= datasize)
- {
- struct hashentry *here = (struct hashentry *) (mapped->data + work);
- ref_t here_key, here_packet;
-
-#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
- between those memory writes. It is very unlikely to hit it,
- so check alignment only if a misaligned load can crash the
- application. */
- if ((uintptr_t) here & (__alignof__ (*here) - 1))
- return NULL;
-#endif
-
- if (type == here->type
- && keylen == here->len
- && (here_key = atomic_forced_read (here->key)) + keylen <= datasize
- && memcmp (key, mapped->data + here_key, keylen) == 0
- && ((here_packet = atomic_forced_read (here->packet))
- + sizeof (struct datahead) <= datasize))
- {
- /* We found the entry. Increment the appropriate counter. */
- struct datahead *dh
- = (struct datahead *) (mapped->data + here_packet);
-
-#if !_STRING_ARCH_unaligned
- if ((uintptr_t) dh & (__alignof__ (*dh) - 1))
- return NULL;
-#endif
-
- /* See whether we must ignore the entry or whether something
- is wrong because garbage collection is in progress. */
- if (dh->usable
- && here_packet + dh->allocsize <= datasize
- && (here_packet + offsetof (struct datahead, data) + datalen
- <= datasize))
- return dh;
- }
-
- work = atomic_forced_read (here->next);
- /* Prevent endless loops. This should never happen but perhaps
- the database got corrupted, accidentally or deliberately. */
- if (work == trail || loop_cnt-- == 0)
- break;
- if (tick)
- {
- struct hashentry *trailelem;
- trailelem = (struct hashentry *) (mapped->data + trail);
-
-#if !_STRING_ARCH_unaligned
- /* We have to redo the checks. Maybe the data changed. */
- if ((uintptr_t) trailelem & (__alignof__ (*trailelem) - 1))
- return NULL;
-#endif
-
- if (trail + MINIMUM_HASHENTRY_SIZE > datasize)
- return NULL;
-
- trail = atomic_forced_read (trailelem->next);
- }
- tick = 1 - tick;
- }
-
- return NULL;
-}
-
-
-/* Create a socket connected to a name. */
-int
-__nscd_open_socket (const char *key, size_t keylen, request_type type,
- void *response, size_t responselen)
-{
- /* This should never happen and it is something the nscd daemon
- enforces, too. He it helps to limit the amount of stack
- used. */
- if (keylen > MAXKEYLEN)
- return -1;
-
- int saved_errno = errno;
-
- int sock = open_socket (type, key, keylen);
- if (sock >= 0)
- {
- /* Wait for data. */
- if (wait_on_socket (sock, 5 * 1000) > 0)
- {
- ssize_t nbytes = TEMP_FAILURE_RETRY (__read (sock, response,
- responselen));
- if (nbytes == (ssize_t) responselen)
- return sock;
- }
-
- close_not_cancel_no_status (sock);
- }
-
- __set_errno (saved_errno);
-
- return -1;
-}
diff --git a/nscd/nscd_initgroups.c b/nscd/nscd_initgroups.c
deleted file mode 100644
index 00c650896a..0000000000
--- a/nscd/nscd_initgroups.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/* Copyright (C) 2004-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-#include <assert.h>
-#include <errno.h>
-#include <grp.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <not-cancel.h>
-
-#include "nscd-client.h"
-#include "nscd_proto.h"
-
-
-/* We use the same mapping as in nscd_getgr. */
-libc_locked_map_ptr (extern, __gr_map_handle) attribute_hidden;
-
-
-int
-__nscd_getgrouplist (const char *user, gid_t group, long int *size,
- gid_t **groupsp, long int limit)
-{
- size_t userlen = strlen (user) + 1;
- int gc_cycle;
- int nretries = 0;
-
- /* If the mapping is available, try to search there instead of
- communicating with the nscd. */
- struct mapped_database *mapped;
- mapped = __nscd_get_map_ref (GETFDGR, "group", &__gr_map_handle, &gc_cycle);
-
- retry:;
- char *respdata = NULL;
- int retval = -1;
- int sock = -1;
- initgr_response_header initgr_resp;
-
- if (mapped != NO_MAPPING)
- {
- struct datahead *found = __nscd_cache_search (INITGROUPS, user,
- userlen, mapped,
- sizeof initgr_resp);
- if (found != NULL)
- {
- respdata = (char *) (&found->data[0].initgrdata + 1);
- initgr_resp = found->data[0].initgrdata;
- char *recend = (char *) found->data + found->recsize;
-
- /* Now check if we can trust initgr_resp fields. If GC is
- in progress, it can contain anything. */
- if (mapped->head->gc_cycle != gc_cycle)
- {
- retval = -2;
- goto out;
- }
-
- if (respdata + initgr_resp.ngrps * sizeof (int32_t) > recend)
- goto out;
- }
- }
-
- /* If we do not have the cache mapped, try to get the data over the
- socket. */
- if (respdata == NULL)
- {
- sock = __nscd_open_socket (user, userlen, INITGROUPS, &initgr_resp,
- sizeof (initgr_resp));
- if (sock == -1)
- {
- /* nscd not running or wrong version. */
- __nss_not_use_nscd_group = 1;
- goto out;
- }
- }
-
- if (initgr_resp.found == 1)
- {
- /* The following code assumes that gid_t and int32_t are the
- same size. This is the case for al existing implementation.
- If this should change some code needs to be added which
- doesn't use memcpy but instead copies each array element one
- by one. */
- assert (sizeof (int32_t) == sizeof (gid_t));
- assert (initgr_resp.ngrps >= 0);
-
- /* Make sure we have enough room. We always count GROUP in even
- though we might not end up adding it. */
- if (*size < initgr_resp.ngrps + 1)
- {
- gid_t *newp = realloc (*groupsp,
- (initgr_resp.ngrps + 1) * sizeof (gid_t));
- if (newp == NULL)
- /* We cannot increase the buffer size. */
- goto out_close;
-
- *groupsp = newp;
- *size = initgr_resp.ngrps + 1;
- }
-
- if (respdata == NULL)
- {
- /* Read the data from the socket. */
- if ((size_t) __readall (sock, *groupsp, initgr_resp.ngrps
- * sizeof (gid_t))
- == initgr_resp.ngrps * sizeof (gid_t))
- retval = initgr_resp.ngrps;
- }
- else
- {
- /* Just copy the data. */
- retval = initgr_resp.ngrps;
- memcpy (*groupsp, respdata, retval * sizeof (gid_t));
- }
- }
- else
- {
- if (__glibc_unlikely (initgr_resp.found == -1))
- {
- /* The daemon does not cache this database. */
- __nss_not_use_nscd_group = 1;
- goto out_close;
- }
-
- /* No group found yet. */
- retval = 0;
-
- assert (*size >= 1);
- }
-
- /* Check whether GROUP is part of the mix. If not, add it. */
- if (retval >= 0)
- {
- int cnt;
- for (cnt = 0; cnt < retval; ++cnt)
- if ((*groupsp)[cnt] == group)
- break;
-
- if (cnt == retval)
- (*groupsp)[retval++] = group;
- }
-
- out_close:
- if (sock != -1)
- close_not_cancel_no_status (sock);
- out:
- if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
- {
- /* When we come here this means there has been a GC cycle while we
- were looking for the data. This means the data might have been
- inconsistent. Retry if possible. */
- if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
- {
- /* nscd is just running gc now. Disable using the mapping. */
- if (atomic_decrement_val (&mapped->counter) == 0)
- __nscd_unmap (mapped);
- mapped = NO_MAPPING;
- }
-
- if (retval != -1)
- goto retry;
- }
-
- return retval;
-}
diff --git a/nscd/nscd_netgroup.c b/nscd/nscd_netgroup.c
deleted file mode 100644
index 44f37ef957..0000000000
--- a/nscd/nscd_netgroup.c
+++ /dev/null
@@ -1,289 +0,0 @@
-/* Copyright (C) 2011-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-#include <alloca.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <not-cancel.h>
-
-#include "nscd-client.h"
-#include "nscd_proto.h"
-
-int __nss_not_use_nscd_netgroup;
-
-
-libc_locked_map_ptr (static, map_handle);
-/* Note that we only free the structure if necessary. The memory
- mapping is not removed since it is not visible to the malloc
- handling. */
-libc_freeres_fn (pw_map_free)
-{
- if (map_handle.mapped != NO_MAPPING)
- {
- void *p = map_handle.mapped;
- map_handle.mapped = NO_MAPPING;
- free (p);
- }
-}
-
-
-int
-__nscd_setnetgrent (const char *group, struct __netgrent *datap)
-{
- int gc_cycle;
- int nretries = 0;
- size_t group_len = strlen (group) + 1;
-
- /* If the mapping is available, try to search there instead of
- communicating with the nscd. */
- struct mapped_database *mapped;
- mapped = __nscd_get_map_ref (GETFDNETGR, "netgroup", &map_handle, &gc_cycle);
-
- retry:;
- char *respdata = NULL;
- int retval = -1;
- netgroup_response_header netgroup_resp;
-
- if (mapped != NO_MAPPING)
- {
- struct datahead *found = __nscd_cache_search (GETNETGRENT, group,
- group_len, mapped,
- sizeof netgroup_resp);
- if (found != NULL)
- {
- respdata = (char *) (&found->data[0].netgroupdata + 1);
- netgroup_resp = found->data[0].netgroupdata;
- /* Now check if we can trust pw_resp fields. If GC is
- in progress, it can contain anything. */
- if (mapped->head->gc_cycle != gc_cycle)
- {
- retval = -2;
- goto out;
- }
- }
- }
-
- int sock = -1;
- if (respdata == NULL)
- {
- sock = __nscd_open_socket (group, group_len, GETNETGRENT,
- &netgroup_resp, sizeof (netgroup_resp));
- if (sock == -1)
- {
- /* nscd not running or wrong version. */
- __nss_not_use_nscd_netgroup = 1;
- goto out;
- }
- }
-
- if (netgroup_resp.found == 1)
- {
- size_t datalen = netgroup_resp.result_len;
-
- /* If we do not have to read the data here it comes from the
- mapped data and does not have to be freed. */
- if (respdata == NULL)
- {
- /* The data will come via the socket. */
- respdata = malloc (datalen);
- if (respdata == NULL)
- goto out_close;
-
- if ((size_t) __readall (sock, respdata, datalen) != datalen)
- {
- free (respdata);
- goto out_close;
- }
- }
-
- datap->data = respdata;
- datap->data_size = datalen;
- datap->cursor = respdata;
- datap->first = 1;
- datap->nip = (service_user *) -1l;
- datap->known_groups = NULL;
- datap->needed_groups = NULL;
-
- retval = 1;
- }
- else
- {
- if (__glibc_unlikely (netgroup_resp.found == -1))
- {
- /* The daemon does not cache this database. */
- __nss_not_use_nscd_netgroup = 1;
- goto out_close;
- }
-
- /* Set errno to 0 to indicate no error, just no found record. */
- __set_errno (0);
- /* Even though we have not found anything, the result is zero. */
- retval = 0;
- }
-
- out_close:
- if (sock != -1)
- close_not_cancel_no_status (sock);
- out:
- if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
- {
- /* When we come here this means there has been a GC cycle while we
- were looking for the data. This means the data might have been
- inconsistent. Retry if possible. */
- if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
- {
- /* nscd is just running gc now. Disable using the mapping. */
- if (atomic_decrement_val (&mapped->counter) == 0)
- __nscd_unmap (mapped);
- mapped = NO_MAPPING;
- }
-
- if (retval != -1)
- goto retry;
- }
-
- return retval;
-}
-
-
-int
-__nscd_innetgr (const char *netgroup, const char *host, const char *user,
- const char *domain)
-{
- size_t key_len = (strlen (netgroup) + strlen (host ?: "")
- + strlen (user ?: "") + strlen (domain ?: "") + 7);
- char *key;
- bool use_alloca = __libc_use_alloca (key_len);
- if (use_alloca)
- key = alloca (key_len);
- else
- {
- key = malloc (key_len);
- if (key == NULL)
- return -1;
- }
- char *wp = stpcpy (key, netgroup) + 1;
- if (host != NULL)
- {
- *wp++ = '\1';
- wp = stpcpy (wp, host) + 1;
- }
- else
- *wp++ = '\0';
- if (user != NULL)
- {
- *wp++ = '\1';
- wp = stpcpy (wp, user) + 1;
- }
- else
- *wp++ = '\0';
- if (domain != NULL)
- {
- *wp++ = '\1';
- wp = stpcpy (wp, domain) + 1;
- }
- else
- *wp++ = '\0';
- key_len = wp - key;
-
- /* If the mapping is available, try to search there instead of
- communicating with the nscd. */
- int gc_cycle;
- int nretries = 0;
- struct mapped_database *mapped;
- mapped = __nscd_get_map_ref (GETFDNETGR, "netgroup", &map_handle, &gc_cycle);
-
- retry:;
- int retval = -1;
- innetgroup_response_header innetgroup_resp;
- int sock = -1;
-
- if (mapped != NO_MAPPING)
- {
- struct datahead *found = __nscd_cache_search (INNETGR, key,
- key_len, mapped,
- sizeof innetgroup_resp);
- if (found != NULL)
- {
- innetgroup_resp = found->data[0].innetgroupdata;
- /* Now check if we can trust pw_resp fields. If GC is
- in progress, it can contain anything. */
- if (mapped->head->gc_cycle != gc_cycle)
- {
- retval = -2;
- goto out;
- }
-
- goto found_entry;
- }
- }
-
- sock = __nscd_open_socket (key, key_len, INNETGR,
- &innetgroup_resp, sizeof (innetgroup_resp));
- if (sock == -1)
- {
- /* nscd not running or wrong version. */
- __nss_not_use_nscd_netgroup = 1;
- goto out;
- }
-
- found_entry:
- if (innetgroup_resp.found == 1)
- retval = innetgroup_resp.result;
- else
- {
- if (__glibc_unlikely (innetgroup_resp.found == -1))
- {
- /* The daemon does not cache this database. */
- __nss_not_use_nscd_netgroup = 1;
- goto out_close;
- }
-
- /* Set errno to 0 to indicate no error, just no found record. */
- __set_errno (0);
- /* Even though we have not found anything, the result is zero. */
- retval = 0;
- }
-
- out_close:
- if (sock != -1)
- close_not_cancel_no_status (sock);
- out:
- if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
- {
- /* When we come here this means there has been a GC cycle while we
- were looking for the data. This means the data might have been
- inconsistent. Retry if possible. */
- if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
- {
- /* nscd is just running gc now. Disable using the mapping. */
- if (atomic_decrement_val (&mapped->counter) == 0)
- __nscd_unmap (mapped);
- mapped = NO_MAPPING;
- }
-
- if (retval != -1)
- goto retry;
- }
-
- if (! use_alloca)
- free (key);
-
- return retval;
-}
diff --git a/nscd/nscd_proto.h b/nscd/nscd_proto.h
deleted file mode 100644
index 7c61821e74..0000000000
--- a/nscd/nscd_proto.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* Copyright (C) 1998-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-#ifndef _NSCD_PROTO_H
-#define _NSCD_PROTO_H 1
-
-#include <grp.h>
-#include <netdb.h>
-#include <pwd.h>
-
-/* Interval in which we transfer retry to contact the NSCD. */
-#define NSS_NSCD_RETRY 100
-
-/* Type needed in the interfaces. */
-struct nscd_ai_result;
-
-
-/* Variables for communication between NSCD handler functions and NSS. */
-extern int __nss_not_use_nscd_passwd attribute_hidden;
-extern int __nss_not_use_nscd_group attribute_hidden;
-extern int __nss_not_use_nscd_hosts attribute_hidden;
-extern int __nss_not_use_nscd_services attribute_hidden;
-extern int __nss_not_use_nscd_netgroup attribute_hidden;
-
-extern int __nscd_getpwnam_r (const char *name, struct passwd *resultbuf,
- char *buffer, size_t buflen,
- struct passwd **result);
-extern int __nscd_getpwuid_r (uid_t uid, struct passwd *resultbuf,
- char *buffer, size_t buflen,
- struct passwd **result);
-extern int __nscd_getgrnam_r (const char *name, struct group *resultbuf,
- char *buffer, size_t buflen,
- struct group **result);
-extern int __nscd_getgrgid_r (gid_t gid, struct group *resultbuf,
- char *buffer, size_t buflen,
- struct group **result);
-extern int __nscd_gethostbyname_r (const char *name,
- struct hostent *resultbuf,
- char *buffer, size_t buflen,
- struct hostent **result, int *h_errnop);
-extern int __nscd_gethostbyname2_r (const char *name, int af,
- struct hostent *resultbuf,
- char *buffer, size_t buflen,
- struct hostent **result, int *h_errnop);
-extern int __nscd_gethostbyaddr_r (const void *addr, socklen_t len, int type,
- struct hostent *resultbuf,
- char *buffer, size_t buflen,
- struct hostent **result, int *h_errnop);
-extern int __nscd_getai (const char *key, struct nscd_ai_result **result,
- int *h_errnop);
-extern int __nscd_getgrouplist (const char *user, gid_t group, long int *size,
- gid_t **groupsp, long int limit);
-extern int __nscd_getservbyname_r (const char *name, const char *proto,
- struct servent *result_buf, char *buf,
- size_t buflen, struct servent **result);
-extern int __nscd_getservbyport_r (int port, const char *proto,
- struct servent *result_buf, char *buf,
- size_t buflen, struct servent **result);
-extern int __nscd_innetgr (const char *netgroup, const char *host,
- const char *user, const char *domain);
-extern int __nscd_setnetgrent (const char *group, struct __netgrent *datap);
-
-
-#endif /* _NSCD_PROTO_H */
diff --git a/nscd/nscd_setup_thread.c b/nscd/nscd_setup_thread.c
deleted file mode 100644
index c3670ad943..0000000000
--- a/nscd/nscd_setup_thread.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Setup of nscd worker threads. Stub verison.
- Copyright (C) 2004-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#include <nscd.h>
-
-
-int
-setup_thread (struct database_dyn *db)
-{
- /* Nothing. */
- return 0;
-}
diff --git a/nscd/nscd_stat.c b/nscd/nscd_stat.c
deleted file mode 100644
index feb1c98ac3..0000000000
--- a/nscd/nscd_stat.c
+++ /dev/null
@@ -1,318 +0,0 @@
-/* Copyright (c) 1998-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-#include <errno.h>
-#include <error.h>
-#include <inttypes.h>
-#include <langinfo.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <unistd.h>
-#include <libintl.h>
-
-#include "nscd.h"
-#include "dbg_log.h"
-#include "selinux.h"
-#ifdef HAVE_SELINUX
-# include <selinux/selinux.h>
-# include <selinux/avc.h>
-#endif /* HAVE_SELINUX */
-
-
-/* We use this to make sure the receiver is the same. */
-static const char compilation[21] = __DATE__ " " __TIME__;
-
-/* Statistic data for one database. */
-struct dbstat
-{
- int enabled;
- int check_file;
- int shared;
- int persistent;
- size_t module;
-
- unsigned long int postimeout;
- unsigned long int negtimeout;
-
- size_t nentries;
- size_t maxnentries;
- size_t maxnsearched;
- size_t datasize;
- size_t dataused;
-
- uintmax_t poshit;
- uintmax_t neghit;
- uintmax_t posmiss;
- uintmax_t negmiss;
-
- uintmax_t rdlockdelayed;
- uintmax_t wrlockdelayed;
-
- uintmax_t addfailed;
-};
-
-/* Record for transmitting statistics. */
-struct statdata
-{
- char version[sizeof (compilation)];
- int debug_level;
- time_t runtime;
- unsigned long int client_queued;
- int nthreads;
- int max_nthreads;
- int paranoia;
- time_t restart_interval;
- unsigned int reload_count;
- int ndbs;
- struct dbstat dbs[lastdb];
-#ifdef HAVE_SELINUX
- struct avc_cache_stats cstats;
-#endif /* HAVE_SELINUX */
-};
-
-
-void
-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;
- data.client_queued = client_queued;
- data.nthreads = nthreads;
- data.max_nthreads = max_nthreads;
- data.paranoia = paranoia;
- data.restart_interval = restart_interval;
- data.reload_count = reload_count;
- data.ndbs = lastdb;
-
- for (cnt = 0; cnt < lastdb; ++cnt)
- {
- memset (&data.dbs[cnt], 0, sizeof (data.dbs[cnt]));
- data.dbs[cnt].enabled = dbs[cnt].enabled;
- data.dbs[cnt].check_file = dbs[cnt].check_file;
- data.dbs[cnt].shared = dbs[cnt].shared;
- data.dbs[cnt].persistent = dbs[cnt].persistent;
- data.dbs[cnt].postimeout = dbs[cnt].postimeout;
- data.dbs[cnt].negtimeout = dbs[cnt].negtimeout;
- if (dbs[cnt].head != NULL)
- {
- data.dbs[cnt].module = dbs[cnt].head->module;
- data.dbs[cnt].poshit = dbs[cnt].head->poshit;
- data.dbs[cnt].neghit = dbs[cnt].head->neghit;
- data.dbs[cnt].posmiss = dbs[cnt].head->posmiss;
- data.dbs[cnt].negmiss = dbs[cnt].head->negmiss;
- data.dbs[cnt].nentries = dbs[cnt].head->nentries;
- data.dbs[cnt].maxnentries = dbs[cnt].head->maxnentries;
- data.dbs[cnt].datasize = dbs[cnt].head->data_size;
- data.dbs[cnt].dataused = dbs[cnt].head->first_free;
- data.dbs[cnt].maxnsearched = dbs[cnt].head->maxnsearched;
- data.dbs[cnt].rdlockdelayed = dbs[cnt].head->rdlockdelayed;
- data.dbs[cnt].wrlockdelayed = dbs[cnt].head->wrlockdelayed;
- data.dbs[cnt].addfailed = dbs[cnt].head->addfailed;
- }
- }
-
- if (selinux_enabled)
- nscd_avc_cache_stats (&data.cstats);
-
- if (TEMP_FAILURE_RETRY (send (fd, &data, sizeof (data), MSG_NOSIGNAL))
- != sizeof (data))
- {
- char buf[256];
- dbg_log (_("cannot write statistics: %s"),
- strerror_r (errno, buf, sizeof (buf)));
- }
-}
-
-
-int
-receive_print_stats (void)
-{
- struct statdata data;
- request_header req;
- ssize_t nbytes;
- int fd;
- int i;
- uid_t uid = getuid ();
- const char *yesstr = _("yes");
- const char *nostr = _("no");
-
- /* Find out whether there is another user but root allowed to
- request statistics. */
- if (uid != 0)
- {
- /* User specified? */
- if(stat_user == NULL || stat_uid != uid)
- {
- if (stat_user != NULL)
- error (EXIT_FAILURE, 0,
- _("Only root or %s is allowed to use this option!"),
- stat_user);
- else
- error (EXIT_FAILURE, 0,
- _("Only root is allowed to use this option!"));
- }
- }
-
- /* Open a socket to the running nscd. */
- fd = nscd_open_socket ();
- if (fd == -1)
- error (EXIT_FAILURE, 0, _("nscd not running!\n"));
-
- /* Send the request. */
- req.version = NSCD_VERSION;
- req.type = GETSTAT;
- req.key_len = 0;
- nbytes = TEMP_FAILURE_RETRY (send (fd, &req, sizeof (request_header),
- MSG_NOSIGNAL));
- if (nbytes != sizeof (request_header))
- {
- int err = errno;
- close (fd);
- error (EXIT_FAILURE, err, _("write incomplete"));
- }
-
- /* Read as much data as we expect. */
- if (TEMP_FAILURE_RETRY (read (fd, &data, sizeof (data))) != sizeof (data)
- || (memcmp (data.version, compilation, sizeof (compilation)) != 0
- /* Yes, this is an assignment! */
- && (errno = EINVAL)))
- {
- /* Not the right version. */
- int err = errno;
- close (fd);
- error (EXIT_FAILURE, err, _("cannot read statistics data"));
- }
-
- printf (_("nscd configuration:\n\n%15d server debug level\n"),
- data.debug_level);
-
- /* We know that we can simply subtract time_t values. */
- unsigned long int diff = data.runtime;
- unsigned int ndays = 0;
- unsigned int nhours = 0;
- unsigned int nmins = 0;
- if (diff > 24 * 60 * 60)
- {
- ndays = diff / (24 * 60 * 60);
- diff %= 24 * 60 * 60;
- }
- if (diff > 60 * 60)
- {
- nhours = diff / (60 * 60);
- diff %= 60 * 60;
- }
- if (diff > 60)
- {
- nmins = diff / 60;
- diff %= 60;
- }
- if (ndays != 0)
- printf (_("%3ud %2uh %2um %2lus server runtime\n"),
- ndays, nhours, nmins, diff);
- else if (nhours != 0)
- printf (_(" %2uh %2um %2lus server runtime\n"), nhours, nmins, diff);
- else if (nmins != 0)
- printf (_(" %2um %2lus server runtime\n"), nmins, diff);
- else
- printf (_(" %2lus server runtime\n"), diff);
-
- printf (_("%15d current number of threads\n"
- "%15d maximum number of threads\n"
- "%15lu number of times clients had to wait\n"
- "%15s paranoia mode enabled\n"
- "%15lu restart internal\n"
- "%15u reload count\n"),
- data.nthreads, data.max_nthreads, data.client_queued,
- data.paranoia ? yesstr : nostr,
- (unsigned long int) data.restart_interval, data.reload_count);
-
- for (i = 0; i < lastdb; ++i)
- {
- unsigned long int hit = data.dbs[i].poshit + data.dbs[i].neghit;
- unsigned long int all = hit + data.dbs[i].posmiss + data.dbs[i].negmiss;
- const char *enabled = data.dbs[i].enabled ? yesstr : nostr;
- const char *check_file = data.dbs[i].check_file ? yesstr : nostr;
- const char *shared = data.dbs[i].shared ? yesstr : nostr;
- const char *persistent = data.dbs[i].persistent ? yesstr : nostr;
-
- if (enabled[0] == '\0')
- /* The locale does not provide this information so we have to
- translate it ourself. Since we should avoid short translation
- terms we artifically increase the length. */
- enabled = data.dbs[i].enabled ? yesstr : nostr;
- if (check_file[0] == '\0')
- check_file = data.dbs[i].check_file ? yesstr : nostr;
- if (shared[0] == '\0')
- shared = data.dbs[i].shared ? yesstr : nostr;
- if (persistent[0] == '\0')
- persistent = data.dbs[i].persistent ? yesstr : nostr;
-
- if (all == 0)
- /* If nothing happened so far report a 0% hit rate. */
- all = 1;
-
- printf (_("\n%s cache:\n\n"
- "%15s cache is enabled\n"
- "%15s cache is persistent\n"
- "%15s cache is shared\n"
- "%15zu suggested size\n"
- "%15zu total data pool size\n"
- "%15zu used data pool size\n"
- "%15lu seconds time to live for positive entries\n"
- "%15lu seconds time to live for negative entries\n"
- "%15" PRIuMAX " cache hits on positive entries\n"
- "%15" PRIuMAX " cache hits on negative entries\n"
- "%15" PRIuMAX " cache misses on positive entries\n"
- "%15" PRIuMAX " cache misses on negative entries\n"
- "%15lu%% cache hit rate\n"
- "%15zu current number of cached values\n"
- "%15zu maximum number of cached values\n"
- "%15zu maximum chain length searched\n"
- "%15" PRIuMAX " number of delays on rdlock\n"
- "%15" PRIuMAX " number of delays on wrlock\n"
- "%15" PRIuMAX " memory allocations failed\n"
- "%15s check /etc/%s for changes\n"),
- dbnames[i], enabled, persistent, shared,
- data.dbs[i].module,
- data.dbs[i].datasize, data.dbs[i].dataused,
- data.dbs[i].postimeout, data.dbs[i].negtimeout,
- data.dbs[i].poshit, data.dbs[i].neghit,
- data.dbs[i].posmiss, data.dbs[i].negmiss,
- (100 * hit) / all,
- data.dbs[i].nentries, data.dbs[i].maxnentries,
- data.dbs[i].maxnsearched,
- data.dbs[i].rdlockdelayed,
- data.dbs[i].wrlockdelayed,
- data.dbs[i].addfailed, check_file, dbnames[i]);
- }
-
- if (selinux_enabled)
- nscd_avc_print_stats (&data.cstats);
-
- close (fd);
-
- exit (0);
-}
diff --git a/nscd/pwdcache.c b/nscd/pwdcache.c
deleted file mode 100644
index 721f4c617b..0000000000
--- a/nscd/pwdcache.c
+++ /dev/null
@@ -1,552 +0,0 @@
-/* Cache handling for passwd lookup.
- Copyright (C) 1998-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#include <alloca.h>
-#include <assert.h>
-#include <errno.h>
-#include <error.h>
-#include <libintl.h>
-#include <pwd.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/socket.h>
-#include <stackinfo.h>
-
-#include "nscd.h"
-#include "dbg_log.h"
-#ifdef HAVE_SENDFILE
-# include <kernel-features.h>
-#endif
-
-/* This is the standard reply in case the service is disabled. */
-static const pw_response_header disabled =
-{
- .version = NSCD_VERSION,
- .found = -1,
- .pw_name_len = 0,
- .pw_passwd_len = 0,
- .pw_uid = -1,
- .pw_gid = -1,
- .pw_gecos_len = 0,
- .pw_dir_len = 0,
- .pw_shell_len = 0
-};
-
-/* This is the struct describing how to write this record. */
-const struct iovec pwd_iov_disabled =
-{
- .iov_base = (void *) &disabled,
- .iov_len = sizeof (disabled)
-};
-
-
-/* This is the standard reply in case we haven't found the dataset. */
-static const pw_response_header notfound =
-{
- .version = NSCD_VERSION,
- .found = 0,
- .pw_name_len = 0,
- .pw_passwd_len = 0,
- .pw_uid = -1,
- .pw_gid = -1,
- .pw_gecos_len = 0,
- .pw_dir_len = 0,
- .pw_shell_len = 0
-};
-
-
-static time_t
-cache_addpw (struct database_dyn *db, int fd, request_header *req,
- const void *key, struct passwd *pwd, uid_t owner,
- struct hashentry *const he, struct datahead *dh, int errval)
-{
- bool all_written = true;
- ssize_t total;
- time_t t = time (NULL);
-
- /* We allocate all data in one memory block: the iov vector,
- the response header and the dataset itself. */
- struct dataset
- {
- struct datahead head;
- pw_response_header resp;
- char strdata[0];
- } *dataset;
-
- assert (offsetof (struct dataset, resp) == offsetof (struct datahead, data));
-
- time_t timeout = MAX_TIMEOUT_VALUE;
- if (pwd == NULL)
- {
- if (he != NULL && errval == EAGAIN)
- {
- /* If we have an old record available but cannot find one
- now because the service is not available we keep the old
- record and make sure it does not get removed. */
- if (reload_count != UINT_MAX && dh->nreloads == reload_count)
- /* Do not reset the value if we never not reload the record. */
- dh->nreloads = reload_count - 1;
-
- /* Reload with the same time-to-live value. */
- timeout = dh->timeout = t + db->postimeout;
-
- total = 0;
- }
- else
- {
- /* We have no data. This means we send the standard reply for this
- case. */
- total = sizeof (notfound);
-
- if (fd != -1
- && TEMP_FAILURE_RETRY (send (fd, &notfound, total,
- MSG_NOSIGNAL)) != total)
- all_written = false;
-
- /* If we have a transient error or cannot permanently store
- the result, so be it. */
- if (errno == EAGAIN || __builtin_expect (db->negtimeout == 0, 0))
- {
- /* Mark the old entry as obsolete. */
- if (dh != NULL)
- dh->usable = false;
- }
- else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
- + req->key_len), 1)) != NULL)
- {
- timeout = datahead_init_neg (&dataset->head,
- (sizeof (struct dataset)
- + req->key_len), total,
- db->negtimeout);
-
- /* This is the reply. */
- memcpy (&dataset->resp, &notfound, total);
-
- /* Copy the key data. */
- char *key_copy = memcpy (dataset->strdata, key, req->key_len);
-
- /* If necessary, we also propagate the data to disk. */
- if (db->persistent)
- {
- // XXX async OK?
- uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
- msync ((void *) pval,
- ((uintptr_t) dataset & pagesize_m1)
- + sizeof (struct dataset) + req->key_len, MS_ASYNC);
- }
-
- (void) cache_add (req->type, key_copy, req->key_len,
- &dataset->head, true, db, owner, he == NULL);
-
- pthread_rwlock_unlock (&db->lock);
-
- /* Mark the old entry as obsolete. */
- if (dh != NULL)
- dh->usable = false;
- }
- }
- }
- else
- {
- /* Determine the I/O structure. */
- size_t pw_name_len = strlen (pwd->pw_name) + 1;
- size_t pw_passwd_len = strlen (pwd->pw_passwd) + 1;
- size_t pw_gecos_len = strlen (pwd->pw_gecos) + 1;
- size_t pw_dir_len = strlen (pwd->pw_dir) + 1;
- size_t pw_shell_len = strlen (pwd->pw_shell) + 1;
- char *cp;
- const size_t key_len = strlen (key);
- const size_t buf_len = 3 * sizeof (pwd->pw_uid) + key_len + 1;
- char *buf = alloca (buf_len);
- ssize_t n;
-
- /* We need this to insert the `byuid' entry. */
- int key_offset;
- n = snprintf (buf, buf_len, "%d%c%n%s", pwd->pw_uid, '\0',
- &key_offset, (char *) key) + 1;
-
- total = (offsetof (struct dataset, strdata)
- + pw_name_len + pw_passwd_len
- + pw_gecos_len + pw_dir_len + pw_shell_len);
-
- /* If we refill the cache, first assume the reconrd did not
- change. Allocate memory on the cache since it is likely
- discarded anyway. If it turns out to be necessary to have a
- new record we can still allocate real memory. */
- bool alloca_used = false;
- dataset = NULL;
-
- if (he == NULL)
- {
- /* Prevent an INVALIDATE request from pruning the data between
- the two calls to cache_add. */
- if (db->propagate)
- pthread_mutex_lock (&db->prune_run_lock);
- dataset = (struct dataset *) mempool_alloc (db, total + n, 1);
- }
-
- if (dataset == NULL)
- {
- if (he == NULL && db->propagate)
- pthread_mutex_unlock (&db->prune_run_lock);
-
- /* We cannot permanently add the result in the moment. But
- we can provide the result as is. Store the data in some
- temporary memory. */
- dataset = (struct dataset *) alloca (total + n);
-
- /* We cannot add this record to the permanent database. */
- alloca_used = true;
- }
-
- 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;
- dataset->resp.pw_name_len = pw_name_len;
- dataset->resp.pw_passwd_len = pw_passwd_len;
- dataset->resp.pw_uid = pwd->pw_uid;
- dataset->resp.pw_gid = pwd->pw_gid;
- dataset->resp.pw_gecos_len = pw_gecos_len;
- dataset->resp.pw_dir_len = pw_dir_len;
- dataset->resp.pw_shell_len = pw_shell_len;
-
- cp = dataset->strdata;
-
- /* Copy the strings over into the buffer. */
- cp = mempcpy (cp, pwd->pw_name, pw_name_len);
- cp = mempcpy (cp, pwd->pw_passwd, pw_passwd_len);
- cp = mempcpy (cp, pwd->pw_gecos, pw_gecos_len);
- cp = mempcpy (cp, pwd->pw_dir, pw_dir_len);
- cp = mempcpy (cp, pwd->pw_shell, pw_shell_len);
-
- /* Finally the stringified UID value. */
- memcpy (cp, buf, n);
- char *key_copy = cp + key_offset;
- assert (key_copy == (char *) rawmemchr (cp, '\0') + 1);
-
- assert (cp == dataset->strdata + total - offsetof (struct dataset,
- strdata));
-
- /* Now we can determine whether on refill we have to create a new
- record or not. */
- if (he != NULL)
- {
- assert (fd == -1);
-
- if (dataset->head.allocsize == dh->allocsize
- && dataset->head.recsize == dh->recsize
- && memcmp (&dataset->resp, dh->data,
- dh->allocsize - offsetof (struct dataset, resp)) == 0)
- {
- /* The data has not changed. We will just bump the
- timeout value. Note that the new record has been
- allocated on the stack and need not be freed. */
- dh->timeout = dataset->head.timeout;
- ++dh->nreloads;
- }
- else
- {
- /* We have to create a new record. Just allocate
- appropriate memory and copy it. */
- struct dataset *newp
- = (struct dataset *) mempool_alloc (db, total + n, 1);
- if (newp != NULL)
- {
- /* Adjust pointer into the memory block. */
- cp = (char *) newp + (cp - (char *) dataset);
- key_copy = (char *) newp + (key_copy - (char *) dataset);
-
- dataset = memcpy (newp, dataset, total + n);
- alloca_used = false;
- }
-
- /* Mark the old record as obsolete. */
- dh->usable = false;
- }
- }
- else
- {
- /* We write the dataset before inserting it to the database
- since while inserting this thread might block and so would
- unnecessarily let the receiver wait. */
- assert (fd != -1);
-
-#ifdef HAVE_SENDFILE
- if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
- {
- assert (db->wr_fd != -1);
- assert ((char *) &dataset->resp > (char *) db->data);
- assert ((char *) dataset - (char *) db->head
- + total
- <= (sizeof (struct database_pers_head)
- + db->head->module * sizeof (ref_t)
- + db->head->data_size));
- ssize_t written = sendfileall (fd, db->wr_fd,
- (char *) &dataset->resp
- - (char *) db->head,
- dataset->head.recsize);
- if (written != dataset->head.recsize)
- {
-# ifndef __ASSUME_SENDFILE
- if (written == -1 && errno == ENOSYS)
- goto use_write;
-# endif
- all_written = false;
- }
- }
- else
-# ifndef __ASSUME_SENDFILE
- use_write:
-# endif
-#endif
- if (writeall (fd, &dataset->resp, dataset->head.recsize)
- != dataset->head.recsize)
- all_written = false;
- }
-
-
- /* Add the record to the database. But only if it has not been
- stored on the stack. */
- if (! alloca_used)
- {
- /* If necessary, we also propagate the data to disk. */
- if (db->persistent)
- {
- // XXX async OK?
- uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
- msync ((void *) pval,
- ((uintptr_t) dataset & pagesize_m1) + total + n,
- MS_ASYNC);
- }
-
- /* NB: in the following code we always must add the entry
- marked with FIRST first. Otherwise we end up with
- dangling "pointers" in case a latter hash entry cannot be
- added. */
- bool first = true;
-
- /* If the request was by UID, add that entry first. */
- if (req->type == GETPWBYUID)
- {
- if (cache_add (GETPWBYUID, cp, key_offset, &dataset->head, true,
- db, owner, he == NULL) < 0)
- goto out;
-
- first = false;
- }
- /* If the key is different from the name add a separate entry. */
- else if (strcmp (key_copy, dataset->strdata) != 0)
- {
- if (cache_add (GETPWBYNAME, key_copy, key_len + 1,
- &dataset->head, true, db, owner, he == NULL) < 0)
- goto out;
-
- first = false;
- }
-
- /* We have to add the value for both, byname and byuid. */
- if ((req->type == GETPWBYNAME || db->propagate)
- && __builtin_expect (cache_add (GETPWBYNAME, dataset->strdata,
- pw_name_len, &dataset->head,
- first, db, owner, he == NULL)
- == 0, 1))
- {
- if (req->type == GETPWBYNAME && db->propagate)
- (void) cache_add (GETPWBYUID, cp, key_offset, &dataset->head,
- false, db, owner, false);
- }
-
- out:
- pthread_rwlock_unlock (&db->lock);
- if (he == NULL && db->propagate)
- pthread_mutex_unlock (&db->prune_run_lock);
- }
- }
-
- if (__builtin_expect (!all_written, 0) && debug_level > 0)
- {
- char buf[256];
- dbg_log (_("short write in %s: %s"), __FUNCTION__,
- strerror_r (errno, buf, sizeof (buf)));
- }
-
- return timeout;
-}
-
-
-union keytype
-{
- void *v;
- uid_t u;
-};
-
-
-static int
-lookup (int type, union keytype key, struct passwd *resultbufp, char *buffer,
- size_t buflen, struct passwd **pwd)
-{
- if (type == GETPWBYNAME)
- return __getpwnam_r (key.v, resultbufp, buffer, buflen, pwd);
- else
- return __getpwuid_r (key.u, resultbufp, buffer, buflen, pwd);
-}
-
-
-static time_t
-addpwbyX (struct database_dyn *db, int fd, request_header *req,
- union keytype key, const char *keystr, uid_t c_uid,
- struct hashentry *he, struct datahead *dh)
-{
- /* Search for the entry matching the key. Please note that we don't
- look again in the table whether the dataset is now available. We
- simply insert it. It does not matter if it is in there twice. The
- pruning function only will look at the timestamp. */
- size_t buflen = 1024;
- char *buffer = (char *) alloca (buflen);
- struct passwd resultbuf;
- struct passwd *pwd;
- bool use_malloc = false;
- int errval = 0;
-
- if (__glibc_unlikely (debug_level > 0))
- {
- if (he == NULL)
- dbg_log (_("Haven't found \"%s\" in password cache!"), keystr);
- else
- dbg_log (_("Reloading \"%s\" in password cache!"), keystr);
- }
-
- while (lookup (req->type, key, &resultbuf, buffer, buflen, &pwd) != 0
- && (errval = errno) == ERANGE)
- {
- errno = 0;
-
- if (__glibc_unlikely (buflen > 32768))
- {
- char *old_buffer = buffer;
- buflen *= 2;
- buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
- if (buffer == NULL)
- {
- /* We ran out of memory. We cannot do anything but
- sending a negative response. In reality this should
- never happen. */
- pwd = NULL;
- buffer = old_buffer;
-
- /* We set the error to indicate this is (possibly) a
- temporary error and that it does not mean the entry
- is not available at all. */
- errval = EAGAIN;
- break;
- }
- use_malloc = true;
- }
- else
- /* Allocate a new buffer on the stack. If possible combine it
- with the previously allocated buffer. */
- buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
- }
-
- /* Add the entry to the cache. */
- time_t timeout = cache_addpw (db, fd, req, keystr, pwd, c_uid, he, dh,
- errval);
-
- if (use_malloc)
- free (buffer);
-
- return timeout;
-}
-
-
-void
-addpwbyname (struct database_dyn *db, int fd, request_header *req,
- void *key, uid_t c_uid)
-{
- union keytype u = { .v = key };
-
- addpwbyX (db, fd, req, u, key, c_uid, NULL, NULL);
-}
-
-
-time_t
-readdpwbyname (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh)
-{
- request_header req =
- {
- .type = GETPWBYNAME,
- .key_len = he->len
- };
- union keytype u = { .v = db->data + he->key };
-
- return addpwbyX (db, -1, &req, u, db->data + he->key, he->owner, he, dh);
-}
-
-
-void
-addpwbyuid (struct database_dyn *db, int fd, request_header *req,
- void *key, uid_t c_uid)
-{
- char *ep;
- uid_t uid = strtoul ((char *) key, &ep, 10);
-
- if (*(char *) key == '\0' || *ep != '\0') /* invalid numeric uid */
- {
- if (debug_level > 0)
- dbg_log (_("Invalid numeric uid \"%s\"!"), (char *) key);
-
- errno = EINVAL;
- return;
- }
-
- union keytype u = { .u = uid };
-
- addpwbyX (db, fd, req, u, key, c_uid, NULL, NULL);
-}
-
-
-time_t
-readdpwbyuid (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh)
-{
- char *ep;
- uid_t uid = strtoul (db->data + he->key, &ep, 10);
-
- /* Since the key has been added before it must be OK. */
- assert (*(db->data + he->key) != '\0' && *ep == '\0');
-
- request_header req =
- {
- .type = GETPWBYUID,
- .key_len = he->len
- };
- union keytype u = { .u = uid };
-
- return addpwbyX (db, -1, &req, u, db->data + he->key, he->owner, he, dh);
-}
diff --git a/nscd/res_hconf.c b/nscd/res_hconf.c
deleted file mode 100644
index 14b0e300bc..0000000000
--- a/nscd/res_hconf.c
+++ /dev/null
@@ -1,13 +0,0 @@
-/* Add the include here so that we can redefine __fxprintf. */
-#include <stdio.h>
-
-/* Rename symbols for protected names used in libc itself. */
-#define __ioctl ioctl
-#define __socket socket
-#define __strchrnul strchrnul
-#define __strncasecmp strncasecmp
-
-#define __fxprintf(args...) /* ignore */
-
-
-#include "../resolv/res_hconf.c"
diff --git a/nscd/selinux.c b/nscd/selinux.c
deleted file mode 100644
index f7bcd8e4c8..0000000000
--- a/nscd/selinux.c
+++ /dev/null
@@ -1,453 +0,0 @@
-/* SELinux access controls for nscd.
- Copyright (C) 2004-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Matthew Rickard <mjricka@epoch.ncsc.mil>, 2004.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-#include "config.h"
-#include <error.h>
-#include <errno.h>
-#include <libintl.h>
-#include <pthread.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <syslog.h>
-#include <unistd.h>
-#include <sys/prctl.h>
-#include <selinux/avc.h>
-#include <selinux/selinux.h>
-#ifdef HAVE_LIBAUDIT
-# include <libaudit.h>
-#endif
-
-#include "dbg_log.h"
-#include "selinux.h"
-
-
-#ifdef HAVE_SELINUX
-/* Global variable to tell if the kernel has SELinux support. */
-int selinux_enabled;
-
-/* Define mappings of request type to AVC permission name. */
-static const char *perms[LASTREQ] =
-{
- [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. */
-static struct avc_entry_ref aeref;
-
-/* Thread to listen for SELinux status changes via netlink. */
-static pthread_t avc_notify_thread;
-
-#ifdef HAVE_LIBAUDIT
-/* Prototype for supporting the audit daemon */
-static void log_callback (const char *fmt, ...);
-#endif
-
-/* Prototypes for AVC callback functions. */
-static void *avc_create_thread (void (*run) (void));
-static void avc_stop_thread (void *thread);
-static void *avc_alloc_lock (void);
-static void avc_get_lock (void *lock);
-static void avc_release_lock (void *lock);
-static void avc_free_lock (void *lock);
-
-/* AVC callback structures for use in avc_init. */
-static const struct avc_log_callback log_cb =
-{
-#ifdef HAVE_LIBAUDIT
- .func_log = log_callback,
-#else
- .func_log = dbg_log,
-#endif
- .func_audit = NULL
-};
-static const struct avc_thread_callback thread_cb =
-{
- .func_create_thread = avc_create_thread,
- .func_stop_thread = avc_stop_thread
-};
-static const struct avc_lock_callback lock_cb =
-{
- .func_alloc_lock = avc_alloc_lock,
- .func_get_lock = avc_get_lock,
- .func_release_lock = avc_release_lock,
- .func_free_lock = avc_free_lock
-};
-
-#ifdef HAVE_LIBAUDIT
-/* The audit system's netlink socket descriptor */
-static int audit_fd = -1;
-
-/* When an avc denial occurs, log it to audit system */
-static void
-log_callback (const char *fmt, ...)
-{
- if (audit_fd >= 0)
- {
- va_list ap;
- va_start (ap, fmt);
-
- char *buf;
- int e = vasprintf (&buf, fmt, ap);
- if (e < 0)
- {
- buf = alloca (BUFSIZ);
- vsnprintf (buf, BUFSIZ, fmt, ap);
- }
-
- /* FIXME: need to attribute this to real user, using getuid for now */
- audit_log_user_avc_message (audit_fd, AUDIT_USER_AVC, buf, NULL, NULL,
- NULL, getuid ());
-
- if (e >= 0)
- free (buf);
-
- va_end (ap);
- }
-}
-
-/* Initialize the connection to the audit system */
-static void
-audit_init (void)
-{
- audit_fd = audit_open ();
- if (audit_fd < 0
- /* If kernel doesn't support audit, bail out */
- && errno != EINVAL && errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT)
- dbg_log (_("Failed opening connection to the audit subsystem: %m"));
-}
-
-
-# ifdef HAVE_LIBCAP
-static const cap_value_t new_cap_list[] =
- { CAP_AUDIT_WRITE };
-# define nnew_cap_list (sizeof (new_cap_list) / sizeof (new_cap_list[0]))
-static const cap_value_t tmp_cap_list[] =
- { CAP_AUDIT_WRITE, CAP_SETUID, CAP_SETGID };
-# define ntmp_cap_list (sizeof (tmp_cap_list) / sizeof (tmp_cap_list[0]))
-
-cap_t
-preserve_capabilities (void)
-{
- if (getuid () != 0)
- /* Not root, then we cannot preserve anything. */
- return NULL;
-
- if (prctl (PR_SET_KEEPCAPS, 1) == -1)
- {
- dbg_log (_("Failed to set keep-capabilities"));
- do_exit (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed"));
- /* NOTREACHED */
- }
-
- cap_t tmp_caps = cap_init ();
- cap_t new_caps = NULL;
- if (tmp_caps != NULL)
- new_caps = cap_init ();
-
- if (tmp_caps == NULL || new_caps == NULL)
- {
- if (tmp_caps != NULL)
- cap_free (tmp_caps);
-
- dbg_log (_("Failed to initialize drop of capabilities"));
- do_exit (EXIT_FAILURE, 0, _("cap_init failed"));
- }
-
- /* There is no reason why these should not work. */
- cap_set_flag (new_caps, CAP_PERMITTED, nnew_cap_list,
- (cap_value_t *) new_cap_list, CAP_SET);
- cap_set_flag (new_caps, CAP_EFFECTIVE, nnew_cap_list,
- (cap_value_t *) new_cap_list, CAP_SET);
-
- cap_set_flag (tmp_caps, CAP_PERMITTED, ntmp_cap_list,
- (cap_value_t *) tmp_cap_list, CAP_SET);
- cap_set_flag (tmp_caps, CAP_EFFECTIVE, ntmp_cap_list,
- (cap_value_t *) tmp_cap_list, CAP_SET);
-
- int res = cap_set_proc (tmp_caps);
-
- cap_free (tmp_caps);
-
- if (__glibc_unlikely (res != 0))
- {
- cap_free (new_caps);
- dbg_log (_("Failed to drop capabilities"));
- do_exit (EXIT_FAILURE, 0, _("cap_set_proc failed"));
- }
-
- return new_caps;
-}
-
-void
-install_real_capabilities (cap_t new_caps)
-{
- /* If we have no capabilities there is nothing to do here. */
- if (new_caps == NULL)
- return;
-
- if (cap_set_proc (new_caps))
- {
- cap_free (new_caps);
- dbg_log (_("Failed to drop capabilities"));
- do_exit (EXIT_FAILURE, 0, _("cap_set_proc failed"));
- /* NOTREACHED */
- }
-
- cap_free (new_caps);
-
- if (prctl (PR_SET_KEEPCAPS, 0) == -1)
- {
- dbg_log (_("Failed to unset keep-capabilities"));
- do_exit (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed"));
- /* NOTREACHED */
- }
-}
-# endif /* HAVE_LIBCAP */
-#endif /* HAVE_LIBAUDIT */
-
-/* Determine if we are running on an SELinux kernel. Set selinux_enabled
- to the result. */
-void
-nscd_selinux_enabled (int *selinux_enabled)
-{
- *selinux_enabled = is_selinux_enabled ();
- if (*selinux_enabled < 0)
- {
- dbg_log (_("Failed to determine if kernel supports SELinux"));
- do_exit (EXIT_FAILURE, 0, NULL);
- }
-}
-
-
-/* Create thread for AVC netlink notification. */
-static void *
-avc_create_thread (void (*run) (void))
-{
- int rc;
-
- rc =
- pthread_create (&avc_notify_thread, NULL, (void *(*) (void *)) run, NULL);
- if (rc != 0)
- do_exit (EXIT_FAILURE, rc, _("Failed to start AVC thread"));
-
- return &avc_notify_thread;
-}
-
-
-/* Stop AVC netlink thread. */
-static void
-avc_stop_thread (void *thread)
-{
- pthread_cancel (*(pthread_t *) thread);
-}
-
-
-/* Allocate a new AVC lock. */
-static void *
-avc_alloc_lock (void)
-{
- pthread_mutex_t *avc_mutex;
-
- avc_mutex = malloc (sizeof (pthread_mutex_t));
- if (avc_mutex == NULL)
- do_exit (EXIT_FAILURE, errno, _("Failed to create AVC lock"));
- pthread_mutex_init (avc_mutex, NULL);
-
- return avc_mutex;
-}
-
-
-/* Acquire an AVC lock. */
-static void
-avc_get_lock (void *lock)
-{
- pthread_mutex_lock (lock);
-}
-
-
-/* Release an AVC lock. */
-static void
-avc_release_lock (void *lock)
-{
- pthread_mutex_unlock (lock);
-}
-
-
-/* Free an AVC lock. */
-static void
-avc_free_lock (void *lock)
-{
- pthread_mutex_destroy (lock);
- free (lock);
-}
-
-
-/* Initialize the user space access vector cache (AVC) for NSCD along with
- log/thread/lock callbacks. */
-void
-nscd_avc_init (void)
-{
- avc_entry_ref_init (&aeref);
-
- if (avc_init ("avc", NULL, &log_cb, &thread_cb, &lock_cb) < 0)
- do_exit (EXIT_FAILURE, errno, _("Failed to start AVC"));
- else
- dbg_log (_("Access Vector Cache (AVC) started"));
-#ifdef HAVE_LIBAUDIT
- audit_init ();
-#endif
-}
-
-
-/* Check the permission from the caller (via getpeercon) to nscd.
- 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)
-{
- /* Initialize to NULL so we know what to free in case of failure. */
- security_context_t scon = NULL;
- security_context_t tcon = NULL;
- 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)
- {
- dbg_log (_("Error getting context of socket peer"));
- goto out;
- }
- if (getcon (&tcon) < 0)
- {
- dbg_log (_("Error getting context of nscd"));
- goto out;
- }
- if (avc_context_to_sid (scon, &ssid) < 0
- || avc_context_to_sid (tcon, &tsid) < 0)
- {
- dbg_log (_("Error getting sid from context"));
- goto out;
- }
-
- /* 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)
- freecon (scon);
- if (tcon)
- freecon (tcon);
- if (ssid)
- sidput (ssid);
- if (tsid)
- sidput (tsid);
-
- return rc;
-}
-
-
-/* Wrapper to get AVC statistics. */
-void
-nscd_avc_cache_stats (struct avc_cache_stats *cstats)
-{
- avc_cache_stats (cstats);
-}
-
-
-/* Print the AVC statistics to stdout. */
-void
-nscd_avc_print_stats (struct avc_cache_stats *cstats)
-{
- printf (_("\nSELinux AVC Statistics:\n\n"
- "%15u entry lookups\n"
- "%15u entry hits\n"
- "%15u entry misses\n"
- "%15u entry discards\n"
- "%15u CAV lookups\n"
- "%15u CAV hits\n"
- "%15u CAV probes\n"
- "%15u CAV misses\n"),
- cstats->entry_lookups, cstats->entry_hits, cstats->entry_misses,
- cstats->entry_discards, cstats->cav_lookups, cstats->cav_hits,
- cstats->cav_probes, cstats->cav_misses);
-}
-
-#endif /* HAVE_SELINUX */
diff --git a/nscd/selinux.h b/nscd/selinux.h
deleted file mode 100644
index 052d62a6fb..0000000000
--- a/nscd/selinux.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* Header for nscd SELinux access controls.
- Copyright (C) 2004-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Matthew Rickard <mjricka@epoch.ncsc.mil>, 2004.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-#ifndef _SELINUX_H
-#define _SELINUX_H 1
-
-#include "nscd.h"
-#ifdef HAVE_LIBCAP
-# include <sys/capability.h>
-#endif
-
-#ifdef HAVE_SELINUX
-/* Global variable to tell if the kernel has SELinux support. */
-extern int selinux_enabled;
-
-/* Define this for AVC stat usage. */
-struct avc_cache_stats;
-
-/* Initialize the userspace AVC. */
-extern void nscd_avc_init (void);
-/* Determine if we are running on an SELinux kernel. */
-extern void nscd_selinux_enabled (int *selinux_enabled);
-/* Check if the client has permission for the request type. */
-extern int nscd_request_avc_has_perm (int fd, request_type req);
-/* Initialize AVC statistic information. */
-extern void nscd_avc_cache_stats (struct avc_cache_stats *cstats);
-/* Display statistics on AVC usage. */
-extern void nscd_avc_print_stats (struct avc_cache_stats *cstats);
-
-# ifdef HAVE_LIBCAP
-/* Preserve capabilities to connect to the audit daemon. */
-extern cap_t preserve_capabilities (void);
-/* Install final capabilities. */
-extern void install_real_capabilities (cap_t new_caps);
-# endif
-#else
-# define selinux_enabled 0
-# define nscd_avc_init() (void) 0
-# define nscd_selinux_enabled(selinux_enabled) (void) 0
-# define nscd_request_avc_has_perm(fd, req) 0
-# define nscd_avc_cache_stats(cstats) (void) 0
-# define nscd_avc_print_stats(cstats) (void) 0
-#endif /* HAVE_SELINUX */
-
-#endif /* _SELINUX_H */
diff --git a/nscd/servicescache.c b/nscd/servicescache.c
deleted file mode 100644
index 131ba6ddcc..0000000000
--- a/nscd/servicescache.c
+++ /dev/null
@@ -1,474 +0,0 @@
-/* Cache handling for services lookup.
- Copyright (C) 2007-2017 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@drepper.com>, 2007.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#include <alloca.h>
-#include <assert.h>
-#include <errno.h>
-#include <libintl.h>
-#include <netdb.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <sys/mman.h>
-#include <kernel-features.h>
-
-#include "nscd.h"
-#include "dbg_log.h"
-
-
-/* This is the standard reply in case the service is disabled. */
-static const serv_response_header disabled =
-{
- .version = NSCD_VERSION,
- .found = -1,
- .s_name_len = 0,
- .s_proto_len = 0,
- .s_aliases_cnt = 0,
- .s_port = -1
-};
-
-/* This is the struct describing how to write this record. */
-const struct iovec serv_iov_disabled =
-{
- .iov_base = (void *) &disabled,
- .iov_len = sizeof (disabled)
-};
-
-
-/* This is the standard reply in case we haven't found the dataset. */
-static const serv_response_header notfound =
-{
- .version = NSCD_VERSION,
- .found = 0,
- .s_name_len = 0,
- .s_proto_len = 0,
- .s_aliases_cnt = 0,
- .s_port = -1
-};
-
-
-static time_t
-cache_addserv (struct database_dyn *db, int fd, request_header *req,
- const void *key, struct servent *serv, uid_t owner,
- struct hashentry *const he, struct datahead *dh, int errval)
-{
- bool all_written = true;
- ssize_t total;
- time_t t = time (NULL);
-
- /* We allocate all data in one memory block: the iov vector,
- the response header and the dataset itself. */
- struct dataset
- {
- struct datahead head;
- serv_response_header resp;
- char strdata[0];
- } *dataset;
-
- assert (offsetof (struct dataset, resp) == offsetof (struct datahead, data));
-
- time_t timeout = MAX_TIMEOUT_VALUE;
- if (serv == NULL)
- {
- if (he != NULL && errval == EAGAIN)
- {
- /* If we have an old record available but cannot find one
- now because the service is not available we keep the old
- record and make sure it does not get removed. */
- if (reload_count != UINT_MAX)
- /* Do not reset the value if we never not reload the record. */
- dh->nreloads = reload_count - 1;
-
- /* Reload with the same time-to-live value. */
- timeout = dh->timeout = t + db->postimeout;
-
- total = 0;
- }
- else
- {
- /* We have no data. This means we send the standard reply for this
- case. */
- total = sizeof (notfound);
-
- if (fd != -1
- && TEMP_FAILURE_RETRY (send (fd, &notfound, total,
- MSG_NOSIGNAL)) != total)
- all_written = false;
-
- /* If we have a transient error or cannot permanently store
- the result, so be it. */
- if (errval == EAGAIN || __builtin_expect (db->negtimeout == 0, 0))
- {
- /* Mark the old entry as obsolete. */
- if (dh != NULL)
- dh->usable = false;
- }
- else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
- + req->key_len), 1)) != NULL)
- {
- timeout = datahead_init_neg (&dataset->head,
- (sizeof (struct dataset)
- + req->key_len), total,
- db->negtimeout);
-
- /* This is the reply. */
- memcpy (&dataset->resp, &notfound, total);
-
- /* Copy the key data. */
- memcpy (dataset->strdata, key, req->key_len);
-
- /* If necessary, we also propagate the data to disk. */
- if (db->persistent)
- {
- // XXX async OK?
- uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
- msync ((void *) pval,
- ((uintptr_t) dataset & pagesize_m1)
- + sizeof (struct dataset) + req->key_len, MS_ASYNC);
- }
-
- (void) cache_add (req->type, &dataset->strdata, req->key_len,
- &dataset->head, true, db, owner, he == NULL);
-
- pthread_rwlock_unlock (&db->lock);
-
- /* Mark the old entry as obsolete. */
- if (dh != NULL)
- dh->usable = false;
- }
- }
- }
- else
- {
- /* Determine the I/O structure. */
- size_t s_name_len = strlen (serv->s_name) + 1;
- size_t s_proto_len = strlen (serv->s_proto) + 1;
- uint32_t *s_aliases_len;
- size_t s_aliases_cnt;
- char *aliases;
- char *cp;
- size_t cnt;
-
- /* Determine the number of aliases. */
- s_aliases_cnt = 0;
- for (cnt = 0; serv->s_aliases[cnt] != NULL; ++cnt)
- ++s_aliases_cnt;
- /* Determine the length of all aliases. */
- s_aliases_len = (uint32_t *) alloca (s_aliases_cnt * sizeof (uint32_t));
- total = 0;
- for (cnt = 0; cnt < s_aliases_cnt; ++cnt)
- {
- s_aliases_len[cnt] = strlen (serv->s_aliases[cnt]) + 1;
- total += s_aliases_len[cnt];
- }
-
- total += (offsetof (struct dataset, strdata)
- + s_name_len
- + s_proto_len
- + s_aliases_cnt * sizeof (uint32_t));
-
- /* If we refill the cache, first assume the reconrd did not
- change. Allocate memory on the cache since it is likely
- discarded anyway. If it turns out to be necessary to have a
- new record we can still allocate real memory. */
- bool alloca_used = false;
- dataset = NULL;
-
- if (he == NULL)
- dataset = (struct dataset *) mempool_alloc (db, total + req->key_len,
- 1);
-
- if (dataset == NULL)
- {
- /* We cannot permanently add the result in the moment. But
- we can provide the result as is. Store the data in some
- temporary memory. */
- dataset = (struct dataset *) alloca (total + req->key_len);
-
- /* We cannot add this record to the permanent database. */
- alloca_used = true;
- }
-
- 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;
- dataset->resp.s_name_len = s_name_len;
- dataset->resp.s_proto_len = s_proto_len;
- dataset->resp.s_port = serv->s_port;
- dataset->resp.s_aliases_cnt = s_aliases_cnt;
-
- cp = dataset->strdata;
-
- cp = mempcpy (cp, serv->s_name, s_name_len);
- cp = mempcpy (cp, serv->s_proto, s_proto_len);
- cp = mempcpy (cp, s_aliases_len, s_aliases_cnt * sizeof (uint32_t));
-
- /* Then the aliases. */
- aliases = cp;
- for (cnt = 0; cnt < s_aliases_cnt; ++cnt)
- cp = mempcpy (cp, serv->s_aliases[cnt], s_aliases_len[cnt]);
-
- assert (cp
- == dataset->strdata + total - offsetof (struct dataset,
- strdata));
-
- char *key_copy = memcpy (cp, key, req->key_len);
-
- /* Now we can determine whether on refill we have to create a new
- record or not. */
- if (he != NULL)
- {
- assert (fd == -1);
-
- if (total + req->key_len == dh->allocsize
- && total - offsetof (struct dataset, resp) == dh->recsize
- && memcmp (&dataset->resp, dh->data,
- dh->allocsize - offsetof (struct dataset, resp)) == 0)
- {
- /* The data has not changed. We will just bump the
- timeout value. Note that the new record has been
- allocated on the stack and need not be freed. */
- dh->timeout = dataset->head.timeout;
- ++dh->nreloads;
- }
- else
- {
- /* We have to create a new record. Just allocate
- appropriate memory and copy it. */
- struct dataset *newp
- = (struct dataset *) mempool_alloc (db, total + req->key_len,
- 1);
- if (newp != NULL)
- {
- /* Adjust pointers into the memory block. */
- aliases = (char *) newp + (aliases - (char *) dataset);
- assert (key_copy != NULL);
- key_copy = (char *) newp + (key_copy - (char *) dataset);
-
- dataset = memcpy (newp, dataset, total + req->key_len);
- alloca_used = false;
- }
-
- /* Mark the old record as obsolete. */
- dh->usable = false;
- }
- }
- else
- {
- /* We write the dataset before inserting it to the database
- since while inserting this thread might block and so would
- unnecessarily keep the receiver waiting. */
- assert (fd != -1);
-
-#ifdef HAVE_SENDFILE
- if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
- {
- assert (db->wr_fd != -1);
- assert ((char *) &dataset->resp > (char *) db->data);
- assert ((char *) dataset - (char *) db->head
- + total
- <= (sizeof (struct database_pers_head)
- + db->head->module * sizeof (ref_t)
- + db->head->data_size));
- ssize_t written = sendfileall (fd, db->wr_fd,
- (char *) &dataset->resp
- - (char *) db->head,
- dataset->head.recsize);
- if (written != dataset->head.recsize)
- {
-# ifndef __ASSUME_SENDFILE
- if (written == -1 && errno == ENOSYS)
- goto use_write;
-# endif
- all_written = false;
- }
- }
- else
-# ifndef __ASSUME_SENDFILE
- use_write:
-# endif
-#endif
- if (writeall (fd, &dataset->resp, dataset->head.recsize)
- != dataset->head.recsize)
- all_written = false;
- }
-
- /* Add the record to the database. But only if it has not been
- stored on the stack. */
- if (! alloca_used)
- {
- /* If necessary, we also propagate the data to disk. */
- if (db->persistent)
- {
- // XXX async OK?
- uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
- msync ((void *) pval,
- ((uintptr_t) dataset & pagesize_m1)
- + total + req->key_len, MS_ASYNC);
- }
-
- (void) cache_add (req->type, key_copy, req->key_len,
- &dataset->head, true, db, owner, he == NULL);
-
- pthread_rwlock_unlock (&db->lock);
- }
- }
-
- if (__builtin_expect (!all_written, 0) && debug_level > 0)
- {
- char buf[256];
- dbg_log (_("short write in %s: %s"), __FUNCTION__,
- strerror_r (errno, buf, sizeof (buf)));
- }
-
- return timeout;
-}
-
-
-static int
-lookup (int type, char *key, struct servent *resultbufp, char *buffer,
- size_t buflen, struct servent **serv)
-{
- char *proto = strrchr (key, '/');
- if (proto != NULL && proto != key)
- {
- key = strndupa (key, proto - key);
- if (proto[1] == '\0')
- proto = NULL;
- else
- ++proto;
- }
-
- if (type == GETSERVBYNAME)
- return __getservbyname_r (key, proto, resultbufp, buffer, buflen, serv);
-
- assert (type == GETSERVBYPORT);
- return __getservbyport_r (atol (key), proto, resultbufp, buffer, buflen,
- serv);
-}
-
-
-static time_t
-addservbyX (struct database_dyn *db, int fd, request_header *req,
- char *key, uid_t uid, struct hashentry *he, struct datahead *dh)
-{
- /* Search for the entry matching the key. Please note that we don't
- look again in the table whether the dataset is now available. We
- simply insert it. It does not matter if it is in there twice. The
- pruning function only will look at the timestamp. */
- size_t buflen = 1024;
- char *buffer = (char *) alloca (buflen);
- struct servent resultbuf;
- struct servent *serv;
- bool use_malloc = false;
- int errval = 0;
-
- if (__glibc_unlikely (debug_level > 0))
- {
- if (he == NULL)
- dbg_log (_("Haven't found \"%s\" in services cache!"), key);
- else
- dbg_log (_("Reloading \"%s\" in services cache!"), key);
- }
-
- while (lookup (req->type, key, &resultbuf, buffer, buflen, &serv) != 0
- && (errval = errno) == ERANGE)
- {
- errno = 0;
-
- if (__glibc_unlikely (buflen > 32768))
- {
- char *old_buffer = buffer;
- buflen *= 2;
- buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
- if (buffer == NULL)
- {
- /* We ran out of memory. We cannot do anything but
- sending a negative response. In reality this should
- never happen. */
- serv = NULL;
- buffer = old_buffer;
-
- /* We set the error to indicate this is (possibly) a
- temporary error and that it does not mean the entry
- is not available at all. */
- errval = EAGAIN;
- break;
- }
- use_malloc = true;
- }
- else
- /* Allocate a new buffer on the stack. If possible combine it
- with the previously allocated buffer. */
- buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
- }
-
- time_t timeout = cache_addserv (db, fd, req, key, serv, uid, he, dh, errval);
-
- if (use_malloc)
- free (buffer);
-
- return timeout;
-}
-
-
-void
-addservbyname (struct database_dyn *db, int fd, request_header *req,
- void *key, uid_t uid)
-{
- addservbyX (db, fd, req, key, uid, NULL, NULL);
-}
-
-
-time_t
-readdservbyname (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh)
-{
- request_header req =
- {
- .type = GETSERVBYNAME,
- .key_len = he->len
- };
-
- return addservbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
-}
-
-
-void
-addservbyport (struct database_dyn *db, int fd, request_header *req,
- void *key, uid_t uid)
-{
- addservbyX (db, fd, req, key, uid, NULL, NULL);
-}
-
-
-time_t
-readdservbyport (struct database_dyn *db, struct hashentry *he,
- struct datahead *dh)
-{
- request_header req =
- {
- .type = GETSERVBYPORT,
- .key_len = he->len
- };
-
- return addservbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
-}