xref: /freebsd/usr.bin/cap_mkdb/cap_mkdb.c (revision daf1cffce2e07931f27c6c6998652e90df6ba87e)
1 /*-
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  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 the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY 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 #ifndef lint
35 static const char copyright[] =
36 "@(#) Copyright (c) 1992, 1993\n\
37 	The Regents of the University of California.  All rights reserved.\n";
38 #endif /* not lint */
39 
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)cap_mkdb.c	8.1 (Berkeley) 6/6/93";
43 #endif
44 static const char rcsid[] =
45 	"$FreeBSD$";
46 #endif /* not lint */
47 
48 #include <sys/param.h>
49 #include <sys/stat.h>
50 
51 #include <db.h>
52 #include <err.h>
53 #include <fcntl.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <unistd.h>
58 
59 void	 db_build __P((char **));
60 void	 dounlink __P((void));
61 void	 usage __P((void));
62 
63 DB *capdbp;
64 int verbose;
65 char *capdb, *capname, buf[8 * 1024];
66 
67 /*
68  * Mkcapdb creates a capability hash database for quick retrieval of capability
69  * records.  The database contains 2 types of entries: records and references
70  * marked by the first byte in the data.  A record entry contains the actual
71  * capability record whereas a reference contains the name (key) under which
72  * the correct record is stored.
73  */
74 int
75 main(argc, argv)
76 	int argc;
77 	char *argv[];
78 {
79 	int c;
80 
81 	capname = NULL;
82 	while ((c = getopt(argc, argv, "f:v")) != -1) {
83 		switch(c) {
84 		case 'f':
85 			capname = optarg;
86 			break;
87 		case 'v':
88 			verbose = 1;
89 			break;
90 		case '?':
91 		default:
92 			usage();
93 		}
94 	}
95 	argc -= optind;
96 	argv += optind;
97 
98 	if (*argv == NULL)
99 		usage();
100 
101 	/*
102 	 * The database file is the first argument if no name is specified.
103 	 * Make arrangements to unlink it if exit badly.
104 	 */
105 	(void)snprintf(buf, sizeof(buf), "%s.db", capname ? capname : *argv);
106 	if ((capname = strdup(buf)) == NULL)
107 		errx(1, "strdup failed");
108 	if ((capdbp = dbopen(capname,
109 	    O_CREAT | O_TRUNC | O_RDWR, DEFFILEMODE, DB_HASH, NULL)) == NULL)
110 		err(1, "%s", buf);
111 
112 	if (atexit(dounlink))
113 		err(1, "atexit");
114 
115 	db_build(argv);
116 
117 	if (capdbp->close(capdbp) < 0)
118 		err(1, "%s", capname);
119 	capname = NULL;
120 	exit(0);
121 }
122 
123 void
124 dounlink()
125 {
126 	if (capname != NULL)
127 		(void)unlink(capname);
128 }
129 
130 /*
131  * Any changes to these definitions should be made also in the getcap(3)
132  * library routines.
133  */
134 #define RECOK	(char)0
135 #define TCERR	(char)1
136 #define SHADOW	(char)2
137 
138 /*
139  * Db_build() builds the name and capabilty databases according to the
140  * details above.
141  */
142 void
143 db_build(ifiles)
144 	char **ifiles;
145 {
146 	DBT key, data;
147 	recno_t reccnt;
148 	size_t len, bplen;
149 	int st;
150 	char *bp, *p, *t;
151 
152 	data.data = NULL;
153 	key.data = NULL;
154 	for (reccnt = 0, bplen = 0; (st = cgetnext(&bp, ifiles)) > 0;) {
155 
156 		/*
157 		 * Allocate enough memory to store record, terminating
158 		 * NULL and one extra byte.
159 		 */
160 		len = strlen(bp);
161 		if (bplen <= len + 2) {
162 			bplen += MAX(256, len + 2);
163 			if ((data.data = realloc(data.data, bplen)) == NULL)
164 				errx(1, "malloc failed");
165 		}
166 
167 		/* Find the end of the name field. */
168 		if ((p = strchr(bp, ':')) == NULL) {
169 			warnx("no name field: %.*s", (int)MIN(len, 20), bp);
170 			continue;
171 		}
172 
173 		/* First byte of stored record indicates status. */
174 		switch(st) {
175 		case 1:
176 			((char *)(data.data))[0] = RECOK;
177 			break;
178 		case 2:
179 			((char *)(data.data))[0] = TCERR;
180 			warnx("record not tc expanded: %.*s", p - bp, bp);
181 			break;
182 		}
183 
184 		/* Create the stored record. */
185 		memmove(&((u_char *)(data.data))[1], bp, len + 1);
186 		data.size = len + 2;
187 
188 		/* Store the record under the name field. */
189 		key.data = bp;
190 		key.size = p - bp;
191 
192 		switch(capdbp->put(capdbp, &key, &data, R_NOOVERWRITE)) {
193 		case -1:
194 			err(1, "put");
195 			/* NOTREACHED */
196 		case 1:
197 			warnx("ignored duplicate: %.*s",
198 			    (int)key.size, (char *)key.data);
199 			continue;
200 		}
201 		++reccnt;
202 
203 		/* If only one name, ignore the rest. */
204 		if ((p = strchr(bp, '|')) == NULL)
205 			continue;
206 
207 		/* The rest of the names reference the entire name. */
208 		((char *)(data.data))[0] = SHADOW;
209 		memmove(&((u_char *)(data.data))[1], key.data, key.size);
210 		data.size = key.size + 1;
211 
212 		/* Store references for other names. */
213 		for (p = t = bp;; ++p) {
214 			if (p > t && (*p == ':' || *p == '|')) {
215 				key.size = p - t;
216 				key.data = t;
217 				switch(capdbp->put(capdbp,
218 				    &key, &data, R_NOOVERWRITE)) {
219 				case -1:
220 					err(1, "put");
221 					/* NOTREACHED */
222 				case 1:
223 					warnx("ignored duplicate: %.*s",
224 					    (int)key.size, (char *)key.data);
225 				}
226 				t = p + 1;
227 			}
228 			if (*p == ':')
229 				break;
230 		}
231 	}
232 
233 	switch(st) {
234 	case -1:
235 		err(1, "file argument");
236 		/* NOTREACHED */
237 	case -2:
238 		errx(1, "potential reference loop detected");
239 		/* NOTREACHED */
240 	}
241 
242 	if (verbose)
243 		(void)printf("cap_mkdb: %d capability records\n", reccnt);
244 }
245 
246 void
247 usage()
248 {
249 	(void)fprintf(stderr,
250 	    "usage: cap_mkdb [-v] [-f outfile] file [file ...]\n");
251 	exit(1);
252 }
253