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