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