]>
Commit | Line | Data |
---|---|---|
bb330e25 AF |
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 | |
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) | |
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 | |
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 | ||
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 | |
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 | |
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 | |
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; | |
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 | |
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 | |
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 | |
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, ¬found, 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, ¬found, 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 | +} | |
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 | |
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]; | |
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 | |
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 | |
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 | |
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); | |
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] = | |
1097 | [pwddb] = "passwd", | |
1098 | [grpdb] = "group", | |
1099 | [hstdb] = "hosts", | |
1100 | - [servdb] = "services" | |
1101 | + [servdb] = "services", | |
1102 | + [netgrdb] = "netgroup" | |
1103 | }; | |
1104 | ||
1105 | ||
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 | |
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 | +} | |
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 | |
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 */ | |
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 | |
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. */ | |
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 | |
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) | |
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; | |
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 | ||
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 | |
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); | |
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[]) | |
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 | } | |
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 | |
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 | ||
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 | |
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 | +} | |
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 | |
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 | ||
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 | |
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 | |
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 | |
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" | |
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 | |
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 | |
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; | |
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; |