]> git.ipfire.org Git - ipfire-2.x.git/blame - src/patches/glibc/glibc-rh629823.patch
dhcpcd: fix delay after dhcp down.
[ipfire-2.x.git] / src / patches / glibc / glibc-rh629823.patch
CommitLineData
bb330e25
AF
1diff -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
4@@ -1,4 +1,4 @@
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.
8
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])
17 {
18 int n = __nscd_getgrouplist (user, group, size, groupsp, limit);
19 if (n >= 0)
20diff -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
23@@ -28,6 +28,7 @@
24 #include "netgroup.h"
25 #include "nsswitch.h"
26 #include <sysdep.h>
27+#include <nscd/nscd_proto.h>
28
29
30 /* Protect above variable against multiple uses at the same time. */
31@@ -101,7 +102,7 @@ endnetgrent_hook (struct __netgrent *dat
32 {
33 enum nss_status (*endfct) (struct __netgrent *);
34
35- if (datap->nip == NULL)
36+ if (datap->nip == NULL || datap->nip == (service_user *) -1l)
37 return;
38
39 endfct = __nss_lookup_function (datap->nip, "endnetgrent");
40@@ -189,8 +190,21 @@ setnetgrent (const char *group)
41
42 __libc_lock_lock (lock);
43
44+ if (__nss_not_use_nscd_netgroup > 0
45+ && ++__nss_not_use_nscd_netgroup > NSS_NSCD_RETRY)
46+ __nss_not_use_nscd_netgroup = 0;
47+
48+ if (!__nss_not_use_nscd_netgroup
49+ && !__nss_database_custom[NSS_DBSIDX_netgroup])
50+ {
51+ result = __nscd_setnetgrent (group, &dataset);
52+ if (result >= 0)
53+ goto out;
54+ }
55+
56 result = internal_setnetgrent (group, &dataset);
57
58+ out:
59 __libc_lock_unlock (lock);
60
61 return result;
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)
65
66+
67+static enum nss_status
68+nscd_getnetgrent (struct __netgrent *datap, char *buffer, size_t buflen,
69+ int *errnop)
70+{
71+ if (datap->cursor >= datap->data + datap->data_size)
72+ return NSS_STATUS_UNAVAIL;
73+
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;
81+
82+ return NSS_STATUS_SUCCESS;
83+}
84+
85+
86 int
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"))
95- == NULL);
96+ int no_more = datap->nip == NULL;
97+ if (! no_more)
98+ {
99+ if (datap->nip == (service_user *) -1l)
100+ fct = nscd_getnetgrent;
101+ else
102+ {
103+ fct = __nss_lookup_function (datap->nip, "getnetgrent_r");
104+ no_more = fct == NULL;
105+ }
106+ }
107+
108 while (! no_more)
109 {
110 status = (*fct) (datap, buffer, buflen, &errno);
111@@ -337,6 +380,18 @@ int
112 innetgr (const char *netgroup, const char *host, const char *user,
113 const char *domain)
114 {
115+ if (__nss_not_use_nscd_netgroup > 0
116+ && ++__nss_not_use_nscd_netgroup > NSS_NSCD_RETRY)
117+ __nss_not_use_nscd_netgroup = 0;
118+
119+ if (!__nss_not_use_nscd_netgroup
120+ && !__nss_database_custom[NSS_DBSIDX_netgroup])
121+ {
122+ int result = __nscd_innetgr (netgroup, host, user, domain);
123+ if (result >= 0)
124+ return result;
125+ }
126+
127 union
128 {
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;
136 continue;
137 }
138
139diff -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
142@@ -22,7 +22,7 @@
143 subdir := nscd
144
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
148 aux := nscd_helper
149
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 \
157+ netgroupcache
158
159 ifeq ($(have-thread-library),yes)
160
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)
166
167 ifeq (yesyes,$(have-fpie)$(build-shared))
168 relro-LDFLAGS += -Wl,-z,now
169diff -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
180 };
181
182
183@@ -70,7 +72,7 @@ static time_t (*const readdfcts[LASTREQ]
184
185 This function must be called with the read-lock held. */
186 struct datahead *
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)
190 {
191 unsigned long int hash = __nis_hash (key, len) % table->head->module;
192diff -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
195@@ -57,11 +57,6 @@
196 #endif
197
198
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);
203-
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"
216 };
217
218 /* The control data structures for the services. */
219@@ -189,6 +187,27 @@ struct database_dyn dbs[lastdb] =
220 .wr_fd = -1,
221 .ro_fd = -1,
222 .mmap_used = false
223+ },
224+ [netgrdb] = {
225+ .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
226+ .prune_lock = PTHREAD_MUTEX_INITIALIZER,
227+ .prune_run_lock = PTHREAD_MUTEX_INITIALIZER,
228+ .enabled = 0,
229+ .check_file = 1,
230+ .persistent = 0,
231+ .propagate = 0, /* Not used. */
232+ .shared = 0,
233+ .max_db_size = DEFAULT_MAX_DB_SIZE,
234+ .suggested_module = DEFAULT_SUGGESTED_MODULE,
235+ .reset_res = 0,
236+ .filename = "/etc/netgroup",
237+ .db_filename = _PATH_NSCD_NETGROUP_DB,
238+ .disabled_iov = &netgroup_iov_disabled,
239+ .postimeout = 28800,
240+ .negtimeout = 20,
241+ .wr_fd = -1,
242+ .ro_fd = -1,
243+ .mmap_used = false
244 }
245 };
246
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] }
256 };
257
258
259@@ -366,7 +388,8 @@ check_use (const char *data, nscd_ssize_
260 static int
261 verify_persistent_db (void *mem, struct database_pers_head *readhead, int dbnr)
262 {
263- assert (dbnr == pwddb || dbnr == grpdb || dbnr == hstdb || dbnr == servdb);
264+ assert (dbnr == pwddb || dbnr == grpdb || dbnr == hstdb || dbnr == servdb
265+ || dbnr == netgrdb);
266
267 time_t now = time (NULL);
268
269@@ -1241,6 +1264,14 @@ request from '%s' [%ld] not handled due
270 addservbyport (db, fd, req, key, uid);
271 break;
272
273+ case GETNETGRENT:
274+ addgetnetgrent (db, fd, req, key, uid);
275+ break;
276+
277+ case INNETGR:
278+ addinnetgr (db, fd, req, key, uid);
279+ break;
280+
281 case GETSTAT:
282 case SHUTDOWN:
283 case INVALIDATE:
284@@ -1287,6 +1318,7 @@ request from '%s' [%ld] not handled due
285 case GETFDGR:
286 case GETFDHST:
287 case GETFDSERV:
288+ case GETFDNETGR:
289 #ifdef SCM_RIGHTS
290 send_ro_fd (reqinfo[req->type].db, key, fd);
291 #endif
292diff -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
295@@ -0,0 +1,667 @@
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.
300+
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.
305+
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.
310+
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. */
314+
315+#include <alloca.h>
316+#include <assert.h>
317+#include <errno.h>
318+#include <libintl.h>
319+#include <stdbool.h>
320+#include <unistd.h>
321+#include <sys/mman.h>
322+
323+#include "../inet/netgroup.h"
324+#include "nscd.h"
325+#include "dbg_log.h"
326+#ifdef HAVE_SENDFILE
327+# include <kernel-features.h>
328+#endif
329+
330+
331+/* This is the standard reply in case the service is disabled. */
332+static const netgroup_response_header disabled =
333+{
334+ .version = NSCD_VERSION,
335+ .found = -1,
336+ .nresults = 0,
337+ .result_len = 0
338+};
339+
340+/* This is the struct describing how to write this record. */
341+const struct iovec netgroup_iov_disabled =
342+{
343+ .iov_base = (void *) &disabled,
344+ .iov_len = sizeof (disabled)
345+};
346+
347+
348+/* This is the standard reply in case we haven't found the dataset. */
349+static const netgroup_response_header notfound =
350+{
351+ .version = NSCD_VERSION,
352+ .found = 0,
353+ .nresults = 0,
354+ .result_len = 0
355+};
356+
357+
358+struct dataset
359+{
360+ struct datahead head;
361+ netgroup_response_header resp;
362+ char strdata[0];
363+};
364+
365+
366+static time_t
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)
370+{
371+ if (__builtin_expect (debug_level > 0, 0))
372+ {
373+ if (he == NULL)
374+ dbg_log (_("Haven't found \"%s\" in netgroup cache!"), key);
375+ else
376+ dbg_log (_("Reloading \"%s\" in netgroup cache!"), key);
377+ }
378+
379+ static service_user *netgroup_database;
380+ time_t timeout;
381+ struct dataset *dataset;
382+ bool cacheable = false;
383+ ssize_t total;
384+
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;
393+ union
394+ {
395+ struct name_list elem;
396+ char mem[sizeof (struct name_list) + group_len];
397+ } first_needed;
398+
399+ if (netgroup_database == NULL
400+ && __nss_database_lookup ("netgroup", NULL, NULL, &netgroup_database))
401+ {
402+ /* No such service. */
403+ total = sizeof (notfound);
404+ timeout = time (NULL) + db->negtimeout;
405+
406+ if (fd != -1)
407+ TEMP_FAILURE_RETRY (send (fd, &notfound, total, MSG_NOSIGNAL));
408+
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)
412+ {
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;
418+
419+ /* Compute the timeout time. */
420+ timeout = dataset->head.timeout = time (NULL) + db->negtimeout;
421+ dataset->head.ttl = db->negtimeout;
422+
423+ /* This is the reply. */
424+ memcpy (&dataset->resp, &notfound, total);
425+
426+ /* Copy the key data. */
427+ memcpy (dataset->strdata, key, req->key_len);
428+
429+ cacheable = true;
430+ }
431+
432+ goto writeout;
433+ }
434+
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;
440+
441+ while (data.needed_groups != NULL)
442+ {
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;
447+ else
448+ data.needed_groups->next = this_group->next;
449+ this_group->next = data.known_groups;
450+ data.known_groups = this_group;
451+
452+ union
453+ {
454+ enum nss_status (*f) (const char *, struct __netgrent *);
455+ void *ptr;
456+ } setfct;
457+
458+ service_user *nip = netgroup_database;
459+ int no_more = __nss_lookup (&nip, "setnetgrent", NULL, &setfct.ptr);
460+ while (!no_more)
461+ {
462+ enum nss_status status
463+ = DL_CALL_FCT (*setfct.f, (data.known_groups->name, &data));
464+
465+ if (status == NSS_STATUS_SUCCESS)
466+ {
467+ union
468+ {
469+ enum nss_status (*f) (struct __netgrent *, char *, size_t,
470+ int *);
471+ void *ptr;
472+ } getfct;
473+ getfct.ptr = __nss_lookup_function (nip, "getnetgrent_r");
474+ if (getfct.f != NULL)
475+ while (1)
476+ {
477+ int e;
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. */
483+ break;
484+ if (status == NSS_STATUS_SUCCESS)
485+ {
486+ if (data.type == triple_val)
487+ {
488+ const char *nhost = data.val.triple.host;
489+ const char *nuser = data.val.triple.user;
490+ const char *ndomain = data.val.triple.domain;
491+
492+ if (data.val.triple.host > data.val.triple.user
493+ || data.val.triple.user > data.val.triple.domain)
494+ {
495+ const char *last = MAX (nhost,
496+ MAX (nuser, ndomain));
497+ size_t bufused = (last + strlen (last) + 1
498+ - buffer);
499+
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;
505+
506+ if (buflen - req->key_len - bufused < needed)
507+ {
508+ size_t newsize = MAX (2 * buflen,
509+ buflen + 2 * needed);
510+ if (use_malloc || newsize > 1024 * 1024)
511+ {
512+ buflen = newsize;
513+ char *newbuf = xrealloc (use_malloc
514+ ? buffer
515+ : NULL,
516+ buflen);
517+
518+ buffer = newbuf;
519+ use_malloc = true;
520+ }
521+ else
522+ extend_alloca (buffer, buflen, newsize);
523+ }
524+
525+ nhost = memcpy (buffer + bufused,
526+ nhost, hostlen);
527+ nuser = memcpy ((char *) nhost + hostlen,
528+ nuser, userlen);
529+ ndomain = memcpy ((char *) nuser + userlen,
530+ ndomain, domainlen);
531+ }
532+
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;
538+ ++nentries;
539+ }
540+ else
541+ {
542+ /* Check that the group has not been
543+ requested before. */
544+ struct name_list *runp = data.needed_groups;
545+ if (runp != NULL)
546+ while (1)
547+ {
548+ if (strcmp (runp->name, data.val.group) == 0)
549+ break;
550+
551+ runp = runp->next;
552+ if (runp == data.needed_groups)
553+ {
554+ runp = NULL;
555+ break;
556+ }
557+ }
558+
559+ if (runp == NULL)
560+ {
561+ runp = data.known_groups;
562+ while (runp != NULL)
563+ if (strcmp (runp->name, data.val.group) == 0)
564+ break;
565+ else
566+ runp = runp->next;
567+ }
568+
569+ if (runp == NULL)
570+ {
571+ /* A new group is requested. */
572+ size_t namelen = strlen (data.val.group) + 1;
573+ struct name_list *newg = alloca (sizeof (*newg)
574+ + namelen);
575+ memcpy (newg->name, data.val.group, namelen);
576+ if (data.needed_groups == NULL)
577+ data.needed_groups = newg->next = newg;
578+ else
579+ {
580+ newg->next = data.needed_groups->next;
581+ data.needed_groups->next = newg;
582+ data.needed_groups = newg;
583+ }
584+ }
585+ }
586+ }
587+ else if (status == NSS_STATUS_UNAVAIL && e == ERANGE)
588+ {
589+ size_t newsize = 2 * buflen;
590+ if (use_malloc || newsize > 1024 * 1024)
591+ {
592+ buflen = newsize;
593+ char *newbuf = xrealloc (use_malloc
594+ ? buffer : NULL, buflen);
595+
596+ buffer = newbuf;
597+ use_malloc = true;
598+ }
599+ else
600+ extend_alloca (buffer, buflen, newsize);
601+ }
602+ }
603+
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));
608+
609+ break;
610+ }
611+
612+ no_more = __nss_next2 (&nip, "setnetgrent", NULL, &setfct.ptr,
613+ status, 0);
614+ }
615+ }
616+
617+ total = buffilled;
618+
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;
628+
629+ dataset->resp.version = NSCD_VERSION;
630+ dataset->resp.found = 1;
631+ dataset->resp.nresults = nentries;
632+ dataset->resp.result_len = buffilled - sizeof (*dataset);
633+
634+ assert (buflen - buffilled >= req->key_len);
635+ key_copy = memcpy (buffer + buffilled, key, req->key_len);
636+ buffilled += req->key_len;
637+
638+ /* Now we can determine whether on refill we have to create a new
639+ record or not. */
640+ if (he != NULL)
641+ {
642+ assert (fd == -1);
643+
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)
648+ {
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;
654+ ++dh->nreloads;
655+ dataset = (struct dataset *) dh;
656+
657+ goto out;
658+ }
659+ }
660+
661+ {
662+ struct dataset *newp
663+ = (struct dataset *) mempool_alloc (db, total + req->key_len, 1);
664+ if (__builtin_expect (newp != NULL, 1))
665+ {
666+ /* Adjust pointer into the memory block. */
667+ key_copy = (char *) newp + (key_copy - buffer);
668+
669+ dataset = memcpy (newp, dataset, total + req->key_len);
670+ cacheable = true;
671+
672+ if (he != NULL)
673+ /* Mark the old record as obsolete. */
674+ dh->usable = false;
675+ }
676+ }
677+
678+ if (he == NULL && fd != -1)
679+ {
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. */
683+ writeout:
684+#ifdef HAVE_SENDFILE
685+ if (__builtin_expect (db->mmap_used, 1) && cacheable)
686+ {
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
694+ ssize_t written =
695+# endif
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)
700+ goto use_write;
701+# endif
702+ }
703+ else
704+#endif
705+ {
706+#if defined HAVE_SENDFILE && !defined __ASSUME_SENDFILE
707+ use_write:
708+#endif
709+ writeall (fd, &dataset->resp, dataset->head.recsize);
710+ }
711+ }
712+
713+ if (cacheable)
714+ {
715+ /* If necessary, we also propagate the data to disk. */
716+ if (db->persistent)
717+ {
718+ // XXX async OK?
719+ uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
720+ msync ((void *) pval,
721+ ((uintptr_t) dataset & pagesize_m1) + total + req->key_len,
722+ MS_ASYNC);
723+ }
724+
725+ (void) cache_add (req->type, key_copy, req->key_len, &dataset->head,
726+ true, db, uid, he == NULL);
727+
728+ pthread_rwlock_unlock (&db->lock);
729+
730+ /* Mark the old entry as obsolete. */
731+ if (dh != NULL)
732+ dh->usable = false;
733+ }
734+
735+ out:
736+ if (use_malloc)
737+ free (buffer);
738+
739+ *resultp = dataset;
740+
741+ return timeout;
742+}
743+
744+
745+static time_t
746+addinnetgrX (struct database_dyn *db, int fd, request_header *req,
747+ char *key, uid_t uid, struct hashentry *he,
748+ struct datahead *dh)
749+{
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;
754+ if (host != NULL)
755+ key = (char *) rawmemchr (key, '\0') + 1;
756+ const char *user = *key++ ? key : NULL;
757+ if (user != NULL)
758+ key = (char *) rawmemchr (key, '\0') + 1;
759+ const char *domain = *key++ ? key : NULL;
760+
761+ if (__builtin_expect (debug_level > 0, 0))
762+ {
763+ if (he == NULL)
764+ dbg_log (_("Haven't found \"%s (%s,%s,%s)\" in netgroup cache!"),
765+ group, host ?: "", user ?: "", domain ?: "");
766+ else
767+ dbg_log (_("Reloading \"%s (%s,%s,%s)\" in netgroup cache!"),
768+ group, host ?: "", user ?: "", domain ?: "");
769+ }
770+
771+ struct dataset *result = (struct dataset *) cache_search (GETNETGRENT,
772+ group, group_len,
773+ db, uid);
774+ time_t timeout;
775+ if (result != NULL)
776+ timeout = result->head.timeout;
777+ else
778+ {
779+ request_header req_get =
780+ {
781+ .type = GETNETGRENT,
782+ .key_len = group_len
783+ };
784+ timeout = addgetnetgrentX (db, -1, &req_get, group, uid, NULL, NULL,
785+ &result);
786+ }
787+
788+ struct indataset
789+ {
790+ struct datahead head;
791+ innetgroup_response_header resp;
792+ } *dataset
793+ = (struct indataset *) mempool_alloc (db,
794+ sizeof (*dataset) + req->key_len,
795+ 1);
796+ struct indataset dataset_mem;
797+ bool cacheable = true;
798+ if (__builtin_expect (dataset == NULL, 0))
799+ {
800+ cacheable = false;
801+ dataset = &dataset_mem;
802+ }
803+
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;
811+
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;
816+
817+ char *key_copy = memcpy ((char *) (dataset + 1), group, req->key_len);
818+
819+ if (dataset->resp.found)
820+ {
821+ const char *triplets = (const char *) (&result->resp + 1);
822+
823+ for (nscd_ssize_t i = result->resp.nresults; i > 0; --i)
824+ {
825+ bool success = true;
826+
827+ if (host != NULL)
828+ success = strcmp (host, triplets) == 0;
829+ triplets = (const char *) rawmemchr (triplets, '\0') + 1;
830+
831+ if (success && user != NULL)
832+ success = strcmp (user, triplets) == 0;
833+ triplets = (const char *) rawmemchr (triplets, '\0') + 1;
834+
835+ if (success && (domain == NULL || strcmp (domain, triplets) == 0))
836+ {
837+ dataset->resp.result = 1;
838+ break;
839+ }
840+ triplets = (const char *) rawmemchr (triplets, '\0') + 1;
841+ }
842+ }
843+
844+ if (he != NULL && dh->data[0].innetgroupdata.result == dataset->resp.result)
845+ {
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;
851+ ++dh->nreloads;
852+ return timeout;
853+ }
854+
855+ if (he == NULL)
856+ {
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. */
860+ assert (fd != -1);
861+
862+#ifdef HAVE_SENDFILE
863+ if (__builtin_expect (db->mmap_used, 1) && cacheable)
864+ {
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
872+ ssize_t written =
873+# endif
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)
879+ goto use_write;
880+# endif
881+ }
882+ else
883+# ifndef __ASSUME_SENDFILE
884+ use_write:
885+# endif
886+#endif
887+ writeall (fd, &dataset->resp, sizeof (innetgroup_response_header));
888+ }
889+
890+ if (cacheable)
891+ {
892+ /* If necessary, we also propagate the data to disk. */
893+ if (db->persistent)
894+ {
895+ // XXX async OK?
896+ uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
897+ msync ((void *) pval,
898+ ((uintptr_t) dataset & pagesize_m1) + sizeof (*dataset)
899+ + req->key_len,
900+ MS_ASYNC);
901+ }
902+
903+ (void) cache_add (req->type, key_copy, req->key_len, &dataset->head,
904+ true, db, uid, he == NULL);
905+
906+ pthread_rwlock_unlock (&db->lock);
907+
908+ /* Mark the old entry as obsolete. */
909+ if (dh != NULL)
910+ dh->usable = false;
911+ }
912+
913+ return timeout;
914+}
915+
916+
917+void
918+addgetnetgrent (struct database_dyn *db, int fd, request_header *req,
919+ void *key, uid_t uid)
920+{
921+ struct dataset *ignore;
922+
923+ addgetnetgrentX (db, fd, req, key, uid, NULL, NULL, &ignore);
924+}
925+
926+
927+time_t
928+readdgetnetgrent (struct database_dyn *db, struct hashentry *he,
929+ struct datahead *dh)
930+{
931+ request_header req =
932+ {
933+ .type = GETNETGRENT,
934+ .key_len = he->len
935+ };
936+ struct dataset *ignore;
937+
938+ return addgetnetgrentX (db, -1, &req, db->data + he->key, he->owner, he, dh,
939+ &ignore);
940+}
941+
942+
943+void
944+addinnetgr (struct database_dyn *db, int fd, request_header *req,
945+ void *key, uid_t uid)
946+{
947+ addinnetgrX (db, fd, req, key, uid, NULL, NULL);
948+}
949+
950+
951+time_t
952+readdinnetgr (struct database_dyn *db, struct hashentry *he,
953+ struct datahead *dh)
954+{
955+ request_header req =
956+ {
957+ .type = INNETGR,
958+ .key_len = he->len
959+ };
960+
961+ return addinnetgrX (db, -1, &req, db->data + he->key, he->owner, he, dh);
962+}
963diff -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
967 GETSERVBYNAME,
968 GETSERVBYPORT,
969 GETFDSERV,
970+ GETNETGRENT,
971+ INNETGR,
972+ GETFDNETGR,
973 LASTREQ
974 } request_type;
975
976@@ -171,6 +174,24 @@ typedef struct
977 } serv_response_header;
978
979
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. */
982+typedef struct
983+{
984+ int32_t version;
985+ int32_t found;
986+ nscd_ssize_t nresults;
987+ nscd_ssize_t result_len;
988+} netgroup_response_header;
989+
990+typedef struct
991+{
992+ int32_t version;
993+ int32_t found;
994+ int32_t result;
995+} innetgroup_response_header;
996+
997+
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;
1008 nscd_time_t align2;
1009 } data[0];
1010diff -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
1013@@ -77,3 +77,12 @@
1014 persistent services yes
1015 shared services yes
1016 max-db-size services 33554432
1017+
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
1026diff -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
1030 grpdb,
1031 hstdb,
1032 servdb,
1033+ netgrdb,
1034 lastdb
1035 } dbtype;
1036
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"
1042
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;
1050
1051
1052 /* Initial number of threads to run. */
1053@@ -185,6 +188,11 @@ extern gid_t old_gid;
1054
1055 /* Prototypes for global functions. */
1056
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);
1061+
1062 /* nscd.c */
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__));
1067
1068 /* cache.c */
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,
1073 uid_t owner);
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);
1079
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);
1089+
1090 /* mem.c */
1091 extern void *mempool_alloc (struct database_dyn *db, size_t len,
1092 int data_alloc);
1093diff -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] =
1097 [pwddb] = "passwd",
1098 [grpdb] = "group",
1099 [hstdb] = "hosts",
1100- [servdb] = "services"
1101+ [servdb] = "services",
1102+ [netgrdb] = "netgroup"
1103 };
1104
1105
1106diff -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
1109@@ -0,0 +1,290 @@
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.
1113+
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.
1118+
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.
1123+
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. */
1128+
1129+#include <alloca.h>
1130+#include <errno.h>
1131+#include <stdlib.h>
1132+#include <string.h>
1133+#include <not-cancel.h>
1134+
1135+#include "nscd-client.h"
1136+#include "nscd_proto.h"
1137+
1138+int __nss_not_use_nscd_netgroup;
1139+
1140+
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
1144+ handling. */
1145+libc_freeres_fn (pw_map_free)
1146+{
1147+ if (map_handle.mapped != NO_MAPPING)
1148+ {
1149+ void *p = map_handle.mapped;
1150+ map_handle.mapped = NO_MAPPING;
1151+ free (p);
1152+ }
1153+}
1154+
1155+
1156+int
1157+__nscd_setnetgrent (const char *group, struct __netgrent *datap)
1158+{
1159+ int gc_cycle;
1160+ int nretries = 0;
1161+ size_t group_len = strlen (group);
1162+
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);
1167+
1168+ retry:;
1169+ char *respdata = NULL;
1170+ int retval = -1;
1171+ netgroup_response_header netgroup_resp;
1172+
1173+ if (mapped != NO_MAPPING)
1174+ {
1175+ struct datahead *found = __nscd_cache_search (GETNETGRENT, group,
1176+ group_len, mapped,
1177+ sizeof netgroup_resp);
1178+ if (found != NULL)
1179+ {
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)
1185+ {
1186+ retval = -2;
1187+ goto out;
1188+ }
1189+ }
1190+ }
1191+
1192+ int sock = -1;
1193+ if (respdata == NULL)
1194+ {
1195+ sock = __nscd_open_socket (group, group_len, GETNETGRENT,
1196+ &netgroup_resp, sizeof (netgroup_resp));
1197+ if (sock == -1)
1198+ {
1199+ /* nscd not running or wrong version. */
1200+ __nss_not_use_nscd_netgroup = 1;
1201+ goto out;
1202+ }
1203+ }
1204+
1205+ if (netgroup_resp.found == 1)
1206+ {
1207+ size_t datalen = netgroup_resp.result_len;
1208+
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)
1212+ {
1213+ /* The data will come via the socket. */
1214+ respdata = malloc (datalen);
1215+ if (respdata == NULL)
1216+ goto out_close;
1217+
1218+ if ((size_t) __readall (sock, respdata, datalen) != datalen)
1219+ {
1220+ free (respdata);
1221+ goto out_close;
1222+ }
1223+ }
1224+
1225+ datap->data = respdata;
1226+ datap->data_size = datalen;
1227+ datap->cursor = respdata;
1228+ datap->first = 1;
1229+ datap->nip = (service_user *) -1l;
1230+ datap->known_groups = NULL;
1231+ datap->needed_groups = NULL;
1232+
1233+ retval = 1;
1234+ }
1235+ else
1236+ {
1237+ if (__builtin_expect (netgroup_resp.found == -1, 0))
1238+ {
1239+ /* The daemon does not cache this database. */
1240+ __nss_not_use_nscd_netgroup = 1;
1241+ goto out_close;
1242+ }
1243+
1244+ /* Set errno to 0 to indicate no error, just no found record. */
1245+ __set_errno (0);
1246+ /* Even though we have not found anything, the result is zero. */
1247+ retval = 0;
1248+ }
1249+
1250+ out_close:
1251+ if (sock != -1)
1252+ close_not_cancel_no_status (sock);
1253+ out:
1254+ if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
1255+ {
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)
1260+ {
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;
1265+ }
1266+
1267+ if (retval != -1)
1268+ goto retry;
1269+ }
1270+
1271+ return retval;
1272+}
1273+
1274+
1275+int
1276+__nscd_innetgr (const char *netgroup, const char *host, const char *user,
1277+ const char *domain)
1278+{
1279+ size_t key_len = (strlen (netgroup) + strlen (host ?: "")
1280+ + strlen (user ?: "") + strlen (domain ?: "") + 7);
1281+ char *key;
1282+ bool use_alloca = __libc_use_alloca (key_len);
1283+ if (use_alloca)
1284+ key = alloca (key_len);
1285+ else
1286+ {
1287+ key = malloc (key_len);
1288+ if (key == NULL)
1289+ return -1;
1290+ }
1291+ char *wp = stpcpy (key, netgroup) + 1;
1292+ if (host != NULL)
1293+ {
1294+ *wp++ = '\1';
1295+ wp = stpcpy (wp, host) + 1;
1296+ }
1297+ else
1298+ *wp++ = '\0';
1299+ if (user != NULL)
1300+ {
1301+ *wp++ = '\1';
1302+ wp = stpcpy (wp, user) + 1;
1303+ }
1304+ else
1305+ *wp++ = '\0';
1306+ if (domain != NULL)
1307+ {
1308+ *wp++ = '\1';
1309+ wp = stpcpy (wp, domain) + 1;
1310+ }
1311+ else
1312+ *wp++ = '\0';
1313+ key_len = wp - key;
1314+
1315+ /* If the mapping is available, try to search there instead of
1316+ communicating with the nscd. */
1317+ int gc_cycle;
1318+ int nretries = 0;
1319+ struct mapped_database *mapped;
1320+ mapped = __nscd_get_map_ref (GETFDNETGR, "netgroup", &map_handle, &gc_cycle);
1321+
1322+ retry:;
1323+ int retval = -1;
1324+ innetgroup_response_header innetgroup_resp;
1325+ int sock = -1;
1326+
1327+ if (mapped != NO_MAPPING)
1328+ {
1329+ struct datahead *found = __nscd_cache_search (INNETGR, key,
1330+ key_len, mapped,
1331+ sizeof innetgroup_resp);
1332+ if (found != NULL)
1333+ {
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)
1338+ {
1339+ retval = -2;
1340+ goto out;
1341+ }
1342+
1343+ goto found_entry;
1344+ }
1345+ }
1346+
1347+ sock = __nscd_open_socket (key, key_len, INNETGR,
1348+ &innetgroup_resp, sizeof (innetgroup_resp));
1349+ if (sock == -1)
1350+ {
1351+ /* nscd not running or wrong version. */
1352+ __nss_not_use_nscd_netgroup = 1;
1353+ goto out;
1354+ }
1355+
1356+ found_entry:
1357+ if (innetgroup_resp.found == 1)
1358+ retval = innetgroup_resp.result;
1359+ else
1360+ {
1361+ if (__builtin_expect (innetgroup_resp.found == -1, 0))
1362+ {
1363+ /* The daemon does not cache this database. */
1364+ __nss_not_use_nscd_netgroup = 1;
1365+ goto out_close;
1366+ }
1367+
1368+ /* Set errno to 0 to indicate no error, just no found record. */
1369+ __set_errno (0);
1370+ /* Even though we have not found anything, the result is zero. */
1371+ retval = 0;
1372+ }
1373+
1374+ out_close:
1375+ if (sock != -1)
1376+ close_not_cancel_no_status (sock);
1377+ out:
1378+ if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
1379+ {
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)
1384+ {
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;
1389+ }
1390+
1391+ if (retval != -1)
1392+ goto retry;
1393+ }
1394+
1395+ if (! use_alloca)
1396+ free (key);
1397+
1398+ return retval;
1399+}
1400diff -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
1403@@ -1,4 +1,4 @@
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.
1408
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;
1414
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);
1424+
1425
1426 #endif /* _NSCD_PROTO_H */
1427diff -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
1430@@ -1,5 +1,5 @@
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.
1436
1437@@ -46,7 +46,7 @@
1438 int selinux_enabled;
1439
1440 /* Define mappings of access vector permissions to request types. */
1441-static const int perms[LASTREQ] =
1442+static const access_vector_t perms[LASTREQ] =
1443 {
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,
1449 #endif
1450+#ifdef NSCD__GETNETGRP
1451+ [GETNETGRENT] = NSCD__GETNETGRP,
1452+ [INNETGR] = NSCD__GETNETGRP,
1453+ [GETFDNETGR] = NSCD__SHMEMNETGRP,
1454+#endif
1455 };
1456
1457 /* Store an entry ref to speed AVC decisions. */
1458diff -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
1461@@ -1,4 +1,5 @@
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.
1466
1467 # The GNU C Library is free software; you can redistribute it and/or
1468@@ -39,7 +40,7 @@ databases = proto service hosts network
1469 others := getent
1470 install-bin := getent
1471
1472-tests = test-netdb
1473+tests = test-netdb tst-nss-test1
1474 xtests = bug-erange
1475
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
1481+
1482+
1483+distribute += nss_test1.c
1484+
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
1488+ $(build-module)
1489+$(objpfx)/libnss_test1.so$(libnss_test1.so-version): $(objpfx)/libnss_test1.so
1490+ $(make-link)
1491+$(objpfx)tst-nss-test1.out: $(objpfx)/libnss_test1.so$(libnss_test1.so-version)
1492diff -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;
1497
1498 __nss_passwd_lookup2; __nss_group_lookup2; __nss_hosts_lookup2;
1499- __nss_services_lookup2; __nss_next2;
1500+ __nss_services_lookup2; __nss_next2; __nss_lookup;
1501 }
1502 }
1503
1504diff -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
1507@@ -1,4 +1,4 @@
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.
1512
1513@@ -87,6 +87,8 @@
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
1519 #endif
1520
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;
1525
1526- if (!NOT_USENSCD_NAME)
1527+ if (!NOT_USENSCD_NAME
1528+ && !__nss_database_custom[CONCAT2 (NSS_DBSIDX_, DATABASE_NAME)])
1529 {
1530 nscd_status = NSCD_NAME (ADD_VARIABLES, resbuf, buffer, buflen, result
1531 H_ERRNO_VAR);
1532diff -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[])
1537 {
1538 int result = 0;
1539- int i;
1540
1541 if (number == 0)
1542 {
1543@@ -474,18 +473,28 @@ netgroup_keys (int number, char *key[])
1544 return 3;
1545 }
1546
1547- for (i = 0; i < number; ++i)
1548+ if (number == 4)
1549 {
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];
1554+
1555+ printf ("%-21s (%s,%s,%s) = %d\n",
1556+ key[0], host ?: "", user ?: "", domain ?: "",
1557+ innetgr (key[0], host, user, domain));
1558+ }
1559+ else if (number == 1)
1560+ {
1561+ if (!setnetgrent (key[0]))
1562 result = 2;
1563 else
1564 {
1565 char *p[3];
1566
1567- printf ("%-21s", key[i]);
1568+ printf ("%-21s", key[0]);
1569
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');
1574 }
1575 }
1576diff -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
1579@@ -1,5 +1,5 @@
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.
1584
1585 The GNU C Library is free software; you can redistribute it and/or
1586@@ -29,7 +29,7 @@
1587 DATABASE -- string of the database file's name ("hosts", "passwd").
1588
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'.
1592
1593 NEED_H_ERRNO - defined iff an arg `int *herrnop' is used.
1594
1595@@ -229,7 +229,7 @@ strtou32 (const char *nptr, char **endpt
1596 char **list = parse_list (&line, buf_start, buf_end, '\0', errnop); \
1597 if (list) \
1598 result->TRAILING_LIST_MEMBER = list; \
1599- else \
1600+ else \
1601 return -1; /* -1 indicates we ran out of space. */ \
1602 }
1603
1604diff -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
1607@@ -0,0 +1,154 @@
1608+#include <errno.h>
1609+#include <nss.h>
1610+#include <pthread.h>
1611+#include <string.h>
1612+
1613+
1614+#define COPY_IF_ROOM(s) \
1615+ ({ size_t len_ = strlen (s) + 1; \
1616+ char *start_ = cp; \
1617+ buflen - (cp - buffer) < len_ \
1618+ ? NULL \
1619+ : (cp = mempcpy (cp, s, len_), start_); })
1620+
1621+
1622+/* Password handling. */
1623+#include <pwd.h>
1624+
1625+static struct passwd pwd_data[] =
1626+ {
1627+#define PWD(u) \
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 *) "*" }
1631+ PWD (100),
1632+ PWD (30),
1633+ PWD (200),
1634+ PWD (60),
1635+ PWD (20000)
1636+ };
1637+#define npwd_data (sizeof (pwd_data) / sizeof (pwd_data[0]))
1638+
1639+static size_t pwd_iter;
1640+#define CURPWD pwd_data[pwd_iter]
1641+
1642+static pthread_mutex_t pwd_lock = PTHREAD_MUTEX_INITIALIZER;
1643+
1644+
1645+enum nss_status
1646+_nss_test1_setpwent (int stayopen)
1647+{
1648+ pwd_iter = 0;
1649+ return NSS_STATUS_SUCCESS;
1650+}
1651+
1652+
1653+enum nss_status
1654+_nss_test1_endpwent (void)
1655+{
1656+ return NSS_STATUS_SUCCESS;
1657+}
1658+
1659+
1660+enum nss_status
1661+_nss_test1_getpwent_r (struct passwd *result, char *buffer, size_t buflen,
1662+ int *errnop)
1663+{
1664+ char *cp = buffer;
1665+ int res = NSS_STATUS_SUCCESS;
1666+
1667+ pthread_mutex_lock (&pwd_lock);
1668+
1669+ if (pwd_iter >= npwd_data)
1670+ res = NSS_STATUS_NOTFOUND;
1671+ else
1672+ {
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);
1680+
1681+ if (result->pw_name == NULL || result->pw_passwd == NULL
1682+ || result->pw_gecos == NULL || result->pw_dir == NULL
1683+ || result->pw_shell == NULL)
1684+ {
1685+ *errnop = ERANGE;
1686+ res = NSS_STATUS_TRYAGAIN;
1687+ }
1688+
1689+ ++pwd_iter;
1690+ }
1691+
1692+ pthread_mutex_unlock (&pwd_lock);
1693+
1694+ return res;
1695+}
1696+
1697+
1698+enum nss_status
1699+_nss_test1_getpwuid_r (uid_t uid, struct passwd *result, char *buffer,
1700+ size_t buflen, int *errnop)
1701+{
1702+ for (size_t idx = 0; idx < npwd_data; ++idx)
1703+ if (pwd_data[idx].pw_uid == uid)
1704+ {
1705+ char *cp = buffer;
1706+ int res = NSS_STATUS_SUCCESS;
1707+
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);
1715+
1716+ if (result->pw_name == NULL || result->pw_passwd == NULL
1717+ || result->pw_gecos == NULL || result->pw_dir == NULL
1718+ || result->pw_shell == NULL)
1719+ {
1720+ *errnop = ERANGE;
1721+ res = NSS_STATUS_TRYAGAIN;
1722+ }
1723+
1724+ return res;
1725+ }
1726+
1727+ return NSS_STATUS_NOTFOUND;
1728+}
1729+
1730+
1731+enum nss_status
1732+_nss_test1_getpwnam_r (const char *name, struct passwd *result, char *buffer,
1733+ size_t buflen, int *errnop)
1734+{
1735+ for (size_t idx = 0; idx < npwd_data; ++idx)
1736+ if (strcmp (pwd_data[idx].pw_name, name) == 0)
1737+ {
1738+ char *cp = buffer;
1739+ int res = NSS_STATUS_SUCCESS;
1740+
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);
1748+
1749+ if (result->pw_name == NULL || result->pw_passwd == NULL
1750+ || result->pw_gecos == NULL || result->pw_dir == NULL
1751+ || result->pw_shell == NULL)
1752+ {
1753+ *errnop = ERANGE;
1754+ res = NSS_STATUS_TRYAGAIN;
1755+ }
1756+
1757+ return res;
1758+ }
1759+
1760+ return NSS_STATUS_NOTFOUND;
1761+}
1762diff -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
1765@@ -1,4 +1,4 @@
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.
1770
1771@@ -71,6 +71,9 @@ static const struct
1772 };
1773 #define ndatabases (sizeof (databases) / sizeof (databases[0]))
1774
1775+/* Flags whether custom rules for database is set. */
1776+bool __nss_database_custom[NSS_DBSIDX_max];
1777+
1778
1779 __libc_lock_define_initialized (static, lock)
1780
1781@@ -165,6 +168,7 @@ __nss_lookup (service_user **ni, const c
1782
1783 return *fctp != NULL ? 0 : (*ni)->next == NULL ? 1 : -1;
1784 }
1785+libc_hidden_def (__nss_lookup)
1786
1787
1788 /* -1 == not found
1789@@ -265,6 +269,7 @@ __nss_configure_lookup (const char *dbna
1790
1791 /* Install new rules. */
1792 *databases[cnt].dbp = new_db;
1793+ __nss_database_custom[cnt] = true;
1794
1795 __libc_lock_unlock (lock);
1796
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;
1802 }
1803
1804
1805diff -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
1808@@ -1,4 +1,4 @@
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.
1813
1814@@ -28,6 +28,7 @@
1815 #include <resolv.h>
1816 #include <search.h>
1817 #include <dlfcn.h>
1818+#include <stdbool.h>
1819
1820 /* Actions performed after lookup finished. */
1821 typedef enum
1822@@ -96,6 +97,19 @@ typedef struct name_database
1823 } name_database;
1824
1825
1826+/* Indices into DATABASES in nsswitch.c and __NSS_DATABASE_CUSTOM. */
1827+enum
1828+ {
1829+#define DEFINE_DATABASE(arg) NSS_DBSIDX_##arg,
1830+#include "databases.def"
1831+#undef DEFINE_DATABASE
1832+ NSS_DBSIDX_max
1833+ };
1834+
1835+/* Flags whether custom rules for database is set. */
1836+extern bool __nss_database_custom[NSS_DBSIDX_max];
1837+
1838+
1839 /* Interface functions for NSS. */
1840
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)
1849
1850 /* Determine the next step in the lookup process according to the
1851 result STATUS of the call to the last function returned by
1852diff -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
1855@@ -0,0 +1,72 @@
1856+#include <nss.h>
1857+#include <pwd.h>
1858+#include <stdio.h>
1859+#include <stdlib.h>
1860+#include <string.h>
1861+
1862+
1863+static int
1864+do_test (void)
1865+{
1866+ int retval = 0;
1867+
1868+ __nss_configure_lookup ("passwd", "test1");
1869+
1870+ static const unsigned int pwdids[] = { 100, 30, 200, 60, 20000 };
1871+#define npwdids (sizeof (pwdids) / sizeof (pwdids[0]))
1872+ setpwent ();
1873+
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)
1878+ {
1879+ printf ("passwd entry %ju wrong (%s, %u)\n",
1880+ np - pwdids, p->pw_name, p->pw_uid);
1881+ retval = 1;
1882+ break;
1883+ }
1884+
1885+ endpwent ();
1886+
1887+ for (int i = npwdids - 1; i >= 0; --i)
1888+ {
1889+ char buf[30];
1890+ snprintf (buf, sizeof (buf), "name%u", pwdids[i]);
1891+
1892+ struct passwd *p = getpwnam (buf);
1893+ if (p == NULL || p->pw_uid != pwdids[i] || strcmp (buf, p->pw_name) != 0)
1894+ {
1895+ printf ("passwd entry \"%s\" wrong\n", buf);
1896+ retval = 1;
1897+ }
1898+
1899+ p = getpwuid (pwdids[i]);
1900+ if (p == NULL || p->pw_uid != pwdids[i] || strcmp (buf, p->pw_name) != 0)
1901+ {
1902+ printf ("passwd entry %u wrong\n", pwdids[i]);
1903+ retval = 1;
1904+ }
1905+
1906+ snprintf (buf, sizeof (buf), "name%u", pwdids[i] + 1);
1907+
1908+ p = getpwnam (buf);
1909+ if (p != NULL)
1910+ {
1911+ printf ("passwd entry \"%s\" wrong\n", buf);
1912+ retval = 1;
1913+ }
1914+
1915+ p = getpwuid (pwdids[i] + 1);
1916+ if (p != NULL)
1917+ {
1918+ printf ("passwd entry %u wrong\n", pwdids[i] + 1);
1919+ retval = 1;
1920+ }
1921+ }
1922+
1923+ return retval;
1924+}
1925+
1926+#define TEST_FUNCTION do_test ()
1927+#include "../test-skeleton.c"
1928diff -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
1934
1935+# Tests for NSS. They must have the same NSS_SHLIB_REVISION number as
1936+# the rest.
1937+.*-.*-.* libnss_test1=2
1938+
1939 # Version for libnsl with YP and NIS+ functions.
1940 alpha.*-.*-linux.* libnsl=1.1
1941 .*-.*-.* libnsl=1
1942diff -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;
1948
1949- if (!__nss_not_use_nscd_hosts)
1950+ if (!__nss_not_use_nscd_hosts
1951+ && !__nss_database_custom[NSS_DBSIDX_hosts])
1952 {
1953 /* Try to use nscd. */
1954 struct nscd_ai_result *air = NULL;