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