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