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
main(argc,argv)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
domapfile(mapfile,mf)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
dogrpfile(grpfile,gf)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
dopwdfile(pwdfile,pf)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
dohostfile(hostfile,hf)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 *
openfile(fname)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
syntaxerror()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
Atoi(str)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
check_getname(lp,name,skip,term,com)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
multdef(name)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
hash(str,size)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
wasprinted(name)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
storegid(gid,user)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
printgroups(user,gid)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
parseargs(argc,argv)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
put_s(s)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
put_d(d)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