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 (c) 1994, by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 /*
28  * For SUNWnskit - version 1.1
29  *
30  * Based on:
31  *	#pragma ident	"%Z%%M%	%I%	%E% SMI"	(SMI4.1 1.6)
32  */
33 
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <stdio.h>
38 #include <ctype.h>
39 #include <pwd.h>
40 #include <rpcsvc/ypclnt.h>
41 #include "util.h"
42 #include "table.h"
43 #include "getgroup.h"
44 
45 #define	MAXDOMAINLEN 256
46 #define	MAXGROUPLEN 1024
47 
48 /*
49  * Reverse the netgroup file. A flag of "-u" means reverse by username,
50  * one of "-h" means reverse by hostname. Each line in the output file
51  * will begin with a key formed by concatenating the host or user name
52  * with the domain name. The key will be followed by a tab, then the
53  * comma-separated, newline-terminated list of groups to which the
54  * user or host belongs.
55  *
56  * Exception: Groups to which everyone belongs (universal groups) will
57  * not be included in the list.  The universal groups will be listed under
58  * the special name "*".
59  *
60  * Thus to find out all the groups that user "foo" of domain "bar" is in,
61  * lookup the groups under  foo.bar, foo.*, *.bar and *.*.
62  *
63  */
64 
65 
66 
67 /* Stores a list of strings */
68 typedef struct stringnode *stringlist;
69 struct stringnode {
70     char *str;
71     stringlist next;
72 };
73 typedef struct stringnode stringnode;
74 
75 
76 
77 /* Stores a list of (name,list-of-groups) */
78 typedef struct groupentrynode *groupentrylist;
79 struct groupentrynode {
80     char *name;
81     stringlist groups;
82     groupentrylist next;
83 };
84 typedef struct groupentrynode groupentrynode;
85 
86 stringtable ngtable;
87 
88 static groupentrylist grouptable[TABLESIZE];
89 
90 static char *nextgroup(void);
91 static void storegroup(char *group, struct grouplist *glist, int byuser);
92 static void enter(char *name, char *group);
93 static void appendgroup(groupentrylist grlist, char *group);
94 static groupentrylist newentry(char *name, char *group);
95 static void loadtable(FILE *nf);
96 static void dumptable(void);
97 
98 int
99 main(argc, argv)
100     int argc;
101     char *argv[];
102 {
103 	char *group;
104 	struct grouplist *glist;
105 	int byuser;
106 
107 	loadtable(stdin);
108 	if (argc == 2 && argv[1][0] == '-' &&
109 			(argv[1][1] == 'u' || argv[1][1] == 'h')) {
110 		byuser = (argv[1][1] == 'u');
111 	} else {
112 		(void) fprintf(stderr,
113 				"usage: %s -h (by host), %s -u (by user)\n",
114 				argv[0], argv[0]);
115 		exit(1);
116 	}
117 
118 	while (group = nextgroup()) {
119 		glist = my_getgroup(group);
120 		storegroup(group, glist, byuser);
121 	}
122 	dumptable();
123 
124 	return (0);
125 }
126 
127 /*
128  *	Get the next netgroup from /etc/netgroup
129  */
130 static char *
131 nextgroup(void)
132 {
133 	static int index = -1;
134 	static tablelist cur = NULL;
135 	char *group;
136 
137 	while (cur == NULL) {
138 		if (++index == TABLESIZE) {
139 			return (NULL);
140 		}
141 		cur = ngtable[index];
142 	}
143 	group = cur->key;
144 	cur = cur->next;
145 	return (group);
146 }
147 
148 
149 
150 /*
151  * Dump out all of the stored info into a file
152  */
153 static void
154 dumptable(void)
155 {
156 	int i;
157 	groupentrylist entry;
158 	stringlist groups;
159 
160 	for (i = 0; i < TABLESIZE; i++) {
161 		if (entry = grouptable[i]) {
162 			while (entry) {
163 				fputs(entry->name, stdout);
164 				putc('\t', stdout);
165 				for (groups = entry->groups; groups;
166 						groups = groups->next) {
167 					fputs(groups->str, stdout);
168 					if (groups->next) {
169 						putc(',', stdout);
170 					}
171 				}
172 				putc('\n', stdout);
173 				entry = entry->next;
174 			}
175 		}
176 	}
177 }
178 
179 
180 
181 
182 /*
183  *	Add a netgroup to a user's list of netgroups
184  */
185 static void
186 storegroup(char *group, struct grouplist *glist, int byuser)
187 {
188 	char *name;	/* username or hostname */
189 	char *domain;
190 	char *key;
191 	static char *universal = "*";
192 
193 	for (; glist; glist = glist->gl_nxt) {
194 		name = byuser ? glist->gl_name : glist->gl_machine;
195 		if (!name) {
196 		    name = universal;
197 		} else if (!isalnum(*name) && *name != '_') {
198 		    continue;
199 		}
200 		domain = glist->gl_domain;
201 		if (!domain) {
202 		    domain = universal;
203 		}
204 		key = malloc((unsigned) (strlen(name)+strlen(domain)+2));
205 		(void) sprintf(key, "%s.%s", name, domain);
206 		enter(key, group);
207 	}
208 }
209 
210 
211 
212 static groupentrylist
213 newentry(char *name, char *group)
214 {
215 	groupentrylist new;
216 
217 	new = MALLOC(groupentrynode);
218 
219 	STRCPY(new->name, name);
220 
221 	new->groups = MALLOC(stringnode);
222 	new->groups->str = group;
223 	new->groups->next = NULL;
224 
225 	new->next = NULL;
226 	return (new);
227 }
228 
229 static void
230 appendgroup(groupentrylist grlist, char *group)
231 {
232 	stringlist cur, prev;
233 
234 	for (cur = grlist->groups; cur; prev = cur, cur = cur->next) {
235 		if (strcmp(group, cur->str) == 0) {
236 		    return;
237 		}
238 	}
239 	prev->next = MALLOC(stringnode);
240 	cur = prev->next;
241 	cur->str = group;
242 	cur->next = NULL;
243 }
244 
245 static void
246 enter(char *name, char *group)
247 {
248 	int key;
249 	groupentrylist gel;
250 	groupentrylist gelprev;
251 
252 	key = tablekey(name);
253 	if (grouptable[key] == NULL) {
254 		grouptable[key] = newentry(name, group);
255 	} else {
256 		gel = grouptable[key];
257 		while (gel && strcmp(gel->name, name)) {
258 		    gelprev = gel;
259 		    gel = gel->next;
260 		}
261 		if (gel) {
262 		    appendgroup(gel, group);
263 		} else {
264 		    gelprev->next = newentry(name, group);
265 		}
266 	}
267 }
268 
269 /*
270  * Load up a hash table with the info in /etc/netgroup
271  */
272 static void
273 loadtable(FILE *nf)
274 {
275 	char buf[MAXGROUPLEN];
276 	char *p;
277 	char *group;
278 	char *line;
279 
280 	while (getline(buf, MAXGROUPLEN, nf)) {
281 		for (p = buf; *p && isspace((int)*p); p++)
282 			;	/* skip leading blanks */
283 		for (; *p && *p != '#' && *p != ' ' && *p != '\t'; p++)
284 			;
285 		if (*p == EOS || *p == '#')
286 			continue;
287 		*p++ = EOS;
288 
289 		while (*p == ' ' || *p == '\t') {
290 			p++;
291 		}
292 		if (*p == EOS || *p == '#')
293 			continue;
294 
295 		STRCPY(group, buf);
296 		STRCPY(line, p);
297 		store(ngtable, group, line);
298 	}
299 }
300