1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
7 * Reserved.  This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License").  You may not use this file
10 * except in compliance with the License.  Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT.  Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24#if !defined(lint) && defined(SCCSIDS)
25static	char sccsid[] = "@(#)getnetgrent.c	1.2 90/07/20 4.1NFSSRC; from 1.22 88/02/08 Copyr 1985 Sun Micro";
26#endif
27
28/*
29 * Copyright (c) 1985 by Sun Microsystems, Inc.
30 */
31
32#include <stdio.h>
33#include <ctype.h>
34#include <stdlib.h>
35#include <string.h>
36#include <rpcsvc/ypclnt.h>
37
38#define MAXGROUPLEN 1024
39
40/*
41 * access members of a netgroup
42 */
43
44static struct grouplist {		/* also used by pwlib */
45	char	*gl_machine;
46	char	*gl_name;
47	char	*gl_domain;
48	struct	grouplist *gl_nxt;
49} *grouplist, *grlist;
50
51
52struct list {			/* list of names to check for loops */
53	char *name;
54	struct list *nxt;
55};
56
57static	void doit();
58static	char *fill();
59static	char *match();
60
61static	char *domain;
62static	char *oldgrp;
63
64char	*NETGROUP = "netgroup";
65
66void _old_endnetgrent(void);
67void _old_setnetgrent(char *);
68
69void _old_setnetgrent(grp)
70	char *grp;
71{
72
73	if (oldgrp == NULL)
74		oldgrp = (char *)calloc(1,256);
75	if (strcmp(oldgrp, grp) == 0)
76		grlist = grouplist;
77	else {
78		if (grouplist != NULL)
79			_old_endnetgrent();
80		doit(grp, (struct list *) NULL);
81		grlist = grouplist;
82		(void) strcpy(oldgrp, grp);
83	}
84}
85
86void _old_endnetgrent()
87{
88	register struct grouplist *gl;
89
90	for (gl = grouplist; gl != NULL; gl = gl->gl_nxt) {
91		if (gl->gl_name)
92			free(gl->gl_name);
93		if (gl->gl_domain)
94			free(gl->gl_domain);
95		if (gl->gl_machine)
96			free(gl->gl_machine);
97		free((char *) gl);
98	}
99	grouplist = NULL;
100	grlist = NULL;
101	if (oldgrp) {
102		free(oldgrp);
103		oldgrp = 0;
104	}
105}
106
107int _old_getnetgrent(machinep, namep, domainp)
108	char **machinep, **namep, **domainp;
109{
110
111	if (grlist == 0)
112		return (0);
113	*machinep = grlist->gl_machine;
114	*namep = grlist->gl_name;
115	*domainp = grlist->gl_domain;
116	grlist = grlist->gl_nxt;
117	return (1);
118}
119
120/*
121 * recursive function to find the members of netgroup "group". "list" is
122 * the path followed through the netgroups so far, to check for cycles.
123 */
124static void
125doit(group,list)
126	char *group;
127	struct list *list;
128{
129	register char *p, *q;
130	register struct list *ls;
131	struct list this_group;
132	char *val;
133	struct grouplist *gpls;
134
135	/*
136	 * check for non-existing groups
137	 */
138	if ((val = match(group)) == NULL)
139		return;
140
141	/*
142	 * check for cycles
143	 */
144	for (ls = list; ls != NULL; ls = ls->nxt)
145		if (strcmp(ls->name, group) == 0) {
146			(void) fprintf(stderr,
147			    "Cycle detected in /etc/netgroup: %s.\n", group);
148			return;
149		}
150
151	ls = &this_group;
152	ls->name = group;
153	ls->nxt = list;
154	list = ls;
155
156	p = val;
157	while (p != NULL) {
158		while (*p == ' ' || *p == '\t')
159			p++;
160		if (*p == 0 || *p =='#')
161			break;
162		if (*p == '(') {
163			gpls = (struct grouplist *)
164			    malloc(sizeof(struct grouplist));
165			p++;
166			if (!(p = fill(p,&gpls->gl_machine,',')))
167				goto syntax_error;
168			if (!(p = fill(p,&gpls->gl_name,',')))
169				goto syntax_error;
170			if (!(p = fill(p,&gpls->gl_domain,')')))
171				goto syntax_error;
172			gpls->gl_nxt = grouplist;
173			grouplist = gpls;
174		} else {
175			q = strpbrk(p, " \t\n#");
176			if (q && *q == '#')
177				break;
178			*q = 0;
179			doit(p,list);
180			*q = ' ';
181		}
182		p = strpbrk(p, " \t");
183	}
184	return;
185
186syntax_error:
187	(void) fprintf(stderr,"syntax error in /etc/netgroup\n");
188	(void) fprintf(stderr,"--- %s\n",val);
189	return;
190}
191
192/*
193 * Fill a buffer "target" selectively from buffer "start".
194 * "termchar" terminates the information in start, and preceding
195 * or trailing white space is ignored. The location just after the
196 * terminating character is returned.
197 */
198static char *
199fill(start,target,termchar)
200	char *start, **target, termchar;
201{
202	register char *p, *q;
203	char *r;
204	unsigned size;
205
206	for (p = start; *p == ' ' || *p == '\t'; p++)
207		;
208	r = index(p, termchar);
209	if (r == NULL)
210		return (NULL);
211	if (p == r)
212		*target = NULL;
213	else {
214		for (q = r-1; *q == ' ' || *q == '\t'; q--)
215			;
216		size = q - p + 1;
217		*target = malloc(size+1);
218		(void) strncpy(*target,p,(int) size);
219		(*target)[size] = 0;
220	}
221	return (r+1);
222}
223
224static char *
225match(group)
226	char *group;
227{
228	char *val;
229	int vallen;
230
231	if (domain == NULL)
232		(void) yp_get_default_domain(&domain );
233	if (yp_match(domain, NETGROUP, group, strlen(group), &val, &vallen))
234		return (NULL);
235	return (val);
236}
237