netgroup_mkdb.c revision 1.9 1 /* $NetBSD: netgroup_mkdb.c,v 1.9 1999/11/28 04:40:21 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.9 1999/11/28 04:40:21 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 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 = emalloc(e->n_size);
490
491 if (e->n_next == NULL) {
492 str_append(str, "", ' ');
493 return;
494 }
495
496 for (e = e->n_next; e != NULL; e = e->n_next) {
497 switch (e->n_type) {
498 case _NG_NAME:
499 (void) snprintf(ptr, e->n_size, "%s", e->n_name);
500 break;
501
502 case _NG_GROUP:
503 (void) snprintf(ptr, e->n_size, "(%s,%s,%s)",
504 NG_EMPTY(e->n_group->ng_host),
505 NG_EMPTY(e->n_group->ng_user),
506 NG_EMPTY(e->n_group->ng_domain));
507 break;
508
509 default:
510 errx(1, "Internal error: Bad netgroup type\n");
511 break;
512 }
513 str_append(str, ptr, ' ');
514 }
515 free(ptr);
516 }
517
518
519 /*
520 * ng_rprint(): Pretty print all reverse netgroup mappings in the given entry
521 */
522 static void
523 ng_rprint(db, str)
524 DB *db;
525 struct string *str;
526 {
527 int pos;
528 DBT key, data;
529
530 for (pos = R_FIRST;; pos = R_NEXT)
531 switch ((db->seq)(db, &key, &data, pos)) {
532 case 0:
533 str_append(str, (char *) key.data, ',');
534 break;
535
536 case 1:
537 return;
538
539 default:
540 err(1, "seq");
541 break;
542 }
543 }
544
545
546 #ifdef DEBUG_NG
547 /*
548 * ng_dump(): Pretty print all netgroups in the given database
549 */
550 static void
551 ng_dump(db)
552 DB *db;
553 {
554 int pos;
555 DBT key, data;
556 struct nentry *e;
557 struct string buf;
558
559 for (pos = R_FIRST;; pos = R_NEXT)
560 switch ((db->seq)(db, &key, &data, pos)) {
561 case 0:
562 memcpy(&e, data.data, sizeof(e));
563 str_init(&buf);
564 assert(e->n_type == _NG_NAME);
565
566 ng_print(e, &buf);
567 (void) fprintf(stderr, "%s\t%s\n", e->n_name,
568 buf.s_str ? buf.s_str : "");
569 str_free(&buf);
570 break;
571
572 case 1:
573 return;
574
575 default:
576 err(1, "seq");
577 return;
578 }
579 }
580
581
582 /*
583 * ng_rdump(): Pretty print all reverse mappings in the given database
584 */
585 static void
586 ng_rdump(db)
587 DB *db;
588 {
589 int pos;
590 DBT key, data;
591 DB *xdb;
592 struct string buf;
593
594 for (pos = R_FIRST;; pos = R_NEXT)
595 switch ((db->seq)(db, &key, &data, pos)) {
596 case 0:
597 memcpy(&xdb, data.data, sizeof(xdb));
598 str_init(&buf);
599 ng_rprint(xdb, &buf);
600 (void) fprintf(stderr, "%s\t%s\n",
601 (char *) key.data,
602 buf.s_str ? buf.s_str : "");
603 str_free(&buf);
604 break;
605
606 case 1:
607 return;
608
609 default:
610 err(1, "seq");
611 return;
612 }
613 }
614 #endif /* DEBUG_NG */
615
616
617 /*
618 * ng_write(): Dump the database into a file.
619 */
620 static void
621 ng_write(odb, idb, k)
622 DB *odb, *idb;
623 int k;
624 {
625 int pos;
626 DBT key, data;
627 struct nentry *e;
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(&e, data.data, sizeof(e));
634 str_init(&skey);
635 str_init(&sdata);
636 assert(e->n_type == _NG_NAME);
637
638 str_prepend(&skey, e->n_name, k);
639 ng_print(e, &sdata);
640 key.data = (u_char *) skey.s_str;
641 key.size = skey.s_len + 1;
642 data.data = (u_char *) sdata.s_str;
643 data.size = sdata.s_len + 1;
644
645 switch ((odb->put)(odb, &key, &data, R_NOOVERWRITE)) {
646 case 0:
647 break;
648
649 case -1:
650 err(1, "put");
651 break;
652
653 case 1:
654 default:
655 abort();
656 break;
657 }
658
659 str_free(&skey);
660 str_free(&sdata);
661 break;
662
663 case 1:
664 return;
665
666 default:
667 err(1, "seq");
668 return;
669 }
670 }
671
672
673 /*
674 * ng_rwrite(): Write the database
675 */
676 static void
677 ng_rwrite(odb, idb, k)
678 DB *odb;
679 DB *idb;
680 int k;
681 {
682 int pos;
683 DBT key, data;
684 DB *xdb;
685 struct string skey, sdata;
686
687 for (pos = R_FIRST;; pos = R_NEXT)
688 switch ((idb->seq)(idb, &key, &data, pos)) {
689 case 0:
690 memcpy(&xdb, data.data, sizeof(xdb));
691 str_init(&skey);
692 str_init(&sdata);
693
694 str_prepend(&skey, (char *) key.data, k);
695 ng_rprint(xdb, &sdata);
696 key.data = (u_char *) skey.s_str;
697 key.size = skey.s_len + 1;
698 data.data = (u_char *) sdata.s_str;
699 data.size = sdata.s_len + 1;
700
701 switch ((odb->put)(odb, &key, &data, R_NOOVERWRITE)) {
702 case 0:
703 break;
704
705 case -1:
706 err(1, "put");
707 break;
708
709 case 1:
710 default:
711 abort();
712 break;
713 }
714
715 str_free(&skey);
716 str_free(&sdata);
717 break;
718
719 case 1:
720 return;
721
722 default:
723 err(1, "seq");
724 return;
725 }
726 }
727
728
729 /*
730 * usage(): Print usage message and exit
731 */
732 static void
733 usage()
734 {
735 extern const char *__progname;
736 fprintf(stderr, "usage: %s [-o db] file\n", __progname);
737 exit(1);
738 }
739