1 1.1 christos /* 2 1.1 christos * Copyright 2015-2024 The OpenSSL Project Authors. All Rights Reserved. 3 1.1 christos * Copyright (c) 2013-2014 Timo Ters <timo.teras (at) gmail.com> 4 1.1 christos * 5 1.1 christos * Licensed under the Apache License 2.0 (the "License"). You may not use 6 1.1 christos * this file except in compliance with the License. You can obtain a copy 7 1.1 christos * in the file LICENSE in the source distribution or at 8 1.1 christos * https://www.openssl.org/source/license.html 9 1.1 christos */ 10 1.1 christos 11 1.1 christos #include "internal/e_os.h" /* LIST_SEPARATOR_CHAR */ 12 1.1 christos #include "apps.h" 13 1.1 christos #include "progs.h" 14 1.1 christos 15 1.1.1.2 christos #if defined(OPENSSL_SYS_UNIX) || defined(__APPLE__) || (defined(__VMS) && defined(__DECC) && __CRTL_VER >= 80300000) 16 1.1.1.2 christos #include <unistd.h> 17 1.1.1.2 christos #include <stdio.h> 18 1.1.1.2 christos #include <limits.h> 19 1.1.1.2 christos #include <errno.h> 20 1.1.1.2 christos #include <string.h> 21 1.1.1.2 christos #include <ctype.h> 22 1.1.1.2 christos #include <sys/stat.h> 23 1.1 christos 24 1.1 christos /* 25 1.1 christos * Make sure that the processing of symbol names is treated the same as when 26 1.1 christos * libcrypto is built. This is done automatically for public headers (see 27 1.1 christos * include/openssl/__DECC_INCLUDE_PROLOGUE.H and __DECC_INCLUDE_EPILOGUE.H), 28 1.1 christos * but not for internal headers. 29 1.1 christos */ 30 1.1.1.2 christos #ifdef __VMS 31 1.1.1.2 christos #pragma names save 32 1.1.1.2 christos #pragma names as_is, shortened 33 1.1.1.2 christos #endif 34 1.1.1.2 christos 35 1.1.1.2 christos #include "internal/o_dir.h" 36 1.1.1.2 christos 37 1.1.1.2 christos #ifdef __VMS 38 1.1.1.2 christos #pragma names restore 39 1.1.1.2 christos #endif 40 1.1.1.2 christos 41 1.1.1.2 christos #include <openssl/evp.h> 42 1.1.1.2 christos #include <openssl/pem.h> 43 1.1.1.2 christos #include <openssl/x509.h> 44 1.1.1.2 christos 45 1.1.1.2 christos #ifndef PATH_MAX 46 1.1.1.2 christos #define PATH_MAX 4096 47 1.1.1.2 christos #endif 48 1.1.1.2 christos #define MAX_COLLISIONS 256 49 1.1 christos 50 1.1.1.2 christos #if defined(OPENSSL_SYS_VXWORKS) 51 1.1 christos /* 52 1.1 christos * VxWorks has no symbolic links 53 1.1 christos */ 54 1.1 christos 55 1.1.1.2 christos #define lstat(path, buf) stat(path, buf) 56 1.1 christos 57 1.1 christos int symlink(const char *target, const char *linkpath) 58 1.1 christos { 59 1.1 christos errno = ENOSYS; 60 1.1 christos return -1; 61 1.1 christos } 62 1.1 christos 63 1.1 christos ssize_t readlink(const char *pathname, char *buf, size_t bufsiz) 64 1.1 christos { 65 1.1 christos errno = ENOSYS; 66 1.1 christos return -1; 67 1.1 christos } 68 1.1.1.2 christos #endif 69 1.1 christos 70 1.1 christos typedef struct hentry_st { 71 1.1 christos struct hentry_st *next; 72 1.1 christos char *filename; 73 1.1 christos unsigned short old_id; 74 1.1 christos unsigned char need_symlink; 75 1.1 christos unsigned char digest[EVP_MAX_MD_SIZE]; 76 1.1 christos } HENTRY; 77 1.1 christos 78 1.1 christos typedef struct bucket_st { 79 1.1 christos struct bucket_st *next; 80 1.1 christos HENTRY *first_entry, *last_entry; 81 1.1 christos unsigned int hash; 82 1.1 christos unsigned short type; 83 1.1 christos unsigned short num_needed; 84 1.1 christos } BUCKET; 85 1.1 christos 86 1.1 christos enum Type { 87 1.1 christos /* Keep in sync with |suffixes|, below. */ 88 1.1.1.2 christos TYPE_CERT = 0, 89 1.1.1.2 christos TYPE_CRL = 1 90 1.1 christos }; 91 1.1 christos 92 1.1 christos enum Hash { 93 1.1.1.2 christos HASH_OLD, 94 1.1.1.2 christos HASH_NEW, 95 1.1.1.2 christos HASH_BOTH 96 1.1 christos }; 97 1.1 christos 98 1.1 christos static int evpmdsize; 99 1.1 christos static const EVP_MD *evpmd; 100 1.1 christos static int remove_links = 1; 101 1.1 christos static int verbose = 0; 102 1.1 christos static BUCKET *hash_table[257]; 103 1.1 christos 104 1.1 christos static const char *suffixes[] = { "", "r" }; 105 1.1 christos static const char *extensions[] = { "pem", "crt", "cer", "crl" }; 106 1.1 christos 107 1.1 christos static void bit_set(unsigned char *set, unsigned int bit) 108 1.1 christos { 109 1.1 christos set[bit >> 3] |= 1 << (bit & 0x7); 110 1.1 christos } 111 1.1 christos 112 1.1 christos static int bit_isset(unsigned char *set, unsigned int bit) 113 1.1 christos { 114 1.1 christos return set[bit >> 3] & (1 << (bit & 0x7)); 115 1.1 christos } 116 1.1 christos 117 1.1 christos /* 118 1.1 christos * Process an entry; return number of errors. 119 1.1 christos */ 120 1.1 christos static int add_entry(enum Type type, unsigned int hash, const char *filename, 121 1.1.1.2 christos const unsigned char *digest, int need_symlink, 122 1.1.1.2 christos unsigned short old_id) 123 1.1 christos { 124 1.1 christos static BUCKET nilbucket; 125 1.1 christos static HENTRY nilhentry; 126 1.1 christos BUCKET *bp; 127 1.1 christos HENTRY *ep, *found = NULL; 128 1.1 christos unsigned int ndx = (type + hash) % OSSL_NELEM(hash_table); 129 1.1 christos 130 1.1 christos for (bp = hash_table[ndx]; bp; bp = bp->next) 131 1.1 christos if (bp->type == type && bp->hash == hash) 132 1.1 christos break; 133 1.1 christos if (bp == NULL) { 134 1.1 christos bp = app_malloc(sizeof(*bp), "hash bucket"); 135 1.1 christos *bp = nilbucket; 136 1.1 christos bp->next = hash_table[ndx]; 137 1.1 christos bp->type = type; 138 1.1 christos bp->hash = hash; 139 1.1 christos hash_table[ndx] = bp; 140 1.1 christos } 141 1.1 christos 142 1.1 christos for (ep = bp->first_entry; ep; ep = ep->next) { 143 1.1 christos if (digest && memcmp(digest, ep->digest, (size_t)evpmdsize) == 0) { 144 1.1 christos BIO_printf(bio_err, 145 1.1.1.2 christos "%s: warning: skipping duplicate %s in %s\n", 146 1.1.1.2 christos opt_getprog(), 147 1.1.1.2 christos type == TYPE_CERT ? "certificate" : "CRL", filename); 148 1.1 christos return 0; 149 1.1 christos } 150 1.1 christos if (strcmp(filename, ep->filename) == 0) { 151 1.1 christos found = ep; 152 1.1 christos if (digest == NULL) 153 1.1 christos break; 154 1.1 christos } 155 1.1 christos } 156 1.1 christos ep = found; 157 1.1 christos if (ep == NULL) { 158 1.1 christos if (bp->num_needed >= MAX_COLLISIONS) { 159 1.1 christos BIO_printf(bio_err, 160 1.1.1.2 christos "%s: error: hash table overflow for %s\n", 161 1.1.1.2 christos opt_getprog(), filename); 162 1.1 christos return 1; 163 1.1 christos } 164 1.1 christos ep = app_malloc(sizeof(*ep), "collision bucket"); 165 1.1 christos *ep = nilhentry; 166 1.1 christos ep->old_id = ~0; 167 1.1 christos ep->filename = OPENSSL_strdup(filename); 168 1.1 christos if (ep->filename == NULL) { 169 1.1 christos OPENSSL_free(ep); 170 1.1 christos ep = NULL; 171 1.1 christos BIO_printf(bio_err, "out of memory\n"); 172 1.1 christos return 1; 173 1.1 christos } 174 1.1 christos if (bp->last_entry) 175 1.1 christos bp->last_entry->next = ep; 176 1.1 christos if (bp->first_entry == NULL) 177 1.1 christos bp->first_entry = ep; 178 1.1 christos bp->last_entry = ep; 179 1.1 christos } 180 1.1 christos 181 1.1 christos if (old_id < ep->old_id) 182 1.1 christos ep->old_id = old_id; 183 1.1 christos if (need_symlink && !ep->need_symlink) { 184 1.1 christos ep->need_symlink = 1; 185 1.1 christos bp->num_needed++; 186 1.1 christos memcpy(ep->digest, digest, (size_t)evpmdsize); 187 1.1 christos } 188 1.1 christos return 0; 189 1.1 christos } 190 1.1 christos 191 1.1 christos /* 192 1.1 christos * Check if a symlink goes to the right spot; return 0 if okay. 193 1.1 christos * This can be -1 if bad filename, or an error count. 194 1.1 christos */ 195 1.1 christos static int handle_symlink(const char *filename, const char *fullpath) 196 1.1 christos { 197 1.1 christos unsigned int hash = 0; 198 1.1 christos int i, type, id; 199 1.1 christos unsigned char ch; 200 1.1 christos char linktarget[PATH_MAX], *endptr; 201 1.1 christos ossl_ssize_t n; 202 1.1 christos 203 1.1 christos for (i = 0; i < 8; i++) { 204 1.1 christos ch = filename[i]; 205 1.1 christos if (!isxdigit(ch)) 206 1.1 christos return -1; 207 1.1 christos hash <<= 4; 208 1.1 christos hash += OPENSSL_hexchar2int(ch); 209 1.1 christos } 210 1.1 christos if (filename[i++] != '.') 211 1.1 christos return -1; 212 1.1 christos for (type = OSSL_NELEM(suffixes) - 1; type > 0; type--) 213 1.1 christos if (OPENSSL_strncasecmp(&filename[i], 214 1.1.1.2 christos suffixes[type], strlen(suffixes[type])) 215 1.1.1.2 christos == 0) 216 1.1 christos break; 217 1.1 christos 218 1.1 christos i += strlen(suffixes[type]); 219 1.1 christos 220 1.1 christos id = strtoul(&filename[i], &endptr, 10); 221 1.1 christos if (*endptr != '\0') 222 1.1 christos return -1; 223 1.1 christos 224 1.1 christos n = readlink(fullpath, linktarget, sizeof(linktarget)); 225 1.1 christos if (n < 0 || n >= (int)sizeof(linktarget)) 226 1.1 christos return -1; 227 1.1 christos linktarget[n] = 0; 228 1.1 christos 229 1.1 christos return add_entry(type, hash, linktarget, NULL, 0, id); 230 1.1 christos } 231 1.1 christos 232 1.1 christos /* 233 1.1 christos * process a file, return number of errors. 234 1.1 christos */ 235 1.1 christos static int do_file(const char *filename, const char *fullpath, enum Hash h) 236 1.1 christos { 237 1.1.1.2 christos STACK_OF(X509_INFO) *inf = NULL; 238 1.1 christos X509_INFO *x; 239 1.1 christos const X509_NAME *name = NULL; 240 1.1 christos BIO *b; 241 1.1 christos const char *ext; 242 1.1 christos unsigned char digest[EVP_MAX_MD_SIZE]; 243 1.1 christos int type, errs = 0; 244 1.1 christos size_t i; 245 1.1 christos 246 1.1 christos /* Does it end with a recognized extension? */ 247 1.1 christos if ((ext = strrchr(filename, '.')) == NULL) 248 1.1 christos goto end; 249 1.1 christos for (i = 0; i < OSSL_NELEM(extensions); i++) { 250 1.1 christos if (OPENSSL_strcasecmp(extensions[i], ext + 1) == 0) 251 1.1 christos break; 252 1.1 christos } 253 1.1 christos if (i >= OSSL_NELEM(extensions)) 254 1.1 christos goto end; 255 1.1 christos 256 1.1 christos /* Does it have X.509 data in it? */ 257 1.1 christos if ((b = BIO_new_file(fullpath, "r")) == NULL) { 258 1.1 christos BIO_printf(bio_err, "%s: error: skipping %s, cannot open file\n", 259 1.1.1.2 christos opt_getprog(), filename); 260 1.1 christos errs++; 261 1.1 christos goto end; 262 1.1 christos } 263 1.1 christos inf = PEM_X509_INFO_read_bio(b, NULL, NULL, NULL); 264 1.1 christos BIO_free(b); 265 1.1 christos if (inf == NULL) 266 1.1 christos goto end; 267 1.1 christos 268 1.1 christos if (sk_X509_INFO_num(inf) != 1) { 269 1.1 christos BIO_printf(bio_err, 270 1.1.1.2 christos "%s: warning: skipping %s, " 271 1.1.1.2 christos "it does not contain exactly one certificate or CRL\n", 272 1.1.1.2 christos opt_getprog(), filename); 273 1.1 christos /* This is not an error. */ 274 1.1 christos goto end; 275 1.1 christos } 276 1.1 christos x = sk_X509_INFO_value(inf, 0); 277 1.1 christos if (x->x509 != NULL) { 278 1.1 christos type = TYPE_CERT; 279 1.1 christos name = X509_get_subject_name(x->x509); 280 1.1 christos if (!X509_digest(x->x509, evpmd, digest, NULL)) { 281 1.1 christos BIO_printf(bio_err, "out of memory\n"); 282 1.1 christos ++errs; 283 1.1 christos goto end; 284 1.1 christos } 285 1.1 christos } else if (x->crl != NULL) { 286 1.1 christos type = TYPE_CRL; 287 1.1 christos name = X509_CRL_get_issuer(x->crl); 288 1.1 christos if (!X509_CRL_digest(x->crl, evpmd, digest, NULL)) { 289 1.1 christos BIO_printf(bio_err, "out of memory\n"); 290 1.1 christos ++errs; 291 1.1 christos goto end; 292 1.1 christos } 293 1.1 christos } else { 294 1.1 christos ++errs; 295 1.1 christos goto end; 296 1.1 christos } 297 1.1 christos if (name != NULL) { 298 1.1 christos if (h == HASH_NEW || h == HASH_BOTH) { 299 1.1 christos int ok; 300 1.1.1.2 christos unsigned long hash_value = X509_NAME_hash_ex(name, 301 1.1.1.2 christos app_get0_libctx(), app_get0_propq(), &ok); 302 1.1 christos 303 1.1 christos if (ok) { 304 1.1 christos errs += add_entry(type, hash_value, filename, digest, 1, ~0); 305 1.1 christos } else { 306 1.1 christos BIO_printf(bio_err, "%s: error calculating SHA1 hash value\n", 307 1.1.1.2 christos opt_getprog()); 308 1.1 christos errs++; 309 1.1 christos } 310 1.1 christos } 311 1.1 christos if ((h == HASH_OLD) || (h == HASH_BOTH)) 312 1.1 christos errs += add_entry(type, X509_NAME_hash_old(name), 313 1.1.1.2 christos filename, digest, 1, ~0); 314 1.1 christos } 315 1.1 christos 316 1.1 christos end: 317 1.1 christos sk_X509_INFO_pop_free(inf, X509_INFO_free); 318 1.1 christos return errs; 319 1.1 christos } 320 1.1 christos 321 1.1 christos static void str_free(char *s) 322 1.1 christos { 323 1.1 christos OPENSSL_free(s); 324 1.1 christos } 325 1.1 christos 326 1.1 christos static int ends_with_dirsep(const char *path) 327 1.1 christos { 328 1.1 christos if (*path != '\0') 329 1.1 christos path += strlen(path) - 1; 330 1.1.1.2 christos #if defined __VMS 331 1.1 christos if (*path == ']' || *path == '>' || *path == ':') 332 1.1 christos return 1; 333 1.1.1.2 christos #elif defined _WIN32 334 1.1 christos if (*path == '\\') 335 1.1 christos return 1; 336 1.1.1.2 christos #endif 337 1.1 christos return *path == '/'; 338 1.1 christos } 339 1.1 christos 340 1.1.1.2 christos static int sk_strcmp(const char *const *a, const char *const *b) 341 1.1 christos { 342 1.1 christos return strcmp(*a, *b); 343 1.1 christos } 344 1.1 christos 345 1.1 christos /* 346 1.1 christos * Process a directory; return number of errors found. 347 1.1 christos */ 348 1.1 christos static int do_dir(const char *dirname, enum Hash h) 349 1.1 christos { 350 1.1 christos BUCKET *bp, *nextbp; 351 1.1 christos HENTRY *ep, *nextep; 352 1.1 christos OPENSSL_DIR_CTX *d = NULL; 353 1.1 christos struct stat st; 354 1.1 christos unsigned char idmask[MAX_COLLISIONS / 8]; 355 1.1 christos int n, numfiles, nextid, dirlen, buflen, errs = 0; 356 1.1 christos size_t i, fname_max_len = 20; /* maximum length of "%08x.r%d" */ 357 1.1 christos const char *pathsep = ""; 358 1.1 christos const char *filename; 359 1.1 christos char *buf = NULL, *copy = NULL; 360 1.1 christos STACK_OF(OPENSSL_STRING) *files = NULL; 361 1.1 christos 362 1.1 christos if (app_access(dirname, W_OK) < 0) { 363 1.1 christos BIO_printf(bio_err, "Skipping %s, can't write\n", dirname); 364 1.1 christos return 1; 365 1.1 christos } 366 1.1 christos dirlen = strlen(dirname); 367 1.1 christos if (dirlen != 0 && !ends_with_dirsep(dirname)) { 368 1.1 christos pathsep = "/"; 369 1.1 christos dirlen++; 370 1.1 christos } 371 1.1 christos 372 1.1 christos if (verbose) 373 1.1 christos BIO_printf(bio_out, "Doing %s\n", dirname); 374 1.1 christos 375 1.1 christos if ((files = sk_OPENSSL_STRING_new(sk_strcmp)) == NULL) { 376 1.1 christos BIO_printf(bio_err, "Skipping %s, out of memory\n", dirname); 377 1.1 christos errs = 1; 378 1.1 christos goto err; 379 1.1 christos } 380 1.1 christos while ((filename = OPENSSL_DIR_read(&d, dirname)) != NULL) { 381 1.1 christos size_t fname_len = strlen(filename); 382 1.1 christos 383 1.1 christos if ((copy = OPENSSL_strdup(filename)) == NULL 384 1.1.1.2 christos || sk_OPENSSL_STRING_push(files, copy) == 0) { 385 1.1 christos OPENSSL_free(copy); 386 1.1 christos OPENSSL_DIR_end(&d); 387 1.1 christos BIO_puts(bio_err, "out of memory\n"); 388 1.1 christos errs = 1; 389 1.1 christos goto err; 390 1.1 christos } 391 1.1 christos if (fname_len > fname_max_len) 392 1.1 christos fname_max_len = fname_len; 393 1.1 christos } 394 1.1 christos OPENSSL_DIR_end(&d); 395 1.1 christos sk_OPENSSL_STRING_sort(files); 396 1.1 christos 397 1.1 christos buflen = dirlen + fname_max_len + 1; 398 1.1 christos buf = app_malloc(buflen, "filename buffer"); 399 1.1 christos 400 1.1 christos numfiles = sk_OPENSSL_STRING_num(files); 401 1.1 christos for (n = 0; n < numfiles; ++n) { 402 1.1 christos filename = sk_OPENSSL_STRING_value(files, n); 403 1.1 christos if (BIO_snprintf(buf, buflen, "%s%s%s", 404 1.1.1.2 christos dirname, pathsep, filename) 405 1.1.1.2 christos >= buflen) 406 1.1 christos continue; 407 1.1 christos if (lstat(buf, &st) < 0) 408 1.1 christos continue; 409 1.1 christos if (S_ISLNK(st.st_mode) && handle_symlink(filename, buf) == 0) 410 1.1 christos continue; 411 1.1 christos errs += do_file(filename, buf, h); 412 1.1 christos } 413 1.1 christos 414 1.1 christos for (i = 0; i < OSSL_NELEM(hash_table); i++) { 415 1.1 christos for (bp = hash_table[i]; bp; bp = nextbp) { 416 1.1 christos nextbp = bp->next; 417 1.1 christos nextid = 0; 418 1.1 christos memset(idmask, 0, (bp->num_needed + 7) / 8); 419 1.1 christos for (ep = bp->first_entry; ep; ep = ep->next) 420 1.1 christos if (ep->old_id < bp->num_needed) 421 1.1 christos bit_set(idmask, ep->old_id); 422 1.1 christos 423 1.1 christos for (ep = bp->first_entry; ep; ep = nextep) { 424 1.1 christos nextep = ep->next; 425 1.1 christos if (ep->old_id < bp->num_needed) { 426 1.1 christos /* Link exists, and is used as-is */ 427 1.1 christos BIO_snprintf(buf, buflen, "%08x.%s%d", bp->hash, 428 1.1.1.2 christos suffixes[bp->type], ep->old_id); 429 1.1 christos if (verbose) 430 1.1 christos BIO_printf(bio_out, "link %s -> %s\n", 431 1.1.1.2 christos ep->filename, buf); 432 1.1 christos } else if (ep->need_symlink) { 433 1.1 christos /* New link needed (it may replace something) */ 434 1.1 christos while (bit_isset(idmask, nextid)) 435 1.1 christos nextid++; 436 1.1 christos 437 1.1 christos BIO_snprintf(buf, buflen, "%s%s%08x.%s%d", 438 1.1.1.2 christos dirname, pathsep, bp->hash, 439 1.1.1.2 christos suffixes[bp->type], nextid); 440 1.1 christos if (verbose) 441 1.1 christos BIO_printf(bio_out, "link %s -> %s\n", 442 1.1.1.2 christos ep->filename, &buf[dirlen]); 443 1.1 christos if (unlink(buf) < 0 && errno != ENOENT) { 444 1.1 christos BIO_printf(bio_err, 445 1.1.1.2 christos "%s: Can't unlink %s, %s\n", 446 1.1.1.2 christos opt_getprog(), buf, strerror(errno)); 447 1.1 christos errs++; 448 1.1 christos } 449 1.1 christos if (symlink(ep->filename, buf) < 0) { 450 1.1 christos BIO_printf(bio_err, 451 1.1.1.2 christos "%s: Can't symlink %s, %s\n", 452 1.1.1.2 christos opt_getprog(), ep->filename, 453 1.1.1.2 christos strerror(errno)); 454 1.1 christos errs++; 455 1.1 christos } 456 1.1 christos bit_set(idmask, nextid); 457 1.1 christos } else if (remove_links) { 458 1.1 christos /* Link to be deleted */ 459 1.1 christos BIO_snprintf(buf, buflen, "%s%s%08x.%s%d", 460 1.1.1.2 christos dirname, pathsep, bp->hash, 461 1.1.1.2 christos suffixes[bp->type], ep->old_id); 462 1.1 christos if (verbose) 463 1.1 christos BIO_printf(bio_out, "unlink %s\n", 464 1.1.1.2 christos &buf[dirlen]); 465 1.1 christos if (unlink(buf) < 0 && errno != ENOENT) { 466 1.1 christos BIO_printf(bio_err, 467 1.1.1.2 christos "%s: Can't unlink %s, %s\n", 468 1.1.1.2 christos opt_getprog(), buf, strerror(errno)); 469 1.1 christos errs++; 470 1.1 christos } 471 1.1 christos } 472 1.1 christos OPENSSL_free(ep->filename); 473 1.1 christos OPENSSL_free(ep); 474 1.1 christos } 475 1.1 christos OPENSSL_free(bp); 476 1.1 christos } 477 1.1 christos hash_table[i] = NULL; 478 1.1 christos } 479 1.1 christos 480 1.1.1.2 christos err: 481 1.1 christos sk_OPENSSL_STRING_pop_free(files, str_free); 482 1.1 christos OPENSSL_free(buf); 483 1.1 christos return errs; 484 1.1 christos } 485 1.1 christos 486 1.1 christos typedef enum OPTION_choice { 487 1.1 christos OPT_COMMON, 488 1.1.1.2 christos OPT_COMPAT, 489 1.1.1.2 christos OPT_OLD, 490 1.1.1.2 christos OPT_N, 491 1.1.1.2 christos OPT_VERBOSE, 492 1.1 christos OPT_PROV_ENUM 493 1.1 christos } OPTION_CHOICE; 494 1.1 christos 495 1.1 christos const OPTIONS rehash_options[] = { 496 1.1.1.2 christos { OPT_HELP_STR, 1, '-', "Usage: %s [options] [directory...]\n" }, 497 1.1 christos 498 1.1 christos OPT_SECTION("General"), 499 1.1.1.2 christos { "help", OPT_HELP, '-', "Display this summary" }, 500 1.1.1.2 christos { "h", OPT_HELP, '-', "Display this summary" }, 501 1.1.1.2 christos { "compat", OPT_COMPAT, '-', "Create both new- and old-style hash links" }, 502 1.1.1.2 christos { "old", OPT_OLD, '-', "Use old-style hash to generate links" }, 503 1.1.1.2 christos { "n", OPT_N, '-', "Do not remove existing links" }, 504 1.1 christos 505 1.1 christos OPT_SECTION("Output"), 506 1.1.1.2 christos { "v", OPT_VERBOSE, '-', "Verbose output" }, 507 1.1 christos 508 1.1 christos OPT_PROV_OPTIONS, 509 1.1 christos 510 1.1 christos OPT_PARAMETERS(), 511 1.1.1.2 christos { "directory", 0, 0, "One or more directories to process (optional)" }, 512 1.1.1.2 christos { NULL } 513 1.1 christos }; 514 1.1 christos 515 1.1 christos int rehash_main(int argc, char **argv) 516 1.1 christos { 517 1.1 christos const char *env, *prog; 518 1.1 christos char *e, *m; 519 1.1 christos int errs = 0; 520 1.1 christos OPTION_CHOICE o; 521 1.1 christos enum Hash h = HASH_NEW; 522 1.1 christos 523 1.1 christos prog = opt_init(argc, argv, rehash_options); 524 1.1 christos while ((o = opt_next()) != OPT_EOF) { 525 1.1 christos switch (o) { 526 1.1 christos case OPT_EOF: 527 1.1 christos case OPT_ERR: 528 1.1 christos BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); 529 1.1 christos goto end; 530 1.1 christos case OPT_HELP: 531 1.1 christos opt_help(rehash_options); 532 1.1 christos goto end; 533 1.1 christos case OPT_COMPAT: 534 1.1 christos h = HASH_BOTH; 535 1.1 christos break; 536 1.1 christos case OPT_OLD: 537 1.1 christos h = HASH_OLD; 538 1.1 christos break; 539 1.1 christos case OPT_N: 540 1.1 christos remove_links = 0; 541 1.1 christos break; 542 1.1 christos case OPT_VERBOSE: 543 1.1 christos verbose = 1; 544 1.1 christos break; 545 1.1 christos case OPT_PROV_CASES: 546 1.1 christos if (!opt_provider(o)) 547 1.1 christos goto end; 548 1.1 christos break; 549 1.1 christos } 550 1.1 christos } 551 1.1 christos 552 1.1 christos /* Optional arguments are directories to scan. */ 553 1.1 christos argc = opt_num_rest(); 554 1.1 christos argv = opt_rest(); 555 1.1 christos 556 1.1 christos evpmd = EVP_sha1(); 557 1.1 christos evpmdsize = EVP_MD_get_size(evpmd); 558 1.1 christos 559 1.1 christos if (evpmdsize <= 0 || evpmdsize > EVP_MAX_MD_SIZE) 560 1.1 christos goto end; 561 1.1 christos 562 1.1 christos if (*argv != NULL) { 563 1.1 christos while (*argv != NULL) 564 1.1 christos errs += do_dir(*argv++, h); 565 1.1 christos } else if ((env = getenv(X509_get_default_cert_dir_env())) != NULL) { 566 1.1 christos char lsc[2] = { LIST_SEPARATOR_CHAR, '\0' }; 567 1.1 christos m = OPENSSL_strdup(env); 568 1.1 christos if (m == NULL) { 569 1.1 christos BIO_puts(bio_err, "out of memory\n"); 570 1.1 christos errs = 1; 571 1.1 christos goto end; 572 1.1 christos } 573 1.1 christos for (e = strtok(m, lsc); e != NULL; e = strtok(NULL, lsc)) 574 1.1 christos errs += do_dir(e, h); 575 1.1 christos OPENSSL_free(m); 576 1.1 christos } else { 577 1.1 christos errs += do_dir(X509_get_default_cert_dir(), h); 578 1.1 christos } 579 1.1 christos 580 1.1.1.2 christos end: 581 1.1 christos return errs; 582 1.1 christos } 583 1.1 christos 584 1.1 christos #else 585 1.1 christos const OPTIONS rehash_options[] = { 586 1.1.1.2 christos { NULL } 587 1.1 christos }; 588 1.1 christos 589 1.1 christos int rehash_main(int argc, char **argv) 590 1.1 christos { 591 1.1 christos BIO_printf(bio_err, "Not available; use c_rehash script\n"); 592 1.1 christos return 1; 593 1.1 christos } 594 1.1 christos 595 1.1 christos #endif /* defined(OPENSSL_SYS_UNIX) || defined(__APPLE__) */ 596