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 (C) 1990-2000, Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 28 #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 main(argc, argv) 114 int argc; 115 char *argv[]; 116 { 117 FILE *pf, *mf, *gf, *hf; 118 119 cmdname = argv[0]; 120 if (!parseargs(argc, argv)) { 121 (void) fprintf(stderr, 122 "usage: %s [-q] [-pghm filename]\n", cmdname); 123 exit(1); 124 } 125 (void) getdomainname(domain, sizeof (domain)); 126 127 pf = openfile(pwdfile); 128 gf = openfile(grpfile); 129 hf = openfile(hostfile); 130 mf = fopen(mapfile, "r"); 131 132 133 if (mf != NULL) { 134 domapfile(mapfile, mf); 135 } 136 dogrpfile(grpfile, gf); 137 dopwdfile(pwdfile, pf); 138 dohostfile(hostfile, hf); 139 140 exit(0); 141 /* NOTREACHED */ 142 } 143 144 /* 145 * Parse the network id mapping file 146 */ 147 domapfile(mapfile, mf) 148 char *mapfile; 149 FILE *mf; 150 { 151 char **lp; 152 char line[MAXLINELEN]; 153 char name[MAXNAMELEN]; 154 int uid, gid; 155 156 curfile = mapfile; 157 curline = 0; 158 while (lp = getline(line, sizeof (line), mf, &curline, "#")) { 159 check_getname(lp, name, WHITE, WHITE, "#"); 160 if (wasprinted(name)) { 161 multdef(name); 162 continue; 163 } 164 put_s(name); 165 (void) putchar(' '); 166 check_getname(lp, name, WHITE, COLON, "#"); 167 uid = Atoi(name); 168 put_d(uid); 169 (void) putchar(':'); 170 if (uid == 0) { 171 check_getname(lp, name, WHITE, "\t\n ", "#"); 172 put_s(name); 173 (void) putchar(' '); 174 } else { 175 check_getname(lp, name, WHITE, ",\n", "#"); 176 gid = Atoi(name); 177 put_d(gid); 178 while (getname(name, sizeof (name), WHITE, ",\n", lp, 179 "#") >= 0) { 180 gid = Atoi(name); 181 (void) putchar(','); 182 put_d(gid); 183 } 184 } 185 (void) putchar('\n'); 186 } 187 } 188 189 190 /* 191 * Parse the groups file 192 */ 193 dogrpfile(grpfile, gf) 194 char *grpfile; 195 FILE *gf; 196 { 197 char **lp; 198 char line[MAXLINELEN]; 199 char name[MAXNAMELEN]; 200 int gid; 201 202 curfile = grpfile; 203 curline = 0; 204 while (lp = getline(line, sizeof (line), gf, &curline, "")) { 205 check_getname(lp, name, WHITE, COLON, ""); 206 if (name[0] == '+') { 207 continue; 208 } 209 check_getname(lp, name, WHITE, COLON, ""); /* ignore passwd */ 210 check_getname(lp, name, WHITE, COLON, ""); 211 gid = Atoi(name); 212 while (getname(name, sizeof (name), WHITE, COMMA, lp, 213 "") >= 0) { 214 storegid(gid, name); 215 } 216 } 217 } 218 219 220 /* 221 * Parse the password file 222 */ 223 dopwdfile(pwdfile, pf) 224 char *pwdfile; 225 FILE *pf; 226 { 227 char **lp; 228 char line[MAXLINELEN]; 229 char name[MAXNAMELEN]; 230 char user[MAXNAMELEN]; 231 int uid, gid; 232 233 curfile = pwdfile; 234 curline = 0; 235 236 while (lp = getline(line, sizeof (line), pf, &curline, "")) { 237 check_getname(lp, user, WHITE, COLON, ""); /* username */ 238 if (user[0] == '-' || user[0] == '+') { 239 continue; /* NIS entry */ 240 } 241 check_getname(lp, name, WHITE, COLON, ""); /* ignore passwd */ 242 check_getname(lp, name, WHITE, COLON, ""); /* but get uid */ 243 uid = Atoi(name); 244 user2netname(name, uid, domain); 245 if (wasprinted(name)) { 246 multdef(name); 247 continue; 248 } 249 put_s(name); 250 (void) putchar(' '); 251 check_getname(lp, name, WHITE, COLON, ""); 252 gid = Atoi(name); 253 put_d(uid); 254 (void) putchar(':'); 255 printgroups(user, gid); 256 } 257 } 258 259 260 /* 261 * Parse the hosts file 262 */ 263 dohostfile(hostfile, hf) 264 char *hostfile; 265 FILE *hf; 266 { 267 char **lp; 268 char line[MAXLINELEN]; 269 char name[MAXNAMELEN]; 270 char netname[MAXNETNAMELEN]; 271 272 curfile = hostfile; 273 curline = 0; 274 while (lp = getline(line, sizeof (line), hf, &curline, "#")) { 275 check_getname(lp, name, WHITE, WHITE, "#"); 276 if (getname(name, MAXNAMELEN, WHITE, WHITE, lp, "#") != 1) { 277 continue; 278 } 279 host2netname(netname, name, domain); 280 if (wasprinted(netname)) { 281 multdef(netname); 282 continue; 283 } 284 (void) printf("%s 0:%.*s\n", netname, sizeof (name), name); 285 } 286 } 287 288 /* 289 * Open a file, exit on failure 290 */ 291 static FILE * 292 openfile(fname) 293 char *fname; 294 { 295 FILE *f; 296 297 f = fopen(fname, "r"); 298 if (f == NULL) { 299 (void) fprintf(stderr, "%s: can't open %s\n", cmdname, fname); 300 exit(1); 301 } 302 return (f); 303 } 304 305 /* 306 * Print syntax error message, then exit 307 */ 308 syntaxerror() 309 { 310 (void) fprintf(stderr, "%s: syntax error in file \"%s\", line %d\n", 311 cmdname, curfile, curline); 312 exit(1); 313 } 314 315 316 /* 317 * an atoi() that prints a message and exits upong failure 318 */ 319 static int 320 Atoi(str) 321 char *str; 322 { 323 int res; 324 325 if (!sscanf(str, "%d", &res)) { 326 syntaxerror(); 327 } 328 return (res); 329 } 330 331 332 /* 333 * Attempt to get a token from a file, print a message and exit upon failure 334 */ 335 check_getname(lp, name, skip, term, com) 336 char **lp; 337 char *name; 338 char *skip; 339 char *term; 340 char *com; 341 { 342 if (getname(name, MAXNAMELEN, skip, term, lp, com) != 1) { 343 syntaxerror(); 344 } 345 } 346 347 /* 348 * Something was defined more than once 349 */ 350 multdef(name) 351 char *name; 352 { 353 if (!quietmode) { 354 (void) fprintf(stderr, 355 "%s: %s multiply defined, other definitions ignored\n", 356 cmdname, name); 357 } 358 } 359 360 static 361 hash(str, size) 362 unsigned char *str; 363 int size; 364 { 365 unsigned val; 366 int flip; 367 368 val = 0; 369 flip = 0; 370 while (*str) { 371 if (flip) { 372 val ^= (*str++ << 6); 373 } else { 374 val ^= *str++; 375 } 376 flip = !flip; 377 } 378 return (val % size); 379 } 380 381 382 /* 383 * Check if an item has been printed 384 * If not, store the item into the printed item table 385 */ 386 static 387 wasprinted(name) 388 char *name; 389 { 390 struct string_list *s; 391 int val; 392 393 val = hash((unsigned char *) name, PRNTABSIZE); 394 for (s = printed[val]; s != NULL && strcmp(s->str, name); s = s->next) 395 ; 396 if (s != NULL) { 397 return (1); 398 } 399 s = (struct string_list *)malloc(sizeof (struct string_list)); 400 s->str = malloc((unsigned)strlen(name) + 1); 401 (void) strcpy(s->str, name); 402 s->next = printed[val]; 403 printed[val] = s; 404 return (0); 405 } 406 407 /* 408 * Add gid to the list of a user's groups 409 */ 410 storegid(gid, user) 411 int gid; 412 char *user; 413 { 414 struct group_list *g; 415 int i; 416 int val; 417 418 val = hash((unsigned char *) user, GRPTABSIZE); 419 for (g = groups[val]; g != NULL && strcmp(g->user, user); g = g->next) 420 ; 421 if (g == NULL) { 422 g = (struct group_list *)malloc(sizeof (struct group_list)); 423 g->user = malloc((unsigned)strlen(user) + 1); 424 (void) strcpy(g->user, user); 425 g->group_len = 1; 426 g->groups[0] = gid; 427 g->next = groups[val]; 428 groups[val] = g; 429 } else { 430 for (i = 0; i < g->group_len; i++) { 431 if (g->groups[i] == gid) { 432 return; 433 } 434 } 435 if (g->group_len >= NUMGIDS) { 436 (void) fprintf(stderr, "%s: %s's groups exceed %d\n", 437 cmdname, user, NGROUPS_MAX); 438 return; 439 } 440 g->groups[g->group_len++] = gid; 441 } 442 } 443 444 /* 445 * print out a user's groups 446 */ 447 printgroups(user, gid) 448 char *user; 449 int gid; 450 { 451 struct group_list *g; 452 int i; 453 int val; 454 455 val = hash((unsigned char *) user, GRPTABSIZE); 456 for (g = groups[val]; g != NULL && strcmp(g->user, user); g = g->next) 457 ; 458 put_d(gid); 459 if (g != NULL) { 460 for (i = 0; i < g->group_len; i++) { 461 if (gid != g->groups[i]) { 462 (void) putchar(','); 463 put_d(g->groups[i]); 464 } 465 } 466 } 467 (void) putchar('\n'); 468 } 469 470 471 /* 472 * Parse command line arguments 473 */ 474 parseargs(argc, argv) 475 int argc; 476 char *argv[]; 477 { 478 int i; 479 int j; 480 static struct { 481 char letter; 482 char *standard; 483 char **filename; 484 } whattodo[] = { 485 { 'p', PASSWD, &pwdfile }, 486 { 'g', GROUP, &grpfile }, 487 { 'm', IDMAP, &mapfile }, 488 { 'h', HOSTS, &hostfile } 489 }; 490 491 #define TABSIZE sizeof (whattodo)/sizeof (whattodo[0]) 492 493 for (i = 1; i < argc; i++) { 494 if (argv[i][0] == '-') { 495 if (argv[i][2] != 0) { 496 return (0); 497 } 498 if (argv[i][1] == 'q') { 499 quietmode = 1; 500 continue; 501 } 502 for (j = 0; j < TABSIZE; j++) { 503 if (whattodo[j].letter == argv[i][1]) { 504 if (*whattodo[j].filename != 505 whattodo[j].standard) { 506 return (0); 507 } 508 if (++i == argc) { 509 return (0); 510 } 511 *whattodo[j].filename = argv[i]; 512 break; 513 } 514 } 515 if (j == TABSIZE) { 516 return (0); 517 } 518 } 519 } 520 return (1); 521 } 522 523 /* 524 * Print a string, quickly 525 */ 526 put_s(s) 527 char *s; 528 { 529 (void) fwrite(s, strlen(s), 1, stdout); 530 } 531 532 /* 533 * Print an integer, quickly 534 */ 535 put_d(d) 536 int d; 537 { 538 char buf[20]; 539 char *p; 540 541 if (d == 0) { 542 (void) putchar('0'); 543 return; 544 } 545 if (d < 0) { 546 (void) putchar('-'); 547 d = -d; 548 } 549 p = buf + sizeof (buf); 550 *--p = 0; 551 while (d > 0) { 552 *--p = (d % 10) + '0'; 553 d /= 10; 554 } 555 put_s(p); 556 } 557