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