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