getnetgrent.c revision 2830:5228d1267a01
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
48static const char *netgrent_attrs[] = {
49	_N_TRIPLE,
50	_N_MEMBER,
51	(char *)NULL
52};
53
54typedef struct netgroup_name {
55	char *name;
56	struct netgroup_name *next;
57	struct netgroup_name *next_hash;
58} netgroup_name_t;
59
60typedef 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
66typedef 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
75typedef 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
83typedef unsigned int hash_t;
84
85static hash_t
86get_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
105static int
106add_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
142static netgroup_name_t *
143get_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
159static void
160free_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 */
189static int
190domcmp(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
227static int
228split_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
302static int
303match_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
460static int
461match_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
472static int
473add_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
492static int
493add_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 */
509static nss_status_t
510top_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	netgroup_table_t	tab;
521	netgroup_name_t		*ng;
522	int			ret;
523
524	(void) memset(&tab, 0, sizeof (tab));
525
526	if (add_netgroup_name(netgrname, &tab) != 0)
527	    return ((nss_status_t)NSS_NOTFOUND);
528
529	while ((ng = get_next_netgroup(&tab)) != NULL) {
530	    if (_ldap_filter_name(name, ng->name, sizeof (name)) != 0)
531		break;
532	    ret = snprintf(searchfilter, sizeof (searchfilter), _F_SETMEMBER,
533		    name);
534	    if (ret >= sizeof (searchfilter) || ret < 0)
535		break;
536
537	    ret = snprintf(userdata, sizeof (userdata), _F_SETMEMBER_SSD, name);
538	    if (ret >= sizeof (userdata) || ret < 0)
539		break;
540
541	    rc = __ns_ldap_firstEntry(_NETGROUP, searchfilter,
542		_merge_SSD_filter, netgrent_attrs, NULL, 0, &cookie, &result,
543		&error, userdata);
544
545	    (void) __ns_ldap_freeError(&error);
546	    while (rc == NS_LDAP_SUCCESS && result != NULL) {
547		if (match_triple(ia, result) == 1) {
548		    /* We found a match */
549		    ia->status = NSS_NETGR_FOUND;
550		    status = NSS_SUCCESS;
551		    break;
552		}
553
554		rc = add_netgroup_member(result, &tab);
555		(void) __ns_ldap_freeResult(&result);
556
557		if (rc != NS_LDAP_SUCCESS)
558			break;
559		rc = __ns_ldap_nextEntry(cookie, &result, &error);
560		(void) __ns_ldap_freeError(&error);
561	    }
562	    (void) __ns_ldap_freeResult(&result);
563	    (void) __ns_ldap_endEntry(&cookie, &error);
564	    (void) __ns_ldap_freeError(&error);
565
566	    if (status == NSS_SUCCESS ||
567			(rc != NS_LDAP_SUCCESS && rc != NS_LDAP_NOTFOUND))
568		break;
569	}
570
571	(void) __ns_ldap_freeResult(&result);
572	(void) __ns_ldap_endEntry(&cookie, &error);
573	(void) __ns_ldap_freeError(&error);
574	free_netgroup_table(&tab);
575	return (status);
576}
577
578/*
579 * __netgr_in checks only checks the netgroup specified in ngroup
580 */
581static nss_status_t
582__netgr_in(void *a, char *netgrname)
583{
584	struct nss_innetgr_args	*ia = (struct nss_innetgr_args *)a;
585	nss_status_t		status = NSS_NOTFOUND;
586
587#ifdef DEBUG
588	(void) fprintf(stdout, "\n[getnetgrent.c: netgr_in]\n");
589	(void) fprintf(stdout, "\tmachine: argc[%d]='%s' user: "
590			    "argc[%d]='%s',\n\tdomain:argc[%d]='%s' "
591			    "netgroup: argc[%d]='%s'\n",
592			    NSS_NETGR_MACHINE,
593			    PRINT_VAL(ia->arg[NSS_NETGR_MACHINE]),
594			    NSS_NETGR_USER,
595			    PRINT_VAL(ia->arg[NSS_NETGR_USER]),
596			    NSS_NETGR_DOMAIN,
597			    PRINT_VAL(ia->arg[NSS_NETGR_DOMAIN]),
598			    NSS_NETGR_N,
599			    PRINT_VAL(ia->arg[NSS_NETGR_N]));
600	(void) fprintf(stdout, "\tgroups='%s'\n", netgrname);
601#endif	/* DEBUG */
602
603	ia->status = NSS_NETGR_NO;
604
605	if (netgrname == NULL)
606		return (status);
607
608	return (top_down_search(ia, netgrname));
609}
610
611/*ARGSUSED0*/
612static nss_status_t
613netgr_in(ldap_backend_ptr be, void *a)
614{
615	struct nss_innetgr_args	*ia = (struct nss_innetgr_args *)a;
616	int	i;
617	nss_status_t	rc = (nss_status_t)NSS_NOTFOUND;
618
619	ia->status = NSS_NETGR_NO;
620	for (i = 0; i < ia->groups.argc; i++) {
621		rc = __netgr_in(a, ia->groups.argv[i]);
622		if (ia->status == NSS_NETGR_FOUND)
623			return (NSS_SUCCESS);
624	}
625	return (rc);
626}
627
628/*
629 *
630 */
631
632static nss_status_t
633getnetgr_ldap_setent(ldap_backend_ptr be, void *a)
634{
635	const char	*netgroup = (const char *) a;
636	getnetgrent_cookie_t	*cookie;
637
638#ifdef	DEBUG
639	(void) fprintf(stdout, "\n[getnetgrent.c: getnetgr_ldap_setent]\n");
640#endif	/* DEBUG */
641
642	cookie = (getnetgrent_cookie_t *)be->netgroup_cookie;
643	if (cookie != NULL && cookie->netgroup != NULL) {
644		/* is this another set on the same netgroup */
645		if (strcmp(cookie->netgroup, netgroup) == 0)
646			return ((nss_status_t)NSS_SUCCESS);
647	}
648
649	return (NSS_NOTFOUND);
650}
651
652static void
653free_getnetgrent_cookie(getnetgrent_cookie_t **cookie)
654{
655	ns_ldap_error_t	*error = NULL;
656	getnetgrent_cookie_t *p = *cookie;
657
658#ifdef DEBUG
659	(void) fprintf(stdout, "\n[getnetgrent.c: free_getnetgrent_cookie]\n");
660#endif	/* DEBUG */
661
662	if (p == NULL)
663		return;
664
665	(void) __ns_ldap_freeResult(&p->results);
666	(void) __ns_ldap_endEntry(&p->cookie, &error);
667	(void) __ns_ldap_freeError(&error);
668	free_netgroup_table(&p->tab);
669	free(p->netgroup);
670	free(p);
671	*cookie = NULL;
672}
673
674/*ARGSUSED1*/
675static nss_status_t
676getnetgr_ldap_endent(ldap_backend_ptr be, void *a)
677{
678
679#ifdef	DEBUG
680	(void) fprintf(stdout, "\n[getnetgrent.c: getnetgr_ldap_endent]\n");
681#endif	/* DEBUG */
682
683	free_getnetgrent_cookie((getnetgrent_cookie_t **)&be->netgroup_cookie);
684
685	return ((nss_status_t)NSS_NOTFOUND);
686}
687
688
689/*ARGSUSED1*/
690static nss_status_t
691getnetgr_ldap_destr(ldap_backend_ptr be, void *a)
692{
693
694#ifdef	DEBUG
695	(void) fprintf(stdout, "\n[getnetgrent.c: getnetgr_ldap_destr]\n");
696#endif	/* DEBUG */
697
698	free_getnetgrent_cookie((getnetgrent_cookie_t **)&be->netgroup_cookie);
699	free(be);
700
701	return ((nss_status_t)NSS_NOTFOUND);
702}
703
704
705static nss_status_t
706getnetgr_ldap_getent(ldap_backend_ptr be, void *a)
707{
708	struct nss_getnetgrent_args	*args;
709	getnetgrent_cookie_t	*p;
710	char			searchfilter[SEARCHFILTERLEN];
711	char			userdata[SEARCHFILTERLEN];
712	char			name[SEARCHFILTERLEN];
713	int			rc;
714	void			*cookie = NULL;
715	ns_ldap_result_t	*result = NULL;
716	ns_ldap_error_t		*error = NULL;
717	char			**attrs;
718	char			*hostname, *username, *domain;
719	char			*buffer;
720	nss_status_t		status = NSS_SUCCESS;
721	netgroup_name_t		*ng;
722	int			ret;
723
724#ifdef	DEBUG
725	(void) fprintf(stdout, "\n[getnetgrent.c: getnetgr_ldap_getent]\n");
726#endif	/* DEBUG */
727
728	args = (struct nss_getnetgrent_args *)a;
729
730	args->status = NSS_NETGR_NO;
731
732	p = (getnetgrent_cookie_t *)be->netgroup_cookie;
733	if (p == NULL)
734		return ((nss_status_t)NSS_SUCCESS);
735
736	for (;;) {
737	    while (p->cookie == NULL) {
738		ng = get_next_netgroup(&p->tab);
739		if (ng == NULL)	 /* no more */
740		    break;
741
742		if (_ldap_filter_name(name, ng->name, sizeof (name)) != 0)
743			break;
744
745		ret = snprintf(searchfilter, sizeof (searchfilter),
746			_F_SETMEMBER, name);
747		if (ret >= sizeof (searchfilter) || ret < 0)
748			break;
749
750		ret = snprintf(userdata, sizeof (userdata), _F_SETMEMBER_SSD,
751			name);
752		if (ret >= sizeof (userdata) || ret < 0)
753			break;
754
755		result = NULL;
756		rc = __ns_ldap_firstEntry(_NETGROUP, searchfilter,
757			_merge_SSD_filter, netgrent_attrs, NULL, 0, &cookie,
758			&result, &error, userdata);
759		(void) __ns_ldap_freeError(&error);
760
761		if (rc == NS_LDAP_SUCCESS && result != NULL) {
762			p->cookie = cookie;
763			p->results = result;
764			break;
765		}
766		(void) __ns_ldap_freeResult(&result);
767		(void) __ns_ldap_endEntry(&cookie, &error);
768		(void) __ns_ldap_freeError(&error);
769	    }
770	    if (p->cookie == NULL)
771		break;
772	    if (p->results == NULL) {
773		result = NULL;
774		rc = __ns_ldap_nextEntry(p->cookie, &result, &error);
775		(void) __ns_ldap_freeError(&error);
776		if (rc == NS_LDAP_SUCCESS && result != NULL)
777			p->results = result;
778		else {
779		    (void) __ns_ldap_freeResult(&result);
780		    (void) __ns_ldap_endEntry(&p->cookie, &error);
781		    (void) __ns_ldap_freeError(&error);
782		    p->cookie = NULL;
783		}
784	    }
785	    if (p->results == NULL)
786		continue;
787
788	    if (p->entry == NULL)
789		p->entry = p->results->entry;
790
791	    if (p->entry == NULL)
792		continue;
793
794	    if (p->attrs == NULL) {
795		attrs = __ns_ldap_getAttr(p->entry, _N_TRIPLE);
796		if (attrs != NULL && *attrs != NULL)
797		    p->attrs = attrs;
798	    }
799
800	    if (p->attrs != NULL) {
801		attrs = p->attrs;
802		buffer = args->buffer;
803
804		if (strlcpy(buffer, *attrs, args->buflen) >= args->buflen) {
805		    status = NSS_STR_PARSE_ERANGE;
806		    break;
807		}
808
809		rc = split_triple(buffer, &hostname, &username, &domain);
810		attrs++;
811		if (attrs != NULL && *attrs != NULL)
812		    p->attrs = attrs;
813		else
814		    p->attrs = NULL;
815		if (rc == 0) {
816		    args->retp[NSS_NETGR_MACHINE] = hostname;
817		    args->retp[NSS_NETGR_USER] = username;
818		    args->retp[NSS_NETGR_DOMAIN] = domain;
819		    args->status = NSS_NETGR_FOUND;
820		    if (p->attrs != NULL)
821			break;
822		}
823	    }
824
825	    if (p->attrs == NULL) {
826		rc = add_netgroup_member_entry(p->entry, &p->tab);
827		if (rc != 0) {
828		    args->status = NSS_NETGR_NO;
829		    break;
830		}
831
832		p->entry = p->entry->next;
833		if (p->entry == NULL)
834		    (void) __ns_ldap_freeResult(&p->results);
835		if (args->status == NSS_NETGR_FOUND)
836		    break;
837	    }
838	}
839
840	return (status);
841}
842
843static ldap_backend_op_t getnetgroup_ops[] = {
844	getnetgr_ldap_destr,
845	getnetgr_ldap_endent,
846	getnetgr_ldap_setent,
847	getnetgr_ldap_getent,
848};
849
850/*
851 *
852 */
853
854static nss_status_t
855netgr_set(ldap_backend_ptr be, void *a)
856{
857	struct nss_setnetgrent_args	*args =
858				(struct nss_setnetgrent_args *)a;
859	ldap_backend_ptr		get_be;
860	getnetgrent_cookie_t		*p;
861
862#ifdef DEBUG
863	(void) fprintf(stdout, "\n[getnetgrent.c: netgr_set]\n");
864	(void) fprintf(stdout,
865		"\targs->netgroup: %s\n", ISNULL(args->netgroup));
866#endif /* DEBUG */
867
868	if (args->netgroup == NULL)
869		return ((nss_status_t)NSS_NOTFOUND);
870
871	free_getnetgrent_cookie((getnetgrent_cookie_t **)&be->netgroup_cookie);
872	p = (getnetgrent_cookie_t *)calloc(1, sizeof (getnetgrent_cookie_t));
873	if (p == NULL)
874		return ((nss_status_t)NSS_NOTFOUND);
875	p->netgroup = strdup(args->netgroup);
876	if (p->netgroup == NULL) {
877		free(p);
878		return ((nss_status_t)NSS_NOTFOUND);
879	}
880	if (add_netgroup_name(args->netgroup, &p->tab) == -1) {
881		free_getnetgrent_cookie(&p);
882		return ((nss_status_t)NSS_NOTFOUND);
883	}
884
885	/* now allocate and return iteration backend structure */
886	if ((get_be = (ldap_backend_ptr)malloc(sizeof (*get_be))) == NULL)
887		return (NSS_UNAVAIL);
888	get_be->ops = getnetgroup_ops;
889	get_be->nops = sizeof (getnetgroup_ops) / sizeof (getnetgroup_ops[0]);
890	get_be->tablename = NULL;
891	get_be->attrs = netgrent_attrs;
892	get_be->result = NULL;
893	get_be->ldapobj2str = NULL;
894	get_be->setcalled = 1;
895	get_be->filter = NULL;
896	get_be->toglue = NULL;
897	get_be->enumcookie = NULL;
898	get_be->netgroup_cookie = p;
899	args->iterator = (nss_backend_t *)get_be;
900
901	(void) __ns_ldap_freeResult(&be->result);
902
903	return (NSS_SUCCESS);
904}
905
906
907/*ARGSUSED1*/
908static nss_status_t
909netgr_ldap_destr(ldap_backend_ptr be, void *a)
910{
911
912#ifdef	DEBUG
913	(void) fprintf(stdout, "\n[getnetgrent.c: netgr_ldap_destr]\n");
914#endif	/* DEBUG */
915
916	(void) _clean_ldap_backend(be);
917
918	return ((nss_status_t)NSS_NOTFOUND);
919}
920
921
922
923
924static ldap_backend_op_t netgroup_ops[] = {
925	netgr_ldap_destr,
926	0,
927	0,
928	0,
929	netgr_in,		/*	innetgr()	*/
930	netgr_set		/*	setnetgrent()	*/
931};
932
933
934/*
935 * _nss_ldap_netgroup_constr is where life begins. This function calls the
936 * generic ldap constructor function to define and build the abstract data
937 * types required to support ldap operations.
938 */
939
940/*ARGSUSED0*/
941nss_backend_t *
942_nss_ldap_netgroup_constr(const char *dummy1, const char *dummy2,
943			const char *dummy3)
944{
945
946#ifdef	DEBUG
947	(void) fprintf(stdout,
948		    "\n[getnetgrent.c: _nss_ldap_netgroup_constr]\n");
949#endif	/* DEBUG */
950
951	return ((nss_backend_t *)_nss_ldap_constr(netgroup_ops,
952		sizeof (netgroup_ops)/sizeof (netgroup_ops[0]), _NETGROUP,
953		netgrent_attrs, NULL));
954}
955