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