GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/netgroup_mkdb/netgroup_mkdb.c Lines: 0 242 0.0 %
Date: 2017-11-13 Branches: 0 117 0.0 %

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