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