xref: /illumos-gate/usr/src/cmd/ypcmd/mknetid/mknetid.c (revision c8d9a41c357577f316e58fb2603f85c598f01afb)
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 (c) 2016 by Delphix. All rights reserved.
25  */
26 
27 /*
28  * Network name to unix credential database generator.
29  * Uses /etc/passwd, /etc/group, /etc/hosts and /etc/netid to
30  * create the database.
31  *
32  * If some user appears in passwd, they get an entry like:
33  *	sun.<uid>@<domainname>	<uid>:<gid1>,<gid2>,...
34  * If some host appears in hosts, it gets an entry like:
35  *	sun.<hostname>@<domainname>	0:<hostname>
36  *
37  * The file /etc/netid is used to add other domains (possibly non-unix)
38  * to the database.
39  */
40 #include <stdio.h>
41 #include <pwd.h>
42 #include <limits.h>
43 #include <sys/param.h>
44 #include <rpc/rpc.h>
45 #include <rpc/key_prot.h>
46 
47 
48 #define	MAXNAMELEN	256
49 #define	MAXLINELEN	1024
50 #define	MAXDOMAINLEN	32
51 
52 #define	GRPTABSIZE	256		/* size of group table */
53 #define	PRNTABSIZE	4096		/* size of printed item table */
54 
55 #define	NUMGIDS	(NGROUPS_MAX + 1)	/* group-access-list + gid */
56 
57 extern char **getaline();
58 extern char *malloc();
59 extern char *strcpy();
60 
61 /*
62  * The group list
63  * Store username and groups to which they belong
64  */
65 struct group_list {
66 	char *user;
67 	int group_len;
68 	int groups[NUMGIDS];
69 	struct group_list *next;
70 };
71 
72 /*
73  * General purpose list of strings
74  */
75 struct string_list {
76 	char *str;
77 	struct string_list *next;
78 };
79 
80 static FILE *openfile();
81 static char *scanargs();
82 static int atoi();
83 
84 static char *cmdname;	/* name of this program */
85 static int quietmode;	/* quiet mode: don't print error messages */
86 static char *curfile;	/* name of file we are parsing */
87 static int curline;		/* current line parsed in this file */
88 
89 static struct group_list *groups[GRPTABSIZE];	/* group table */
90 static struct string_list *printed[PRNTABSIZE];	/* printed item table */
91 static char domain[MAXDOMAINLEN];	/* name of our domain */
92 
93 static char PASSWD[] = "/etc/passwd";	/* default passwd database */
94 static char IDMAP[] = "/etc/idmap";	/* default net-id map database */
95 static char GROUP[] = "/etc/group";	/* default group database */
96 static char HOSTS[] = "/etc/hosts";	/* default hosts database */
97 
98 static char *pwdfile = PASSWD;	/* password file to parse */
99 static char *grpfile = GROUP;	/* group file */
100 static char *hostfile = HOSTS;	/* hosts file */
101 static char *mapfile = IDMAP;	/* network id file */
102 
103 /*
104  * Various separaters
105  */
106 static char WHITE[] = "\t ";
107 static char COLON[] = ":";
108 static char COMMA[] = ",";
109 
110 void domapfile(char *, FILE *);
111 void dogrpfile(char *, FILE *);
112 void dopwdfile(char *, FILE *);
113 void dohostfile(char *, FILE *);
114 static int Atoi(char *);
115 void check_getname(char **, char *, char *, char *, char *);
116 void multdef(char *);
117 static int wasprinted(char *);
118 void storegid(int, char *);
119 void printgroups(char *, int);
120 int parseargs(int, char *[]);
121 void put_s(char *);
122 void put_d(int);
123 
124 
125 int
126 main(argc, argv)
127 	int argc;
128 	char *argv[];
129 {
130 	FILE *pf, *mf, *gf, *hf;
131 
132 	cmdname = argv[0];
133 	if (!parseargs(argc, argv)) {
134 		(void) fprintf(stderr,
135 			"usage: %s [-q] [-pghm filename]\n", cmdname);
136 		exit(1);
137 	}
138 	(void) getdomainname(domain, sizeof (domain));
139 
140 	pf = openfile(pwdfile);
141 	gf = openfile(grpfile);
142 	hf = openfile(hostfile);
143 	mf = fopen(mapfile, "r");
144 
145 
146 	if (mf != NULL) {
147 		domapfile(mapfile, mf);
148 	}
149 	dogrpfile(grpfile, gf);
150 	dopwdfile(pwdfile, pf);
151 	dohostfile(hostfile, hf);
152 
153 	return (0);
154 	/* NOTREACHED */
155 }
156 
157 /*
158  * Parse the network id mapping file
159  */
160 void
161 domapfile(mapfile, mf)
162 	char *mapfile;
163 	FILE *mf;
164 {
165 	char **lp;
166 	char line[MAXLINELEN];
167 	char name[MAXNAMELEN];
168 	int uid, gid;
169 
170 	curfile = mapfile;
171 	curline = 0;
172 	while (lp = getaline(line, sizeof (line), mf, &curline, "#")) {
173 		check_getname(lp, name, WHITE, WHITE, "#");
174 		if (wasprinted(name)) {
175 			multdef(name);
176 			continue;
177 		}
178 		put_s(name);
179 		(void) putchar(' ');
180 		check_getname(lp, name, WHITE, COLON, "#");
181 		uid = Atoi(name);
182 		put_d(uid);
183 		(void) putchar(':');
184 		if (uid == 0) {
185 			check_getname(lp, name, WHITE, "\t\n ", "#");
186 			put_s(name);
187 			(void) putchar(' ');
188 		} else {
189 			check_getname(lp, name, WHITE, ",\n", "#");
190 			gid = Atoi(name);
191 			put_d(gid);
192 			while (getname(name, sizeof (name), WHITE, ",\n", lp,
193 					"#") >= 0) {
194 				gid = Atoi(name);
195 				(void) putchar(',');
196 				put_d(gid);
197 			}
198 		}
199 		(void) putchar('\n');
200 	}
201 }
202 
203 
204 /*
205  * Parse the groups file
206  */
207 void
208 dogrpfile(grpfile, gf)
209 	char *grpfile;
210 	FILE *gf;
211 {
212 	char **lp;
213 	char line[MAXLINELEN];
214 	char name[MAXNAMELEN];
215 	int gid;
216 
217 	curfile = grpfile;
218 	curline = 0;
219 	while (lp = getaline(line, sizeof (line), gf, &curline, "")) {
220 		check_getname(lp, name, WHITE, COLON, "");
221 		if (name[0] == '+') {
222 			continue;
223 		}
224 		check_getname(lp, name, WHITE, COLON, ""); /* ignore passwd */
225 		check_getname(lp, name, WHITE, COLON, "");
226 		gid = Atoi(name);
227 		while (getname(name, sizeof (name), WHITE, COMMA, lp,
228 				"") >= 0) {
229 			storegid(gid, name);
230 		}
231 	}
232 }
233 
234 
235 /*
236  * Parse the password file
237  */
238 void
239 dopwdfile(pwdfile, pf)
240 	char *pwdfile;
241 	FILE *pf;
242 {
243 	char **lp;
244 	char line[MAXLINELEN];
245 	char name[MAXNAMELEN];
246 	char user[MAXNAMELEN];
247 	int uid, gid;
248 
249 	curfile = pwdfile;
250 	curline = 0;
251 
252 	while (lp = getaline(line, sizeof (line), pf, &curline, "")) {
253 		check_getname(lp, user, WHITE, COLON, ""); 	/* username */
254 		if (user[0] == '-' || user[0] == '+') {
255 			continue;	/* NIS entry */
256 		}
257 		check_getname(lp, name, WHITE, COLON, ""); /* ignore passwd */
258 		check_getname(lp, name, WHITE, COLON, ""); /* but get uid */
259 		uid = Atoi(name);
260 		user2netname(name, uid, domain);
261 		if (wasprinted(name)) {
262 			multdef(name);
263 			continue;
264 		}
265 		put_s(name);
266 		(void) putchar(' ');
267 		check_getname(lp, name, WHITE, COLON, "");
268 		gid = Atoi(name);
269 		put_d(uid);
270 		(void) putchar(':');
271 		printgroups(user, gid);
272 	}
273 }
274 
275 
276 /*
277  * Parse the hosts file
278  */
279 void
280 dohostfile(hostfile, hf)
281 	char *hostfile;
282 	FILE *hf;
283 {
284 	char **lp;
285 	char line[MAXLINELEN];
286 	char name[MAXNAMELEN];
287 	char netname[MAXNETNAMELEN];
288 
289 	curfile = hostfile;
290 	curline = 0;
291 	while (lp = getaline(line, sizeof (line), hf, &curline, "#")) {
292 		check_getname(lp, name, WHITE, WHITE, "#");
293 		if (getname(name, MAXNAMELEN, WHITE, WHITE, lp, "#") != 1) {
294 			continue;
295 		}
296 		host2netname(netname, name, domain);
297 		if (wasprinted(netname)) {
298 			multdef(netname);
299 			continue;
300 		}
301 		(void) printf("%s 0:%.*s\n", netname, sizeof (name), name);
302 	}
303 }
304 
305 /*
306  * Open a file, exit on failure
307  */
308 static FILE *
309 openfile(fname)
310 	char *fname;
311 {
312 	FILE *f;
313 
314 	f = fopen(fname, "r");
315 	if (f == NULL) {
316 		(void) fprintf(stderr, "%s: can't open %s\n", cmdname, fname);
317 		exit(1);
318 	}
319 	return (f);
320 }
321 
322 /*
323  * Print syntax error message, then exit
324  */
325 void
326 syntaxerror()
327 {
328 	(void) fprintf(stderr, "%s: syntax error in file \"%s\", line %d\n",
329 	    cmdname, curfile, curline);
330 	exit(1);
331 }
332 
333 
334 /*
335  * an atoi() that prints a message and exits upong failure
336  */
337 static int
338 Atoi(str)
339 	char *str;
340 {
341 	int res;
342 
343 	if (!sscanf(str, "%d", &res)) {
344 		syntaxerror();
345 	}
346 	return (res);
347 }
348 
349 
350 /*
351  * Attempt to get a token from a file, print a message and exit upon failure
352  */
353 void
354 check_getname(lp, name, skip, term, com)
355 	char **lp;
356 	char *name;
357 	char *skip;
358 	char *term;
359 	char *com;
360 {
361 	if (getname(name, MAXNAMELEN, skip, term, lp, com) != 1) {
362 		syntaxerror();
363 	}
364 }
365 
366 /*
367  * Something was defined more than once
368  */
369 void
370 multdef(name)
371 	char *name;
372 {
373 	if (!quietmode) {
374 		(void) fprintf(stderr,
375 			"%s: %s multiply defined, other definitions ignored\n",
376 			cmdname, name);
377 	}
378 }
379 
380 static int
381 hash(str, size)
382 	unsigned char *str;
383 	int size;
384 {
385 	unsigned val;
386 	int flip;
387 
388 	val = 0;
389 	flip = 0;
390 	while (*str) {
391 		if (flip) {
392 			val ^= (*str++ << 6);
393 		} else {
394 			val ^= *str++;
395 		}
396 		flip = !flip;
397 	}
398 	return (val % size);
399 }
400 
401 
402 /*
403  * Check if an item has been printed
404  * If not, store the item into the printed item table
405  */
406 static int
407 wasprinted(name)
408 	char *name;
409 {
410 	struct string_list *s;
411 	int val;
412 
413 	val = hash((unsigned char *) name, PRNTABSIZE);
414 	for (s = printed[val]; s != NULL && strcmp(s->str, name); s = s->next)
415 		;
416 	if (s != NULL) {
417 		return (1);
418 	}
419 	s = (struct string_list *)malloc(sizeof (struct string_list));
420 	s->str = malloc((unsigned)strlen(name) + 1);
421 	(void) strcpy(s->str, name);
422 	s->next = printed[val];
423 	printed[val] = s;
424 	return (0);
425 }
426 
427 /*
428  * Add gid to the list of a user's groups
429  */
430 void
431 storegid(gid, user)
432 	int gid;
433 	char *user;
434 {
435 	struct group_list *g;
436 	int i;
437 	int val;
438 
439 	val = hash((unsigned char *) user, GRPTABSIZE);
440 	for (g = groups[val]; g != NULL && strcmp(g->user, user); g = g->next)
441 		;
442 	if (g == NULL) {
443 		g = (struct group_list *)malloc(sizeof (struct group_list));
444 		g->user = malloc((unsigned)strlen(user) + 1);
445 		(void) strcpy(g->user, user);
446 		g->group_len = 1;
447 		g->groups[0] = gid;
448 		g->next = groups[val];
449 		groups[val] = g;
450 	} else {
451 		for (i = 0; i < g->group_len; i++) {
452 			if (g->groups[i] == gid) {
453 				return;
454 			}
455 		}
456 		if (g->group_len >= NUMGIDS) {
457 			(void) fprintf(stderr, "%s: %s's groups exceed %d\n",
458 				cmdname, user, NGROUPS_MAX);
459 			return;
460 		}
461 		g->groups[g->group_len++] = gid;
462 	}
463 }
464 
465 /*
466  * print out a user's groups
467  */
468 void
469 printgroups(user, gid)
470 	char *user;
471 	int gid;
472 {
473 	struct group_list *g;
474 	int i;
475 	int val;
476 
477 	val = hash((unsigned char *) user, GRPTABSIZE);
478 	for (g = groups[val]; g != NULL && strcmp(g->user, user); g = g->next)
479 		;
480 	put_d(gid);
481 	if (g != NULL) {
482 		for (i = 0; i < g->group_len; i++) {
483 			if (gid != g->groups[i]) {
484 				(void) putchar(',');
485 				put_d(g->groups[i]);
486 			}
487 		}
488 	}
489 	(void) putchar('\n');
490 }
491 
492 
493 /*
494  * Parse command line arguments
495  */
496 int
497 parseargs(argc, argv)
498 	int argc;
499 	char *argv[];
500 {
501 	int i;
502 	int j;
503 	static struct {
504 		char letter;
505 		char *standard;
506 		char **filename;
507 	} whattodo[] = {
508 		{ 'p', PASSWD, &pwdfile },
509 		{ 'g', GROUP, &grpfile },
510 		{ 'm', IDMAP, &mapfile },
511 		{ 'h', HOSTS, &hostfile }
512 	};
513 
514 #define	TABSIZE  sizeof (whattodo)/sizeof (whattodo[0])
515 
516 	for (i = 1; i < argc; i++) {
517 		if (argv[i][0] == '-') {
518 			if (argv[i][2] != 0) {
519 				return (0);
520 			}
521 			if (argv[i][1] == 'q') {
522 				quietmode = 1;
523 				continue;
524 			}
525 			for (j = 0; j < TABSIZE; j++) {
526 				if (whattodo[j].letter == argv[i][1]) {
527 					if (*whattodo[j].filename !=
528 							whattodo[j].standard) {
529 						return (0);
530 					}
531 					if (++i == argc) {
532 						return (0);
533 					}
534 					*whattodo[j].filename = argv[i];
535 					break;
536 				}
537 			}
538 			if (j == TABSIZE) {
539 				return (0);
540 			}
541 		}
542 	}
543 	return (1);
544 }
545 
546 /*
547  * Print a string, quickly
548  */
549 void
550 put_s(s)
551 	char *s;
552 {
553 	(void) fwrite(s, strlen(s), 1, stdout);
554 }
555 
556 /*
557  * Print an integer, quickly
558  */
559 void
560 put_d(d)
561 	int d;
562 {
563 	char buf[20];
564 	char *p;
565 
566 	if (d == 0) {
567 		(void) putchar('0');
568 		return;
569 	}
570 	if (d < 0) {
571 		(void) putchar('-');
572 		d = -d;
573 	}
574 	p = buf + sizeof (buf);
575 	*--p = 0;
576 	while (d > 0) {
577 		*--p = (d % 10) + '0';
578 		d /= 10;
579 	}
580 	put_s(p);
581 }
582