GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/cap_mkdb/cap_mkdb.c Lines: 7 100 7.0 %
Date: 2017-11-07 Branches: 3 61 4.9 %

Line Branch Exec Source
1
/*	$OpenBSD: cap_mkdb.c,v 1.22 2015/12/04 19:15:54 jmc Exp $	*/
2
/*	$NetBSD: cap_mkdb.c,v 1.5 1995/09/02 05:47:12 jtc Exp $	*/
3
4
/*-
5
 * Copyright (c) 1992, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
#include <sys/stat.h>
34
35
#include <db.h>
36
#include <err.h>
37
#include <errno.h>
38
#include <fcntl.h>
39
#include <limits.h>
40
#include <stdio.h>
41
#include <stdlib.h>
42
#include <string.h>
43
#include <ctype.h>
44
#include <unistd.h>
45
46
#define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
47
#define MAXIMUM(a, b)	(((a) > (b)) ? (a) : (b))
48
49
void	 db_build(char **);
50
void	 dounlink(void);
51
void	 usage(void);
52
int	 igetnext(char **, char **);
53
int	 main(int, char *[]);
54
55
DB *capdbp;
56
int verbose;
57
char *capname, buf[8 * 1024];
58
59
HASHINFO openinfo = {
60
	4096,		/* bsize */
61
	16,		/* ffactor */
62
	256,		/* nelem */
63
	2048 * 1024,	/* cachesize */
64
	NULL,		/* hash() */
65
	0		/* lorder */
66
};
67
68
/*
69
 * cap_mkdb creates a capability hash database for quick retrieval of capability
70
 * records.  The database contains 2 types of entries: records and references
71
 * marked by the first byte in the data.  A record entry contains the actual
72
 * capability record whereas a reference contains the name (key) under which
73
 * the correct record is stored.
74
 */
75
int
76
main(int argc, char *argv[])
77
{
78
	int c;
79
80
2
	if (pledge("stdio rpath wpath cpath flock", NULL) == -1)
81
		err(1, "pledge");
82
83
1
	capname = NULL;
84
2
	while ((c = getopt(argc, argv, "f:iv")) != -1) {
85
1
		switch(c) {
86
		case 'f':
87
			capname = optarg;
88
			break;
89
		case 'v':
90
			verbose = 1;
91
			break;
92
		case '?':
93
		default:
94
1
			usage();
95
1
		}
96
	}
97
	argc -= optind;
98
	argv += optind;
99
100
	if (*argv == NULL)
101
		usage();
102
103
	/*
104
	 * The database file is the first argument if no name is specified.
105
	 * Make arrangements to unlink it if we exit badly.
106
	 */
107
	(void)snprintf(buf, sizeof(buf), "%s.db", capname ? capname : *argv);
108
	if ((capname = strdup(buf)) == NULL)
109
		err(1, NULL);
110
	if ((capdbp = dbopen(capname, O_CREAT | O_TRUNC | O_RDWR,
111
	    DEFFILEMODE, DB_HASH, &openinfo)) == NULL)
112
		err(1, "%s", buf);
113
114
	if (atexit(dounlink))
115
		err(1, "atexit");
116
117
	db_build(argv);
118
119
	if (capdbp->close(capdbp) < 0)
120
		err(1, "%s", capname);
121
	capname = NULL;
122
	exit(0);
123
}
124
125
void
126
dounlink(void)
127
{
128
	if (capname != NULL)
129
		(void)unlink(capname);
130
}
131
132
/*
133
 * Any changes to these definitions should be made also in the getcap(3)
134
 * library routines.
135
 */
136
#define RECOK	(char)0
137
#define TCERR	(char)1
138
#define SHADOW	(char)2
139
140
/*
141
 * db_build() builds the name and capability databases according to the
142
 * details above.
143
 */
144
void
145
db_build(char **ifiles)
146
{
147
	DBT key, data;
148
	recno_t reccnt;
149
	size_t len, bplen;
150
	int st;
151
	char *bp, *p, *t, *capbeg, *capend;
152
153
	cgetusedb(0);		/* disable reading of .db files in getcap(3) */
154
155
	data.data = NULL;
156
	key.data = NULL;
157
	for (reccnt = 0, bplen = 0; (st = cgetnext(&bp, ifiles)) > 0;) {
158
159
		/*
160
		 * Allocate enough memory to store the size of the record plus
161
		 * a terminating NULL and one extra byte.
162
		 */
163
		len = strlen(bp);
164
		if (bplen <= len + 2) {
165
			int newbplen = bplen + MAXIMUM(256, len + 2);
166
			void *newdata;
167
168
			if ((newdata = realloc(data.data, newbplen)) == NULL)
169
				err(1, NULL);
170
			data.data = newdata;
171
			bplen = newbplen;
172
		}
173
174
		/* Find the end of the name field. */
175
		if ((p = strchr(bp, ':')) == NULL) {
176
			warnx("no name field: %.*s", (int)MINIMUM(len, 20), bp);
177
			continue;
178
		}
179
180
		/* First byte of stored record indicates status. */
181
		switch(st) {
182
		case 1:
183
			((char *)(data.data))[0] = RECOK;
184
			break;
185
		case 2:
186
			((char *)(data.data))[0] = TCERR;
187
			warnx("Record not tc expanded: %.*s", (int)(p - bp), bp);
188
			break;
189
		}
190
191
		/* Create the stored record. */
192
		t = (char *)data.data + 1;
193
		/* Copy the cap name and trailing ':' */
194
		len = p - bp + 1;
195
		memcpy(t, bp, len);
196
		t += len;
197
198
		/* Copy entry, collapsing empty fields. */
199
		capbeg = p + 1;
200
		while (*capbeg) {
201
			/* Skip empty fields. */
202
			if ((len = strspn(capbeg, ": \t\n\r")))
203
				capbeg += len;
204
205
			/* Find the end of this cap and copy it w/ : */
206
			capend = strchr(capbeg, ':');
207
			if (capend)
208
				len = capend - capbeg + 1;
209
			else
210
				len = strlen(capbeg);
211
			memcpy(t, capbeg, len);
212
			t += len;
213
			capbeg += len;
214
		}
215
		*t = '\0';
216
		data.size = t - (char *)data.data + 1;
217
218
		/* Store the record under the name field. */
219
		key.data = bp;
220
		key.size = p - bp;
221
222
		switch(capdbp->put(capdbp, &key, &data, R_NOOVERWRITE)) {
223
		case -1:
224
			err(1, "put");
225
			/* NOTREACHED */
226
		case 1:
227
			warnx("ignored duplicate: %.*s",
228
			    (int)key.size, (char *)key.data);
229
			continue;
230
		}
231
		++reccnt;
232
233
		/* If only one name, ignore the rest. */
234
		if ((p = strchr(bp, '|')) == NULL)
235
			continue;
236
237
		/* The rest of the names reference the entire name. */
238
		((char *)(data.data))[0] = SHADOW;
239
		(void) memmove(&((u_char *)(data.data))[1], key.data, key.size);
240
		data.size = key.size + 1;
241
242
		/* Store references for other names. */
243
		for (p = t = bp;; ++p) {
244
			if (p > t && (*p == ':' || *p == '|')) {
245
				key.size = p - t;
246
				key.data = t;
247
248
				/*
249
				 * If this is the last entry and contains any
250
				 * spaces, it is a description rather than an
251
				 * alias, so skip it and break.
252
				 */
253
				if (*p != '|' &&
254
				    memchr(key.data, ' ', key.size) != NULL)
255
					break;
256
257
				switch(capdbp->put(capdbp,
258
				    &key, &data, R_NOOVERWRITE)) {
259
				case -1:
260
					err(1, "put");
261
					/* NOTREACHED */
262
				case 1:
263
					warnx("ignored duplicate: %.*s",
264
					      (int)key.size, (char *)key.data);
265
				}
266
				t = p + 1;
267
			}
268
			if (*p == ':')
269
				break;
270
		}
271
		free(bp);
272
	}
273
274
	switch(st) {
275
	case -1:
276
		err(1, "file argument");
277
		/* NOTREACHED */
278
	case -2:
279
		errx(1, "potential reference loop detected");
280
		/* NOTREACHED */
281
	}
282
283
	if (verbose)
284
		(void)printf("cap_mkdb: %d capability records\n", reccnt);
285
}
286
287
void
288
usage(void)
289
{
290
1
	(void)fprintf(stderr,
291
	    "usage: cap_mkdb [-v] [-f outfile] file1 [file2 ...]\n");
292
	exit(1);
293
}