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 if (pledge("stdio rpath wpath cpath", NULL) == -1) 81 err(1, "pledge"); 82 83 capname = NULL; 84 while ((c = getopt(argc, argv, "f:iv")) != -1) { 85 switch(c) { 86 case 'f': 87 capname = optarg; 88 break; 89 case 'v': 90 verbose = 1; 91 break; 92 case '?': 93 default: 94 usage(); 95 } 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 (void)fprintf(stderr, 291 "usage: cap_mkdb [-v] [-f outfile] file1 [file2 ...]\n"); 292 exit(1); 293 } 294