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