netgroup_mkdb.c revision 1.8 1 /* $NetBSD: netgroup_mkdb.c,v 1.8 1997/10/17 11:49:05 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 #include <sys/cdefs.h>
34 #ifndef lint
35 __RCSID("$NetBSD: netgroup_mkdb.c,v 1.8 1997/10/17 11:49:05 lukem 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, 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, 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'\n",
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 default:
294 abort();
295 break;
296 }
297 }
298 }
299 (void) fclose(fp);
300 return db;
301 }
302
303
304 /*
305 * ng_insert(): Insert named key into the database, and return its associated
306 * string database
307 */
308 static DB *
309 ng_insert(db, name)
310 DB *db;
311 const char *name;
312 {
313 DB *xdb = NULL;
314 DBT key, data;
315
316 key.data = (u_char *) name;
317 key.size = strlen(name) + 1;
318
319 switch ((db->get)(db, &key, &data, 0)) {
320 case 0:
321 memcpy(&xdb, data.data, sizeof(xdb));
322 break;
323
324 case 1:
325 xdb = dbopen(NULL, O_RDWR | O_CREAT | O_EXCL, 0, DB_HASH, NULL);
326 if (xdb == NULL)
327 err(1, "dbopen");
328
329 data.data = (u_char *) & xdb;
330 data.size = sizeof(xdb);
331 switch ((db->put)(db, &key, &data, R_NOOVERWRITE)) {
332 case 0:
333 break;
334
335 case -1:
336 err(1, "db put `%s'", name);
337 break;
338
339 case 1:
340 default:
341 abort();
342 }
343 break;
344
345 case -1:
346 err(1, "db get `%s'", name);
347 break;
348
349 default:
350 abort();
351 break;
352 }
353
354 return xdb;
355 }
356
357
358 /*
359 * ng_reventry(): Recursively add all the netgroups to the group entry.
360 */
361 static void
362 ng_reventry(db, udb, fe, name, s, ss)
363 DB *db, *udb;
364 struct nentry *fe;
365 char *name;
366 size_t s;
367 StringList *ss;
368 {
369 DBT key, data;
370 struct nentry *e;
371 struct netgroup *ng;
372 char *p;
373 DB *xdb;
374
375 if (sl_find(ss, fe->n_name) != NULL) {
376 warnx("Cycle in netgroup `%s'", name);
377 return;
378 }
379 sl_add(ss, fe->n_name);
380
381 for (e = fe->n_next; e != NULL; e = e->n_next)
382 switch (e->n_type) {
383 case _NG_GROUP:
384 ng = e->n_group;
385 p = _ng_makekey(*((char **)(((char *) ng) + s)),
386 ng->ng_domain, e->n_size);
387 xdb = ng_insert(udb, p);
388 key.data = (u_char *) name;
389 key.size = strlen(name) + 1;
390 data.data = NULL;
391 data.size = 0;
392 switch ((xdb->put)(xdb, &key, &data, R_NOOVERWRITE)) {
393 case 0:
394 case 1:
395 break;
396
397 case -1:
398 err(1, "db put `%s'", name);
399 return;
400
401 default:
402 abort();
403 break;
404 }
405 free(p);
406 break;
407
408 case _NG_NAME:
409 key.data = (u_char *) e->n_name;
410 key.size = strlen(e->n_name) + 1;
411 switch ((db->get)(db, &key, &data, 0)) {
412 struct nentry *rfe;
413 case 0:
414 (void) memcpy(&rfe, data.data, sizeof(rfe));
415 ng_reventry(db, udb, rfe, name, s, ss);
416 break;
417
418 case 1:
419 break;
420
421 case -1:
422 err(1, "db get `%s'", e->n_name);
423 return;
424
425 default:
426 abort();
427 return;
428 }
429 break;
430
431 default:
432 abort();
433 break;
434 }
435 }
436
437
438 /*
439 * ng_reverse(): Reverse the database
440 */
441 static DB *
442 ng_reverse(db, s)
443 DB *db;
444 size_t s;
445 {
446 int pos;
447 StringList *sl;
448 DBT key, data;
449 struct nentry *fe;
450 DB *udb = dbopen(NULL, O_RDWR | O_CREAT | O_EXCL, 0,
451 DB_HASH, NULL);
452
453 if (udb == NULL)
454 err(1, "dbopen");
455
456 for (pos = R_FIRST;; pos = R_NEXT)
457 switch ((db->seq)(db, &key, &data, pos)) {
458 case 0:
459 sl = sl_init();
460 memcpy(&fe, data.data, sizeof(fe));
461 ng_reventry(db, udb, fe, (char *) key.data, s, sl);
462 sl_free(sl, 0);
463 break;
464
465 case 1:
466 return udb;
467
468 case -1:
469 err(1, "seq");
470 return udb;
471 }
472
473 return udb;
474 }
475
476
477 /*
478 * ng_print(): Pretty print a netgroup entry
479 */
480 static void
481 ng_print(e, str)
482 struct nentry *e;
483 struct string *str;
484 {
485 char *ptr = emalloc(e->n_size);
486
487 if (e->n_next == NULL) {
488 str_append(str, "", ' ');
489 return;
490 }
491
492 for (e = e->n_next; e != NULL; e = e->n_next) {
493 switch (e->n_type) {
494 case _NG_NAME:
495 (void) snprintf(ptr, e->n_size, "%s", e->n_name);
496 break;
497
498 case _NG_GROUP:
499 (void) snprintf(ptr, e->n_size, "(%s,%s,%s)",
500 NG_EMPTY(e->n_group->ng_host),
501 NG_EMPTY(e->n_group->ng_user),
502 NG_EMPTY(e->n_group->ng_domain));
503 break;
504
505 default:
506 errx(1, "Internal error: Bad netgroup type\n");
507 break;
508 }
509 str_append(str, ptr, ' ');
510 }
511 free(ptr);
512 }
513
514
515 /*
516 * ng_rprint(): Pretty print all reverse netgroup mappings in the given entry
517 */
518 static void
519 ng_rprint(db, str)
520 DB *db;
521 struct string *str;
522 {
523 int pos;
524 DBT key, data;
525
526 for (pos = R_FIRST;; pos = R_NEXT)
527 switch ((db->seq)(db, &key, &data, pos)) {
528 case 0:
529 str_append(str, (char *) key.data, ',');
530 break;
531
532 case 1:
533 return;
534
535 default:
536 err(1, "seq");
537 break;
538 }
539 }
540
541
542 #ifdef DEBUG_NG
543 /*
544 * ng_dump(): Pretty print all netgroups in the given database
545 */
546 static void
547 ng_dump(db)
548 DB *db;
549 {
550 int pos;
551 DBT key, data;
552 struct nentry *e;
553 struct string buf;
554
555 for (pos = R_FIRST;; pos = R_NEXT)
556 switch ((db->seq)(db, &key, &data, pos)) {
557 case 0:
558 memcpy(&e, data.data, sizeof(e));
559 str_init(&buf);
560 assert(e->n_type == _NG_NAME);
561
562 ng_print(e, &buf);
563 (void) fprintf(stderr, "%s\t%s\n", e->n_name,
564 buf.s_str ? buf.s_str : "");
565 str_free(&buf);
566 break;
567
568 case 1:
569 return;
570
571 default:
572 err(1, "seq");
573 return;
574 }
575 }
576
577
578 /*
579 * ng_rdump(): Pretty print all reverse mappings in the given database
580 */
581 static void
582 ng_rdump(db)
583 DB *db;
584 {
585 int pos;
586 DBT key, data;
587 DB *xdb;
588 struct string buf;
589
590 for (pos = R_FIRST;; pos = R_NEXT)
591 switch ((db->seq)(db, &key, &data, pos)) {
592 case 0:
593 memcpy(&xdb, data.data, sizeof(xdb));
594 str_init(&buf);
595 ng_rprint(xdb, &buf);
596 (void) fprintf(stderr, "%s\t%s\n",
597 (char *) key.data,
598 buf.s_str ? buf.s_str : "");
599 str_free(&buf);
600 break;
601
602 case 1:
603 return;
604
605 default:
606 err(1, "seq");
607 return;
608 }
609 }
610 #endif /* DEBUG_NG */
611
612
613 /*
614 * ng_write(): Dump the database into a file.
615 */
616 static void
617 ng_write(odb, idb, k)
618 DB *odb, *idb;
619 int k;
620 {
621 int pos;
622 DBT key, data;
623 struct nentry *e;
624 struct string skey, sdata;
625
626 for (pos = R_FIRST;; pos = R_NEXT)
627 switch ((idb->seq)(idb, &key, &data, pos)) {
628 case 0:
629 memcpy(&e, data.data, sizeof(e));
630 str_init(&skey);
631 str_init(&sdata);
632 assert(e->n_type == _NG_NAME);
633
634 str_prepend(&skey, e->n_name, k);
635 ng_print(e, &sdata);
636 key.data = (u_char *) skey.s_str;
637 key.size = skey.s_len + 1;
638 data.data = (u_char *) sdata.s_str;
639 data.size = sdata.s_len + 1;
640
641 switch ((odb->put)(odb, &key, &data, R_NOOVERWRITE)) {
642 case 0:
643 break;
644
645 case -1:
646 err(1, "put");
647 break;
648
649 case 1:
650 default:
651 abort();
652 break;
653 }
654
655 str_free(&skey);
656 str_free(&sdata);
657 break;
658
659 case 1:
660 return;
661
662 default:
663 err(1, "seq");
664 return;
665 }
666 }
667
668
669 /*
670 * ng_rwrite(): Write the database
671 */
672 static void
673 ng_rwrite(odb, idb, k)
674 DB *odb;
675 DB *idb;
676 int k;
677 {
678 int pos;
679 DBT key, data;
680 DB *xdb;
681 struct string skey, sdata;
682
683 for (pos = R_FIRST;; pos = R_NEXT)
684 switch ((idb->seq)(idb, &key, &data, pos)) {
685 case 0:
686 memcpy(&xdb, data.data, sizeof(xdb));
687 str_init(&skey);
688 str_init(&sdata);
689
690 str_prepend(&skey, (char *) key.data, k);
691 ng_rprint(xdb, &sdata);
692 key.data = (u_char *) skey.s_str;
693 key.size = skey.s_len + 1;
694 data.data = (u_char *) sdata.s_str;
695 data.size = sdata.s_len + 1;
696
697 switch ((odb->put)(odb, &key, &data, R_NOOVERWRITE)) {
698 case 0:
699 break;
700
701 case -1:
702 err(1, "put");
703 break;
704
705 case 1:
706 default:
707 abort();
708 break;
709 }
710
711 str_free(&skey);
712 str_free(&sdata);
713 break;
714
715 case 1:
716 return;
717
718 default:
719 err(1, "seq");
720 return;
721 }
722 }
723
724
725 /*
726 * usage(): Print usage message and exit
727 */
728 static void
729 usage()
730 {
731 extern const char *__progname;
732 fprintf(stderr, "usage: %s [-o db] file\n", __progname);
733 exit(1);
734 }
735