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