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