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 * @(#) Copyright (c) 1992, 1993 The Regents of the University of California. All rights reserved. 34 * @(#)cap_mkdb.c 8.1 (Berkeley) 6/6/93 35 * $FreeBSD: src/usr.bin/cap_mkdb/cap_mkdb.c,v 1.14 2005/02/22 23:29:53 ru Exp $ 36 * $DragonFly: src/usr.bin/cap_mkdb/cap_mkdb.c,v 1.5 2007/09/25 04:53:48 pavalos Exp $ 37 */ 38 39 #include <sys/param.h> 40 #include <sys/stat.h> 41 42 #include <db.h> 43 #include <err.h> 44 #include <fcntl.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <unistd.h> 49 50 void db_build(char **); 51 void dounlink(void); 52 void usage(void); 53 54 DB *capdbp; 55 int verbose; 56 char *capdb, *capname, buf[8 * 1024]; 57 58 HASHINFO openinfo = { 59 4096, /* bsize */ 60 0, /* ffactor */ 61 0, /* nelem */ 62 0, /* cachesize */ 63 NULL, /* hash() */ 64 0 /* lorder */ 65 }; 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(int argc, char **argv) 76 { 77 int byteorder, c; 78 79 capname = NULL; 80 byteorder = 0; 81 while ((c = getopt(argc, argv, "bf:lv")) != -1) { 82 switch(c) { 83 case 'b': 84 case 'l': 85 if (byteorder != 0) 86 usage(); 87 byteorder = c == 'b' ? 4321 : 1234; 88 break; 89 case 'f': 90 capname = optarg; 91 break; 92 case 'v': 93 verbose = 1; 94 break; 95 case '?': 96 default: 97 usage(); 98 } 99 } 100 argc -= optind; 101 argv += optind; 102 103 if (*argv == NULL) 104 usage(); 105 106 /* Set byte order. */ 107 openinfo.lorder = byteorder; 108 109 /* 110 * The database file is the first argument if no name is specified. 111 * Make arrangements to unlink it if exit badly. 112 */ 113 (void)snprintf(buf, sizeof(buf), "%s.db", capname ? capname : *argv); 114 if ((capname = strdup(buf)) == NULL) 115 errx(1, "strdup failed"); 116 if ((capdbp = dbopen(capname, O_CREAT | O_TRUNC | O_RDWR, 117 DEFFILEMODE, DB_HASH, &openinfo)) == NULL) 118 err(1, "%s", buf); 119 120 if (atexit(dounlink)) 121 err(1, "atexit"); 122 123 db_build(argv); 124 125 if (capdbp->close(capdbp) < 0) 126 err(1, "%s", capname); 127 capname = NULL; 128 exit(0); 129 } 130 131 void 132 dounlink(void) 133 { 134 if (capname != NULL) 135 (void)unlink(capname); 136 } 137 138 /* 139 * Any changes to these definitions should be made also in the getcap(3) 140 * library routines. 141 */ 142 #define RECOK (char)0 143 #define TCERR (char)1 144 #define SHADOW (char)2 145 146 /* 147 * Db_build() builds the name and capability databases according to the 148 * details above. 149 */ 150 void 151 db_build(char **ifiles) 152 { 153 DBT key, data; 154 recno_t reccnt; 155 size_t len, bplen; 156 int st; 157 char *bp, *p, *t; 158 159 data.data = NULL; 160 key.data = NULL; 161 for (reccnt = 0, bplen = 0; (st = cgetnext(&bp, ifiles)) > 0;) { 162 163 /* 164 * Allocate enough memory to store record, terminating 165 * NULL and one extra byte. 166 */ 167 len = strlen(bp); 168 if (bplen <= len + 2) { 169 bplen += MAX(256, len + 2); 170 if ((data.data = realloc(data.data, bplen)) == NULL) 171 errx(1, "malloc failed"); 172 } 173 174 /* Find the end of the name field. */ 175 if ((p = strchr(bp, ':')) == NULL) { 176 warnx("no name field: %.*s", (int)MIN(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), 188 bp); 189 break; 190 } 191 192 /* Create the stored record. */ 193 memmove(&((u_char *)(data.data))[1], bp, len + 1); 194 data.size = len + 2; 195 196 /* Store the record under the name field. */ 197 key.data = bp; 198 key.size = p - bp; 199 200 switch(capdbp->put(capdbp, &key, &data, R_NOOVERWRITE)) { 201 case -1: 202 err(1, "put"); 203 /* NOTREACHED */ 204 case 1: 205 warnx("ignored duplicate: %.*s", 206 (int)key.size, (char *)key.data); 207 continue; 208 } 209 ++reccnt; 210 211 /* If only one name, ignore the rest. */ 212 *p = '\0'; 213 if (strchr(bp, '|') == NULL) 214 continue; 215 *p = ':'; 216 217 /* The rest of the names reference the entire name. */ 218 ((char *)(data.data))[0] = SHADOW; 219 memmove(&((u_char *)(data.data))[1], key.data, key.size); 220 data.size = key.size + 1; 221 222 /* Store references for other names. */ 223 for (p = t = bp;; ++p) { 224 if (p > t && (*p == ':' || *p == '|')) { 225 key.size = p - t; 226 key.data = t; 227 switch(capdbp->put(capdbp, 228 &key, &data, R_NOOVERWRITE)) { 229 case -1: 230 err(1, "put"); 231 /* NOTREACHED */ 232 case 1: 233 warnx("ignored duplicate: %.*s", 234 (int)key.size, (char *)key.data); 235 } 236 t = p + 1; 237 } 238 if (*p == ':') 239 break; 240 } 241 } 242 243 switch(st) { 244 case -1: 245 err(1, "file argument"); 246 /* NOTREACHED */ 247 case -2: 248 errx(1, "potential reference loop detected"); 249 /* NOTREACHED */ 250 } 251 252 if (verbose) 253 (void)printf("cap_mkdb: %d capability records\n", reccnt); 254 } 255 256 void 257 usage(void) 258 { 259 (void)fprintf(stderr, 260 "usage: cap_mkdb [-b | -l] [-v] [-f outfile] file ...\n"); 261 exit(1); 262 } 263