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