1 /*- 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char copyright[] = 10 "@(#) Copyright (c) 1992, 1993\n\ 11 The Regents of the University of California. All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)cap_mkdb.c 8.1 (Berkeley) 06/06/93"; 16 #endif /* not lint */ 17 18 #include <sys/param.h> 19 #include <sys/stat.h> 20 21 #include <db.h> 22 #include <err.h> 23 #include <errno.h> 24 #include <fcntl.h> 25 #include <limits.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <unistd.h> 30 31 void db_build __P((char **)); 32 void dounlink __P((void)); 33 void usage __P((void)); 34 35 DB *capdbp; 36 int verbose; 37 char *capdb, *capname, buf[8 * 1024]; 38 39 /* 40 * Mkcapdb creates a capability hash database for quick retrieval of capability 41 * records. The database contains 2 types of entries: records and references 42 * marked by the first byte in the data. A record entry contains the actual 43 * capability record whereas a reference contains the name (key) under which 44 * the correct record is stored. 45 */ 46 int 47 main(argc, argv) 48 int argc; 49 char *argv[]; 50 { 51 int c; 52 53 capname = NULL; 54 while ((c = getopt(argc, argv, "f:v")) != EOF) { 55 switch(c) { 56 case 'f': 57 capname = optarg; 58 break; 59 case 'v': 60 verbose = 1; 61 break; 62 case '?': 63 default: 64 usage(); 65 } 66 } 67 argc -= optind; 68 argv += optind; 69 70 if (*argv == NULL) 71 usage(); 72 73 /* 74 * The database file is the first argument if no name is specified. 75 * Make arrangements to unlink it if exit badly. 76 */ 77 (void)snprintf(buf, sizeof(buf), "%s.db", capname ? capname : *argv); 78 if ((capname = strdup(buf)) == NULL) 79 err(1, ""); 80 if ((capdbp = dbopen(capname, 81 O_CREAT | O_TRUNC | O_RDWR, DEFFILEMODE, DB_HASH, NULL)) == NULL) 82 err(1, "%s", buf); 83 84 if (atexit(dounlink)) 85 err(1, "atexit"); 86 87 db_build(argv); 88 89 if (capdbp->close(capdbp) < 0) 90 err(1, "%s", capname); 91 capname = NULL; 92 exit(0); 93 } 94 95 void 96 dounlink() 97 { 98 if (capname != NULL) 99 (void)unlink(capname); 100 } 101 102 /* 103 * Any changes to these definitions should be made also in the getcap(3) 104 * library routines. 105 */ 106 #define RECOK (char)0 107 #define TCERR (char)1 108 #define SHADOW (char)2 109 110 /* 111 * Db_build() builds the name and capabilty databases according to the 112 * details above. 113 */ 114 void 115 db_build(ifiles) 116 char **ifiles; 117 { 118 DBT key, data; 119 recno_t reccnt; 120 size_t len, bplen; 121 int st; 122 char *bp, *p, *t; 123 124 data.data = NULL; 125 key.data = NULL; 126 for (reccnt = 0, bplen = 0; (st = cgetnext(&bp, ifiles)) > 0;) { 127 128 /* 129 * Allocate enough memory to store record, terminating 130 * NULL and one extra byte. 131 */ 132 len = strlen(bp); 133 if (bplen <= len + 2) { 134 bplen += MAX(256, len + 2); 135 if ((data.data = realloc(data.data, bplen)) == NULL) 136 err(1, ""); 137 } 138 139 /* Find the end of the name field. */ 140 if ((p = strchr(bp, ':')) == NULL) { 141 warnx("no name field: %.*s", MIN(len, 20), bp); 142 continue; 143 } 144 145 /* First byte of stored record indicates status. */ 146 switch(st) { 147 case 1: 148 ((char *)(data.data))[0] = RECOK; 149 break; 150 case 2: 151 ((char *)(data.data))[0] = TCERR; 152 warnx("Record not tc expanded: %.*s", p - bp, bp); 153 break; 154 } 155 156 /* Create the stored record. */ 157 memmove(&((u_char *)(data.data))[1], bp, len + 1); 158 data.size = len + 2; 159 160 /* Store the record under the name field. */ 161 key.data = bp; 162 key.size = p - bp; 163 164 switch(capdbp->put(capdbp, &key, &data, R_NOOVERWRITE)) { 165 case -1: 166 err(1, "put"); 167 /* NOTREACHED */ 168 case 1: 169 warnx("ignored duplicate: %.*s", 170 key.size, (char *)key.data); 171 continue; 172 } 173 ++reccnt; 174 175 /* If only one name, ignore the rest. */ 176 if ((p = strchr(bp, '|')) == NULL) 177 continue; 178 179 /* The rest of the names reference the entire name. */ 180 ((char *)(data.data))[0] = SHADOW; 181 memmove(&((u_char *)(data.data))[1], key.data, key.size); 182 data.size = key.size + 1; 183 184 /* Store references for other names. */ 185 for (p = t = bp;; ++p) { 186 if (p > t && (*p == ':' || *p == '|')) { 187 key.size = p - t; 188 key.data = t; 189 switch(capdbp->put(capdbp, 190 &key, &data, R_NOOVERWRITE)) { 191 case -1: 192 err(1, "put"); 193 /* NOTREACHED */ 194 case 1: 195 warnx("ignored duplicate: %.*s", 196 key.size, (char *)key.data); 197 } 198 t = p + 1; 199 } 200 if (*p == ':') 201 break; 202 } 203 } 204 205 switch(st) { 206 case -1: 207 err(1, "file argument"); 208 /* NOTREACHED */ 209 case -2: 210 errx(1, "potential reference loop detected"); 211 /* NOTREACHED */ 212 } 213 214 if (verbose) 215 (void)printf("cap_mkdb: %d capability records\n", reccnt); 216 } 217 218 void 219 usage() 220 { 221 (void)fprintf(stderr, 222 "usage: cap_mkdb [-v] [-f outfile] file1 [file2 ...]\n"); 223 exit(1); 224 } 225