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