1 diff -Nrup a/grp/initgroups.c b/grp/initgroups.c
2 --- a/grp/initgroups.c 2012-08-06 15:07:48.935060494 -0600
3 +++ b/grp/initgroups.c 2012-08-23 14:19:49.370442142 -0600
5 -/* Copyright (C) 1989,91,93,1996-2005,2006,2008 Free Software Foundation, Inc.
6 +/* Copyright (C) 1989,91,93,1996-2006,2008,2010 Free Software Foundation, Inc.
7 This file is part of the GNU C Library.
9 The GNU C Library is free software; you can redistribute it and/or
10 @@ -58,7 +58,8 @@ internal_getgrouplist (const char *user,
11 if (__nss_not_use_nscd_group > 0
12 && ++__nss_not_use_nscd_group > NSS_NSCD_RETRY)
13 __nss_not_use_nscd_group = 0;
14 - if (!__nss_not_use_nscd_group)
15 + if (!__nss_not_use_nscd_group
16 + && !__nss_database_custom[NSS_DBSIDX_group])
18 int n = __nscd_getgrouplist (user, group, size, groupsp, limit);
20 diff -Nrup a/inet/getnetgrent_r.c b/inet/getnetgrent_r.c
21 --- a/inet/getnetgrent_r.c 2010-05-04 05:27:23.000000000 -0600
22 +++ b/inet/getnetgrent_r.c 2012-08-06 15:10:05.865520055 -0600
27 +#include <nscd/nscd_proto.h>
30 /* Protect above variable against multiple uses at the same time. */
31 @@ -101,7 +102,7 @@ endnetgrent_hook (struct __netgrent *dat
33 enum nss_status (*endfct) (struct __netgrent *);
35 - if (datap->nip == NULL)
36 + if (datap->nip == NULL || datap->nip == (service_user *) -1l)
39 endfct = __nss_lookup_function (datap->nip, "endnetgrent");
40 @@ -189,8 +190,21 @@ setnetgrent (const char *group)
42 __libc_lock_lock (lock);
44 + if (__nss_not_use_nscd_netgroup > 0
45 + && ++__nss_not_use_nscd_netgroup > NSS_NSCD_RETRY)
46 + __nss_not_use_nscd_netgroup = 0;
48 + if (!__nss_not_use_nscd_netgroup
49 + && !__nss_database_custom[NSS_DBSIDX_netgroup])
51 + result = __nscd_setnetgrent (group, &dataset);
56 result = internal_setnetgrent (group, &dataset);
59 __libc_lock_unlock (lock);
62 @@ -226,6 +240,26 @@ int internal_getnetgrent_r (char **hostp
63 char *buffer, size_t buflen, int *errnop);
64 libc_hidden_proto (internal_getnetgrent_r)
67 +static enum nss_status
68 +nscd_getnetgrent (struct __netgrent *datap, char *buffer, size_t buflen,
71 + if (datap->cursor >= datap->data + datap->data_size)
72 + return NSS_STATUS_UNAVAIL;
74 + datap->type = triple_val;
75 + datap->val.triple.host = datap->cursor;
76 + datap->cursor = (char *) __rawmemchr (datap->cursor, '\0') + 1;
77 + datap->val.triple.user = datap->cursor;
78 + datap->cursor = (char *) __rawmemchr (datap->cursor, '\0') + 1;
79 + datap->val.triple.domain = datap->cursor;
80 + datap->cursor = (char *) __rawmemchr (datap->cursor, '\0') + 1;
82 + return NSS_STATUS_SUCCESS;
87 internal_getnetgrent_r (char **hostp, char **userp, char **domainp,
88 struct __netgrent *datap,
89 @@ -239,9 +273,18 @@ internal_getnetgrent_r (char **hostp, ch
90 /* Run through available functions, starting with the same function last
91 run. We will repeat each function as long as it succeeds, and then go
92 on to the next service action. */
93 - int no_more = (datap->nip == NULL
94 - || (fct = __nss_lookup_function (datap->nip, "getnetgrent_r"))
96 + int no_more = datap->nip == NULL;
99 + if (datap->nip == (service_user *) -1l)
100 + fct = nscd_getnetgrent;
103 + fct = __nss_lookup_function (datap->nip, "getnetgrent_r");
104 + no_more = fct == NULL;
110 status = (*fct) (datap, buffer, buflen, &errno);
111 @@ -337,6 +380,18 @@ int
112 innetgr (const char *netgroup, const char *host, const char *user,
115 + if (__nss_not_use_nscd_netgroup > 0
116 + && ++__nss_not_use_nscd_netgroup > NSS_NSCD_RETRY)
117 + __nss_not_use_nscd_netgroup = 0;
119 + if (!__nss_not_use_nscd_netgroup
120 + && !__nss_database_custom[NSS_DBSIDX_netgroup])
122 + int result = __nscd_innetgr (netgroup, host, user, domain);
129 int (*f) (const char *, struct __netgrent *);
130 @@ -444,7 +499,7 @@ innetgr (const char *netgroup, const cha
131 entry.needed_groups = tmp->next;
132 tmp->next = entry.known_groups;
133 entry.known_groups = tmp;
134 - current_group = entry.known_groups->name;
135 + current_group = tmp->name;
139 diff -Nrup a/nscd/Makefile b/nscd/Makefile
140 --- a/nscd/Makefile 2010-05-04 05:27:23.000000000 -0600
141 +++ b/nscd/Makefile 2012-08-06 15:08:19.045941627 -0600
145 routines := nscd_getpw_r nscd_getgr_r nscd_gethst_r nscd_getai \
146 - nscd_initgroups nscd_getserv_r
147 + nscd_initgroups nscd_getserv_r nscd_netgroup
150 include ../Makeconfig
151 @@ -34,7 +34,8 @@ nscd-modules := nscd connections pwdcach
152 getgrnam_r getgrgid_r hstcache gethstbyad_r gethstbynm3_r \
153 getsrvbynm_r getsrvbypt_r servicescache \
154 dbg_log nscd_conf nscd_stat cache mem nscd_setup_thread \
155 - xmalloc xstrdup aicache initgrcache gai res_hconf
156 + xmalloc xstrdup aicache initgrcache gai res_hconf \
159 ifeq ($(have-thread-library),yes)
161 @@ -122,6 +123,7 @@ CFLAGS-servicescache.c += $(nscd-cflags)
162 CFLAGS-getsrvbynm_r.c += $(nscd-cflags)
163 CFLAGS-getsrvbypt_r.c += $(nscd-cflags)
164 CFLAGS-res_hconf.c += $(nscd-cflags)
165 +CFLAGS-netgroupcache.c += $(nscd-cflags)
167 ifeq (yesyes,$(have-fpie)$(build-shared))
168 relro-LDFLAGS += -Wl,-z,now
169 diff -Nrup a/nscd/cache.c b/nscd/cache.c
170 --- a/nscd/cache.c 2012-08-06 15:07:48.973060344 -0600
171 +++ b/nscd/cache.c 2012-08-06 15:08:19.046941626 -0600
172 @@ -60,7 +60,9 @@ static time_t (*const readdfcts[LASTREQ]
173 [GETAI] = readdhstai,
174 [INITGROUPS] = readdinitgroups,
175 [GETSERVBYNAME] = readdservbyname,
176 - [GETSERVBYPORT] = readdservbyport
177 + [GETSERVBYPORT] = readdservbyport,
178 + [GETNETGRENT] = readdgetnetgrent,
179 + [INNETGR] = readdinnetgr
183 @@ -70,7 +72,7 @@ static time_t (*const readdfcts[LASTREQ]
185 This function must be called with the read-lock held. */
187 -cache_search (request_type type, void *key, size_t len,
188 +cache_search (request_type type, const void *key, size_t len,
189 struct database_dyn *table, uid_t owner)
191 unsigned long int hash = __nis_hash (key, len) % table->head->module;
192 diff -Nrup a/nscd/connections.c b/nscd/connections.c
193 --- a/nscd/connections.c 2012-08-06 15:07:49.076059937 -0600
194 +++ b/nscd/connections.c 2012-08-21 21:36:10.210358578 -0600
199 -/* Wrapper functions with error checking for standard functions. */
200 -extern void *xmalloc (size_t n);
201 -extern void *xcalloc (size_t n, size_t s);
202 -extern void *xrealloc (void *o, size_t n);
204 /* Support to run nscd as an unprivileged user */
205 const char *server_user;
206 static uid_t server_uid;
207 @@ -100,7 +95,10 @@ const char *const serv2str[LASTREQ] =
208 [INITGROUPS] = "INITGROUPS",
209 [GETSERVBYNAME] = "GETSERVBYNAME",
210 [GETSERVBYPORT] = "GETSERVBYPORT",
211 - [GETFDSERV] = "GETFDSERV"
212 + [GETFDSERV] = "GETFDSERV",
213 + [GETNETGRENT] = "GETNETGRENT",
214 + [INNETGR] = "INNETGR",
215 + [GETFDNETGR] = "GETFDNETGR"
218 /* The control data structures for the services. */
219 @@ -189,6 +187,27 @@ struct database_dyn dbs[lastdb] =
225 + .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
226 + .prune_lock = PTHREAD_MUTEX_INITIALIZER,
227 + .prune_run_lock = PTHREAD_MUTEX_INITIALIZER,
231 + .propagate = 0, /* Not used. */
233 + .max_db_size = DEFAULT_MAX_DB_SIZE,
234 + .suggested_module = DEFAULT_SUGGESTED_MODULE,
236 + .filename = "/etc/netgroup",
237 + .db_filename = _PATH_NSCD_NETGROUP_DB,
238 + .disabled_iov = &netgroup_iov_disabled,
239 + .postimeout = 28800,
247 @@ -218,7 +237,10 @@ static struct
248 [INITGROUPS] = { true, &dbs[grpdb] },
249 [GETSERVBYNAME] = { true, &dbs[servdb] },
250 [GETSERVBYPORT] = { true, &dbs[servdb] },
251 - [GETFDSERV] = { false, &dbs[servdb] }
252 + [GETFDSERV] = { false, &dbs[servdb] },
253 + [GETNETGRENT] = { true, &dbs[netgrdb] },
254 + [INNETGR] = { true, &dbs[netgrdb] },
255 + [GETFDNETGR] = { false, &dbs[netgrdb] }
259 @@ -366,7 +388,8 @@ check_use (const char *data, nscd_ssize_
261 verify_persistent_db (void *mem, struct database_pers_head *readhead, int dbnr)
263 - assert (dbnr == pwddb || dbnr == grpdb || dbnr == hstdb || dbnr == servdb);
264 + assert (dbnr == pwddb || dbnr == grpdb || dbnr == hstdb || dbnr == servdb
265 + || dbnr == netgrdb);
267 time_t now = time (NULL);
269 @@ -1241,6 +1264,14 @@ request from '%s' [%ld] not handled due
270 addservbyport (db, fd, req, key, uid);
274 + addgetnetgrent (db, fd, req, key, uid);
278 + addinnetgr (db, fd, req, key, uid);
284 @@ -1287,6 +1318,7 @@ request from '%s' [%ld] not handled due
290 send_ro_fd (reqinfo[req->type].db, key, fd);
292 diff -Nrup a/nscd/netgroupcache.c b/nscd/netgroupcache.c
293 --- a/nscd/netgroupcache.c 1969-12-31 17:00:00.000000000 -0700
294 +++ b/nscd/netgroupcache.c 2012-08-24 11:38:05.118254176 -0600
296 +/* Cache handling for netgroup lookup.
297 + Copyright (C) 2011 Free Software Foundation, Inc.
298 + This file is part of the GNU C Library.
299 + Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
301 + This program is free software; you can redistribute it and/or modify
302 + it under the terms of the GNU General Public License as published
303 + by the Free Software Foundation; version 2 of the License, or
304 + (at your option) any later version.
306 + This program is distributed in the hope that it will be useful,
307 + but WITHOUT ANY WARRANTY; without even the implied warranty of
308 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
309 + GNU General Public License for more details.
311 + You should have received a copy of the GNU General Public License
312 + along with this program; if not, write to the Free Software Foundation,
313 + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
318 +#include <libintl.h>
319 +#include <stdbool.h>
321 +#include <sys/mman.h>
323 +#include "../inet/netgroup.h"
325 +#include "dbg_log.h"
326 +#ifdef HAVE_SENDFILE
327 +# include <kernel-features.h>
331 +/* This is the standard reply in case the service is disabled. */
332 +static const netgroup_response_header disabled =
334 + .version = NSCD_VERSION,
340 +/* This is the struct describing how to write this record. */
341 +const struct iovec netgroup_iov_disabled =
343 + .iov_base = (void *) &disabled,
344 + .iov_len = sizeof (disabled)
348 +/* This is the standard reply in case we haven't found the dataset. */
349 +static const netgroup_response_header notfound =
351 + .version = NSCD_VERSION,
360 + struct datahead head;
361 + netgroup_response_header resp;
367 +addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
368 + const char *key, uid_t uid, struct hashentry *he,
369 + struct datahead *dh, struct dataset **resultp)
371 + if (__builtin_expect (debug_level > 0, 0))
374 + dbg_log (_("Haven't found \"%s\" in netgroup cache!"), key);
376 + dbg_log (_("Reloading \"%s\" in netgroup cache!"), key);
379 + static service_user *netgroup_database;
381 + struct dataset *dataset;
382 + bool cacheable = false;
385 + char *key_copy = NULL;
386 + struct __netgrent data;
387 + size_t buflen = MAX (1024, sizeof (*dataset) + req->key_len);
388 + size_t buffilled = sizeof (*dataset);
389 + char *buffer = NULL;
390 + size_t nentries = 0;
391 + bool use_malloc = false;
392 + size_t group_len = strlen (key) + 1;
395 + struct name_list elem;
396 + char mem[sizeof (struct name_list) + group_len];
399 + if (netgroup_database == NULL
400 + && __nss_database_lookup ("netgroup", NULL, NULL, &netgroup_database))
402 + /* No such service. */
403 + total = sizeof (notfound);
404 + timeout = time (NULL) + db->negtimeout;
407 + TEMP_FAILURE_RETRY (send (fd, ¬found, total, MSG_NOSIGNAL));
409 + dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1);
410 + /* If we cannot permanently store the result, so be it. */
411 + if (dataset != NULL)
413 + dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
414 + dataset->head.recsize = total;
415 + dataset->head.notfound = true;
416 + dataset->head.nreloads = 0;
417 + dataset->head.usable = true;
419 + /* Compute the timeout time. */
420 + timeout = dataset->head.timeout = time (NULL) + db->negtimeout;
421 + dataset->head.ttl = db->negtimeout;
423 + /* This is the reply. */
424 + memcpy (&dataset->resp, ¬found, total);
426 + /* Copy the key data. */
427 + memcpy (dataset->strdata, key, req->key_len);
435 + memset (&data, '\0', sizeof (data));
436 + buffer = alloca (buflen);
437 + first_needed.elem.next = &first_needed.elem;
438 + memcpy (first_needed.elem.name, key, group_len);
439 + data.needed_groups = &first_needed.elem;
441 + while (data.needed_groups != NULL)
443 + /* Add the next group to the list of those which are known. */
444 + struct name_list *this_group = data.needed_groups->next;
445 + if (this_group == data.needed_groups)
446 + data.needed_groups = NULL;
448 + data.needed_groups->next = this_group->next;
449 + this_group->next = data.known_groups;
450 + data.known_groups = this_group;
454 + enum nss_status (*f) (const char *, struct __netgrent *);
458 + service_user *nip = netgroup_database;
459 + int no_more = __nss_lookup (&nip, "setnetgrent", NULL, &setfct.ptr);
462 + enum nss_status status
463 + = DL_CALL_FCT (*setfct.f, (data.known_groups->name, &data));
465 + if (status == NSS_STATUS_SUCCESS)
469 + enum nss_status (*f) (struct __netgrent *, char *, size_t,
473 + getfct.ptr = __nss_lookup_function (nip, "getnetgrent_r");
474 + if (getfct.f != NULL)
478 + status = getfct.f (&data, buffer + buffilled,
479 + buflen - buffilled, &e);
480 + if (status == NSS_STATUS_RETURN)
481 + /* This was the last one for this group. Look
482 + at next group if available. */
484 + if (status == NSS_STATUS_SUCCESS)
486 + if (data.type == triple_val)
488 + const char *nhost = data.val.triple.host;
489 + const char *nuser = data.val.triple.user;
490 + const char *ndomain = data.val.triple.domain;
492 + if (data.val.triple.host > data.val.triple.user
493 + || data.val.triple.user > data.val.triple.domain)
495 + const char *last = MAX (nhost,
496 + MAX (nuser, ndomain));
497 + size_t bufused = (last + strlen (last) + 1
500 + /* We have to make temporary copies. */
501 + size_t hostlen = strlen (nhost) + 1;
502 + size_t userlen = strlen (nuser) + 1;
503 + size_t domainlen = strlen (ndomain) + 1;
504 + size_t needed = hostlen + userlen + domainlen;
506 + if (buflen - req->key_len - bufused < needed)
508 + size_t newsize = MAX (2 * buflen,
509 + buflen + 2 * needed);
510 + if (use_malloc || newsize > 1024 * 1024)
513 + char *newbuf = xrealloc (use_malloc
522 + extend_alloca (buffer, buflen, newsize);
525 + nhost = memcpy (buffer + bufused,
527 + nuser = memcpy ((char *) nhost + hostlen,
529 + ndomain = memcpy ((char *) nuser + userlen,
530 + ndomain, domainlen);
533 + char *wp = buffer + buffilled;
534 + wp = stpcpy (wp, nhost) + 1;
535 + wp = stpcpy (wp, nuser) + 1;
536 + wp = stpcpy (wp, ndomain) + 1;
537 + buffilled = wp - buffer;
542 + /* Check that the group has not been
543 + requested before. */
544 + struct name_list *runp = data.needed_groups;
548 + if (strcmp (runp->name, data.val.group) == 0)
552 + if (runp == data.needed_groups)
561 + runp = data.known_groups;
562 + while (runp != NULL)
563 + if (strcmp (runp->name, data.val.group) == 0)
571 + /* A new group is requested. */
572 + size_t namelen = strlen (data.val.group) + 1;
573 + struct name_list *newg = alloca (sizeof (*newg)
575 + memcpy (newg->name, data.val.group, namelen);
576 + if (data.needed_groups == NULL)
577 + data.needed_groups = newg->next = newg;
580 + newg->next = data.needed_groups->next;
581 + data.needed_groups->next = newg;
582 + data.needed_groups = newg;
587 + else if (status == NSS_STATUS_UNAVAIL && e == ERANGE)
589 + size_t newsize = 2 * buflen;
590 + if (use_malloc || newsize > 1024 * 1024)
593 + char *newbuf = xrealloc (use_malloc
594 + ? buffer : NULL, buflen);
600 + extend_alloca (buffer, buflen, newsize);
604 + enum nss_status (*endfct) (struct __netgrent *);
605 + endfct = __nss_lookup_function (nip, "endnetgrent");
606 + if (endfct != NULL)
607 + (void) DL_CALL_FCT (*endfct, (&data));
612 + no_more = __nss_next2 (&nip, "setnetgrent", NULL, &setfct.ptr,
619 + /* Fill in the dataset. */
620 + dataset = (struct dataset *) buffer;
621 + dataset->head.allocsize = total + req->key_len;
622 + dataset->head.recsize = total - offsetof (struct dataset, resp);
623 + dataset->head.notfound = false;
624 + dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
625 + dataset->head.usable = true;
626 + dataset->head.ttl = db->postimeout;
627 + timeout = dataset->head.timeout = time (NULL) + dataset->head.ttl;
629 + dataset->resp.version = NSCD_VERSION;
630 + dataset->resp.found = 1;
631 + dataset->resp.nresults = nentries;
632 + dataset->resp.result_len = buffilled - sizeof (*dataset);
634 + assert (buflen - buffilled >= req->key_len);
635 + key_copy = memcpy (buffer + buffilled, key, req->key_len);
636 + buffilled += req->key_len;
638 + /* Now we can determine whether on refill we have to create a new
644 + if (dataset->head.allocsize == dh->allocsize
645 + && dataset->head.recsize == dh->recsize
646 + && memcmp (&dataset->resp, dh->data,
647 + dh->allocsize - offsetof (struct dataset, resp)) == 0)
649 + /* The data has not changed. We will just bump the timeout
650 + value. Note that the new record has been allocated on
651 + the stack and need not be freed. */
652 + dh->timeout = dataset->head.timeout;
653 + dh->ttl = dataset->head.ttl;
655 + dataset = (struct dataset *) dh;
662 + struct dataset *newp
663 + = (struct dataset *) mempool_alloc (db, total + req->key_len, 1);
664 + if (__builtin_expect (newp != NULL, 1))
666 + /* Adjust pointer into the memory block. */
667 + key_copy = (char *) newp + (key_copy - buffer);
669 + dataset = memcpy (newp, dataset, total + req->key_len);
673 + /* Mark the old record as obsolete. */
674 + dh->usable = false;
678 + if (he == NULL && fd != -1)
680 + /* We write the dataset before inserting it to the database
681 + since while inserting this thread might block and so would
682 + unnecessarily let the receiver wait. */
684 +#ifdef HAVE_SENDFILE
685 + if (__builtin_expect (db->mmap_used, 1) && cacheable)
687 + assert (db->wr_fd != -1);
688 + assert ((char *) &dataset->resp > (char *) db->data);
689 + assert ((char *) dataset - (char *) db->head + total
690 + <= (sizeof (struct database_pers_head)
691 + + db->head->module * sizeof (ref_t)
692 + + db->head->data_size));
693 +# ifndef __ASSUME_SENDFILE
696 + sendfileall (fd, db->wr_fd, (char *) &dataset->resp
697 + - (char *) db->head, dataset->head.recsize);
698 +# ifndef __ASSUME_SENDFILE
699 + if (written == -1 && errno == ENOSYS)
706 +#if defined HAVE_SENDFILE && !defined __ASSUME_SENDFILE
709 + writeall (fd, &dataset->resp, dataset->head.recsize);
715 + /* If necessary, we also propagate the data to disk. */
716 + if (db->persistent)
719 + uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
720 + msync ((void *) pval,
721 + ((uintptr_t) dataset & pagesize_m1) + total + req->key_len,
725 + (void) cache_add (req->type, key_copy, req->key_len, &dataset->head,
726 + true, db, uid, he == NULL);
728 + pthread_rwlock_unlock (&db->lock);
730 + /* Mark the old entry as obsolete. */
732 + dh->usable = false;
739 + *resultp = dataset;
746 +addinnetgrX (struct database_dyn *db, int fd, request_header *req,
747 + char *key, uid_t uid, struct hashentry *he,
748 + struct datahead *dh)
750 + const char *group = key;
751 + key = (char *) rawmemchr (key, '\0') + 1;
752 + size_t group_len = key - group - 1;
753 + const char *host = *key++ ? key : NULL;
755 + key = (char *) rawmemchr (key, '\0') + 1;
756 + const char *user = *key++ ? key : NULL;
758 + key = (char *) rawmemchr (key, '\0') + 1;
759 + const char *domain = *key++ ? key : NULL;
761 + if (__builtin_expect (debug_level > 0, 0))
764 + dbg_log (_("Haven't found \"%s (%s,%s,%s)\" in netgroup cache!"),
765 + group, host ?: "", user ?: "", domain ?: "");
767 + dbg_log (_("Reloading \"%s (%s,%s,%s)\" in netgroup cache!"),
768 + group, host ?: "", user ?: "", domain ?: "");
771 + struct dataset *result = (struct dataset *) cache_search (GETNETGRENT,
775 + if (result != NULL)
776 + timeout = result->head.timeout;
779 + request_header req_get =
781 + .type = GETNETGRENT,
782 + .key_len = group_len
784 + timeout = addgetnetgrentX (db, -1, &req_get, group, uid, NULL, NULL,
790 + struct datahead head;
791 + innetgroup_response_header resp;
793 + = (struct indataset *) mempool_alloc (db,
794 + sizeof (*dataset) + req->key_len,
796 + struct indataset dataset_mem;
797 + bool cacheable = true;
798 + if (__builtin_expect (dataset == NULL, 0))
801 + dataset = &dataset_mem;
804 + dataset->head.allocsize = sizeof (*dataset) + req->key_len;
805 + dataset->head.recsize = sizeof (innetgroup_response_header);
806 + dataset->head.notfound = result->head.notfound;
807 + dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
808 + dataset->head.usable = true;
809 + dataset->head.ttl = result->head.ttl;
810 + dataset->head.timeout = timeout;
812 + dataset->resp.version = NSCD_VERSION;
813 + dataset->resp.found = result->resp.found;
814 + /* Until we find a matching entry the result is 0. */
815 + dataset->resp.result = 0;
817 + char *key_copy = memcpy ((char *) (dataset + 1), group, req->key_len);
819 + if (dataset->resp.found)
821 + const char *triplets = (const char *) (&result->resp + 1);
823 + for (nscd_ssize_t i = result->resp.nresults; i > 0; --i)
825 + bool success = true;
828 + success = strcmp (host, triplets) == 0;
829 + triplets = (const char *) rawmemchr (triplets, '\0') + 1;
831 + if (success && user != NULL)
832 + success = strcmp (user, triplets) == 0;
833 + triplets = (const char *) rawmemchr (triplets, '\0') + 1;
835 + if (success && (domain == NULL || strcmp (domain, triplets) == 0))
837 + dataset->resp.result = 1;
840 + triplets = (const char *) rawmemchr (triplets, '\0') + 1;
844 + if (he != NULL && dh->data[0].innetgroupdata.result == dataset->resp.result)
846 + /* The data has not changed. We will just bump the timeout
847 + value. Note that the new record has been allocated on
848 + the stack and need not be freed. */
849 + dh->timeout = timeout;
850 + dh->ttl = dataset->head.ttl;
857 + /* We write the dataset before inserting it to the database
858 + since while inserting this thread might block and so would
859 + unnecessarily let the receiver wait. */
862 +#ifdef HAVE_SENDFILE
863 + if (__builtin_expect (db->mmap_used, 1) && cacheable)
865 + assert (db->wr_fd != -1);
866 + assert ((char *) &dataset->resp > (char *) db->data);
867 + assert ((char *) dataset - (char *) db->head + sizeof (*dataset)
868 + <= (sizeof (struct database_pers_head)
869 + + db->head->module * sizeof (ref_t)
870 + + db->head->data_size));
871 +# ifndef __ASSUME_SENDFILE
874 + sendfileall (fd, db->wr_fd,
875 + (char *) &dataset->resp - (char *) db->head,
876 + sizeof (innetgroup_response_header));
877 +# ifndef __ASSUME_SENDFILE
878 + if (written == -1 && errno == ENOSYS)
883 +# ifndef __ASSUME_SENDFILE
887 + writeall (fd, &dataset->resp, sizeof (innetgroup_response_header));
892 + /* If necessary, we also propagate the data to disk. */
893 + if (db->persistent)
896 + uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
897 + msync ((void *) pval,
898 + ((uintptr_t) dataset & pagesize_m1) + sizeof (*dataset)
903 + (void) cache_add (req->type, key_copy, req->key_len, &dataset->head,
904 + true, db, uid, he == NULL);
906 + pthread_rwlock_unlock (&db->lock);
908 + /* Mark the old entry as obsolete. */
910 + dh->usable = false;
918 +addgetnetgrent (struct database_dyn *db, int fd, request_header *req,
919 + void *key, uid_t uid)
921 + struct dataset *ignore;
923 + addgetnetgrentX (db, fd, req, key, uid, NULL, NULL, &ignore);
928 +readdgetnetgrent (struct database_dyn *db, struct hashentry *he,
929 + struct datahead *dh)
931 + request_header req =
933 + .type = GETNETGRENT,
936 + struct dataset *ignore;
938 + return addgetnetgrentX (db, -1, &req, db->data + he->key, he->owner, he, dh,
944 +addinnetgr (struct database_dyn *db, int fd, request_header *req,
945 + void *key, uid_t uid)
947 + addinnetgrX (db, fd, req, key, uid, NULL, NULL);
952 +readdinnetgr (struct database_dyn *db, struct hashentry *he,
953 + struct datahead *dh)
955 + request_header req =
961 + return addinnetgrX (db, -1, &req, db->data + he->key, he->owner, he, dh);
963 diff -Nrup a/nscd/nscd-client.h b/nscd/nscd-client.h
964 --- a/nscd/nscd-client.h 2012-08-06 15:07:49.082059915 -0600
965 +++ b/nscd/nscd-client.h 2012-08-06 15:08:19.090941456 -0600
966 @@ -70,6 +70,9 @@ typedef enum
976 @@ -171,6 +174,24 @@ typedef struct
977 } serv_response_header;
980 +/* Structure send in reply to netgroup query. Note that this struct is
981 + sent also if the service is disabled or there is no record found. */
986 + nscd_ssize_t nresults;
987 + nscd_ssize_t result_len;
988 +} netgroup_response_header;
995 +} innetgroup_response_header;
998 /* Type for offsets in data part of database. */
999 typedef uint32_t ref_t;
1000 /* Value for invalid/no reference. */
1001 @@ -210,6 +231,8 @@ struct datahead
1002 ai_response_header aidata;
1003 initgr_response_header initgrdata;
1004 serv_response_header servdata;
1005 + netgroup_response_header netgroupdata;
1006 + innetgroup_response_header innetgroupdata;
1007 nscd_ssize_t align1;
1010 diff -Nrup a/nscd/nscd.conf b/nscd/nscd.conf
1011 --- a/nscd/nscd.conf 2012-08-06 15:07:48.553062002 -0600
1012 +++ b/nscd/nscd.conf 2012-08-06 15:08:19.091941452 -0600
1014 persistent services yes
1016 max-db-size services 33554432
1018 + enable-cache netgroup yes
1019 + positive-time-to-live netgroup 28800
1020 + negative-time-to-live netgroup 20
1021 + suggested-size netgroup 211
1022 + check-files netgroup yes
1023 + persistent netgroup yes
1024 + shared netgroup yes
1025 + max-db-size netgroup 33554432
1026 diff -Nrup a/nscd/nscd.h b/nscd/nscd.h
1027 --- a/nscd/nscd.h 2012-08-06 15:07:49.085059903 -0600
1028 +++ b/nscd/nscd.h 2012-08-06 15:08:19.093941443 -0600
1029 @@ -38,6 +38,7 @@ typedef enum
1037 @@ -107,6 +108,7 @@ struct database_dyn
1038 #define _PATH_NSCD_GROUP_DB "/var/db/nscd/group"
1039 #define _PATH_NSCD_HOSTS_DB "/var/db/nscd/hosts"
1040 #define _PATH_NSCD_SERVICES_DB "/var/db/nscd/services"
1041 +#define _PATH_NSCD_NETGROUP_DB "/var/db/nscd/netgroup"
1043 /* Path used when not using persistent storage. */
1044 #define _PATH_NSCD_XYZ_DB_TMP "/var/run/nscd/dbXXXXXX"
1045 @@ -140,6 +142,7 @@ extern const struct iovec pwd_iov_disabl
1046 extern const struct iovec grp_iov_disabled;
1047 extern const struct iovec hst_iov_disabled;
1048 extern const struct iovec serv_iov_disabled;
1049 +extern const struct iovec netgroup_iov_disabled;
1052 /* Initial number of threads to run. */
1053 @@ -185,6 +188,11 @@ extern gid_t old_gid;
1055 /* Prototypes for global functions. */
1057 +/* Wrapper functions with error checking for standard functions. */
1058 +extern void *xmalloc (size_t n);
1059 +extern void *xcalloc (size_t n, size_t s);
1060 +extern void *xrealloc (void *o, size_t n);
1063 extern void termination_handler (int signum) __attribute__ ((__noreturn__));
1064 extern int nscd_open_socket (void);
1065 @@ -203,8 +211,8 @@ extern void send_stats (int fd, struct d
1066 extern int receive_print_stats (void) __attribute__ ((__noreturn__));
1069 -extern struct datahead *cache_search (request_type, void *key, size_t len,
1070 - struct database_dyn *table,
1071 +extern struct datahead *cache_search (request_type, const void *key,
1072 + size_t len, struct database_dyn *table,
1074 extern int cache_add (int type, const void *key, size_t len,
1075 struct datahead *packet, bool first,
1076 @@ -273,6 +281,16 @@ extern void addservbyport (struct databa
1077 extern time_t readdservbyport (struct database_dyn *db, struct hashentry *he,
1078 struct datahead *dh);
1080 +/* netgroupcache.c */
1081 +extern void addinnetgr (struct database_dyn *db, int fd, request_header *req,
1082 + void *key, uid_t uid);
1083 +extern time_t readdinnetgr (struct database_dyn *db, struct hashentry *he,
1084 + struct datahead *dh);
1085 +extern void addgetnetgrent (struct database_dyn *db, int fd,
1086 + request_header *req, void *key, uid_t uid);
1087 +extern time_t readdgetnetgrent (struct database_dyn *db, struct hashentry *he,
1088 + struct datahead *dh);
1091 extern void *mempool_alloc (struct database_dyn *db, size_t len,
1093 diff -Nrup a/nscd/nscd_conf.c b/nscd/nscd_conf.c
1094 --- a/nscd/nscd_conf.c 2010-05-04 05:27:23.000000000 -0600
1095 +++ b/nscd/nscd_conf.c 2012-08-06 15:08:19.093941443 -0600
1096 @@ -43,7 +43,8 @@ const char *const dbnames[lastdb] =
1100 - [servdb] = "services"
1101 + [servdb] = "services",
1102 + [netgrdb] = "netgroup"
1106 diff -Nrup a/nscd/nscd_netgroup.c b/nscd/nscd_netgroup.c
1107 --- a/nscd/nscd_netgroup.c 1969-12-31 17:00:00.000000000 -0700
1108 +++ b/nscd/nscd_netgroup.c 2012-08-06 15:08:19.094941439 -0600
1110 +/* Copyright (C) 2011 Free Software Foundation, Inc.
1111 + This file is part of the GNU C Library.
1112 + Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
1114 + The GNU C Library is free software; you can redistribute it and/or
1115 + modify it under the terms of the GNU Lesser General Public
1116 + License as published by the Free Software Foundation; either
1117 + version 2.1 of the License, or (at your option) any later version.
1119 + The GNU C Library is distributed in the hope that it will be useful,
1120 + but WITHOUT ANY WARRANTY; without even the implied warranty of
1121 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1122 + Lesser General Public License for more details.
1124 + You should have received a copy of the GNU Lesser General Public
1125 + License along with the GNU C Library; if not, write to the Free
1126 + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
1127 + 02111-1307 USA. */
1129 +#include <alloca.h>
1131 +#include <stdlib.h>
1132 +#include <string.h>
1133 +#include <not-cancel.h>
1135 +#include "nscd-client.h"
1136 +#include "nscd_proto.h"
1138 +int __nss_not_use_nscd_netgroup;
1141 +libc_locked_map_ptr (static, map_handle);
1142 +/* Note that we only free the structure if necessary. The memory
1143 + mapping is not removed since it is not visible to the malloc
1145 +libc_freeres_fn (pw_map_free)
1147 + if (map_handle.mapped != NO_MAPPING)
1149 + void *p = map_handle.mapped;
1150 + map_handle.mapped = NO_MAPPING;
1157 +__nscd_setnetgrent (const char *group, struct __netgrent *datap)
1161 + size_t group_len = strlen (group);
1163 + /* If the mapping is available, try to search there instead of
1164 + communicating with the nscd. */
1165 + struct mapped_database *mapped;
1166 + mapped = __nscd_get_map_ref (GETFDNETGR, "netgroup", &map_handle, &gc_cycle);
1169 + char *respdata = NULL;
1171 + netgroup_response_header netgroup_resp;
1173 + if (mapped != NO_MAPPING)
1175 + struct datahead *found = __nscd_cache_search (GETNETGRENT, group,
1176 + group_len, mapped,
1177 + sizeof netgroup_resp);
1178 + if (found != NULL)
1180 + respdata = (char *) (&found->data[0].netgroupdata + 1);
1181 + netgroup_resp = found->data[0].netgroupdata;
1182 + /* Now check if we can trust pw_resp fields. If GC is
1183 + in progress, it can contain anything. */
1184 + if (mapped->head->gc_cycle != gc_cycle)
1193 + if (respdata == NULL)
1195 + sock = __nscd_open_socket (group, group_len, GETNETGRENT,
1196 + &netgroup_resp, sizeof (netgroup_resp));
1199 + /* nscd not running or wrong version. */
1200 + __nss_not_use_nscd_netgroup = 1;
1205 + if (netgroup_resp.found == 1)
1207 + size_t datalen = netgroup_resp.result_len;
1209 + /* If we do not have to read the data here it comes from the
1210 + mapped data and does not have to be freed. */
1211 + if (respdata == NULL)
1213 + /* The data will come via the socket. */
1214 + respdata = malloc (datalen);
1215 + if (respdata == NULL)
1218 + if ((size_t) __readall (sock, respdata, datalen) != datalen)
1225 + datap->data = respdata;
1226 + datap->data_size = datalen;
1227 + datap->cursor = respdata;
1229 + datap->nip = (service_user *) -1l;
1230 + datap->known_groups = NULL;
1231 + datap->needed_groups = NULL;
1237 + if (__builtin_expect (netgroup_resp.found == -1, 0))
1239 + /* The daemon does not cache this database. */
1240 + __nss_not_use_nscd_netgroup = 1;
1244 + /* Set errno to 0 to indicate no error, just no found record. */
1246 + /* Even though we have not found anything, the result is zero. */
1252 + close_not_cancel_no_status (sock);
1254 + if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
1256 + /* When we come here this means there has been a GC cycle while we
1257 + were looking for the data. This means the data might have been
1258 + inconsistent. Retry if possible. */
1259 + if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
1261 + /* nscd is just running gc now. Disable using the mapping. */
1262 + if (atomic_decrement_val (&mapped->counter) == 0)
1263 + __nscd_unmap (mapped);
1264 + mapped = NO_MAPPING;
1276 +__nscd_innetgr (const char *netgroup, const char *host, const char *user,
1277 + const char *domain)
1279 + size_t key_len = (strlen (netgroup) + strlen (host ?: "")
1280 + + strlen (user ?: "") + strlen (domain ?: "") + 7);
1282 + bool use_alloca = __libc_use_alloca (key_len);
1284 + key = alloca (key_len);
1287 + key = malloc (key_len);
1291 + char *wp = stpcpy (key, netgroup) + 1;
1295 + wp = stpcpy (wp, host) + 1;
1302 + wp = stpcpy (wp, user) + 1;
1306 + if (domain != NULL)
1309 + wp = stpcpy (wp, domain) + 1;
1313 + key_len = wp - key;
1315 + /* If the mapping is available, try to search there instead of
1316 + communicating with the nscd. */
1319 + struct mapped_database *mapped;
1320 + mapped = __nscd_get_map_ref (GETFDNETGR, "netgroup", &map_handle, &gc_cycle);
1324 + innetgroup_response_header innetgroup_resp;
1327 + if (mapped != NO_MAPPING)
1329 + struct datahead *found = __nscd_cache_search (INNETGR, key,
1331 + sizeof innetgroup_resp);
1332 + if (found != NULL)
1334 + innetgroup_resp = found->data[0].innetgroupdata;
1335 + /* Now check if we can trust pw_resp fields. If GC is
1336 + in progress, it can contain anything. */
1337 + if (mapped->head->gc_cycle != gc_cycle)
1347 + sock = __nscd_open_socket (key, key_len, INNETGR,
1348 + &innetgroup_resp, sizeof (innetgroup_resp));
1351 + /* nscd not running or wrong version. */
1352 + __nss_not_use_nscd_netgroup = 1;
1357 + if (innetgroup_resp.found == 1)
1358 + retval = innetgroup_resp.result;
1361 + if (__builtin_expect (innetgroup_resp.found == -1, 0))
1363 + /* The daemon does not cache this database. */
1364 + __nss_not_use_nscd_netgroup = 1;
1368 + /* Set errno to 0 to indicate no error, just no found record. */
1370 + /* Even though we have not found anything, the result is zero. */
1376 + close_not_cancel_no_status (sock);
1378 + if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
1380 + /* When we come here this means there has been a GC cycle while we
1381 + were looking for the data. This means the data might have been
1382 + inconsistent. Retry if possible. */
1383 + if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
1385 + /* nscd is just running gc now. Disable using the mapping. */
1386 + if (atomic_decrement_val (&mapped->counter) == 0)
1387 + __nscd_unmap (mapped);
1388 + mapped = NO_MAPPING;
1400 diff -Nrup a/nscd/nscd_proto.h b/nscd/nscd_proto.h
1401 --- a/nscd/nscd_proto.h 2010-05-04 05:27:23.000000000 -0600
1402 +++ b/nscd/nscd_proto.h 2012-08-06 15:14:24.446648305 -0600
1404 -/* Copyright (C) 1998-2000, 2002, 2004, 2007 Free Software Foundation, Inc.
1405 +/* Copyright (C) 1998-2000,2002,2004,2007,2011 Free Software Foundation, Inc.
1406 This file is part of the GNU C Library.
1407 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
1409 @@ -36,6 +36,7 @@ extern int __nss_not_use_nscd_passwd att
1410 extern int __nss_not_use_nscd_group attribute_hidden;
1411 extern int __nss_not_use_nscd_hosts attribute_hidden;
1412 extern int __nss_not_use_nscd_services attribute_hidden;
1413 +extern int __nss_not_use_nscd_netgroup attribute_hidden;
1415 extern int __nscd_getpwnam_r (const char *name, struct passwd *resultbuf,
1416 char *buffer, size_t buflen,
1417 @@ -71,5 +72,9 @@ extern int __nscd_getservbyname_r (const
1418 extern int __nscd_getservbyport_r (int port, const char *proto,
1419 struct servent *result_buf, char *buf,
1420 size_t buflen, struct servent **result);
1421 +extern int __nscd_innetgr (const char *netgroup, const char *host,
1422 + const char *user, const char *domain);
1423 +extern int __nscd_setnetgrent (const char *group, struct __netgrent *datap);
1426 #endif /* _NSCD_PROTO_H */
1427 diff -Nrup a/nscd/selinux.c b/nscd/selinux.c
1428 --- a/nscd/selinux.c 2010-05-04 05:27:23.000000000 -0600
1429 +++ b/nscd/selinux.c 2012-08-06 15:08:19.096941431 -0600
1431 /* SELinux access controls for nscd.
1432 - Copyright (C) 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
1433 + Copyright (C) 2004,2005,2006,2007,2009,2011 Free Software Foundation, Inc.
1434 This file is part of the GNU C Library.
1435 Contributed by Matthew Rickard <mjricka@epoch.ncsc.mil>, 2004.
1438 int selinux_enabled;
1440 /* Define mappings of access vector permissions to request types. */
1441 -static const int perms[LASTREQ] =
1442 +static const access_vector_t perms[LASTREQ] =
1444 [GETPWBYNAME] = NSCD__GETPWD,
1445 [GETPWBYUID] = NSCD__GETPWD,
1446 @@ -69,6 +69,11 @@ static const int perms[LASTREQ] =
1447 [GETSERVBYPORT] = NSCD__GETSERV,
1448 [GETFDSERV] = NSCD__SHMEMSERV,
1450 +#ifdef NSCD__GETNETGRP
1451 + [GETNETGRENT] = NSCD__GETNETGRP,
1452 + [INNETGR] = NSCD__GETNETGRP,
1453 + [GETFDNETGR] = NSCD__SHMEMNETGRP,
1457 /* Store an entry ref to speed AVC decisions. */
1458 diff -Nrup a/nss/Makefile b/nss/Makefile
1459 --- a/nss/Makefile 2012-08-06 15:07:48.938060482 -0600
1460 +++ b/nss/Makefile 2012-08-23 14:19:49.382442094 -0600
1462 -# Copyright (C) 1996-1998,2000-2002,2007,2009 Free Software Foundation, Inc.
1463 +# Copyright (C) 1996-1998,2000-2002,2007,2009,2010
1464 +# Free Software Foundation, Inc.
1465 # This file is part of the GNU C Library.
1467 # The GNU C Library is free software; you can redistribute it and/or
1468 @@ -39,7 +40,7 @@ databases = proto service hosts network
1470 install-bin := getent
1473 +tests = test-netdb tst-nss-test1
1476 include ../Makeconfig
1477 @@ -85,3 +86,14 @@ endif
1478 # a statically-linked program that hasn't already loaded it.
1479 $(services:%=$(objpfx)libnss_%.so): $(common-objpfx)libc.so \
1480 $(common-objpfx)libc_nonshared.a
1483 +distribute += nss_test1.c
1485 +CFLAGS-nss_test1.c = -DNOT_IN_libc=1
1486 +$(objpfx)/libnss_test1.so: $(objpfx)nss_test1.os $(common-objpfx)libc.so \
1487 + $(common-objpfx)libc_nonshared.a
1489 +$(objpfx)/libnss_test1.so$(libnss_test1.so-version): $(objpfx)/libnss_test1.so
1491 +$(objpfx)tst-nss-test1.out: $(objpfx)/libnss_test1.so$(libnss_test1.so-version)
1492 diff -Nrup a/nss/Versions b/nss/Versions
1493 --- a/nss/Versions 2012-08-06 15:07:48.939060479 -0600
1494 +++ b/nss/Versions 2012-08-06 15:08:19.096941431 -0600
1495 @@ -12,7 +12,7 @@ libc {
1496 __nss_disable_nscd; __nss_lookup_function; _nss_files_parse_sgent;
1498 __nss_passwd_lookup2; __nss_group_lookup2; __nss_hosts_lookup2;
1499 - __nss_services_lookup2; __nss_next2;
1500 + __nss_services_lookup2; __nss_next2; __nss_lookup;
1504 diff -Nrup a/nss/getXXbyYY_r.c b/nss/getXXbyYY_r.c
1505 --- a/nss/getXXbyYY_r.c 2010-05-04 05:27:23.000000000 -0600
1506 +++ b/nss/getXXbyYY_r.c 2012-08-23 14:19:49.403442011 -0600
1508 -/* Copyright (C) 1996-2004, 2006, 2007, 2009 Free Software Foundation, Inc.
1509 +/* Copyright (C) 1996-2004,2006,2007,2009,2010 Free Software Foundation, Inc.
1510 This file is part of the GNU C Library.
1511 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
1514 # define NOT_USENSCD_NAME ADD_NOT_NSCDUSE (DATABASE_NAME)
1515 # define ADD_NOT_NSCDUSE(name) ADD_NOT_NSCDUSE1 (name)
1516 # define ADD_NOT_NSCDUSE1(name) __nss_not_use_nscd_##name
1517 +# define CONCAT2(arg1, arg2) CONCAT2_2 (arg1, arg2)
1518 +# define CONCAT2_2(arg1, arg2) arg1##arg2
1521 #define FUNCTION_NAME_STRING STRINGIZE (FUNCTION_NAME)
1522 @@ -186,7 +188,8 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, L
1523 if (NOT_USENSCD_NAME > 0 && ++NOT_USENSCD_NAME > NSS_NSCD_RETRY)
1524 NOT_USENSCD_NAME = 0;
1526 - if (!NOT_USENSCD_NAME)
1527 + if (!NOT_USENSCD_NAME
1528 + && !__nss_database_custom[CONCAT2 (NSS_DBSIDX_, DATABASE_NAME)])
1530 nscd_status = NSCD_NAME (ADD_VARIABLES, resbuf, buffer, buflen, result
1532 diff -Nrup a/nss/getent.c b/nss/getent.c
1533 --- a/nss/getent.c 2010-05-04 05:27:23.000000000 -0600
1534 +++ b/nss/getent.c 2012-08-06 15:15:06.479427609 -0600
1535 @@ -466,7 +466,6 @@ static int
1536 netgroup_keys (int number, char *key[])
1543 @@ -474,18 +473,28 @@ netgroup_keys (int number, char *key[])
1547 - for (i = 0; i < number; ++i)
1550 - if (!setnetgrent (key[i]))
1551 + char *host = strcmp (key[1], "*") == 0 ? NULL : key[1];
1552 + char *user = strcmp (key[2], "*") == 0 ? NULL : key[2];
1553 + char *domain = strcmp (key[3], "*") == 0 ? NULL : key[3];
1555 + printf ("%-21s (%s,%s,%s) = %d\n",
1556 + key[0], host ?: "", user ?: "", domain ?: "",
1557 + innetgr (key[0], host, user, domain));
1559 + else if (number == 1)
1561 + if (!setnetgrent (key[0]))
1567 - printf ("%-21s", key[i]);
1568 + printf ("%-21s", key[0]);
1570 while (getnetgrent (p, p + 1, p + 2))
1571 - printf (" (%s, %s, %s)", p[0] ?: " ", p[1] ?: "", p[2] ?: "");
1572 + printf (" (%s,%s,%s)", p[0] ?: " ", p[1] ?: "", p[2] ?: "");
1573 putchar_unlocked ('\n');
1576 diff -Nrup a/nss/nss_files/files-parse.c b/nss/nss_files/files-parse.c
1577 --- a/nss/nss_files/files-parse.c 2010-05-04 05:27:23.000000000 -0600
1578 +++ b/nss/nss_files/files-parse.c 2012-08-23 14:19:49.418441951 -0600
1580 /* Common code for file-based database parsers in nss_files module.
1581 - Copyright (C) 1996-2000, 2003, 2004, 2009 Free Software Foundation, Inc.
1582 + Copyright (C) 1996-2000,2003,2004,2009,2010 Free Software Foundation, Inc.
1583 This file is part of the GNU C Library.
1585 The GNU C Library is free software; you can redistribute it and/or
1587 DATABASE -- string of the database file's name ("hosts", "passwd").
1589 ENTDATA -- if defined, `struct ENTDATA' is used by the parser to store
1590 - things pointed to by the resultant `struct STRUCTURE'.
1591 + things pointed to by the resultant `struct STRUCTURE'.
1593 NEED_H_ERRNO - defined iff an arg `int *herrnop' is used.
1595 @@ -229,7 +229,7 @@ strtou32 (const char *nptr, char **endpt
1596 char **list = parse_list (&line, buf_start, buf_end, '\0', errnop); \
1598 result->TRAILING_LIST_MEMBER = list; \
1601 return -1; /* -1 indicates we ran out of space. */ \
1604 diff -Nrup a/nss/nss_test1.c b/nss/nss_test1.c
1605 --- a/nss/nss_test1.c 1969-12-31 17:00:00.000000000 -0700
1606 +++ b/nss/nss_test1.c 2012-08-23 14:19:49.418441951 -0600
1610 +#include <pthread.h>
1611 +#include <string.h>
1614 +#define COPY_IF_ROOM(s) \
1615 + ({ size_t len_ = strlen (s) + 1; \
1616 + char *start_ = cp; \
1617 + buflen - (cp - buffer) < len_ \
1619 + : (cp = mempcpy (cp, s, len_), start_); })
1622 +/* Password handling. */
1625 +static struct passwd pwd_data[] =
1628 + { .pw_name = (char *) "name" #u, .pw_passwd = (char *) "*", .pw_uid = u, \
1629 + .pw_gid = 100, .pw_gecos = (char *) "*", .pw_dir = (char *) "*", \
1630 + .pw_shell = (char *) "*" }
1637 +#define npwd_data (sizeof (pwd_data) / sizeof (pwd_data[0]))
1639 +static size_t pwd_iter;
1640 +#define CURPWD pwd_data[pwd_iter]
1642 +static pthread_mutex_t pwd_lock = PTHREAD_MUTEX_INITIALIZER;
1646 +_nss_test1_setpwent (int stayopen)
1649 + return NSS_STATUS_SUCCESS;
1654 +_nss_test1_endpwent (void)
1656 + return NSS_STATUS_SUCCESS;
1661 +_nss_test1_getpwent_r (struct passwd *result, char *buffer, size_t buflen,
1664 + char *cp = buffer;
1665 + int res = NSS_STATUS_SUCCESS;
1667 + pthread_mutex_lock (&pwd_lock);
1669 + if (pwd_iter >= npwd_data)
1670 + res = NSS_STATUS_NOTFOUND;
1673 + result->pw_name = COPY_IF_ROOM (CURPWD.pw_name);
1674 + result->pw_passwd = COPY_IF_ROOM (CURPWD.pw_passwd);
1675 + result->pw_uid = CURPWD.pw_uid;
1676 + result->pw_gid = CURPWD.pw_gid;
1677 + result->pw_gecos = COPY_IF_ROOM (CURPWD.pw_gecos);
1678 + result->pw_dir = COPY_IF_ROOM (CURPWD.pw_dir);
1679 + result->pw_shell = COPY_IF_ROOM (CURPWD.pw_shell);
1681 + if (result->pw_name == NULL || result->pw_passwd == NULL
1682 + || result->pw_gecos == NULL || result->pw_dir == NULL
1683 + || result->pw_shell == NULL)
1686 + res = NSS_STATUS_TRYAGAIN;
1692 + pthread_mutex_unlock (&pwd_lock);
1699 +_nss_test1_getpwuid_r (uid_t uid, struct passwd *result, char *buffer,
1700 + size_t buflen, int *errnop)
1702 + for (size_t idx = 0; idx < npwd_data; ++idx)
1703 + if (pwd_data[idx].pw_uid == uid)
1705 + char *cp = buffer;
1706 + int res = NSS_STATUS_SUCCESS;
1708 + result->pw_name = COPY_IF_ROOM (pwd_data[idx].pw_name);
1709 + result->pw_passwd = COPY_IF_ROOM (pwd_data[idx].pw_passwd);
1710 + result->pw_uid = pwd_data[idx].pw_uid;
1711 + result->pw_gid = pwd_data[idx].pw_gid;
1712 + result->pw_gecos = COPY_IF_ROOM (pwd_data[idx].pw_gecos);
1713 + result->pw_dir = COPY_IF_ROOM (pwd_data[idx].pw_dir);
1714 + result->pw_shell = COPY_IF_ROOM (pwd_data[idx].pw_shell);
1716 + if (result->pw_name == NULL || result->pw_passwd == NULL
1717 + || result->pw_gecos == NULL || result->pw_dir == NULL
1718 + || result->pw_shell == NULL)
1721 + res = NSS_STATUS_TRYAGAIN;
1727 + return NSS_STATUS_NOTFOUND;
1732 +_nss_test1_getpwnam_r (const char *name, struct passwd *result, char *buffer,
1733 + size_t buflen, int *errnop)
1735 + for (size_t idx = 0; idx < npwd_data; ++idx)
1736 + if (strcmp (pwd_data[idx].pw_name, name) == 0)
1738 + char *cp = buffer;
1739 + int res = NSS_STATUS_SUCCESS;
1741 + result->pw_name = COPY_IF_ROOM (pwd_data[idx].pw_name);
1742 + result->pw_passwd = COPY_IF_ROOM (pwd_data[idx].pw_passwd);
1743 + result->pw_uid = pwd_data[idx].pw_uid;
1744 + result->pw_gid = pwd_data[idx].pw_gid;
1745 + result->pw_gecos = COPY_IF_ROOM (pwd_data[idx].pw_gecos);
1746 + result->pw_dir = COPY_IF_ROOM (pwd_data[idx].pw_dir);
1747 + result->pw_shell = COPY_IF_ROOM (pwd_data[idx].pw_shell);
1749 + if (result->pw_name == NULL || result->pw_passwd == NULL
1750 + || result->pw_gecos == NULL || result->pw_dir == NULL
1751 + || result->pw_shell == NULL)
1754 + res = NSS_STATUS_TRYAGAIN;
1760 + return NSS_STATUS_NOTFOUND;
1762 diff -Nrup a/nss/nsswitch.c b/nss/nsswitch.c
1763 --- a/nss/nsswitch.c 2010-05-04 05:27:23.000000000 -0600
1764 +++ b/nss/nsswitch.c 2012-08-23 14:19:49.430441903 -0600
1766 -/* Copyright (C) 1996-1999, 2001-2007, 2009 Free Software Foundation, Inc.
1767 +/* Copyright (C) 1996-1999,2001-2007,2009,2010 Free Software Foundation, Inc.
1768 This file is part of the GNU C Library.
1769 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
1771 @@ -71,6 +71,9 @@ static const struct
1773 #define ndatabases (sizeof (databases) / sizeof (databases[0]))
1775 +/* Flags whether custom rules for database is set. */
1776 +bool __nss_database_custom[NSS_DBSIDX_max];
1779 __libc_lock_define_initialized (static, lock)
1781 @@ -165,6 +168,7 @@ __nss_lookup (service_user **ni, const c
1783 return *fctp != NULL ? 0 : (*ni)->next == NULL ? 1 : -1;
1785 +libc_hidden_def (__nss_lookup)
1789 @@ -265,6 +269,7 @@ __nss_configure_lookup (const char *dbna
1791 /* Install new rules. */
1792 *databases[cnt].dbp = new_db;
1793 + __nss_database_custom[cnt] = true;
1795 __libc_lock_unlock (lock);
1797 @@ -729,6 +734,7 @@ __nss_disable_nscd (void)
1798 __nss_not_use_nscd_group = -1;
1799 __nss_not_use_nscd_hosts = -1;
1800 __nss_not_use_nscd_services = -1;
1801 + __nss_not_use_nscd_netgroup = -1;
1805 diff -Nrup a/nss/nsswitch.h b/nss/nsswitch.h
1806 --- a/nss/nsswitch.h 2010-05-04 05:27:23.000000000 -0600
1807 +++ b/nss/nsswitch.h 2012-08-23 14:19:49.431441899 -0600
1809 -/* Copyright (C) 1996-1999,2001,2002,2003,2004,2007
1810 +/* Copyright (C) 1996-1999,2001,2002,2003,2004,2007,2010
1811 Free Software Foundation, Inc.
1812 This file is part of the GNU C Library.
1818 +#include <stdbool.h>
1820 /* Actions performed after lookup finished. */
1822 @@ -96,6 +97,19 @@ typedef struct name_database
1826 +/* Indices into DATABASES in nsswitch.c and __NSS_DATABASE_CUSTOM. */
1829 +#define DEFINE_DATABASE(arg) NSS_DBSIDX_##arg,
1830 +#include "databases.def"
1831 +#undef DEFINE_DATABASE
1835 +/* Flags whether custom rules for database is set. */
1836 +extern bool __nss_database_custom[NSS_DBSIDX_max];
1839 /* Interface functions for NSS. */
1841 /* Get the data structure representing the specified database.
1842 @@ -111,7 +125,8 @@ libc_hidden_proto (__nss_database_lookup
1843 position is remembered in NI. The function returns a value < 0 if
1844 an error occurred or no such function exists. */
1845 extern int __nss_lookup (service_user **ni, const char *fct_name,
1846 - const char *fct2_name, void **fctp) attribute_hidden;
1847 + const char *fct2_name, void **fctp);
1848 +libc_hidden_proto (__nss_lookup)
1850 /* Determine the next step in the lookup process according to the
1851 result STATUS of the call to the last function returned by
1852 diff -Nrup a/nss/tst-nss-test1.c b/nss/tst-nss-test1.c
1853 --- a/nss/tst-nss-test1.c 1969-12-31 17:00:00.000000000 -0700
1854 +++ b/nss/tst-nss-test1.c 2012-08-23 14:19:49.432441895 -0600
1859 +#include <stdlib.h>
1860 +#include <string.h>
1868 + __nss_configure_lookup ("passwd", "test1");
1870 + static const unsigned int pwdids[] = { 100, 30, 200, 60, 20000 };
1871 +#define npwdids (sizeof (pwdids) / sizeof (pwdids[0]))
1874 + const unsigned int *np = pwdids;
1875 + for (struct passwd *p = getpwent (); p != NULL; ++np, p = getpwent ())
1876 + if (p->pw_uid != *np || strncmp (p->pw_name, "name", 4) != 0
1877 + || atol (p->pw_name + 4) != *np)
1879 + printf ("passwd entry %ju wrong (%s, %u)\n",
1880 + np - pwdids, p->pw_name, p->pw_uid);
1887 + for (int i = npwdids - 1; i >= 0; --i)
1890 + snprintf (buf, sizeof (buf), "name%u", pwdids[i]);
1892 + struct passwd *p = getpwnam (buf);
1893 + if (p == NULL || p->pw_uid != pwdids[i] || strcmp (buf, p->pw_name) != 0)
1895 + printf ("passwd entry \"%s\" wrong\n", buf);
1899 + p = getpwuid (pwdids[i]);
1900 + if (p == NULL || p->pw_uid != pwdids[i] || strcmp (buf, p->pw_name) != 0)
1902 + printf ("passwd entry %u wrong\n", pwdids[i]);
1906 + snprintf (buf, sizeof (buf), "name%u", pwdids[i] + 1);
1908 + p = getpwnam (buf);
1911 + printf ("passwd entry \"%s\" wrong\n", buf);
1915 + p = getpwuid (pwdids[i] + 1);
1918 + printf ("passwd entry %u wrong\n", pwdids[i] + 1);
1926 +#define TEST_FUNCTION do_test ()
1927 +#include "../test-skeleton.c"
1928 diff -Nrup a/shlib-versions b/shlib-versions
1929 --- a/shlib-versions 2010-05-04 05:27:23.000000000 -0600
1930 +++ b/shlib-versions 2012-08-23 14:19:49.473441732 -0600
1931 @@ -114,6 +114,10 @@ alpha.*-.*-linux.* libresolv=2.1
1932 .*-.*-.* libnss_ldap=2
1933 .*-.*-.* libnss_hesiod=2
1935 +# Tests for NSS. They must have the same NSS_SHLIB_REVISION number as
1937 +.*-.*-.* libnss_test1=2
1939 # Version for libnsl with YP and NIS+ functions.
1940 alpha.*-.*-linux.* libnsl=1.1
1942 diff -Nrup a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
1943 --- a/sysdeps/posix/getaddrinfo.c 2012-08-06 15:07:49.571057983 -0600
1944 +++ b/sysdeps/posix/getaddrinfo.c 2012-08-23 14:19:49.541441461 -0600
1945 @@ -669,7 +669,8 @@ gaih_inet (const char *name, const struc
1946 && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY)
1947 __nss_not_use_nscd_hosts = 0;
1949 - if (!__nss_not_use_nscd_hosts)
1950 + if (!__nss_not_use_nscd_hosts
1951 + && !__nss_database_custom[NSS_DBSIDX_hosts])
1953 /* Try to use nscd. */
1954 struct nscd_ai_result *air = NULL;