xref: /illumos-gate/usr/src/lib/nsswitch/ldap/common/getnetgrent.c (revision 0173c38a73f34277e0c97a19fedfd25d81ba8380)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <syslog.h>
29 #include "ldap_common.h"
30 
31 /* netgroup attributes filters */
32 #define	_N_TRIPLE		"nisnetgrouptriple"
33 #define	_N_MEMBER		"membernisnetgroup"
34 
35 #define	PRINT_VAL(a)		(((a).argc == 0) || ((a).argv == NULL) || \
36 				    ((a).argv[0] == NULL)) ? "*" : (a).argv[0]
37 #define	ISNULL(a)		(a == NULL ? "<NULL>" : a)
38 #define	MAX_DOMAIN_LEN		1024
39 #define	MAX_TRIPLE_LEN		(MAXHOSTNAMELEN + LOGNAME_MAX + \
40 					MAX_DOMAIN_LEN + 5)
41 
42 #define	_F_SETMEMBER		"(&(objectClass=nisNetGroup)(cn=%s))"
43 #define	_F_SETMEMBER_SSD	"(&(%%s)(cn=%s))"
44 
45 #define	N_HASH		257
46 #define	COMMA		','
47 
48 static const char *netgrent_attrs[] = {
49 	_N_TRIPLE,
50 	_N_MEMBER,
51 	(char *)NULL
52 };
53 
54 typedef struct netgroup_name {
55 	char *name;
56 	struct netgroup_name *next;
57 	struct netgroup_name *next_hash;
58 } netgroup_name_t;
59 
60 typedef struct {
61 	netgroup_name_t *hash_list[N_HASH];
62 	netgroup_name_t *to_do;
63 	netgroup_name_t *done;
64 } netgroup_table_t;
65 
66 typedef struct {
67 	ns_ldap_result_t *results;
68 	ns_ldap_entry_t *entry;
69 	char **attrs;
70 	void *cookie;
71 	char *netgroup;
72 	netgroup_table_t tab;
73 } getnetgrent_cookie_t;
74 
75 typedef struct {
76 	struct nss_innetgr_args *ia;
77 	const char *ssd_filter;
78 	const char *netgrname;
79 	const char *membername;
80 	netgroup_table_t tab;
81 } innetgr_cookie_t;
82 
83 typedef unsigned int hash_t;
84 
85 static hash_t
86 get_hash(const char *s)
87 {
88 	unsigned int sum = 0;
89 	unsigned int i;
90 
91 	for (i = 0; s[i] != '\0'; i++)
92 		sum += ((unsigned char *)s)[i];
93 
94 	return ((sum + i) % N_HASH);
95 }
96 
97 /*
98  * Adds a name to the netgroup table
99  *
100  * Returns
101  *	0 if successfully added or already present
102  *	-1 if memory allocation error
103  */
104 
105 static int
106 add_netgroup_name(const char *name, netgroup_table_t *tab)
107 {
108 	hash_t		h;
109 	netgroup_name_t	*ng;
110 	netgroup_name_t	*ng_new;
111 
112 	if (tab == NULL || name == NULL || *name == '\0')
113 	return (NULL);
114 
115 	h = get_hash(name);
116 	ng = tab->hash_list[h];
117 
118 	while (ng != NULL) {
119 		if (strcmp(name, ng->name) == 0)
120 			break;
121 		ng = ng->next_hash;
122 	}
123 
124 	if (ng == NULL) {
125 		ng_new = (netgroup_name_t *)
126 			calloc(1, sizeof (netgroup_name_t));
127 		if (ng_new == NULL)
128 			return (-1);
129 		ng_new->name = strdup(name);
130 		if (ng_new->name == NULL) {
131 			free(ng_new);
132 			return (-1);
133 		}
134 		ng_new->next_hash = tab->hash_list[h];
135 		tab->hash_list[h] = ng_new;
136 		ng_new->next = tab->to_do;
137 		tab->to_do = ng_new;
138 	}
139 	return (0);
140 }
141 
142 static netgroup_name_t *
143 get_next_netgroup(netgroup_table_t *tab)
144 {
145 	netgroup_name_t *ng;
146 
147 	if (tab == NULL)
148 		return (NULL);
149 
150 	ng = tab->to_do;
151 	if (ng != NULL) {
152 		tab->to_do = ng->next;
153 		ng->next = tab->done;
154 		tab->done = ng;
155 	}
156 	return (ng);
157 }
158 
159 static void
160 free_netgroup_table(netgroup_table_t *tab)
161 {
162 	netgroup_name_t *ng, *next;
163 
164 	if (tab == NULL)
165 		return;
166 
167 	for (ng = tab->to_do; ng != NULL; ng = next) {
168 		if (ng->name != NULL)
169 			free(ng->name);
170 		next = ng->next;
171 		free(ng);
172 	}
173 
174 	for (ng = tab->done; ng != NULL; ng = next) {
175 		if (ng->name != NULL)
176 			free(ng->name);
177 		next = ng->next;
178 		free(ng);
179 	}
180 	(void) memset(tab, 0, sizeof (*tab));
181 }
182 
183 /*
184  * domain comparing routine
185  * 	n1: See if n1 is n2 or an ancestor of it
186  * 	n2: (in string terms, n1 is a suffix of n2)
187  * Returns ZERO for success, -1 for failure.
188  */
189 static int
190 domcmp(const char *n1, const char *n2)
191 {
192 #define	PASS	0
193 #define	FAIL	-1
194 
195 	size_t		l1, l2;
196 
197 	if ((n1 == NULL) || (n2 == NULL))
198 		return (FAIL);
199 
200 	l1 = strlen(n1);
201 	l2 = strlen(n2);
202 
203 	/* Turn a blind eye to the presence or absence of trailing periods */
204 	if (l1 != 0 && n1[l1 - 1] == '.') {
205 		--l1;
206 	}
207 	if (l2 != 0 && n2[l2 - 1] == '.') {
208 		--l2;
209 	}
210 	if (l1 > l2) {		/* Can't be a suffix */
211 		return (FAIL);
212 	} else if (l1 == 0) {	/* Trivially a suffix; */
213 				/* (do we want this case?) */
214 		return (PASS);
215 	}
216 	/* So 0 < l1 <= l2 */
217 	if (l1 < l2 && n2[l2 - l1 - 1] != '.') {
218 		return (FAIL);
219 	}
220 	if (strncasecmp(n1, &n2[l2 - l1], l1) == 0) {
221 		return (PASS);
222 	} else {
223 		return (FAIL);
224 	}
225 }
226 
227 static int
228 split_triple(char *triple, char **hostname, char **username, char **domain)
229 {
230 	int	i, syntax_err;
231 	char	*splittriple[3];
232 	char	*p = triple;
233 
234 #ifdef	DEBUG
235 	(void) fprintf(stdout, "\n[getnetgrent.c: split_triple]\n");
236 #endif	/* DEBUG */
237 
238 	if (triple == NULL)
239 		return (-1);
240 
241 	p++;
242 	syntax_err = 0;
243 	for (i = 0; i < 3; i++) {
244 		char	*start;
245 		char	*limit;
246 		const char	*terminators = ",) \t";
247 
248 		if (i == 2) {
249 			/* Don't allow comma */
250 			terminators++;
251 		}
252 		while (isspace(*p)) {
253 			p++;
254 		}
255 		start = p;
256 		limit = strpbrk(start, terminators);
257 		if (limit == 0) {
258 			syntax_err++;
259 			break;
260 		}
261 		p = limit;
262 		while (isspace(*p)) {
263 			p++;
264 		}
265 		if (*p == terminators[0]) {
266 			/*
267 			 * Successfully parsed this name and
268 			 * the separator after it (comma or
269 			 * right paren); leave p ready for
270 			 * next parse.
271 			 */
272 			p++;
273 			if (start == limit) {
274 				/* Wildcard */
275 				splittriple[i] = NULL;
276 			} else {
277 				*limit = '\0';
278 				splittriple[i] = start;
279 			}
280 		} else {
281 			syntax_err++;
282 			break;
283 		}
284 	}
285 
286 	if (syntax_err != 0)
287 		return (-1);
288 
289 	*hostname = splittriple[0];
290 	*username = splittriple[1];
291 	*domain = splittriple[2];
292 
293 	return (0);
294 }
295 
296 /*
297  * Test membership in triple
298  *	return 0 = no match
299  *	return 1 = match
300  */
301 
302 static int
303 match_triple_entry(struct nss_innetgr_args *ia, const ns_ldap_entry_t *entry)
304 {
305 	int	ndomains;
306 	char	**pdomains;
307 	int	nhost;
308 	char	**phost;
309 	int	nusers;
310 	char	**pusers;
311 	char	**attr;
312 	char	triple[MAX_TRIPLE_LEN];
313 	char	*tuser, *thost, *tdomain;
314 	int	i;
315 	char	*current, *limit;
316 	int	pulen, phlen;
317 	char	*pusers0, *phost0;
318 
319 	nhost = ia->arg[NSS_NETGR_MACHINE].argc;
320 	phost = (char **)ia->arg[NSS_NETGR_MACHINE].argv;
321 	if (phost == NULL || *phost == NULL) {
322 		nhost = 0;
323 	} else {
324 		phost0 = phost[0];
325 		phlen = strlen(phost0);
326 	}
327 	nusers = ia->arg[NSS_NETGR_USER].argc;
328 	pusers = (char **)ia->arg[NSS_NETGR_USER].argv;
329 	if (pusers == NULL || *pusers == NULL) {
330 		nusers = 0;
331 	} else {
332 		pusers0 = pusers[0];
333 		pulen = strlen(pusers0);
334 	}
335 	ndomains = ia->arg[NSS_NETGR_DOMAIN].argc;
336 	pdomains = (char **)ia->arg[NSS_NETGR_DOMAIN].argv;
337 	if (pdomains == NULL || *pdomains == NULL)
338 		ndomains = 0;
339 
340 	attr = __ns_ldap_getAttr(entry, _N_TRIPLE);
341 	if (attr == NULL || *attr == NULL)
342 		return (0);
343 
344 	/* Special cases for speedup */
345 	if (nusers == 1 && nhost == 0 && ndomains == 0) {
346 		/* Special case for finding a single user in a netgroup */
347 		for (; *attr; attr++) {
348 			/* jump to first comma and check next character */
349 			current = *attr;
350 			if ((current = strchr(current, COMMA)) == NULL)
351 				continue;
352 			current++;
353 
354 			/* skip whitespaces */
355 			while (isspace(*current))
356 				current++;
357 
358 			/* if user part is null, then treat as wildcard */
359 			if (*current == COMMA)
360 				return (1);
361 
362 			/* compare first character */
363 			if (*pusers0 != *current)
364 				continue;
365 
366 			/* limit username to COMMA */
367 			if ((limit = strchr(current, COMMA)) == NULL)
368 				continue;
369 			*limit = '\0';
370 
371 			/* remove blanks before COMMA */
372 			if ((limit = strpbrk(current, " \t")) != NULL)
373 				*limit = '\0';
374 
375 			/* compare size of username */
376 			if (pulen != strlen(current)) {
377 				continue;
378 			}
379 
380 			/* do actual compare */
381 			if (strncmp(pusers0, current, pulen) == 0) {
382 				return (1);
383 			} else {
384 				continue;
385 			}
386 		}
387 	} else if (nusers == 0 && nhost == 1 && ndomains == 0) {
388 		/* Special case for finding a single host in a netgroup */
389 		for (; *attr; attr++) {
390 
391 			/* jump to first character and check */
392 			current = *attr;
393 			current++;
394 
395 			/* skip whitespaces */
396 			while (isspace(*current))
397 				current++;
398 
399 			/* if host part is null, then treat as wildcard */
400 			if (*current == COMMA)
401 				return (1);
402 
403 			/* compare first character */
404 			if (tolower(*phost0) != tolower(*current))
405 				continue;
406 
407 			/* limit hostname to COMMA */
408 			if ((limit = strchr(current, COMMA)) == NULL)
409 				continue;
410 			*limit = '\0';
411 
412 			/* remove blanks before COMMA */
413 			if ((limit = strpbrk(current, " \t")) != NULL)
414 				*limit = '\0';
415 
416 			/* compare size of hostname */
417 			if (phlen != strlen(current)) {
418 				continue;
419 			}
420 
421 			/* do actual compare */
422 			if (strncasecmp(phost0, current, phlen) == 0) {
423 				return (1);
424 			} else {
425 				continue;
426 			}
427 		}
428 	} else {
429 		for (; *attr; attr++) {
430 			if (strlcpy(triple, *attr,
431 					sizeof (triple)) >= sizeof (triple))
432 				continue;
433 			if (split_triple(triple, &thost, &tuser, &tdomain) != 0)
434 				continue;
435 			if (thost != NULL && *thost != '\0' && nhost != 0) {
436 				for (i = 0; i < nhost; i++)
437 					if (strcasecmp(thost, phost[i]) == 0)
438 						break;
439 				if (i == nhost)
440 				    continue;
441 			}
442 			if (tuser != NULL && *tuser != '\0' && nusers != 0) {
443 				for (i = 0; i < nusers; i++)
444 					if (strcmp(tuser, pusers[i]) == 0)
445 						break;
446 				if (i == nusers)
447 					continue;
448 			}
449 			if (tdomain != NULL && *tdomain != '\0' &&
450 					ndomains != 0) {
451 				for (i = 0; i < ndomains; i++)
452 					if (domcmp(tdomain, pdomains[i]) == 0)
453 						break;
454 				if (i == ndomains)
455 					continue;
456 			}
457 			return (1);
458 		}
459 	}
460 
461 	return (0);
462 }
463 
464 static int
465 match_triple(struct nss_innetgr_args *ia, ns_ldap_result_t *result)
466 {
467 	ns_ldap_entry_t	*entry;
468 
469 	for (entry = result->entry; entry != NULL; entry = entry->next)
470 	    if (match_triple_entry(ia, entry) == 1)
471 		return (1);
472 
473 	return (0);
474 }
475 
476 static int
477 add_netgroup_member_entry(ns_ldap_entry_t *entry, netgroup_table_t *tab)
478 {
479 	char		**attrs;
480 	char		**a;
481 
482 	attrs = __ns_ldap_getAttr(entry, _N_MEMBER);
483 	if (attrs == NULL || *attrs == NULL)
484 		return (0);
485 
486 	for (a = attrs; *a != NULL; a++) {}
487 
488 	do {
489 		a--;
490 		if (add_netgroup_name(*a, tab) != 0)
491 			return (-1);
492 	} while (a > attrs);
493 	return (0);
494 }
495 
496 static int
497 add_netgroup_member(ns_ldap_result_t *result, netgroup_table_t *tab)
498 {
499 	ns_ldap_entry_t	*entry;
500 	int		ret = 0;
501 
502 	for (entry = result->entry; entry != NULL; entry = entry->next) {
503 	    ret = add_netgroup_member_entry(entry, tab);
504 	    if (ret != 0)
505 		break;
506 	}
507 	return (ret);
508 }
509 
510 /*
511  * top_down_search checks only checks the netgroup specified in netgrname
512  */
513 static nss_status_t
514 top_down_search(struct nss_innetgr_args *ia, char *netgrname)
515 {
516 	char			searchfilter[SEARCHFILTERLEN];
517 	char			name[SEARCHFILTERLEN];
518 	char			userdata[SEARCHFILTERLEN];
519 	ns_ldap_result_t	*result = NULL;
520 	ns_ldap_error_t		*error = NULL;
521 	int			rc;
522 	void			*cookie = NULL;
523 	nss_status_t		status = NSS_NOTFOUND;
524 	netgroup_table_t	tab;
525 	netgroup_name_t		*ng;
526 	int			ret;
527 
528 	(void) memset(&tab, 0, sizeof (tab));
529 
530 	if (add_netgroup_name(netgrname, &tab) != 0)
531 	    return ((nss_status_t)NSS_NOTFOUND);
532 
533 	while ((ng = get_next_netgroup(&tab)) != NULL) {
534 	    if (_ldap_filter_name(name, ng->name, sizeof (name)) != 0)
535 		break;
536 	    ret = snprintf(searchfilter, sizeof (searchfilter), _F_SETMEMBER,
537 		    name);
538 	    if (ret >= sizeof (searchfilter) || ret < 0)
539 		break;
540 
541 	    ret = snprintf(userdata, sizeof (userdata), _F_SETMEMBER_SSD, name);
542 	    if (ret >= sizeof (userdata) || ret < 0)
543 		break;
544 
545 	    rc = __ns_ldap_firstEntry(_NETGROUP, searchfilter,
546 		_merge_SSD_filter, netgrent_attrs, NULL, 0, &cookie, &result,
547 		&error, userdata);
548 
549 	    (void) __ns_ldap_freeError(&error);
550 	    while (rc == NS_LDAP_SUCCESS && result != NULL) {
551 		if (match_triple(ia, result) == 1) {
552 		    /* We found a match */
553 		    ia->status = NSS_NETGR_FOUND;
554 		    status = NSS_SUCCESS;
555 		    break;
556 		}
557 
558 		rc = add_netgroup_member(result, &tab);
559 		(void) __ns_ldap_freeResult(&result);
560 
561 		if (rc != NS_LDAP_SUCCESS)
562 			break;
563 		rc = __ns_ldap_nextEntry(cookie, &result, &error);
564 		(void) __ns_ldap_freeError(&error);
565 	    }
566 	    (void) __ns_ldap_freeResult(&result);
567 	    (void) __ns_ldap_endEntry(&cookie, &error);
568 	    (void) __ns_ldap_freeError(&error);
569 
570 	    if (status == NSS_SUCCESS ||
571 			(rc != NS_LDAP_SUCCESS && rc != NS_LDAP_NOTFOUND))
572 		break;
573 	}
574 
575 	(void) __ns_ldap_freeResult(&result);
576 	(void) __ns_ldap_endEntry(&cookie, &error);
577 	(void) __ns_ldap_freeError(&error);
578 	free_netgroup_table(&tab);
579 	return (status);
580 }
581 
582 /*
583  * __netgr_in checks only checks the netgroup specified in ngroup
584  */
585 static nss_status_t
586 __netgr_in(void *a, char *netgrname)
587 {
588 	struct nss_innetgr_args	*ia = (struct nss_innetgr_args *)a;
589 	nss_status_t		status = NSS_NOTFOUND;
590 
591 #ifdef DEBUG
592 	(void) fprintf(stdout, "\n[getnetgrent.c: netgr_in]\n");
593 	(void) fprintf(stdout, "\tmachine: argc[%d]='%s' user: "
594 			    "argc[%d]='%s',\n\tdomain:argc[%d]='%s' "
595 			    "netgroup: argc[%d]='%s'\n",
596 			    NSS_NETGR_MACHINE,
597 			    PRINT_VAL(ia->arg[NSS_NETGR_MACHINE]),
598 			    NSS_NETGR_USER,
599 			    PRINT_VAL(ia->arg[NSS_NETGR_USER]),
600 			    NSS_NETGR_DOMAIN,
601 			    PRINT_VAL(ia->arg[NSS_NETGR_DOMAIN]),
602 			    NSS_NETGR_N,
603 			    PRINT_VAL(ia->arg[NSS_NETGR_N]));
604 	(void) fprintf(stdout, "\tgroups='%s'\n", netgrname);
605 #endif	/* DEBUG */
606 
607 	ia->status = NSS_NETGR_NO;
608 
609 	if (netgrname == NULL)
610 		return (status);
611 
612 	return (top_down_search(ia, netgrname));
613 }
614 
615 /*ARGSUSED0*/
616 static nss_status_t
617 netgr_in(ldap_backend_ptr be, void *a)
618 {
619 	struct nss_innetgr_args	*ia = (struct nss_innetgr_args *)a;
620 	int	i;
621 	nss_status_t	rc = (nss_status_t)NSS_NOTFOUND;
622 
623 	ia->status = NSS_NETGR_NO;
624 	for (i = 0; i < ia->groups.argc; i++) {
625 		rc = __netgr_in(a, ia->groups.argv[i]);
626 		if (ia->status == NSS_NETGR_FOUND)
627 			return (NSS_SUCCESS);
628 	}
629 	return (rc);
630 }
631 
632 /*
633  *
634  */
635 
636 static nss_status_t
637 getnetgr_ldap_setent(ldap_backend_ptr be, void *a)
638 {
639 	const char	*netgroup = (const char *) a;
640 	getnetgrent_cookie_t	*cookie;
641 
642 #ifdef	DEBUG
643 	(void) fprintf(stdout, "\n[getnetgrent.c: getnetgr_ldap_setent]\n");
644 #endif	/* DEBUG */
645 
646 	cookie = (getnetgrent_cookie_t *)be->netgroup_cookie;
647 	if (cookie != NULL && cookie->netgroup != NULL) {
648 		/* is this another set on the same netgroup */
649 		if (strcmp(cookie->netgroup, netgroup) == 0)
650 			return ((nss_status_t)NSS_SUCCESS);
651 	}
652 
653 	return (NSS_NOTFOUND);
654 }
655 
656 static void
657 free_getnetgrent_cookie(getnetgrent_cookie_t **cookie)
658 {
659 	ns_ldap_error_t	*error = NULL;
660 	getnetgrent_cookie_t *p = *cookie;
661 
662 #ifdef DEBUG
663 	(void) fprintf(stdout, "\n[getnetgrent.c: free_getnetgrent_cookie]\n");
664 #endif	/* DEBUG */
665 
666 	if (p == NULL)
667 		return;
668 
669 	(void) __ns_ldap_freeResult(&p->results);
670 	(void) __ns_ldap_endEntry(&p->cookie, &error);
671 	(void) __ns_ldap_freeError(&error);
672 	free_netgroup_table(&p->tab);
673 	free(p->netgroup);
674 	free(p);
675 	*cookie = NULL;
676 }
677 
678 /*ARGSUSED1*/
679 static nss_status_t
680 getnetgr_ldap_endent(ldap_backend_ptr be, void *a)
681 {
682 
683 #ifdef	DEBUG
684 	(void) fprintf(stdout, "\n[getnetgrent.c: getnetgr_ldap_endent]\n");
685 #endif	/* DEBUG */
686 
687 	free_getnetgrent_cookie((getnetgrent_cookie_t **)&be->netgroup_cookie);
688 
689 	return ((nss_status_t)NSS_NOTFOUND);
690 }
691 
692 
693 /*ARGSUSED1*/
694 static nss_status_t
695 getnetgr_ldap_destr(ldap_backend_ptr be, void *a)
696 {
697 
698 #ifdef	DEBUG
699 	(void) fprintf(stdout, "\n[getnetgrent.c: getnetgr_ldap_destr]\n");
700 #endif	/* DEBUG */
701 
702 	free_getnetgrent_cookie((getnetgrent_cookie_t **)&be->netgroup_cookie);
703 	free(be);
704 
705 	return ((nss_status_t)NSS_NOTFOUND);
706 }
707 
708 
709 static nss_status_t
710 getnetgr_ldap_getent(ldap_backend_ptr be, void *a)
711 {
712 	struct nss_getnetgrent_args	*args;
713 	getnetgrent_cookie_t	*p;
714 	char			searchfilter[SEARCHFILTERLEN];
715 	char			userdata[SEARCHFILTERLEN];
716 	char			name[SEARCHFILTERLEN];
717 	int			rc;
718 	void			*cookie = NULL;
719 	ns_ldap_result_t	*result = NULL;
720 	ns_ldap_error_t		*error = NULL;
721 	char			**attrs;
722 	char			*hostname, *username, *domain;
723 	char			*buffer;
724 	nss_status_t		status = NSS_SUCCESS;
725 	netgroup_name_t		*ng;
726 	int			ret;
727 
728 #ifdef	DEBUG
729 	(void) fprintf(stdout, "\n[getnetgrent.c: getnetgr_ldap_getent]\n");
730 #endif	/* DEBUG */
731 
732 	args = (struct nss_getnetgrent_args *)a;
733 
734 	args->status = NSS_NETGR_NO;
735 
736 	p = (getnetgrent_cookie_t *)be->netgroup_cookie;
737 	if (p == NULL)
738 		return ((nss_status_t)NSS_SUCCESS);
739 
740 	for (;;) {
741 	    while (p->cookie == NULL) {
742 		ng = get_next_netgroup(&p->tab);
743 		if (ng == NULL)	 /* no more */
744 		    break;
745 
746 		if (_ldap_filter_name(name, ng->name, sizeof (name)) != 0)
747 			break;
748 
749 		ret = snprintf(searchfilter, sizeof (searchfilter),
750 			_F_SETMEMBER, name);
751 		if (ret >= sizeof (searchfilter) || ret < 0)
752 			break;
753 
754 		ret = snprintf(userdata, sizeof (userdata), _F_SETMEMBER_SSD,
755 			name);
756 		if (ret >= sizeof (userdata) || ret < 0)
757 			break;
758 
759 		result = NULL;
760 		rc = __ns_ldap_firstEntry(_NETGROUP, searchfilter,
761 			_merge_SSD_filter, netgrent_attrs, NULL, 0, &cookie,
762 			&result, &error, userdata);
763 		(void) __ns_ldap_freeError(&error);
764 
765 		if (rc == NS_LDAP_SUCCESS && result != NULL) {
766 			p->cookie = cookie;
767 			p->results = result;
768 			break;
769 		}
770 		(void) __ns_ldap_freeResult(&result);
771 		(void) __ns_ldap_endEntry(&cookie, &error);
772 		(void) __ns_ldap_freeError(&error);
773 	    }
774 	    if (p->cookie == NULL)
775 		break;
776 	    if (p->results == NULL) {
777 		result = NULL;
778 		rc = __ns_ldap_nextEntry(p->cookie, &result, &error);
779 		(void) __ns_ldap_freeError(&error);
780 		if (rc == NS_LDAP_SUCCESS && result != NULL)
781 			p->results = result;
782 		else {
783 		    (void) __ns_ldap_freeResult(&result);
784 		    (void) __ns_ldap_endEntry(&p->cookie, &error);
785 		    (void) __ns_ldap_freeError(&error);
786 		    p->cookie = NULL;
787 		}
788 	    }
789 	    if (p->results == NULL)
790 		continue;
791 
792 	    if (p->entry == NULL)
793 		p->entry = p->results->entry;
794 
795 	    if (p->entry == NULL)
796 		continue;
797 
798 	    if (p->attrs == NULL) {
799 		attrs = __ns_ldap_getAttr(p->entry, _N_TRIPLE);
800 		if (attrs != NULL && *attrs != NULL)
801 		    p->attrs = attrs;
802 	    }
803 
804 	    if (p->attrs != NULL) {
805 		attrs = p->attrs;
806 		buffer = args->buffer;
807 
808 		if (strlcpy(buffer, *attrs, args->buflen) >= args->buflen) {
809 		    status = NSS_STR_PARSE_ERANGE;
810 		    break;
811 		}
812 
813 		rc = split_triple(buffer, &hostname, &username, &domain);
814 		attrs++;
815 		if (attrs != NULL && *attrs != NULL)
816 		    p->attrs = attrs;
817 		else
818 		    p->attrs = NULL;
819 		if (rc == 0) {
820 		    args->retp[NSS_NETGR_MACHINE] = hostname;
821 		    args->retp[NSS_NETGR_USER] = username;
822 		    args->retp[NSS_NETGR_DOMAIN] = domain;
823 		    args->status = NSS_NETGR_FOUND;
824 		    if (p->attrs != NULL)
825 			break;
826 		}
827 	    }
828 
829 	    if (p->attrs == NULL) {
830 		rc = add_netgroup_member_entry(p->entry, &p->tab);
831 		if (rc != 0) {
832 		    args->status = NSS_NETGR_NO;
833 		    break;
834 		}
835 
836 		p->entry = p->entry->next;
837 		if (p->entry == NULL)
838 		    (void) __ns_ldap_freeResult(&p->results);
839 		if (args->status == NSS_NETGR_FOUND)
840 		    break;
841 	    }
842 	}
843 
844 	return (status);
845 }
846 
847 static ldap_backend_op_t getnetgroup_ops[] = {
848 	getnetgr_ldap_destr,
849 	getnetgr_ldap_endent,
850 	getnetgr_ldap_setent,
851 	getnetgr_ldap_getent,
852 };
853 
854 /*
855  *
856  */
857 
858 static nss_status_t
859 netgr_set(ldap_backend_ptr be, void *a)
860 {
861 	struct nss_setnetgrent_args	*args =
862 				(struct nss_setnetgrent_args *)a;
863 	ldap_backend_ptr		get_be;
864 	getnetgrent_cookie_t		*p;
865 
866 #ifdef DEBUG
867 	(void) fprintf(stdout, "\n[getnetgrent.c: netgr_set]\n");
868 	(void) fprintf(stdout,
869 		"\targs->netgroup: %s\n", ISNULL(args->netgroup));
870 #endif /* DEBUG */
871 
872 	if (args->netgroup == NULL)
873 		return ((nss_status_t)NSS_NOTFOUND);
874 
875 	free_getnetgrent_cookie((getnetgrent_cookie_t **)&be->netgroup_cookie);
876 	p = (getnetgrent_cookie_t *)calloc(1, sizeof (getnetgrent_cookie_t));
877 	if (p == NULL)
878 		return ((nss_status_t)NSS_NOTFOUND);
879 	p->netgroup = strdup(args->netgroup);
880 	if (p->netgroup == NULL) {
881 		free(p);
882 		return ((nss_status_t)NSS_NOTFOUND);
883 	}
884 	if (add_netgroup_name(args->netgroup, &p->tab) == -1) {
885 		free_getnetgrent_cookie(&p);
886 		return ((nss_status_t)NSS_NOTFOUND);
887 	}
888 
889 	/* now allocate and return iteration backend structure */
890 	if ((get_be = (ldap_backend_ptr)malloc(sizeof (*get_be))) == NULL)
891 		return (NSS_UNAVAIL);
892 	get_be->ops = getnetgroup_ops;
893 	get_be->nops = sizeof (getnetgroup_ops) / sizeof (getnetgroup_ops[0]);
894 	get_be->tablename = NULL;
895 	get_be->attrs = netgrent_attrs;
896 	get_be->result = NULL;
897 	get_be->ldapobj2ent = NULL;
898 	get_be->setcalled = 1;
899 	get_be->filter = NULL;
900 	get_be->toglue = NULL;
901 	get_be->enumcookie = NULL;
902 	get_be->netgroup_cookie = p;
903 	args->iterator = (nss_backend_t *)get_be;
904 
905 	(void) __ns_ldap_freeResult(&be->result);
906 
907 	return (NSS_SUCCESS);
908 }
909 
910 
911 /*ARGSUSED1*/
912 static nss_status_t
913 netgr_ldap_destr(ldap_backend_ptr be, void *a)
914 {
915 
916 #ifdef	DEBUG
917 	(void) fprintf(stdout, "\n[getnetgrent.c: netgr_ldap_destr]\n");
918 #endif	/* DEBUG */
919 
920 	(void) _clean_ldap_backend(be);
921 
922 	return ((nss_status_t)NSS_NOTFOUND);
923 }
924 
925 
926 
927 
928 static ldap_backend_op_t netgroup_ops[] = {
929 	netgr_ldap_destr,
930 	0,
931 	0,
932 	0,
933 	netgr_in,		/*	innetgr()	*/
934 	netgr_set		/*	setnetgrent()	*/
935 };
936 
937 
938 /*
939  * _nss_ldap_netgroup_constr is where life begins. This function calls the
940  * generic ldap constructor function to define and build the abstract data
941  * types required to support ldap operations.
942  */
943 
944 /*ARGSUSED0*/
945 nss_backend_t *
946 _nss_ldap_netgroup_constr(const char *dummy1, const char *dummy2,
947 			const char *dummy3)
948 {
949 
950 #ifdef	DEBUG
951 	(void) fprintf(stdout,
952 		    "\n[getnetgrent.c: _nss_ldap_netgroup_constr]\n");
953 #endif	/* DEBUG */
954 
955 	return ((nss_backend_t *)_nss_ldap_constr(netgroup_ops,
956 		sizeof (netgroup_ops)/sizeof (netgroup_ops[0]), _NETGROUP,
957 		netgrent_attrs, NULL));
958 }
959