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