xref: /titanic_50/usr/src/lib/nsswitch/ldap/common/getnetgrent.c (revision 4703203d9b3e06246d73931f07359a7ef70f47bf)
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 2007 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 			/* limit hostname to COMMA */
404 			if ((limit = strchr(current, COMMA)) == NULL)
405 				continue;
406 			*limit = '\0';
407 
408 			/* remove blanks before COMMA */
409 			if ((limit = strpbrk(current, " \t")) != NULL)
410 				*limit = '\0';
411 
412 			/* compare size of hostname */
413 			if (phlen != strlen(current)) {
414 				continue;
415 			}
416 
417 			/* do actual compare */
418 			if (strncasecmp(phost0, current, phlen) == 0) {
419 				return (1);
420 			} else {
421 				continue;
422 			}
423 		}
424 	} else {
425 		for (; *attr; attr++) {
426 			if (strlcpy(triple, *attr,
427 			    sizeof (triple)) >= sizeof (triple))
428 				continue;
429 			if (split_triple(triple, &thost, &tuser, &tdomain) != 0)
430 				continue;
431 			if (thost != NULL && *thost != '\0' && nhost != 0) {
432 				for (i = 0; i < nhost; i++)
433 					if (strcasecmp(thost, phost[i]) == 0)
434 						break;
435 				if (i == nhost)
436 					continue;
437 			}
438 			if (tuser != NULL && *tuser != '\0' && nusers != 0) {
439 				for (i = 0; i < nusers; i++)
440 					if (strcmp(tuser, pusers[i]) == 0)
441 						break;
442 				if (i == nusers)
443 					continue;
444 			}
445 			if (tdomain != NULL && *tdomain != '\0' &&
446 			    ndomains != 0) {
447 				for (i = 0; i < ndomains; i++)
448 					if (domcmp(tdomain, pdomains[i]) == 0)
449 						break;
450 				if (i == ndomains)
451 					continue;
452 			}
453 			return (1);
454 		}
455 	}
456 
457 	return (0);
458 }
459 
460 static int
461 match_triple(struct nss_innetgr_args *ia, ns_ldap_result_t *result)
462 {
463 	ns_ldap_entry_t	*entry;
464 
465 	for (entry = result->entry; entry != NULL; entry = entry->next)
466 		if (match_triple_entry(ia, entry) == 1)
467 			return (1);
468 
469 	return (0);
470 }
471 
472 static int
473 add_netgroup_member_entry(ns_ldap_entry_t *entry, netgroup_table_t *tab)
474 {
475 	char		**attrs;
476 	char		**a;
477 
478 	attrs = __ns_ldap_getAttr(entry, _N_MEMBER);
479 	if (attrs == NULL || *attrs == NULL)
480 		return (0);
481 
482 	for (a = attrs; *a != NULL; a++) {}
483 
484 	do {
485 		a--;
486 		if (add_netgroup_name(*a, tab) != 0)
487 			return (-1);
488 	} while (a > attrs);
489 	return (0);
490 }
491 
492 static int
493 add_netgroup_member(ns_ldap_result_t *result, netgroup_table_t *tab)
494 {
495 	ns_ldap_entry_t	*entry;
496 	int		ret = 0;
497 
498 	for (entry = result->entry; entry != NULL; entry = entry->next) {
499 		ret = add_netgroup_member_entry(entry, tab);
500 		if (ret != 0)
501 			break;
502 	}
503 	return (ret);
504 }
505 
506 /*
507  * top_down_search checks only checks the netgroup specified in netgrname
508  */
509 static nss_status_t
510 top_down_search(struct nss_innetgr_args *ia, char *netgrname)
511 {
512 	char			searchfilter[SEARCHFILTERLEN];
513 	char			name[SEARCHFILTERLEN];
514 	char			userdata[SEARCHFILTERLEN];
515 	ns_ldap_result_t	*result = NULL;
516 	ns_ldap_error_t		*error = NULL;
517 	int			rc;
518 	void			*cookie = NULL;
519 	nss_status_t		status = NSS_NOTFOUND;
520 	nss_status_t		status1;
521 	netgroup_table_t	tab;
522 	netgroup_name_t		*ng;
523 	int			ret;
524 
525 	(void) memset(&tab, 0, sizeof (tab));
526 
527 	if (add_netgroup_name(netgrname, &tab) != 0)
528 		return ((nss_status_t)NSS_NOTFOUND);
529 
530 	while ((ng = get_next_netgroup(&tab)) != NULL) {
531 		if (_ldap_filter_name(name, ng->name, sizeof (name)) != 0)
532 			break;
533 		ret = snprintf(searchfilter, sizeof (searchfilter),
534 		    _F_SETMEMBER, name);
535 		if (ret >= sizeof (searchfilter) || ret < 0)
536 			break;
537 
538 		ret = snprintf(userdata, sizeof (userdata), _F_SETMEMBER_SSD,
539 		    name);
540 		if (ret >= sizeof (userdata) || ret < 0)
541 			break;
542 
543 		rc = __ns_ldap_firstEntry(_NETGROUP, searchfilter,
544 		    _merge_SSD_filter, netgrent_attrs, NULL, 0, &cookie,
545 		    &result, &error, userdata);
546 
547 		if (error != NULL) {
548 			status1 = switch_err(rc, error);
549 			if (status1 == NSS_TRYAGAIN) {
550 				(void) __ns_ldap_freeError(&error);
551 				free_netgroup_table(&tab);
552 				return (status1);
553 			}
554 		}
555 
556 		(void) __ns_ldap_freeError(&error);
557 		while (rc == NS_LDAP_SUCCESS && result != NULL) {
558 			if (match_triple(ia, result) == 1) {
559 				/* We found a match */
560 				ia->status = NSS_NETGR_FOUND;
561 				status = NSS_SUCCESS;
562 				break;
563 			}
564 
565 			rc = add_netgroup_member(result, &tab);
566 			(void) __ns_ldap_freeResult(&result);
567 
568 			if (rc != NS_LDAP_SUCCESS)
569 				break;
570 			rc = __ns_ldap_nextEntry(cookie, &result, &error);
571 			if (error != NULL) {
572 				status1 = switch_err(rc, error);
573 				if (status1 == NSS_TRYAGAIN) {
574 					free_netgroup_table(&tab);
575 					(void) __ns_ldap_freeError(&error);
576 					(void) __ns_ldap_endEntry(&cookie,
577 					    &error);
578 					(void) __ns_ldap_freeError(&error);
579 					return (status1);
580 				}
581 			}
582 			(void) __ns_ldap_freeError(&error);
583 		}
584 		(void) __ns_ldap_freeResult(&result);
585 		(void) __ns_ldap_endEntry(&cookie, &error);
586 		(void) __ns_ldap_freeError(&error);
587 
588 		if (status == NSS_SUCCESS ||
589 		    (rc != NS_LDAP_SUCCESS && rc != NS_LDAP_NOTFOUND))
590 		break;
591 	}
592 
593 	(void) __ns_ldap_freeResult(&result);
594 	(void) __ns_ldap_endEntry(&cookie, &error);
595 	(void) __ns_ldap_freeError(&error);
596 	free_netgroup_table(&tab);
597 	return (status);
598 }
599 
600 /*
601  * __netgr_in checks only checks the netgroup specified in ngroup
602  */
603 static nss_status_t
604 __netgr_in(void *a, char *netgrname)
605 {
606 	struct nss_innetgr_args	*ia = (struct nss_innetgr_args *)a;
607 	nss_status_t		status = NSS_NOTFOUND;
608 
609 #ifdef DEBUG
610 	(void) fprintf(stdout, "\n[getnetgrent.c: netgr_in]\n");
611 	(void) fprintf(stdout, "\tmachine: argc[%d]='%s' user: "
612 	    "argc[%d]='%s',\n\tdomain:argc[%d]='%s' "
613 	    "netgroup: argc[%d]='%s'\n",
614 	    NSS_NETGR_MACHINE,
615 	    PRINT_VAL(ia->arg[NSS_NETGR_MACHINE]),
616 	    NSS_NETGR_USER,
617 	    PRINT_VAL(ia->arg[NSS_NETGR_USER]),
618 	    NSS_NETGR_DOMAIN,
619 	    PRINT_VAL(ia->arg[NSS_NETGR_DOMAIN]),
620 	    NSS_NETGR_N,
621 	    PRINT_VAL(ia->arg[NSS_NETGR_N]));
622 	(void) fprintf(stdout, "\tgroups='%s'\n", netgrname);
623 #endif	/* DEBUG */
624 
625 	ia->status = NSS_NETGR_NO;
626 
627 	if (netgrname == NULL)
628 		return (status);
629 
630 	return (top_down_search(ia, netgrname));
631 }
632 
633 /*ARGSUSED0*/
634 static nss_status_t
635 netgr_in(ldap_backend_ptr be, void *a)
636 {
637 	struct nss_innetgr_args	*ia = (struct nss_innetgr_args *)a;
638 	int	i;
639 	nss_status_t	rc = (nss_status_t)NSS_NOTFOUND;
640 
641 	ia->status = NSS_NETGR_NO;
642 	for (i = 0; i < ia->groups.argc; i++) {
643 		rc = __netgr_in(a, ia->groups.argv[i]);
644 		if (ia->status == NSS_NETGR_FOUND)
645 			return (NSS_SUCCESS);
646 	}
647 	return (rc);
648 }
649 
650 /*
651  *
652  */
653 
654 static nss_status_t
655 getnetgr_ldap_setent(ldap_backend_ptr be, void *a)
656 {
657 	const char	*netgroup = (const char *) a;
658 	getnetgrent_cookie_t	*cookie;
659 
660 #ifdef	DEBUG
661 	(void) fprintf(stdout, "\n[getnetgrent.c: getnetgr_ldap_setent]\n");
662 #endif	/* DEBUG */
663 
664 	cookie = (getnetgrent_cookie_t *)be->netgroup_cookie;
665 	if (cookie != NULL && cookie->netgroup != NULL) {
666 		/* is this another set on the same netgroup */
667 		if (strcmp(cookie->netgroup, netgroup) == 0)
668 			return ((nss_status_t)NSS_SUCCESS);
669 	}
670 
671 	return (NSS_NOTFOUND);
672 }
673 
674 static void
675 free_getnetgrent_cookie(getnetgrent_cookie_t **cookie)
676 {
677 	ns_ldap_error_t	*error = NULL;
678 	getnetgrent_cookie_t *p = *cookie;
679 
680 #ifdef DEBUG
681 	(void) fprintf(stdout, "\n[getnetgrent.c: free_getnetgrent_cookie]\n");
682 #endif	/* DEBUG */
683 
684 	if (p == NULL)
685 		return;
686 
687 	(void) __ns_ldap_freeResult(&p->results);
688 	(void) __ns_ldap_endEntry(&p->cookie, &error);
689 	(void) __ns_ldap_freeError(&error);
690 	free_netgroup_table(&p->tab);
691 	free(p->netgroup);
692 	free(p);
693 	*cookie = NULL;
694 }
695 
696 /*ARGSUSED1*/
697 static nss_status_t
698 getnetgr_ldap_endent(ldap_backend_ptr be, void *a)
699 {
700 
701 #ifdef	DEBUG
702 	(void) fprintf(stdout, "\n[getnetgrent.c: getnetgr_ldap_endent]\n");
703 #endif	/* DEBUG */
704 
705 	free_getnetgrent_cookie((getnetgrent_cookie_t **)&be->netgroup_cookie);
706 
707 	return ((nss_status_t)NSS_NOTFOUND);
708 }
709 
710 
711 /*ARGSUSED1*/
712 static nss_status_t
713 getnetgr_ldap_destr(ldap_backend_ptr be, void *a)
714 {
715 
716 #ifdef	DEBUG
717 	(void) fprintf(stdout, "\n[getnetgrent.c: getnetgr_ldap_destr]\n");
718 #endif	/* DEBUG */
719 
720 	free_getnetgrent_cookie((getnetgrent_cookie_t **)&be->netgroup_cookie);
721 	free(be);
722 
723 	return ((nss_status_t)NSS_NOTFOUND);
724 }
725 
726 
727 static nss_status_t
728 getnetgr_ldap_getent(ldap_backend_ptr be, void *a)
729 {
730 	struct nss_getnetgrent_args	*args;
731 	getnetgrent_cookie_t	*p;
732 	char			searchfilter[SEARCHFILTERLEN];
733 	char			userdata[SEARCHFILTERLEN];
734 	char			name[SEARCHFILTERLEN];
735 	int			rc;
736 	void			*cookie = NULL;
737 	ns_ldap_result_t	*result = NULL;
738 	ns_ldap_error_t		*error = NULL;
739 	char			**attrs;
740 	char			*hostname, *username, *domain;
741 	char			*buffer;
742 	nss_status_t		status = NSS_SUCCESS;
743 	netgroup_name_t		*ng;
744 	int			ret;
745 
746 #ifdef	DEBUG
747 	(void) fprintf(stdout, "\n[getnetgrent.c: getnetgr_ldap_getent]\n");
748 #endif	/* DEBUG */
749 
750 	args = (struct nss_getnetgrent_args *)a;
751 
752 	args->status = NSS_NETGR_NO;
753 
754 	p = (getnetgrent_cookie_t *)be->netgroup_cookie;
755 	if (p == NULL)
756 		return ((nss_status_t)NSS_SUCCESS);
757 
758 	for (;;) {
759 		while (p->cookie == NULL) {
760 			ng = get_next_netgroup(&p->tab);
761 			if (ng == NULL)	 /* no more */
762 				break;
763 
764 			if (_ldap_filter_name(name, ng->name,
765 			    sizeof (name)) != 0)
766 				break;
767 
768 			ret = snprintf(searchfilter,
769 			    sizeof (searchfilter),
770 			    _F_SETMEMBER, name);
771 			if (ret >= sizeof (searchfilter) || ret < 0)
772 				break;
773 
774 			ret = snprintf(userdata, sizeof (userdata),
775 			    _F_SETMEMBER_SSD, name);
776 			if (ret >= sizeof (userdata) || ret < 0)
777 				break;
778 
779 			result = NULL;
780 			rc = __ns_ldap_firstEntry(_NETGROUP,
781 			    searchfilter,
782 			    _merge_SSD_filter, netgrent_attrs,
783 			    NULL, 0, &cookie,
784 			    &result, &error, userdata);
785 			(void) __ns_ldap_freeError(&error);
786 
787 			if (rc == NS_LDAP_SUCCESS && result != NULL) {
788 				p->cookie = cookie;
789 				p->results = result;
790 				break;
791 			}
792 			(void) __ns_ldap_freeResult(&result);
793 			(void) __ns_ldap_endEntry(&cookie, &error);
794 			(void) __ns_ldap_freeError(&error);
795 		}
796 		if (p->cookie == NULL)
797 			break;
798 		if (p->results == NULL) {
799 			result = NULL;
800 			rc = __ns_ldap_nextEntry(p->cookie, &result,
801 			    &error);
802 			(void) __ns_ldap_freeError(&error);
803 			if (rc == NS_LDAP_SUCCESS && result != NULL)
804 				p->results = result;
805 			else {
806 				(void) __ns_ldap_freeResult(&result);
807 				(void) __ns_ldap_endEntry(&p->cookie,
808 				    &error);
809 				(void) __ns_ldap_freeError(&error);
810 				p->cookie = NULL;
811 			}
812 		}
813 		if (p->results == NULL)
814 			continue;
815 
816 		if (p->entry == NULL)
817 			p->entry = p->results->entry;
818 
819 		if (p->entry == NULL)
820 			continue;
821 
822 		if (p->attrs == NULL) {
823 			attrs = __ns_ldap_getAttr(p->entry, _N_TRIPLE);
824 			if (attrs != NULL && *attrs != NULL)
825 				p->attrs = attrs;
826 		}
827 
828 		if (p->attrs != NULL) {
829 			attrs = p->attrs;
830 			buffer = args->buffer;
831 
832 			if (strlcpy(buffer, *attrs, args->buflen) >=
833 			    args->buflen) {
834 				status = NSS_STR_PARSE_ERANGE;
835 				break;
836 			}
837 
838 			rc = split_triple(buffer, &hostname, &username,
839 			    &domain);
840 			attrs++;
841 			if (attrs != NULL && *attrs != NULL)
842 				p->attrs = attrs;
843 			else
844 				p->attrs = NULL;
845 			if (rc == 0) {
846 				args->retp[NSS_NETGR_MACHINE] = hostname;
847 				args->retp[NSS_NETGR_USER] = username;
848 				args->retp[NSS_NETGR_DOMAIN] = domain;
849 				args->status = NSS_NETGR_FOUND;
850 				if (p->attrs != NULL)
851 					break;
852 			}
853 		}
854 
855 		if (p->attrs == NULL) {
856 			rc = add_netgroup_member_entry(p->entry, &p->tab);
857 			if (rc != 0) {
858 				args->status = NSS_NETGR_NO;
859 				break;
860 			}
861 
862 			p->entry = p->entry->next;
863 			if (p->entry == NULL)
864 				(void) __ns_ldap_freeResult(&p->results);
865 			if (args->status == NSS_NETGR_FOUND)
866 				break;
867 		}
868 	}
869 
870 	return (status);
871 }
872 
873 static ldap_backend_op_t getnetgroup_ops[] = {
874 	getnetgr_ldap_destr,
875 	getnetgr_ldap_endent,
876 	getnetgr_ldap_setent,
877 	getnetgr_ldap_getent,
878 };
879 
880 /*
881  *
882  */
883 
884 static nss_status_t
885 netgr_set(ldap_backend_ptr be, void *a)
886 {
887 	struct nss_setnetgrent_args	*args =
888 	    (struct nss_setnetgrent_args *)a;
889 	ldap_backend_ptr		get_be;
890 	getnetgrent_cookie_t		*p;
891 
892 #ifdef DEBUG
893 	(void) fprintf(stdout, "\n[getnetgrent.c: netgr_set]\n");
894 	(void) fprintf(stdout,
895 	    "\targs->netgroup: %s\n", ISNULL(args->netgroup));
896 #endif /* DEBUG */
897 
898 	if (args->netgroup == NULL)
899 		return ((nss_status_t)NSS_NOTFOUND);
900 
901 	free_getnetgrent_cookie((getnetgrent_cookie_t **)&be->netgroup_cookie);
902 	p = (getnetgrent_cookie_t *)calloc(1, sizeof (getnetgrent_cookie_t));
903 	if (p == NULL)
904 		return ((nss_status_t)NSS_NOTFOUND);
905 	p->netgroup = strdup(args->netgroup);
906 	if (p->netgroup == NULL) {
907 		free(p);
908 		return ((nss_status_t)NSS_NOTFOUND);
909 	}
910 	if (add_netgroup_name(args->netgroup, &p->tab) == -1) {
911 		free_getnetgrent_cookie(&p);
912 		return ((nss_status_t)NSS_NOTFOUND);
913 	}
914 
915 	/* now allocate and return iteration backend structure */
916 	if ((get_be = (ldap_backend_ptr)malloc(sizeof (*get_be))) == NULL)
917 		return (NSS_UNAVAIL);
918 	get_be->ops = getnetgroup_ops;
919 	get_be->nops = sizeof (getnetgroup_ops) / sizeof (getnetgroup_ops[0]);
920 	get_be->tablename = NULL;
921 	get_be->attrs = netgrent_attrs;
922 	get_be->result = NULL;
923 	get_be->ldapobj2str = NULL;
924 	get_be->setcalled = 1;
925 	get_be->filter = NULL;
926 	get_be->toglue = NULL;
927 	get_be->enumcookie = NULL;
928 	get_be->netgroup_cookie = p;
929 	args->iterator = (nss_backend_t *)get_be;
930 
931 	(void) __ns_ldap_freeResult(&be->result);
932 
933 	return (NSS_SUCCESS);
934 }
935 
936 
937 /*ARGSUSED1*/
938 static nss_status_t
939 netgr_ldap_destr(ldap_backend_ptr be, void *a)
940 {
941 
942 #ifdef	DEBUG
943 	(void) fprintf(stdout, "\n[getnetgrent.c: netgr_ldap_destr]\n");
944 #endif	/* DEBUG */
945 
946 	(void) _clean_ldap_backend(be);
947 
948 	return ((nss_status_t)NSS_NOTFOUND);
949 }
950 
951 
952 
953 
954 static ldap_backend_op_t netgroup_ops[] = {
955 	netgr_ldap_destr,
956 	0,
957 	0,
958 	0,
959 	netgr_in,		/*	innetgr()	*/
960 	netgr_set		/*	setnetgrent()	*/
961 };
962 
963 
964 /*
965  * _nss_ldap_netgroup_constr is where life begins. This function calls the
966  * generic ldap constructor function to define and build the abstract data
967  * types required to support ldap operations.
968  */
969 
970 /*ARGSUSED0*/
971 nss_backend_t *
972 _nss_ldap_netgroup_constr(const char *dummy1, const char *dummy2,
973 			const char *dummy3)
974 {
975 
976 #ifdef	DEBUG
977 	(void) fprintf(stdout,
978 	    "\n[getnetgrent.c: _nss_ldap_netgroup_constr]\n");
979 #endif	/* DEBUG */
980 
981 	return ((nss_backend_t *)_nss_ldap_constr(netgroup_ops,
982 	    sizeof (netgroup_ops)/sizeof (netgroup_ops[0]), _NETGROUP,
983 	    netgrent_attrs, NULL));
984 }
985