"Fossies" - the Fresh Open Source Software Archive 
Member "nss_ldap-265/ldap-netgrp.c" (6 Nov 2009, 24275 Bytes) of package /linux/privat/old/nss_ldap-265.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /* Copyright (C) 2002-2005 Luke Howard.
2 This file is part of the nss_ldap library.
3 Linux support contributed by Larry Lile, <llile@dreamworks.com>, 2002.
4 Solaris support contributed by Luke Howard, <lukeh@padl.com>, 2004.
5
6 The nss_ldap library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
10
11 The nss_ldap library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public
17 License along with the nss_ldap library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20
21 $Id: ldap-netgrp.c,v 2.48 2009/11/06 10:15:26 lukeh Exp $
22 */
23
24 static char rcsId[] =
25 "$Id: ldap-netgrp.c,v 2.48 2009/11/06 10:15:26 lukeh Exp $";
26
27 #include "config.h"
28
29 #include <stdio.h>
30 #include <stdarg.h>
31 #include <ctype.h>
32
33 #ifdef HAVE_PORT_BEFORE_H
34 #include <port_before.h>
35 #endif
36
37 #if defined(HAVE_THREAD_H) && !defined(_AIX)
38 #include <thread.h>
39 #elif defined(HAVE_PTHREAD_H)
40 #include <pthread.h>
41 #endif
42
43 #include <stdlib.h>
44 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <string.h>
47 #include <assert.h>
48
49 #ifdef HAVE_LBER_H
50 #include <lber.h>
51 #endif
52 #ifdef HAVE_LDAP_H
53 #include <ldap.h>
54 #endif
55
56 #ifndef HAVE_SNPRINTF
57 #include "snprintf.h"
58 #endif
59
60 #include "ldap-nss.h"
61 #include "ldap-netgrp.h"
62 #include "util.h"
63
64 #ifdef HAVE_PORT_AFTER_H
65 #include <port_after.h>
66 #endif
67
68 #ifdef HAVE_NSS_H
69 static ent_context_t *_ngbe = NULL;
70 #endif
71
72 #ifdef HAVE_IRS_H
73 enum nss_netgr_status {
74 NSS_NETGR_FOUND,
75 NSS_NETGR_NO,
76 NSS_NETGR_NOMEM
77 };
78
79 struct pvt; /* forward declaration for IRS backend type */
80 #endif /* HAVE_IRS_H */
81
82 #ifdef HAVE_NSSWITCH_H
83 static nss_backend_op_t netgroup_ops[];
84 #endif
85
86 #if defined(HAVE_NSSWITCH_H) || defined(HAVE_IRS_H)
87 struct ldap_innetgr_args
88 {
89 const char *lia_netgroup;
90 enum nss_netgr_status lia_netgr_status;
91 int lia_depth;
92 int lia_erange;
93 };
94
95 typedef struct ldap_innetgr_args ldap_innetgr_args_t;
96
97 static NSS_STATUS do_innetgr_nested (ldap_innetgr_args_t * li_args,
98 const char *nested);
99 #endif /* HAVE_NSSWITCH_H || HAVE_IRS_H */
100
101 /*
102 * I pulled the following macro (EXPAND), functions (strip_whitespace and
103 * _nss_netgroup_parseline) and structures (name_list and __netgrent) from
104 * glibc-2.2.x. _nss_netgroup_parseline became _nss_ldap_parse_netgr after
105 * some modification.
106 *
107 * The rest of the code is modeled on various other _nss_ldap functions.
108 */
109
110 #define EXPAND(needed) \
111 do \
112 { \
113 size_t old_cursor = result->cursor - result->data; \
114 \
115 result->data_size += 512 > 2 * needed ? 512 : 2 * needed; \
116 result->data = realloc (result->data, result->data_size); \
117 \
118 if (result->data == NULL) \
119 { \
120 stat = NSS_UNAVAIL; \
121 goto out; \
122 } \
123 \
124 result->cursor = result->data + old_cursor; \
125 } \
126 while (0)
127
128 /* A netgroup can consist of names of other netgroups. We have to
129 track which netgroups were read and which still have to be read. */
130
131
132 /* Dataset for iterating netgroups. */
133 struct __netgrent
134 {
135 enum
136 { triple_val, group_val }
137 type;
138
139 union
140 {
141 struct
142 {
143 const char *host;
144 const char *user;
145 const char *domain;
146 }
147 triple;
148
149 const char *group;
150 }
151 val;
152
153 /* Room for the data kept between the calls to the netgroup
154 functions. We must avoid global variables. */
155 char *data;
156 size_t data_size;
157 char *cursor;
158 int first;
159
160 struct name_list *known_groups;
161 struct name_list *needed_groups;
162 };
163
164 static char *
165 strip_whitespace (char *str)
166 {
167 char *cp = str;
168
169 /* Skip leading spaces. */
170 while (isspace ((int) *cp))
171 cp++;
172
173 str = cp;
174 while (*cp != '\0' && !isspace ((int) *cp))
175 cp++;
176
177 /* Null-terminate, stripping off any trailing spaces. */
178 *cp = '\0';
179
180 return *str == '\0' ? NULL : str;
181 }
182
183 static NSS_STATUS
184 _nss_ldap_parse_netgr (void *vresultp, char *buffer, size_t buflen)
185 {
186 struct __netgrent *result = (struct __netgrent *) vresultp;
187 char *cp = result->cursor;
188 char *user, *host, *domain;
189
190 /* The netgroup either doesn't exist or is empty. */
191 if (cp == NULL)
192 return NSS_RETURN;
193
194 /* First skip leading spaces. */
195 while (isspace ((int) *cp))
196 ++cp;
197
198 if (*cp != '(')
199 {
200 /* We have a list of other netgroups. */
201 char *name = cp;
202
203 while (*cp != '\0' && !isspace ((int) *cp))
204 ++cp;
205
206 if (name != cp)
207 {
208 /* It is another netgroup name. */
209 int last = *cp == '\0';
210
211 result->type = group_val;
212 result->val.group = name;
213 *cp = '\0';
214 if (!last)
215 ++cp;
216 result->cursor = cp;
217 result->first = 0;
218
219 return NSS_SUCCESS;
220 }
221 return result->first ? NSS_NOTFOUND : NSS_RETURN;
222 }
223
224 /* Match host name. */
225 host = ++cp;
226 while (*cp != ',')
227 if (*cp++ == '\0')
228 return result->first ? NSS_NOTFOUND : NSS_RETURN;
229
230 /* Match user name. */
231 user = ++cp;
232 while (*cp != ',')
233 if (*cp++ == '\0')
234 return result->first ? NSS_NOTFOUND : NSS_RETURN;
235
236 /* Match domain name. */
237 domain = ++cp;
238 while (*cp != ')')
239 if (*cp++ == '\0')
240 return result->first ? NSS_NOTFOUND : NSS_RETURN;
241 ++cp;
242
243 /* When we got here we have found an entry. Before we can copy it
244 to the private buffer we have to make sure it is big enough. */
245 if (cp - host > buflen)
246 return NSS_TRYAGAIN;
247
248 strncpy (buffer, host, cp - host);
249 result->type = triple_val;
250
251 buffer[(user - host) - 1] = '\0';
252 result->val.triple.host = strip_whitespace (buffer);
253
254 buffer[(domain - host) - 1] = '\0';
255 result->val.triple.user = strip_whitespace (buffer + (user - host));
256
257 buffer[(cp - host) - 1] = '\0';
258 result->val.triple.domain = strip_whitespace (buffer + (domain - host));
259
260 /* Remember where we stopped reading. */
261 result->cursor = cp;
262 result->first = 0;
263
264 return NSS_SUCCESS;
265 }
266
267 #ifdef HAVE_NSS_H
268 static NSS_STATUS
269 _nss_ldap_load_netgr (LDAPMessage * e,
270 ldap_state_t * pvt,
271 void *vresultp, char *buffer, size_t buflen)
272 {
273 int attr;
274 int nvals;
275 int valcount = 0;
276 char **vals;
277 char **valiter;
278 struct __netgrent *result = vresultp;
279 NSS_STATUS stat = NSS_SUCCESS;
280
281 for (attr = 0; attr < 2; attr++)
282 {
283 switch (attr)
284 {
285 case 1:
286 vals = _nss_ldap_get_values (e, AT (nisNetgroupTriple));
287 break;
288 default:
289 vals = _nss_ldap_get_values (e, AT (memberNisNetgroup));
290 break;
291 }
292
293 nvals = ldap_count_values (vals);
294
295 if (vals == NULL)
296 continue;
297
298 if (nvals == 0)
299 {
300 ldap_value_free (vals);
301 continue;
302 }
303
304 if (result->data_size > 0
305 && result->cursor - result->data + 1 > result->data_size)
306 EXPAND (1);
307
308 if (result->data_size > 0)
309 *result->cursor++ = ' ';
310
311 valcount += nvals;
312 valiter = vals;
313
314 while (*valiter != NULL)
315 {
316 int curlen = strlen (*valiter);
317 if (result->cursor - result->data + curlen + 1 > result->data_size)
318 EXPAND (curlen + 1);
319 memcpy (result->cursor, *valiter, curlen + 1);
320 result->cursor += curlen;
321 valiter++;
322 if (*valiter != NULL)
323 *result->cursor++ = ' ';
324 }
325 ldap_value_free (vals);
326 }
327
328 result->first = 1;
329 result->cursor = result->data;
330
331 out:
332
333 return stat;
334 }
335
336 NSS_STATUS
337 _nss_ldap_endnetgrent (struct __netgrent * result)
338 {
339 if (result->data != NULL)
340 {
341 free (result->data);
342 result->data = NULL;
343 result->data_size = 0;
344 result->cursor = NULL;
345 }
346
347 LOOKUP_ENDENT (_ngbe);
348 }
349
350 NSS_STATUS
351 _nss_ldap_setnetgrent (char *group, struct __netgrent *result)
352 {
353 int errnop = 0, buflen = 0;
354 char *buffer = (char *) NULL;
355 ldap_args_t a;
356 NSS_STATUS stat = NSS_SUCCESS;
357
358 if (group[0] == '\0')
359 return NSS_UNAVAIL;
360
361 if (result->data != NULL)
362 free (result->data);
363 result->data = result->cursor = NULL;
364 result->data_size = 0;
365
366 LA_INIT (a);
367 LA_STRING (a) = group;
368 LA_TYPE (a) = LA_TYPE_STRING;
369
370 stat =
371 _nss_ldap_getbyname (&a, result, buffer, buflen, &errnop,
372 _nss_ldap_filt_getnetgrent, LM_NETGROUP,
373 _nss_ldap_load_netgr);
374
375 if (stat == NSS_NOTFOUND)
376 return stat;
377
378 LOOKUP_SETENT (_ngbe);
379 }
380
381 NSS_STATUS
382 _nss_ldap_getnetgrent_r (struct __netgrent *result,
383 char *buffer, size_t buflen, int *errnop)
384 {
385 return _nss_ldap_parse_netgr (result, buffer, buflen);
386 }
387 #endif /* HAVE_NSS_H */
388
389 #if defined(HAVE_NSSWITCH_H) || defined(HAVE_IRS_H)
390 /*
391 * Chase nested netgroups. If we can't find a nested netgroup, we try
392 * the next one - don't want to fail authoritatively because of bad
393 * user data.
394 */
395 static NSS_STATUS
396 nn_chase (nss_ldap_netgr_backend_t * ngbe, LDAPMessage ** pEntry)
397 {
398 ldap_args_t a;
399 NSS_STATUS stat = NSS_NOTFOUND;
400
401 debug ("==> nn_chase");
402
403 if (ngbe->state->ec_res != NULL)
404 {
405 ldap_msgfree (ngbe->state->ec_res);
406 ngbe->state->ec_res = NULL;
407 }
408
409 while (ngbe->needed_groups != NULL)
410 {
411 /* If this netgroup has already been seen, avoid it */
412 if (_nss_ldap_namelist_find (ngbe->known_groups, ngbe->needed_groups->name))
413 {
414 _nss_ldap_namelist_pop (&ngbe->needed_groups);
415 continue;
416 }
417
418 LA_INIT (a);
419 LA_TYPE (a) = LA_TYPE_STRING;
420 LA_STRING (a) = ngbe->needed_groups->name;
421
422 debug (":== nn_chase: nested netgroup=%s", LA_STRING (a));
423
424 _nss_ldap_enter ();
425 stat = _nss_ldap_search_s (&a, _nss_ldap_filt_getnetgrent,
426 LM_NETGROUP, NULL, 1, &ngbe->state->ec_res);
427 _nss_ldap_leave ();
428
429 if (stat == NSS_SUCCESS)
430 {
431 /* we have "seen" this netgroup; track it for loop detection */
432 stat = _nss_ldap_namelist_push (&ngbe->known_groups, ngbe->needed_groups->name);
433 if (stat != NSS_SUCCESS)
434 {
435 _nss_ldap_namelist_pop (&ngbe->needed_groups);
436 break;
437 }
438 }
439
440 _nss_ldap_namelist_pop (&ngbe->needed_groups);
441
442 if (stat == NSS_SUCCESS)
443 {
444 /* Check we got an entry, not just a result. */
445 *pEntry = _nss_ldap_first_entry (ngbe->state->ec_res);
446 if (*pEntry == NULL)
447 {
448 ldap_msgfree (ngbe->state->ec_res);
449 ngbe->state->ec_res = NULL;
450 stat = NSS_NOTFOUND;
451 }
452 }
453
454 if (stat == NSS_SUCCESS)
455 {
456 /* found one. */
457 break;
458 }
459 }
460
461 debug ("<== nn_chase result=%d", stat);
462
463 return stat;
464 }
465 #endif /* HAVE_NSSWITCH_H || HAVE_IRS_H */
466
467 #if defined(HAVE_NSSWITCH_H) || defined(HAVE_IRS_H)
468 /*
469 * getnetgrent() inner implementation, used by both Solaris NSS
470 * and IRS/AIX
471 */
472 static NSS_STATUS
473 do_getnetgrent (nss_ldap_netgr_backend_t *be,
474 char *buffer, size_t buflen,
475 enum nss_netgr_status *status,
476 char **machine, char **user, char **domain)
477 {
478 ent_context_t *ctx;
479 NSS_STATUS parseStat = NSS_NOTFOUND;
480
481 /*
482 * This function is called with the pseudo-backend that
483 * we created in _nss_ldap_setnetgrent() (see below)
484 */
485 debug ("==> do_getnetgrent");
486
487 ctx = be->state;
488 assert (ctx != NULL);
489
490 *status = NSS_NETGR_NO;
491 *machine = NULL;
492 *user = NULL;
493 *domain = NULL;
494
495 do
496 {
497 NSS_STATUS resultStat = NSS_SUCCESS;
498 char **vals, **p;
499 ldap_state_t *state = &ctx->ec_state;
500 struct __netgrent __netgrent;
501 LDAPMessage *e = NULL;
502
503 if (state->ls_retry == 0 && state->ls_info.ls_index == -1)
504 {
505 resultStat = NSS_NOTFOUND;
506
507 if (ctx->ec_res != NULL)
508 {
509 e = _nss_ldap_first_entry (ctx->ec_res);
510 if (e != NULL)
511 resultStat = NSS_SUCCESS;
512 }
513
514 if (resultStat != NSS_SUCCESS)
515 {
516 /* chase nested netgroups */
517 resultStat = nn_chase (be, &e);
518 }
519
520 if (resultStat != NSS_SUCCESS)
521 {
522 parseStat = resultStat;
523 break;
524 }
525
526 assert (e != NULL);
527
528 /* Push nested netgroups onto stack for deferred chasing */
529 vals = _nss_ldap_get_values (e, AT (memberNisNetgroup));
530 if (vals != NULL)
531 {
532 for (p = vals; *p != NULL; p++)
533 {
534 parseStat = _nss_ldap_namelist_push (&be->needed_groups, *p);
535 if (parseStat != NSS_SUCCESS)
536 break;
537 }
538 ldap_value_free (vals);
539
540 if (parseStat != NSS_SUCCESS)
541 break; /* out of memory */
542 }
543 }
544 else
545 {
546 assert (ctx->ec_res != NULL);
547 e = _nss_ldap_first_entry (ctx->ec_res);
548 if (e == NULL)
549 {
550 /* This should never happen, but we fail gracefully. */
551 parseStat = NSS_UNAVAIL;
552 break;
553 }
554 }
555
556 /* We have an entry; now, try to parse it. */
557 vals = _nss_ldap_get_values (e, AT (nisNetgroupTriple));
558 if (vals == NULL)
559 {
560 state->ls_info.ls_index = -1;
561 parseStat = NSS_NOTFOUND;
562 ldap_msgfree (ctx->ec_res);
563 ctx->ec_res = NULL;
564 continue;
565 }
566
567 switch (state->ls_info.ls_index)
568 {
569 case 0:
570 /* last time. decrementing ls_index to -1 AND returning
571 * an error code will force this entry to be discared.
572 */
573 parseStat = NSS_NOTFOUND;
574 break;
575 case -1:
576 /* first time */
577 state->ls_info.ls_index = ldap_count_values (vals);
578 /* fall off to default... */
579 default:
580 __netgrent.data = vals[state->ls_info.ls_index - 1];
581 __netgrent.data_size = strlen (vals[state->ls_info.ls_index - 1]);
582 __netgrent.cursor = __netgrent.data;
583 __netgrent.first = 1;
584
585 parseStat = _nss_ldap_parse_netgr (&__netgrent, buffer, buflen);
586 if (parseStat != NSS_SUCCESS)
587 {
588 break;
589 }
590 if (__netgrent.type != triple_val)
591 {
592 parseStat = NSS_NOTFOUND;
593 break;
594 }
595 *machine = (char *) __netgrent.val.triple.host;
596 *user = (char *) __netgrent.val.triple.user;
597 *domain = (char *) __netgrent.val.triple.domain;
598 break;
599 }
600
601 ldap_value_free (vals);
602 state->ls_info.ls_index--;
603
604 /* hold onto the state if we're out of memory XXX */
605 state->ls_retry = (parseStat == NSS_TRYAGAIN ? 1 : 0);
606 *status = (parseStat == NSS_SUCCESS) ? NSS_NETGR_FOUND : NSS_NETGR_NOMEM;
607
608 if (state->ls_retry == 0 && state->ls_info.ls_index == -1)
609 {
610 ldap_msgfree (ctx->ec_res);
611 ctx->ec_res = NULL;
612 }
613 }
614 while (parseStat == NSS_NOTFOUND);
615
616 if (parseStat == NSS_TRYAGAIN)
617 {
618 errno = ERANGE;
619 }
620
621 debug ("<== do_getnetgrent");
622
623 return parseStat;
624 }
625
626 /*
627 * Test a 4-tuple
628 */
629 static NSS_STATUS
630 do_parse_innetgr (LDAPMessage * e, ldap_state_t * pvt,
631 void *result, char *buffer, size_t buflen)
632 {
633 ldap_innetgr_args_t *li_args = (ldap_innetgr_args_t *) result;
634 int count;
635 char **values = NULL;
636 NSS_STATUS stat = NSS_NOTFOUND;
637
638 debug ("==> do_parse_innetgr");
639
640 values = _nss_ldap_get_values (e, ATM (LM_NETGROUP, cn));
641 if (values == NULL)
642 return NSS_NOTFOUND;
643
644 count = ldap_count_values (values);
645
646 while (--count >= 0)
647 {
648 assert (values[count] != NULL);
649
650 if (strcasecmp (li_args->lia_netgroup, values[count]) == 0)
651 {
652 li_args->lia_netgr_status = NSS_NETGR_FOUND;
653 stat = NSS_SUCCESS;
654 }
655 else
656 {
657 stat = do_innetgr_nested (li_args, values[count]);
658 }
659
660 if (stat == NSS_SUCCESS)
661 break;
662 }
663
664 ldap_value_free (values);
665
666 debug ("<== do_parse_innetgr");
667
668 return stat;
669 }
670
671 /*
672 * NB: caller has acquired the global lock
673 */
674 static NSS_STATUS
675 do_innetgr_nested (ldap_innetgr_args_t * li_args, const char *nested)
676 {
677 NSS_STATUS stat;
678 ldap_args_t a;
679 ent_context_t *ctx = NULL;
680
681 debug ("==> do_innetgr_nested netgroup=%s assertion=%s",
682 li_args->lia_netgroup, nested);
683
684 if (li_args->lia_depth >= LDAP_NSS_MAXNETGR_DEPTH)
685 {
686 debug ("<== do_innetgr_nested: maximum depth exceeded");
687 return NSS_NOTFOUND;
688 }
689
690 LA_INIT (a);
691 LA_TYPE (a) = LA_TYPE_STRING;
692 LA_STRING (a) = nested; /* memberNisNetgroup */
693
694 if (_nss_ldap_ent_context_init_locked (&ctx) == NULL)
695 {
696 debug ("<== do_innetgr_nested: failed to initialize context");
697 return NSS_UNAVAIL;
698 }
699
700 li_args->lia_depth++;
701
702 stat = _nss_ldap_getent_ex (&a, &ctx, (void *) li_args, NULL, 0,
703 &li_args->lia_erange, _nss_ldap_filt_innetgr,
704 LM_NETGROUP, NULL, do_parse_innetgr);
705
706 li_args->lia_depth--;
707
708 _nss_ldap_ent_context_release (&ctx);
709
710 debug ("<== do_innetgr_nested status=%d netgr_status=%d",
711 stat, li_args->lia_netgr_status);
712
713 return stat;
714 }
715
716 /*
717 * NB: caller has acquired the global lock
718 */
719 static NSS_STATUS
720 do_innetgr (ldap_innetgr_args_t * li_args,
721 const char *machine, const char *user, const char *domain)
722 {
723 NSS_STATUS stat;
724 ldap_args_t a;
725 ent_context_t *ctx = NULL;
726
727 debug ("==> do_innetgr netgroup=%s", li_args->lia_netgroup);
728
729 /*
730 * First, find which netgroup the 3-tuple belongs to.
731 */
732 LA_INIT (a);
733 LA_TYPE (a) = LA_TYPE_TRIPLE;
734 LA_TRIPLE (a).user = user;
735 LA_TRIPLE (a).host = machine;
736 LA_TRIPLE (a).domain = domain;
737
738 if (_nss_ldap_ent_context_init_locked (&ctx) == NULL)
739 {
740 debug ("<== do_innetgr: failed to initialize context");
741 return NSS_UNAVAIL;
742 }
743
744 stat = _nss_ldap_getent_ex (&a, &ctx, (void *) li_args, NULL, 0,
745 &li_args->lia_erange, NULL, LM_NETGROUP,
746 NULL, do_parse_innetgr);
747
748 _nss_ldap_ent_context_release (&ctx);
749
750 debug ("<== do_innetgr status=%d netgr_status=%d",
751 stat, li_args->lia_netgr_status);
752
753 return stat;
754 }
755 #endif /* HAVE_NSSWITCH_H || HAVE_IRS_H */
756
757 #ifdef HAVE_NSSWITCH_H
758 static NSS_STATUS
759 _nss_ldap_getnetgroup_endent (nss_backend_t * be, void *_args)
760 {
761 LOOKUP_ENDENT (be);
762 }
763
764 static NSS_STATUS
765 _nss_ldap_getnetgroup_setent (nss_backend_t * be, void *_args)
766 {
767 return NSS_SUCCESS;
768 }
769
770 static NSS_STATUS
771 _nss_ldap_getnetgroup_getent (nss_backend_t * _be, void *_args)
772 {
773 nss_ldap_netgr_backend_t *be = (nss_ldap_netgr_backend_t *) _be;
774 struct nss_getnetgrent_args *args = (struct nss_getnetgrent_args *) _args;
775 NSS_STATUS stat;
776
777 _nss_ldap_enter ();
778
779 stat = do_getnetgrent (be,
780 args->buffer,
781 args->buflen,
782 &args->status,
783 &args->retp[NSS_NETGR_MACHINE],
784 &args->retp[NSS_NETGR_USER],
785 &args->retp[NSS_NETGR_DOMAIN]);
786
787 _nss_ldap_leave ();
788
789 return stat;
790 }
791
792 static NSS_STATUS
793 _nss_ldap_innetgr (nss_backend_t * be, void *_args)
794 {
795 struct nss_innetgr_args *args = (struct nss_innetgr_args *) _args;
796 int i;
797
798 /*
799 * Enumerate the groups in args structure and see whether
800 * any 4-tuple was satisfied. This really needs LDAP
801 * component matching to be done efficiently.
802 */
803
804 debug
805 ("==> _nss_ldap_innetgr MACHINE.argc=%d USER.argc=%d DOMAIN.argc=%d groups.argc=%d",
806 args->arg[NSS_NETGR_MACHINE].argc, args->arg[NSS_NETGR_USER].argc,
807 args->arg[NSS_NETGR_DOMAIN].argc, args->groups.argc);
808
809 /* note: mountd on Solaris does set multiple 'groups' with one 'arg' for
810 * efficiency reasons */
811
812 assert (args->arg[NSS_NETGR_MACHINE].argc <= 1);
813 assert (args->arg[NSS_NETGR_USER].argc <= 1);
814 assert (args->arg[NSS_NETGR_DOMAIN].argc <= 1);
815
816 _nss_ldap_enter ();
817
818 const char *machine = (args->arg[NSS_NETGR_MACHINE].argc != 0) ?
819 args->arg[NSS_NETGR_MACHINE].argv[0] : NULL;
820 const char *user = (args->arg[NSS_NETGR_USER].argc != 0) ?
821 args->arg[NSS_NETGR_USER].argv[0] : NULL;
822 const char *domain = (args->arg[NSS_NETGR_DOMAIN].argc != 0) ?
823 args->arg[NSS_NETGR_DOMAIN].argv[0] : NULL;
824
825 for (i = 0; i < args->groups.argc; i++)
826 {
827 NSS_STATUS parseStat;
828 ldap_innetgr_args_t li_args;
829
830 li_args.lia_netgroup = args->groups.argv[i];
831 li_args.lia_netgr_status = NSS_NETGR_NO;
832 li_args.lia_depth = 0;
833 li_args.lia_erange = 0;
834
835 parseStat = do_innetgr (&li_args, machine, user, domain);
836 if (parseStat != NSS_SUCCESS && parseStat != NSS_NOTFOUND)
837 {
838 /* fatal error */
839 if (li_args.lia_erange != 0)
840 errno = ERANGE;
841 break;
842 }
843
844 args->status = li_args.lia_netgr_status;
845
846 if (args->status == NSS_NETGR_FOUND)
847 {
848 _nss_ldap_leave ();
849 debug ("<== _nss_ldap_innetgr (FOUND)");
850 return NSS_SUCCESS;
851 }
852 }
853
854 _nss_ldap_leave ();
855 debug ("<== _nss_ldap_innetgr (not found)");
856 return NSS_NOTFOUND;
857 }
858
859 /*
860 * According to the "documentation", setnetgrent() is really
861 * a getXXXbyYYY() operation that returns a pseudo-backend
862 * through which one may enumerate the netgroup's members.
863 *
864 * ie. this is the constructor for the pseudo-backend.
865 */
866 static NSS_STATUS
867 _nss_ldap_setnetgrent (nss_backend_t * be, void *_args)
868 {
869 NSS_STATUS stat;
870 struct nss_setnetgrent_args *args;
871 nss_ldap_netgr_backend_t *ngbe;
872 ldap_args_t a;
873
874 debug ("==> _nss_ldap_setnetgrent");
875
876 args = (struct nss_setnetgrent_args *) _args;
877 args->iterator = NULL; /* initialize */
878
879 /*
880 * This retrieves the top-level netgroup; nested netgroups
881 * are chased inside the pseudo-backend.
882 */
883
884 LA_INIT (a);
885 LA_TYPE (a) = LA_TYPE_STRING;
886 LA_STRING (a) = args->netgroup; /* cn */
887
888 ngbe = (nss_ldap_netgr_backend_t *) malloc (sizeof (*ngbe));
889 if (ngbe == NULL)
890 {
891 debug ("<== _nss_ldap_setnetgrent");
892 return NSS_UNAVAIL;
893 }
894
895 ngbe->ops = netgroup_ops;
896 ngbe->n_ops = 6;
897 ngbe->state = NULL;
898 ngbe->known_groups = NULL;
899 ngbe->needed_groups = NULL;
900
901 stat = _nss_ldap_default_constr ((nss_ldap_backend_t *) ngbe);
902 if (stat != NSS_SUCCESS)
903 {
904 free (ngbe);
905 debug ("<== _nss_ldap_setnetgrent");
906 return stat;
907 }
908
909 if (_nss_ldap_ent_context_init (&ngbe->state) == NULL)
910 {
911 _nss_ldap_default_destr ((nss_backend_t *) ngbe, NULL);
912 debug ("<== _nss_ldap_setnetgrent");
913 return NSS_UNAVAIL;
914 }
915
916 assert (ngbe->state != NULL);
917 assert (ngbe->state->ec_res == NULL);
918
919 _nss_ldap_enter ();
920 stat = _nss_ldap_search_s (&a, _nss_ldap_filt_getnetgrent,
921 LM_NETGROUP, NULL, 1, &ngbe->state->ec_res);
922 _nss_ldap_leave ();
923
924 if (stat == NSS_SUCCESS)
925 {
926 /* we have "seen" this netgroup; track it for loop detection */
927 stat = _nss_ldap_namelist_push (&ngbe->known_groups, args->netgroup);
928 }
929
930 if (stat == NSS_SUCCESS)
931 {
932 args->iterator = (nss_backend_t *) ngbe;
933 }
934 else
935 {
936 _nss_ldap_default_destr ((nss_backend_t *) ngbe, NULL);
937 }
938
939 debug ("<== _nss_ldap_setnetgrent");
940
941 return stat;
942 }
943
944 static NSS_STATUS
945 _nss_ldap_netgroup_destr (nss_backend_t * _ngbe, void *args)
946 {
947 nss_ldap_netgr_backend_t *ngbe = (nss_ldap_netgr_backend_t *) _ngbe;
948
949 /* free list of nested netgroups */
950 _nss_ldap_namelist_destroy (&ngbe->known_groups);
951 _nss_ldap_namelist_destroy (&ngbe->needed_groups);
952
953 return _nss_ldap_default_destr (_ngbe, args);
954 }
955
956 static nss_backend_op_t netgroup_ops[] = {
957 _nss_ldap_netgroup_destr, /* NSS_DBOP_DESTRUCTOR */
958 _nss_ldap_getnetgroup_endent, /* NSS_DBOP_ENDENT */
959 _nss_ldap_getnetgroup_setent, /* NSS_DBOP_SETENT */
960 _nss_ldap_getnetgroup_getent, /* NSS_DBOP_GETENT */
961 _nss_ldap_innetgr, /* NSS_DBOP_NETGROUP_IN */
962 _nss_ldap_setnetgrent /* NSS_DBOP_NETGROUP_SET */
963 };
964
965 nss_backend_t *
966 _nss_ldap_netgroup_constr (const char *db_name,
967 const char *src_name, const char *cfg_args)
968 {
969 nss_ldap_netgr_backend_t *be;
970
971 if (!(be = (nss_ldap_netgr_backend_t *) malloc (sizeof (*be))))
972 return NULL;
973
974 be->ops = netgroup_ops;
975 be->n_ops = sizeof (netgroup_ops) / sizeof (nss_backend_op_t);
976 be->known_groups = NULL;
977 be->needed_groups = NULL;
978
979 if (_nss_ldap_default_constr ((nss_ldap_backend_t *) be) != NSS_SUCCESS)
980 {
981 free (be);
982 return NULL;
983 }
984
985 return (nss_backend_t *) be;
986 }
987
988 #endif /* !HAVE_NSS_H */
989
990 #ifdef HAVE_IRS_H
991 #include "irs-netgrp.c"
992 #endif /* HAVE_IRS_H */