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