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