1 /* 2 * Copyright (c) 1994 Christos Zoulas 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Christos Zoulas. 16 * 4. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 #ifndef lint 32 static char *rcsid = "$Id: netgroup_mkdb.c,v 1.4 1996/04/27 18:54:31 christos Exp $"; 33 #endif 34 35 #include <sys/types.h> 36 #include <sys/param.h> 37 #include <sys/stat.h> 38 #include <stdlib.h> 39 #include <stddef.h> 40 #include <unistd.h> 41 #include <fcntl.h> 42 #include <db.h> 43 #include <err.h> 44 #include <errno.h> 45 #include <stdio.h> 46 #include <string.h> 47 #define _NETGROUP_PRIVATE 48 #include <netgroup.h> 49 #include <assert.h> 50 51 #include "str.h" 52 #include "util.h" 53 54 #define DEBUG_NG 55 56 #define NEW(a) (a *) emalloc(sizeof(a)) 57 58 struct nentry { 59 int n_type; 60 size_t n_size; /* Buffer size required for printing */ 61 union { 62 char *_name; 63 struct netgroup *_group; 64 } _n; 65 #define n_name _n._name 66 #define n_group _n._group 67 struct nentry *n_next; 68 }; 69 70 71 static DB *ng_insert __P((DB *, const char *)); 72 static void ng_reventry __P((DB *, DB *, struct nentry *, char *, 73 size_t, struct stringlist *)); 74 75 static void ng_print __P((struct nentry *, struct string *)); 76 static void ng_rprint __P((DB *, struct string *)); 77 static DB *ng_reverse __P((DB *, size_t)); 78 static DB *ng_load __P((const char *)); 79 static void ng_write __P((DB *, DB *, int)); 80 static void ng_rwrite __P((DB *, DB *, int)); 81 static void usage __P((void)); 82 static void cleanup __P((void)); 83 84 #ifdef DEBUG_NG 85 static int debug = 0; 86 static void ng_dump __P((DB *)); 87 static void ng_rdump __P((DB *)); 88 #endif /* DEBUG_NG */ 89 90 91 static const char ng_empty[] = ""; 92 #define NG_EMPTY(a) ((a) ? (a) : ng_empty) 93 94 static char *dbname = _PATH_NETGROUP_DB; 95 96 int 97 main(argc, argv) 98 int argc; 99 char **argv; 100 { 101 DB *db, *ndb, *hdb, *udb; 102 int ch; 103 char buf[MAXPATHLEN]; 104 char *fname = _PATH_NETGROUP; 105 106 107 while ((ch = getopt(argc, argv, "do:")) != EOF) 108 switch (ch) { 109 #ifdef DEBUG_NG 110 case 'd': 111 debug++; 112 break; 113 #endif 114 case 'o': 115 dbname = optarg; 116 break; 117 118 case '?': 119 default: 120 usage(); 121 } 122 123 argc -= optind; 124 argv += optind; 125 126 if (argc == 1) 127 fname = *argv; 128 else if (argc > 1) 129 usage(); 130 131 if (atexit(cleanup)) 132 err(1, "Cannot install exit handler"); 133 134 /* Read and parse the netgroup file */ 135 ndb = ng_load(fname); 136 #ifdef DEBUG_NG 137 if (debug) { 138 (void) fprintf(stderr, "#### Database\n"); 139 ng_dump(ndb); 140 } 141 #endif 142 143 /* Reverse the database by host */ 144 hdb = ng_reverse(ndb, offsetof(struct netgroup, ng_host)); 145 #ifdef DEBUG_NG 146 if (debug) { 147 (void) fprintf(stderr, "#### Reverse by host\n"); 148 ng_rdump(hdb); 149 } 150 #endif 151 152 /* Reverse the database by user */ 153 udb = ng_reverse(ndb, offsetof(struct netgroup, ng_user)); 154 #ifdef DEBUG_NG 155 if (debug) { 156 (void) fprintf(stderr, "#### Reverse by user\n"); 157 ng_rdump(udb); 158 } 159 #endif 160 161 (void) snprintf(buf, sizeof(buf), "%s.tmp", dbname); 162 163 db = dbopen(buf, O_RDWR | O_CREAT | O_EXCL, 164 (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH), DB_HASH, NULL); 165 if (!db) 166 err(1, buf); 167 168 ng_write(db, ndb, _NG_KEYBYNAME); 169 ng_rwrite(db, udb, _NG_KEYBYUSER); 170 ng_rwrite(db, hdb, _NG_KEYBYHOST); 171 172 if ((db->close)(db)) 173 err(1, "Error closing database"); 174 175 if (rename(buf, dbname) == -1) 176 err(1, "Cannot rename `%s' to `%s'", buf, dbname); 177 178 return 0; 179 } 180 181 182 /* 183 * cleanup(): Remove temporary files upon exit 184 */ 185 static void 186 cleanup() 187 { 188 char buf[MAXPATHLEN]; 189 (void) snprintf(buf, sizeof(buf), "%s.tmp", dbname); 190 (void) unlink(buf); 191 } 192 193 194 195 /* 196 * ng_load(): Load the netgroup database from a file 197 */ 198 static DB * 199 ng_load(fname) 200 const char *fname; 201 { 202 FILE *fp; 203 DB *db; 204 char *buf; 205 size_t size; 206 struct nentry *tail, *head, *e; 207 char *p, *name; 208 struct netgroup *ng; 209 DBT data, key; 210 211 /* Open the netgroup file */ 212 if ((fp = fopen(fname, "r")) == NULL) 213 err(1, fname); 214 215 db = dbopen(NULL, O_RDWR | O_CREAT | O_EXCL, 0, DB_HASH, NULL); 216 217 if (db == NULL) 218 err(1, "dbopen"); 219 220 while ((buf = getline(fp, &size)) != NULL) { 221 tail = head = NULL; 222 p = buf; 223 224 while (p != NULL) { 225 switch (_ng_parse(&p, &name, &ng)) { 226 case _NG_NONE: 227 /* done with this one */ 228 p = NULL; 229 free(buf); 230 if (head == NULL) 231 break; 232 233 key.data = (u_char *) head->n_name; 234 key.size = strlen(head->n_name) + 1; 235 data.data = (u_char *) & head; 236 data.size = sizeof(head); 237 switch ((db->put)(db, &key, &data, 238 R_NOOVERWRITE)) { 239 case 0: 240 break; 241 242 case 1: 243 warnx("Duplicate entry netgroup `%s'\n", 244 head->n_name); 245 break; 246 247 case -1: 248 err(1, "put"); 249 break; 250 251 default: 252 abort(); 253 break; 254 } 255 break; 256 257 case _NG_NAME: 258 e = NEW(struct nentry); 259 e->n_type = _NG_NAME; 260 e->n_name = name; 261 e->n_next = NULL; 262 e->n_size = size; 263 if (tail == NULL) 264 head = tail = e; 265 else { 266 tail->n_next = e; 267 tail = e; 268 } 269 break; 270 271 case _NG_GROUP: 272 if (tail == NULL) { 273 char fmt[BUFSIZ]; 274 _ng_print(fmt, sizeof(fmt), ng); 275 errx(1, "no netgroup key for %s", fmt); 276 } 277 else { 278 e = NEW(struct nentry); 279 e->n_type = _NG_GROUP; 280 e->n_group = ng; 281 e->n_next = NULL; 282 e->n_size = size; 283 tail->n_next = e; 284 tail = e; 285 } 286 break; 287 288 default: 289 abort(); 290 break; 291 } 292 } 293 } 294 (void) fclose(fp); 295 return db; 296 } 297 298 299 /* 300 * ng_insert(): Insert named key into the database, and return its associated 301 * string database 302 */ 303 static DB * 304 ng_insert(db, name) 305 DB *db; 306 const char *name; 307 { 308 DB *xdb = NULL; 309 DBT key, data; 310 311 key.data = (u_char *) name; 312 key.size = strlen(name) + 1; 313 314 switch ((db->get)(db, &key, &data, 0)) { 315 case 0: 316 memcpy(&xdb, data.data, sizeof(xdb)); 317 break; 318 319 case 1: 320 xdb = dbopen(NULL, O_RDWR | O_CREAT | O_EXCL, 0, DB_HASH, NULL); 321 if (xdb == NULL) 322 err(1, "dbopen"); 323 324 data.data = (u_char *) & xdb; 325 data.size = sizeof(xdb); 326 switch ((db->put)(db, &key, &data, R_NOOVERWRITE)) { 327 case 0: 328 break; 329 330 case -1: 331 err(1, "db put `%s'", name); 332 break; 333 334 case 1: 335 default: 336 abort(); 337 } 338 break; 339 340 case -1: 341 err(1, "db get `%s'", name); 342 break; 343 344 default: 345 abort(); 346 break; 347 } 348 349 return xdb; 350 } 351 352 353 /* 354 * ng_reventry(): Recursively add all the netgroups to the group entry. 355 */ 356 static void 357 ng_reventry(db, udb, fe, name, s, ss) 358 DB *db, *udb; 359 struct nentry *fe; 360 char *name; 361 size_t s; 362 struct stringlist *ss; 363 { 364 DBT key, data; 365 struct nentry *e; 366 struct netgroup *ng; 367 char *p; 368 DB *xdb; 369 370 if (_ng_sl_find(ss, name) != NULL) { 371 warnx("Cycle in netgroup `%s'", name); 372 return; 373 } 374 _ng_sl_add(ss, name); 375 376 for (e = fe->n_next; e != NULL; e = e->n_next) 377 switch (e->n_type) { 378 case _NG_GROUP: 379 ng = e->n_group; 380 p = _ng_makekey(*((char **)(((char *) ng) + s)), 381 ng->ng_domain, e->n_size); 382 xdb = ng_insert(udb, p); 383 key.data = (u_char *) name; 384 key.size = strlen(name) + 1; 385 data.data = NULL; 386 data.size = 0; 387 switch ((xdb->put)(xdb, &key, &data, R_NOOVERWRITE)) { 388 case 0: 389 case 1: 390 break; 391 392 case -1: 393 err(1, "db put `%s'", name); 394 return; 395 396 default: 397 abort(); 398 break; 399 } 400 free(p); 401 break; 402 403 case _NG_NAME: 404 key.data = (u_char *) e->n_name; 405 key.size = strlen(e->n_name) + 1; 406 switch ((db->get)(db, &key, &data, 0)) { 407 case 0: 408 memcpy(&fe, data.data, sizeof(fe)); 409 ng_reventry(db, udb, fe, e->n_name, s, ss); 410 break; 411 412 case 1: 413 break; 414 415 case -1: 416 err(1, "db get `%s'", e->n_name); 417 return; 418 419 default: 420 abort(); 421 return; 422 } 423 break; 424 425 default: 426 abort(); 427 break; 428 } 429 } 430 431 432 /* 433 * ng_reverse(): Reverse the database 434 */ 435 static DB * 436 ng_reverse(db, s) 437 DB *db; 438 size_t s; 439 { 440 int pos; 441 struct stringlist *sl; 442 DBT key, data; 443 struct nentry *fe; 444 DB *udb = dbopen(NULL, O_RDWR | O_CREAT | O_EXCL, 0, 445 DB_HASH, NULL); 446 447 if (udb == NULL) 448 err(1, "dbopen"); 449 450 for (pos = R_FIRST;; pos = R_NEXT) 451 switch ((db->seq)(db, &key, &data, pos)) { 452 case 0: 453 sl = _ng_sl_init(); 454 memcpy(&fe, data.data, sizeof(fe)); 455 ng_reventry(db, udb, fe, (char *) key.data, s, sl); 456 _ng_sl_free(sl, 0); 457 break; 458 459 case 1: 460 return udb; 461 462 case -1: 463 err(1, "seq"); 464 return udb; 465 } 466 467 return udb; 468 } 469 470 471 /* 472 * ng_print(): Pretty print a netgroup entry 473 */ 474 static void 475 ng_print(e, str) 476 struct nentry *e; 477 struct string *str; 478 { 479 char *ptr = emalloc(e->n_size); 480 481 if (e->n_next == NULL) { 482 str_append(str, "", ' '); 483 return; 484 } 485 486 for (e = e->n_next; e != NULL; e = e->n_next) { 487 switch (e->n_type) { 488 case _NG_NAME: 489 (void) snprintf(ptr, e->n_size, "%s", e->n_name); 490 break; 491 492 case _NG_GROUP: 493 (void) snprintf(ptr, e->n_size, "(%s,%s,%s)", 494 NG_EMPTY(e->n_group->ng_host), 495 NG_EMPTY(e->n_group->ng_user), 496 NG_EMPTY(e->n_group->ng_domain)); 497 break; 498 499 default: 500 errx(1, "Internal error: Bad netgroup type\n"); 501 break; 502 } 503 str_append(str, ptr, ' '); 504 } 505 free(ptr); 506 } 507 508 509 /* 510 * ng_rprint(): Pretty print all reverse netgroup mappings in the given entry 511 */ 512 static void 513 ng_rprint(db, str) 514 DB *db; 515 struct string *str; 516 { 517 int pos; 518 DBT key, data; 519 520 for (pos = R_FIRST;; pos = R_NEXT) 521 switch ((db->seq)(db, &key, &data, pos)) { 522 case 0: 523 str_append(str, (char *) key.data, ','); 524 break; 525 526 case 1: 527 return; 528 529 default: 530 err(1, "seq"); 531 break; 532 } 533 } 534 535 536 #ifdef DEBUG_NG 537 /* 538 * ng_dump(): Pretty print all netgroups in the given database 539 */ 540 static void 541 ng_dump(db) 542 DB *db; 543 { 544 int pos; 545 DBT key, data; 546 struct nentry *e; 547 struct string buf; 548 549 for (pos = R_FIRST;; pos = R_NEXT) 550 switch ((db->seq)(db, &key, &data, pos)) { 551 case 0: 552 memcpy(&e, data.data, sizeof(e)); 553 str_init(&buf); 554 assert(e->n_type == _NG_NAME); 555 556 ng_print(e, &buf); 557 (void) fprintf(stderr, "%s\t%s\n", e->n_name, 558 buf.s_str ? buf.s_str : ""); 559 str_free(&buf); 560 break; 561 562 case 1: 563 return; 564 565 default: 566 err(1, "seq"); 567 return; 568 } 569 } 570 571 572 /* 573 * ng_rdump(): Pretty print all reverse mappings in the given database 574 */ 575 static void 576 ng_rdump(db) 577 DB *db; 578 { 579 int pos; 580 DBT key, data; 581 DB *xdb; 582 struct string buf; 583 584 for (pos = R_FIRST;; pos = R_NEXT) 585 switch ((db->seq)(db, &key, &data, pos)) { 586 case 0: 587 memcpy(&xdb, data.data, sizeof(xdb)); 588 str_init(&buf); 589 ng_rprint(xdb, &buf); 590 (void) fprintf(stderr, "%s\t%s\n", 591 (char *) key.data, 592 buf.s_str ? buf.s_str : ""); 593 str_free(&buf); 594 break; 595 596 case 1: 597 return; 598 599 default: 600 err(1, "seq"); 601 return; 602 } 603 } 604 #endif /* DEBUG_NG */ 605 606 607 /* 608 * ng_write(): Dump the database into a file. 609 */ 610 static void 611 ng_write(odb, idb, k) 612 DB *odb, *idb; 613 int k; 614 { 615 int pos; 616 DBT key, data; 617 struct nentry *e; 618 struct string skey, sdata; 619 620 for (pos = R_FIRST;; pos = R_NEXT) 621 switch ((idb->seq)(idb, &key, &data, pos)) { 622 case 0: 623 memcpy(&e, data.data, sizeof(e)); 624 str_init(&skey); 625 str_init(&sdata); 626 assert(e->n_type == _NG_NAME); 627 628 str_prepend(&skey, e->n_name, k); 629 ng_print(e, &sdata); 630 key.data = (u_char *) skey.s_str; 631 key.size = skey.s_len + 1; 632 data.data = (u_char *) sdata.s_str; 633 data.size = sdata.s_len + 1; 634 635 switch ((odb->put)(odb, &key, &data, R_NOOVERWRITE)) { 636 case 0: 637 break; 638 639 case -1: 640 err(1, "put"); 641 break; 642 643 case 1: 644 default: 645 abort(); 646 break; 647 } 648 649 str_free(&skey); 650 str_free(&sdata); 651 break; 652 653 case 1: 654 return; 655 656 default: 657 err(1, "seq"); 658 return; 659 } 660 } 661 662 663 /* 664 * ng_rwrite(): Write the database 665 */ 666 static void 667 ng_rwrite(odb, idb, k) 668 DB *odb; 669 DB *idb; 670 int k; 671 { 672 int pos; 673 DBT key, data; 674 DB *xdb; 675 struct string skey, sdata; 676 677 for (pos = R_FIRST;; pos = R_NEXT) 678 switch ((idb->seq)(idb, &key, &data, pos)) { 679 case 0: 680 memcpy(&xdb, data.data, sizeof(xdb)); 681 str_init(&skey); 682 str_init(&sdata); 683 684 str_prepend(&skey, (char *) key.data, k); 685 ng_rprint(xdb, &sdata); 686 key.data = (u_char *) skey.s_str; 687 key.size = skey.s_len + 1; 688 data.data = (u_char *) sdata.s_str; 689 data.size = sdata.s_len + 1; 690 691 switch ((odb->put)(odb, &key, &data, R_NOOVERWRITE)) { 692 case 0: 693 break; 694 695 case -1: 696 err(1, "put"); 697 break; 698 699 case 1: 700 default: 701 abort(); 702 break; 703 } 704 705 str_free(&skey); 706 str_free(&sdata); 707 break; 708 709 case 1: 710 return; 711 712 default: 713 err(1, "seq"); 714 return; 715 } 716 } 717 718 719 /* 720 * usage(): Print usage message and exit 721 */ 722 static void 723 usage() 724 { 725 extern const char *__progname; 726 fprintf(stderr, "usage: %s [-o db] file\n", __progname); 727 exit(1); 728 } 729