xref: /original-bsd/usr.bin/cap_mkdb/cap_mkdb.c (revision b4971bb3)
1 /*-
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1992, 1993\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)cap_mkdb.c	8.1 (Berkeley) 06/06/93";
16 #endif /* not lint */
17 
18 #include <sys/param.h>
19 #include <sys/stat.h>
20 
21 #include <db.h>
22 #include <err.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <limits.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 
31 void	 db_build __P((char **));
32 void	 dounlink __P((void));
33 void	 usage __P((void));
34 
35 DB *capdbp;
36 int verbose;
37 char *capdb, *capname, buf[8 * 1024];
38 
39 /*
40  * Mkcapdb creates a capability hash database for quick retrieval of capability
41  * records.  The database contains 2 types of entries: records and references
42  * marked by the first byte in the data.  A record entry contains the actual
43  * capability record whereas a reference contains the name (key) under which
44  * the correct record is stored.
45  */
46 int
47 main(argc, argv)
48 	int argc;
49 	char *argv[];
50 {
51 	int c;
52 
53 	capname = NULL;
54 	while ((c = getopt(argc, argv, "f:v")) != EOF) {
55 		switch(c) {
56 		case 'f':
57 			capname = optarg;
58 			break;
59 		case 'v':
60 			verbose = 1;
61 			break;
62 		case '?':
63 		default:
64 			usage();
65 		}
66 	}
67 	argc -= optind;
68 	argv += optind;
69 
70 	if (*argv == NULL)
71 		usage();
72 
73 	/*
74 	 * The database file is the first argument if no name is specified.
75 	 * Make arrangements to unlink it if exit badly.
76 	 */
77 	(void)snprintf(buf, sizeof(buf), "%s.db", capname ? capname : *argv);
78 	if ((capname = strdup(buf)) == NULL)
79 		err(1, "");
80 	if ((capdbp = dbopen(capname,
81 	    O_CREAT | O_TRUNC | O_RDWR, DEFFILEMODE, DB_HASH, NULL)) == NULL)
82 		err(1, "%s", buf);
83 
84 	if (atexit(dounlink))
85 		err(1, "atexit");
86 
87 	db_build(argv);
88 
89 	if (capdbp->close(capdbp) < 0)
90 		err(1, "%s", capname);
91 	capname = NULL;
92 	exit(0);
93 }
94 
95 void
96 dounlink()
97 {
98 	if (capname != NULL)
99 		(void)unlink(capname);
100 }
101 
102 /*
103  * Any changes to these definitions should be made also in the getcap(3)
104  * library routines.
105  */
106 #define RECOK	(char)0
107 #define TCERR	(char)1
108 #define SHADOW	(char)2
109 
110 /*
111  * Db_build() builds the name and capabilty databases according to the
112  * details above.
113  */
114 void
115 db_build(ifiles)
116 	char **ifiles;
117 {
118 	DBT key, data;
119 	recno_t reccnt;
120 	size_t len, bplen;
121 	int st;
122 	char *bp, *p, *t;
123 
124 	data.data = NULL;
125 	key.data = NULL;
126 	for (reccnt = 0, bplen = 0; (st = cgetnext(&bp, ifiles)) > 0;) {
127 
128 		/*
129 		 * Allocate enough memory to store record, terminating
130 		 * NULL and one extra byte.
131 		 */
132 		len = strlen(bp);
133 		if (bplen <= len + 2) {
134 			bplen += MAX(256, len + 2);
135 			if ((data.data = realloc(data.data, bplen)) == NULL)
136 				err(1, "");
137 		}
138 
139 		/* Find the end of the name field. */
140 		if ((p = strchr(bp, ':')) == NULL) {
141 			warnx("no name field: %.*s", MIN(len, 20), bp);
142 			continue;
143 		}
144 
145 		/* First byte of stored record indicates status. */
146 		switch(st) {
147 		case 1:
148 			((char *)(data.data))[0] = RECOK;
149 			break;
150 		case 2:
151 			((char *)(data.data))[0] = TCERR;
152 			warnx("Record not tc expanded: %.*s", p - bp, bp);
153 			break;
154 		}
155 
156 		/* Create the stored record. */
157 		memmove(&((u_char *)(data.data))[1], bp, len + 1);
158 		data.size = len + 2;
159 
160 		/* Store the record under the name field. */
161 		key.data = bp;
162 		key.size = p - bp;
163 
164 		switch(capdbp->put(capdbp, &key, &data, R_NOOVERWRITE)) {
165 		case -1:
166 			err(1, "put");
167 			/* NOTREACHED */
168 		case 1:
169 			warnx("ignored duplicate: %.*s",
170 			    key.size, (char *)key.data);
171 			continue;
172 		}
173 		++reccnt;
174 
175 		/* If only one name, ignore the rest. */
176 		if ((p = strchr(bp, '|')) == NULL)
177 			continue;
178 
179 		/* The rest of the names reference the entire name. */
180 		((char *)(data.data))[0] = SHADOW;
181 		memmove(&((u_char *)(data.data))[1], key.data, key.size);
182 		data.size = key.size + 1;
183 
184 		/* Store references for other names. */
185 		for (p = t = bp;; ++p) {
186 			if (p > t && (*p == ':' || *p == '|')) {
187 				key.size = p - t;
188 				key.data = t;
189 				switch(capdbp->put(capdbp,
190 				    &key, &data, R_NOOVERWRITE)) {
191 				case -1:
192 					err(1, "put");
193 					/* NOTREACHED */
194 				case 1:
195 					warnx("ignored duplicate: %.*s",
196 					    key.size, (char *)key.data);
197 				}
198 				t = p + 1;
199 			}
200 			if (*p == ':')
201 				break;
202 		}
203 	}
204 
205 	switch(st) {
206 	case -1:
207 		err(1, "file argument");
208 		/* NOTREACHED */
209 	case -2:
210 		errx(1, "potential reference loop detected");
211 		/* NOTREACHED */
212 	}
213 
214 	if (verbose)
215 		(void)printf("cap_mkdb: %d capability records\n", reccnt);
216 }
217 
218 void
219 usage()
220 {
221 	(void)fprintf(stderr,
222 	    "usage: cap_mkdb [-v] [-f outfile] file1 [file2 ...]\n");
223 	exit(1);
224 }
225