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