netgroup_mkdb.c revision 1.5.2.1 1 /* $NetBSD: netgroup_mkdb.c,v 1.5.2.1 1996/11/06 00:17:57 lukem 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.2.1 1996/11/06 00:17:57 lukem 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 #include <stringlist.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, struct 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 struct 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, name) != NULL) {
374 warnx("Cycle in netgroup `%s'", name);
375 return;
376 }
377 _sl_add(ss, 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 case 0:
411 memcpy(&fe, data.data, sizeof(fe));
412 ng_reventry(db, udb, fe, e->n_name, s, ss);
413 break;
414
415 case 1:
416 break;
417
418 case -1:
419 err(1, "db get `%s'", e->n_name);
420 return;
421
422 default:
423 abort();
424 return;
425 }
426 break;
427
428 default:
429 abort();
430 break;
431 }
432 }
433
434
435 /*
436 * ng_reverse(): Reverse the database
437 */
438 static DB *
439 ng_reverse(db, s)
440 DB *db;
441 size_t s;
442 {
443 int pos;
444 struct stringlist *sl;
445 DBT key, data;
446 struct nentry *fe;
447 DB *udb = dbopen(NULL, O_RDWR | O_CREAT | O_EXCL, 0,
448 DB_HASH, NULL);
449
450 if (udb == NULL)
451 err(1, "dbopen");
452
453 for (pos = R_FIRST;; pos = R_NEXT)
454 switch ((db->seq)(db, &key, &data, pos)) {
455 case 0:
456 sl = _sl_init();
457 memcpy(&fe, data.data, sizeof(fe));
458 ng_reventry(db, udb, fe, (char *) key.data, s, sl);
459 _sl_free(sl, 0);
460 break;
461
462 case 1:
463 return udb;
464
465 case -1:
466 err(1, "seq");
467 return udb;
468 }
469
470 return udb;
471 }
472
473
474 /*
475 * ng_print(): Pretty print a netgroup entry
476 */
477 static void
478 ng_print(e, str)
479 struct nentry *e;
480 struct string *str;
481 {
482 char *ptr = emalloc(e->n_size);
483
484 if (e->n_next == NULL) {
485 str_append(str, "", ' ');
486 return;
487 }
488
489 for (e = e->n_next; e != NULL; e = e->n_next) {
490 switch (e->n_type) {
491 case _NG_NAME:
492 (void) snprintf(ptr, e->n_size, "%s", e->n_name);
493 break;
494
495 case _NG_GROUP:
496 (void) snprintf(ptr, e->n_size, "(%s,%s,%s)",
497 NG_EMPTY(e->n_group->ng_host),
498 NG_EMPTY(e->n_group->ng_user),
499 NG_EMPTY(e->n_group->ng_domain));
500 break;
501
502 default:
503 errx(1, "Internal error: Bad netgroup type\n");
504 break;
505 }
506 str_append(str, ptr, ' ');
507 }
508 free(ptr);
509 }
510
511
512 /*
513 * ng_rprint(): Pretty print all reverse netgroup mappings in the given entry
514 */
515 static void
516 ng_rprint(db, str)
517 DB *db;
518 struct string *str;
519 {
520 int pos;
521 DBT key, data;
522
523 for (pos = R_FIRST;; pos = R_NEXT)
524 switch ((db->seq)(db, &key, &data, pos)) {
525 case 0:
526 str_append(str, (char *) key.data, ',');
527 break;
528
529 case 1:
530 return;
531
532 default:
533 err(1, "seq");
534 break;
535 }
536 }
537
538
539 #ifdef DEBUG_NG
540 /*
541 * ng_dump(): Pretty print all netgroups in the given database
542 */
543 static void
544 ng_dump(db)
545 DB *db;
546 {
547 int pos;
548 DBT key, data;
549 struct nentry *e;
550 struct string buf;
551
552 for (pos = R_FIRST;; pos = R_NEXT)
553 switch ((db->seq)(db, &key, &data, pos)) {
554 case 0:
555 memcpy(&e, data.data, sizeof(e));
556 str_init(&buf);
557 assert(e->n_type == _NG_NAME);
558
559 ng_print(e, &buf);
560 (void) fprintf(stderr, "%s\t%s\n", e->n_name,
561 buf.s_str ? buf.s_str : "");
562 str_free(&buf);
563 break;
564
565 case 1:
566 return;
567
568 default:
569 err(1, "seq");
570 return;
571 }
572 }
573
574
575 /*
576 * ng_rdump(): Pretty print all reverse mappings in the given database
577 */
578 static void
579 ng_rdump(db)
580 DB *db;
581 {
582 int pos;
583 DBT key, data;
584 DB *xdb;
585 struct string buf;
586
587 for (pos = R_FIRST;; pos = R_NEXT)
588 switch ((db->seq)(db, &key, &data, pos)) {
589 case 0:
590 memcpy(&xdb, data.data, sizeof(xdb));
591 str_init(&buf);
592 ng_rprint(xdb, &buf);
593 (void) fprintf(stderr, "%s\t%s\n",
594 (char *) key.data,
595 buf.s_str ? buf.s_str : "");
596 str_free(&buf);
597 break;
598
599 case 1:
600 return;
601
602 default:
603 err(1, "seq");
604 return;
605 }
606 }
607 #endif /* DEBUG_NG */
608
609
610 /*
611 * ng_write(): Dump the database into a file.
612 */
613 static void
614 ng_write(odb, idb, k)
615 DB *odb, *idb;
616 int k;
617 {
618 int pos;
619 DBT key, data;
620 struct nentry *e;
621 struct string skey, sdata;
622
623 for (pos = R_FIRST;; pos = R_NEXT)
624 switch ((idb->seq)(idb, &key, &data, pos)) {
625 case 0:
626 memcpy(&e, data.data, sizeof(e));
627 str_init(&skey);
628 str_init(&sdata);
629 assert(e->n_type == _NG_NAME);
630
631 str_prepend(&skey, e->n_name, k);
632 ng_print(e, &sdata);
633 key.data = (u_char *) skey.s_str;
634 key.size = skey.s_len + 1;
635 data.data = (u_char *) sdata.s_str;
636 data.size = sdata.s_len + 1;
637
638 switch ((odb->put)(odb, &key, &data, R_NOOVERWRITE)) {
639 case 0:
640 break;
641
642 case -1:
643 err(1, "put");
644 break;
645
646 case 1:
647 default:
648 abort();
649 break;
650 }
651
652 str_free(&skey);
653 str_free(&sdata);
654 break;
655
656 case 1:
657 return;
658
659 default:
660 err(1, "seq");
661 return;
662 }
663 }
664
665
666 /*
667 * ng_rwrite(): Write the database
668 */
669 static void
670 ng_rwrite(odb, idb, k)
671 DB *odb;
672 DB *idb;
673 int k;
674 {
675 int pos;
676 DBT key, data;
677 DB *xdb;
678 struct string skey, sdata;
679
680 for (pos = R_FIRST;; pos = R_NEXT)
681 switch ((idb->seq)(idb, &key, &data, pos)) {
682 case 0:
683 memcpy(&xdb, data.data, sizeof(xdb));
684 str_init(&skey);
685 str_init(&sdata);
686
687 str_prepend(&skey, (char *) key.data, k);
688 ng_rprint(xdb, &sdata);
689 key.data = (u_char *) skey.s_str;
690 key.size = skey.s_len + 1;
691 data.data = (u_char *) sdata.s_str;
692 data.size = sdata.s_len + 1;
693
694 switch ((odb->put)(odb, &key, &data, R_NOOVERWRITE)) {
695 case 0:
696 break;
697
698 case -1:
699 err(1, "put");
700 break;
701
702 case 1:
703 default:
704 abort();
705 break;
706 }
707
708 str_free(&skey);
709 str_free(&sdata);
710 break;
711
712 case 1:
713 return;
714
715 default:
716 err(1, "seq");
717 return;
718 }
719 }
720
721
722 /*
723 * usage(): Print usage message and exit
724 */
725 static void
726 usage()
727 {
728 extern const char *__progname;
729 fprintf(stderr, "usage: %s [-o db] file\n", __progname);
730 exit(1);
731 }
732