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