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.6.2.2 2001/08/02 01:15:51 obrien Exp $ 36 * $DragonFly: src/usr.bin/cap_mkdb/cap_mkdb.c,v 1.2 2003/06/17 04:29:25 dillon 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 int main __P((int, char *[])); 51 void db_build __P((char **)); 52 void dounlink __P((void)); 53 void usage __P((void)); 54 55 DB *capdbp; 56 int verbose; 57 char *capdb, *capname, buf[8 * 1024]; 58 59 /* 60 * Mkcapdb creates a capability hash database for quick retrieval of capability 61 * records. The database contains 2 types of entries: records and references 62 * marked by the first byte in the data. A record entry contains the actual 63 * capability record whereas a reference contains the name (key) under which 64 * the correct record is stored. 65 */ 66 int 67 main(argc, argv) 68 int argc; 69 char *argv[]; 70 { 71 int c; 72 73 capname = NULL; 74 while ((c = getopt(argc, argv, "f:v")) != -1) { 75 switch(c) { 76 case 'f': 77 capname = optarg; 78 break; 79 case 'v': 80 verbose = 1; 81 break; 82 case '?': 83 default: 84 usage(); 85 } 86 } 87 argc -= optind; 88 argv += optind; 89 90 if (*argv == NULL) 91 usage(); 92 93 /* 94 * The database file is the first argument if no name is specified. 95 * Make arrangements to unlink it if exit badly. 96 */ 97 (void)snprintf(buf, sizeof(buf), "%s.db", capname ? capname : *argv); 98 if ((capname = strdup(buf)) == NULL) 99 errx(1, "strdup failed"); 100 if ((capdbp = dbopen(capname, 101 O_CREAT | O_TRUNC | O_RDWR, DEFFILEMODE, DB_HASH, NULL)) == NULL) 102 err(1, "%s", buf); 103 104 if (atexit(dounlink)) 105 err(1, "atexit"); 106 107 db_build(argv); 108 109 if (capdbp->close(capdbp) < 0) 110 err(1, "%s", capname); 111 capname = NULL; 112 exit(0); 113 } 114 115 void 116 dounlink() 117 { 118 if (capname != NULL) 119 (void)unlink(capname); 120 } 121 122 /* 123 * Any changes to these definitions should be made also in the getcap(3) 124 * library routines. 125 */ 126 #define RECOK (char)0 127 #define TCERR (char)1 128 #define SHADOW (char)2 129 130 /* 131 * Db_build() builds the name and capability databases according to the 132 * details above. 133 */ 134 void 135 db_build(ifiles) 136 char **ifiles; 137 { 138 DBT key, data; 139 recno_t reccnt; 140 size_t len, bplen; 141 int st; 142 char *bp, *p, *t; 143 144 data.data = NULL; 145 key.data = NULL; 146 for (reccnt = 0, bplen = 0; (st = cgetnext(&bp, ifiles)) > 0;) { 147 148 /* 149 * Allocate enough memory to store record, terminating 150 * NULL and one extra byte. 151 */ 152 len = strlen(bp); 153 if (bplen <= len + 2) { 154 bplen += MAX(256, len + 2); 155 if ((data.data = realloc(data.data, bplen)) == NULL) 156 errx(1, "malloc failed"); 157 } 158 159 /* Find the end of the name field. */ 160 if ((p = strchr(bp, ':')) == NULL) { 161 warnx("no name field: %.*s", (int)MIN(len, 20), bp); 162 continue; 163 } 164 165 /* First byte of stored record indicates status. */ 166 switch(st) { 167 case 1: 168 ((char *)(data.data))[0] = RECOK; 169 break; 170 case 2: 171 ((char *)(data.data))[0] = TCERR; 172 warnx("record not tc expanded: %.*s", (int)(p - bp), 173 bp); 174 break; 175 } 176 177 /* Create the stored record. */ 178 memmove(&((u_char *)(data.data))[1], bp, len + 1); 179 data.size = len + 2; 180 181 /* Store the record under the name field. */ 182 key.data = bp; 183 key.size = p - bp; 184 185 switch(capdbp->put(capdbp, &key, &data, R_NOOVERWRITE)) { 186 case -1: 187 err(1, "put"); 188 /* NOTREACHED */ 189 case 1: 190 warnx("ignored duplicate: %.*s", 191 (int)key.size, (char *)key.data); 192 continue; 193 } 194 ++reccnt; 195 196 /* If only one name, ignore the rest. */ 197 *p = '\0'; 198 if (strchr(bp, '|') == NULL) 199 continue; 200 *p = ':'; 201 202 /* The rest of the names reference the entire name. */ 203 ((char *)(data.data))[0] = SHADOW; 204 memmove(&((u_char *)(data.data))[1], key.data, key.size); 205 data.size = key.size + 1; 206 207 /* Store references for other names. */ 208 for (p = t = bp;; ++p) { 209 if (p > t && (*p == ':' || *p == '|')) { 210 key.size = p - t; 211 key.data = t; 212 switch(capdbp->put(capdbp, 213 &key, &data, R_NOOVERWRITE)) { 214 case -1: 215 err(1, "put"); 216 /* NOTREACHED */ 217 case 1: 218 warnx("ignored duplicate: %.*s", 219 (int)key.size, (char *)key.data); 220 } 221 t = p + 1; 222 } 223 if (*p == ':') 224 break; 225 } 226 } 227 228 switch(st) { 229 case -1: 230 err(1, "file argument"); 231 /* NOTREACHED */ 232 case -2: 233 errx(1, "potential reference loop detected"); 234 /* NOTREACHED */ 235 } 236 237 if (verbose) 238 (void)printf("cap_mkdb: %d capability records\n", reccnt); 239 } 240 241 void 242 usage() 243 { 244 (void)fprintf(stderr, 245 "usage: cap_mkdb [-v] [-f outfile] file [file ...]\n"); 246 exit(1); 247 } 248