1/* 2 * Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the OpenSSL license (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9#include "apps.h" 10#include <string.h> 11#if !defined(OPENSSL_SYS_MSDOS) 12# include OPENSSL_UNISTD 13#endif 14 15#include <stdlib.h> 16#include <errno.h> 17#include <ctype.h> 18#include <limits.h> 19#include <openssl/bio.h> 20#include <openssl/x509v3.h> 21 22#define MAX_OPT_HELP_WIDTH 30 23const char OPT_HELP_STR[] = "--"; 24const char OPT_MORE_STR[] = "---"; 25 26/* Our state */ 27static char **argv; 28static int argc; 29static int opt_index; 30static char *arg; 31static char *flag; 32static char *dunno; 33static const OPTIONS *unknown; 34static const OPTIONS *opts; 35static char prog[40]; 36 37/* 38 * Return the simple name of the program; removing various platform gunk. 39 */ 40#if defined(OPENSSL_SYS_WIN32) 41char *opt_progname(const char *argv0) 42{ 43 size_t i, n; 44 const char *p; 45 char *q; 46 47 /* find the last '/', '\' or ':' */ 48 for (p = argv0 + strlen(argv0); --p > argv0;) 49 if (*p == '/' || *p == '\\' || *p == ':') { 50 p++; 51 break; 52 } 53 54 /* Strip off trailing nonsense. */ 55 n = strlen(p); 56 if (n > 4 && 57 (strcmp(&p[n - 4], ".exe") == 0 || strcmp(&p[n - 4], ".EXE") == 0)) 58 n -= 4; 59 60 /* Copy over the name, in lowercase. */ 61 if (n > sizeof(prog) - 1) 62 n = sizeof(prog) - 1; 63 for (q = prog, i = 0; i < n; i++, p++) 64 *q++ = tolower((unsigned char)*p); 65 *q = '\0'; 66 return prog; 67} 68 69#elif defined(OPENSSL_SYS_VMS) 70 71char *opt_progname(const char *argv0) 72{ 73 const char *p, *q; 74 75 /* Find last special character sys:[foo.bar]openssl */ 76 for (p = argv0 + strlen(argv0); --p > argv0;) 77 if (*p == ':' || *p == ']' || *p == '>') { 78 p++; 79 break; 80 } 81 82 q = strrchr(p, '.'); 83 strncpy(prog, p, sizeof(prog) - 1); 84 prog[sizeof(prog) - 1] = '\0'; 85 if (q != NULL && q - p < sizeof(prog)) 86 prog[q - p] = '\0'; 87 return prog; 88} 89 90#else 91 92char *opt_progname(const char *argv0) 93{ 94 const char *p; 95 96 /* Could use strchr, but this is like the ones above. */ 97 for (p = argv0 + strlen(argv0); --p > argv0;) 98 if (*p == '/') { 99 p++; 100 break; 101 } 102 strncpy(prog, p, sizeof(prog) - 1); 103 prog[sizeof(prog) - 1] = '\0'; 104 return prog; 105} 106#endif 107 108char *opt_getprog(void) 109{ 110 return prog; 111} 112 113/* Set up the arg parsing. */ 114char *opt_init(int ac, char **av, const OPTIONS *o) 115{ 116 /* Store state. */ 117 argc = ac; 118 argv = av; 119 opt_index = 1; 120 opts = o; 121 opt_progname(av[0]); 122 unknown = NULL; 123 124 for (; o->name; ++o) { 125#ifndef NDEBUG 126 const OPTIONS *next; 127 int duplicated, i; 128#endif 129 130 if (o->name == OPT_HELP_STR || o->name == OPT_MORE_STR) 131 continue; 132#ifndef NDEBUG 133 i = o->valtype; 134 135 /* Make sure options are legit. */ 136 assert(o->name[0] != '-'); 137 assert(o->retval > 0); 138 switch (i) { 139 case 0: case '-': case '/': case '<': case '>': case 'E': case 'F': 140 case 'M': case 'U': case 'f': case 'l': case 'n': case 'p': case 's': 141 case 'u': case 'c': 142 break; 143 default: 144 assert(0); 145 } 146 147 /* Make sure there are no duplicates. */ 148 for (next = o + 1; next->name; ++next) { 149 /* 150 * Some compilers inline strcmp and the assert string is too long. 151 */ 152 duplicated = strcmp(o->name, next->name) == 0; 153 assert(!duplicated); 154 } 155#endif 156 if (o->name[0] == '\0') { 157 assert(unknown == NULL); 158 unknown = o; 159 assert(unknown->valtype == 0 || unknown->valtype == '-'); 160 } 161 } 162 return prog; 163} 164 165static OPT_PAIR formats[] = { 166 {"PEM/DER", OPT_FMT_PEMDER}, 167 {"pkcs12", OPT_FMT_PKCS12}, 168 {"smime", OPT_FMT_SMIME}, 169 {"engine", OPT_FMT_ENGINE}, 170 {"msblob", OPT_FMT_MSBLOB}, 171 {"nss", OPT_FMT_NSS}, 172 {"text", OPT_FMT_TEXT}, 173 {"http", OPT_FMT_HTTP}, 174 {"pvk", OPT_FMT_PVK}, 175 {NULL} 176}; 177 178/* Print an error message about a failed format parse. */ 179int opt_format_error(const char *s, unsigned long flags) 180{ 181 OPT_PAIR *ap; 182 183 if (flags == OPT_FMT_PEMDER) { 184 BIO_printf(bio_err, "%s: Bad format \"%s\"; must be pem or der\n", 185 prog, s); 186 } else { 187 BIO_printf(bio_err, "%s: Bad format \"%s\"; must be one of:\n", 188 prog, s); 189 for (ap = formats; ap->name; ap++) 190 if (flags & ap->retval) 191 BIO_printf(bio_err, " %s\n", ap->name); 192 } 193 return 0; 194} 195 196/* Parse a format string, put it into *result; return 0 on failure, else 1. */ 197int opt_format(const char *s, unsigned long flags, int *result) 198{ 199 switch (*s) { 200 default: 201 return 0; 202 case 'D': 203 case 'd': 204 if ((flags & OPT_FMT_PEMDER) == 0) 205 return opt_format_error(s, flags); 206 *result = FORMAT_ASN1; 207 break; 208 case 'T': 209 case 't': 210 if ((flags & OPT_FMT_TEXT) == 0) 211 return opt_format_error(s, flags); 212 *result = FORMAT_TEXT; 213 break; 214 case 'N': 215 case 'n': 216 if ((flags & OPT_FMT_NSS) == 0) 217 return opt_format_error(s, flags); 218 if (strcmp(s, "NSS") != 0 && strcmp(s, "nss") != 0) 219 return opt_format_error(s, flags); 220 *result = FORMAT_NSS; 221 break; 222 case 'S': 223 case 's': 224 if ((flags & OPT_FMT_SMIME) == 0) 225 return opt_format_error(s, flags); 226 *result = FORMAT_SMIME; 227 break; 228 case 'M': 229 case 'm': 230 if ((flags & OPT_FMT_MSBLOB) == 0) 231 return opt_format_error(s, flags); 232 *result = FORMAT_MSBLOB; 233 break; 234 case 'E': 235 case 'e': 236 if ((flags & OPT_FMT_ENGINE) == 0) 237 return opt_format_error(s, flags); 238 *result = FORMAT_ENGINE; 239 break; 240 case 'H': 241 case 'h': 242 if ((flags & OPT_FMT_HTTP) == 0) 243 return opt_format_error(s, flags); 244 *result = FORMAT_HTTP; 245 break; 246 case '1': 247 if ((flags & OPT_FMT_PKCS12) == 0) 248 return opt_format_error(s, flags); 249 *result = FORMAT_PKCS12; 250 break; 251 case 'P': 252 case 'p': 253 if (s[1] == '\0' || strcmp(s, "PEM") == 0 || strcmp(s, "pem") == 0) { 254 if ((flags & OPT_FMT_PEMDER) == 0) 255 return opt_format_error(s, flags); 256 *result = FORMAT_PEM; 257 } else if (strcmp(s, "PVK") == 0 || strcmp(s, "pvk") == 0) { 258 if ((flags & OPT_FMT_PVK) == 0) 259 return opt_format_error(s, flags); 260 *result = FORMAT_PVK; 261 } else if (strcmp(s, "P12") == 0 || strcmp(s, "p12") == 0 262 || strcmp(s, "PKCS12") == 0 || strcmp(s, "pkcs12") == 0) { 263 if ((flags & OPT_FMT_PKCS12) == 0) 264 return opt_format_error(s, flags); 265 *result = FORMAT_PKCS12; 266 } else { 267 return 0; 268 } 269 break; 270 } 271 return 1; 272} 273 274/* Parse a cipher name, put it in *EVP_CIPHER; return 0 on failure, else 1. */ 275int opt_cipher(const char *name, const EVP_CIPHER **cipherp) 276{ 277 *cipherp = EVP_get_cipherbyname(name); 278 if (*cipherp != NULL) 279 return 1; 280 BIO_printf(bio_err, "%s: Unrecognized flag %s\n", prog, name); 281 return 0; 282} 283 284/* 285 * Parse message digest name, put it in *EVP_MD; return 0 on failure, else 1. 286 */ 287int opt_md(const char *name, const EVP_MD **mdp) 288{ 289 *mdp = EVP_get_digestbyname(name); 290 if (*mdp != NULL) 291 return 1; 292 BIO_printf(bio_err, "%s: Unrecognized flag %s\n", prog, name); 293 return 0; 294} 295 296/* Look through a list of name/value pairs. */ 297int opt_pair(const char *name, const OPT_PAIR* pairs, int *result) 298{ 299 const OPT_PAIR *pp; 300 301 for (pp = pairs; pp->name; pp++) 302 if (strcmp(pp->name, name) == 0) { 303 *result = pp->retval; 304 return 1; 305 } 306 BIO_printf(bio_err, "%s: Value must be one of:\n", prog); 307 for (pp = pairs; pp->name; pp++) 308 BIO_printf(bio_err, "\t%s\n", pp->name); 309 return 0; 310} 311 312/* Parse an int, put it into *result; return 0 on failure, else 1. */ 313int opt_int(const char *value, int *result) 314{ 315 long l; 316 317 if (!opt_long(value, &l)) 318 return 0; 319 *result = (int)l; 320 if (*result != l) { 321 BIO_printf(bio_err, "%s: Value \"%s\" outside integer range\n", 322 prog, value); 323 return 0; 324 } 325 return 1; 326} 327 328static void opt_number_error(const char *v) 329{ 330 size_t i = 0; 331 struct strstr_pair_st { 332 char *prefix; 333 char *name; 334 } b[] = { 335 {"0x", "a hexadecimal"}, 336 {"0X", "a hexadecimal"}, 337 {"0", "an octal"} 338 }; 339 340 for (i = 0; i < OSSL_NELEM(b); i++) { 341 if (strncmp(v, b[i].prefix, strlen(b[i].prefix)) == 0) { 342 BIO_printf(bio_err, 343 "%s: Can't parse \"%s\" as %s number\n", 344 prog, v, b[i].name); 345 return; 346 } 347 } 348 BIO_printf(bio_err, "%s: Can't parse \"%s\" as a number\n", prog, v); 349 return; 350} 351 352/* Parse a long, put it into *result; return 0 on failure, else 1. */ 353int opt_long(const char *value, long *result) 354{ 355 int oerrno = errno; 356 long l; 357 char *endp; 358 359 errno = 0; 360 l = strtol(value, &endp, 0); 361 if (*endp 362 || endp == value 363 || ((l == LONG_MAX || l == LONG_MIN) && errno == ERANGE) 364 || (l == 0 && errno != 0)) { 365 opt_number_error(value); 366 errno = oerrno; 367 return 0; 368 } 369 *result = l; 370 errno = oerrno; 371 return 1; 372} 373 374#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && \ 375 defined(INTMAX_MAX) && defined(UINTMAX_MAX) 376 377/* Parse an intmax_t, put it into *result; return 0 on failure, else 1. */ 378int opt_imax(const char *value, intmax_t *result) 379{ 380 int oerrno = errno; 381 intmax_t m; 382 char *endp; 383 384 errno = 0; 385 m = strtoimax(value, &endp, 0); 386 if (*endp 387 || endp == value 388 || ((m == INTMAX_MAX || m == INTMAX_MIN) && errno == ERANGE) 389 || (m == 0 && errno != 0)) { 390 opt_number_error(value); 391 errno = oerrno; 392 return 0; 393 } 394 *result = m; 395 errno = oerrno; 396 return 1; 397} 398 399/* Parse a uintmax_t, put it into *result; return 0 on failure, else 1. */ 400int opt_umax(const char *value, uintmax_t *result) 401{ 402 int oerrno = errno; 403 uintmax_t m; 404 char *endp; 405 406 errno = 0; 407 m = strtoumax(value, &endp, 0); 408 if (*endp 409 || endp == value 410 || (m == UINTMAX_MAX && errno == ERANGE) 411 || (m == 0 && errno != 0)) { 412 opt_number_error(value); 413 errno = oerrno; 414 return 0; 415 } 416 *result = m; 417 errno = oerrno; 418 return 1; 419} 420#endif 421 422/* 423 * Parse an unsigned long, put it into *result; return 0 on failure, else 1. 424 */ 425int opt_ulong(const char *value, unsigned long *result) 426{ 427 int oerrno = errno; 428 char *endptr; 429 unsigned long l; 430 431 errno = 0; 432 l = strtoul(value, &endptr, 0); 433 if (*endptr 434 || endptr == value 435 || ((l == ULONG_MAX) && errno == ERANGE) 436 || (l == 0 && errno != 0)) { 437 opt_number_error(value); 438 errno = oerrno; 439 return 0; 440 } 441 *result = l; 442 errno = oerrno; 443 return 1; 444} 445 446/* 447 * We pass opt as an int but cast it to "enum range" so that all the 448 * items in the OPT_V_ENUM enumeration are caught; this makes -Wswitch 449 * in gcc do the right thing. 450 */ 451enum range { OPT_V_ENUM }; 452 453int opt_verify(int opt, X509_VERIFY_PARAM *vpm) 454{ 455 int i; 456 ossl_intmax_t t = 0; 457 ASN1_OBJECT *otmp; 458 X509_PURPOSE *xptmp; 459 const X509_VERIFY_PARAM *vtmp; 460 461 assert(vpm != NULL); 462 assert(opt > OPT_V__FIRST); 463 assert(opt < OPT_V__LAST); 464 465 switch ((enum range)opt) { 466 case OPT_V__FIRST: 467 case OPT_V__LAST: 468 return 0; 469 case OPT_V_POLICY: 470 otmp = OBJ_txt2obj(opt_arg(), 0); 471 if (otmp == NULL) { 472 BIO_printf(bio_err, "%s: Invalid Policy %s\n", prog, opt_arg()); 473 return 0; 474 } 475 X509_VERIFY_PARAM_add0_policy(vpm, otmp); 476 break; 477 case OPT_V_PURPOSE: 478 /* purpose name -> purpose index */ 479 i = X509_PURPOSE_get_by_sname(opt_arg()); 480 if (i < 0) { 481 BIO_printf(bio_err, "%s: Invalid purpose %s\n", prog, opt_arg()); 482 return 0; 483 } 484 485 /* purpose index -> purpose object */ 486 xptmp = X509_PURPOSE_get0(i); 487 488 /* purpose object -> purpose value */ 489 i = X509_PURPOSE_get_id(xptmp); 490 491 if (!X509_VERIFY_PARAM_set_purpose(vpm, i)) { 492 BIO_printf(bio_err, 493 "%s: Internal error setting purpose %s\n", 494 prog, opt_arg()); 495 return 0; 496 } 497 break; 498 case OPT_V_VERIFY_NAME: 499 vtmp = X509_VERIFY_PARAM_lookup(opt_arg()); 500 if (vtmp == NULL) { 501 BIO_printf(bio_err, "%s: Invalid verify name %s\n", 502 prog, opt_arg()); 503 return 0; 504 } 505 X509_VERIFY_PARAM_set1(vpm, vtmp); 506 break; 507 case OPT_V_VERIFY_DEPTH: 508 i = atoi(opt_arg()); 509 if (i >= 0) 510 X509_VERIFY_PARAM_set_depth(vpm, i); 511 break; 512 case OPT_V_VERIFY_AUTH_LEVEL: 513 i = atoi(opt_arg()); 514 if (i >= 0) 515 X509_VERIFY_PARAM_set_auth_level(vpm, i); 516 break; 517 case OPT_V_ATTIME: 518 if (!opt_imax(opt_arg(), &t)) 519 return 0; 520 if (t != (time_t)t) { 521 BIO_printf(bio_err, "%s: epoch time out of range %s\n", 522 prog, opt_arg()); 523 return 0; 524 } 525 X509_VERIFY_PARAM_set_time(vpm, (time_t)t); 526 break; 527 case OPT_V_VERIFY_HOSTNAME: 528 if (!X509_VERIFY_PARAM_set1_host(vpm, opt_arg(), 0)) 529 return 0; 530 break; 531 case OPT_V_VERIFY_EMAIL: 532 if (!X509_VERIFY_PARAM_set1_email(vpm, opt_arg(), 0)) 533 return 0; 534 break; 535 case OPT_V_VERIFY_IP: 536 if (!X509_VERIFY_PARAM_set1_ip_asc(vpm, opt_arg())) 537 return 0; 538 break; 539 case OPT_V_IGNORE_CRITICAL: 540 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_IGNORE_CRITICAL); 541 break; 542 case OPT_V_ISSUER_CHECKS: 543 /* NOP, deprecated */ 544 break; 545 case OPT_V_CRL_CHECK: 546 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CRL_CHECK); 547 break; 548 case OPT_V_CRL_CHECK_ALL: 549 X509_VERIFY_PARAM_set_flags(vpm, 550 X509_V_FLAG_CRL_CHECK | 551 X509_V_FLAG_CRL_CHECK_ALL); 552 break; 553 case OPT_V_POLICY_CHECK: 554 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_POLICY_CHECK); 555 break; 556 case OPT_V_EXPLICIT_POLICY: 557 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_EXPLICIT_POLICY); 558 break; 559 case OPT_V_INHIBIT_ANY: 560 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_INHIBIT_ANY); 561 break; 562 case OPT_V_INHIBIT_MAP: 563 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_INHIBIT_MAP); 564 break; 565 case OPT_V_X509_STRICT: 566 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_X509_STRICT); 567 break; 568 case OPT_V_EXTENDED_CRL: 569 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_EXTENDED_CRL_SUPPORT); 570 break; 571 case OPT_V_USE_DELTAS: 572 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_USE_DELTAS); 573 break; 574 case OPT_V_POLICY_PRINT: 575 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NOTIFY_POLICY); 576 break; 577 case OPT_V_CHECK_SS_SIG: 578 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CHECK_SS_SIGNATURE); 579 break; 580 case OPT_V_TRUSTED_FIRST: 581 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_TRUSTED_FIRST); 582 break; 583 case OPT_V_SUITEB_128_ONLY: 584 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_128_LOS_ONLY); 585 break; 586 case OPT_V_SUITEB_128: 587 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_128_LOS); 588 break; 589 case OPT_V_SUITEB_192: 590 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_192_LOS); 591 break; 592 case OPT_V_PARTIAL_CHAIN: 593 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_PARTIAL_CHAIN); 594 break; 595 case OPT_V_NO_ALT_CHAINS: 596 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_ALT_CHAINS); 597 break; 598 case OPT_V_NO_CHECK_TIME: 599 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_CHECK_TIME); 600 break; 601 case OPT_V_ALLOW_PROXY_CERTS: 602 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_ALLOW_PROXY_CERTS); 603 break; 604 } 605 return 1; 606 607} 608 609/* 610 * Parse the next flag (and value if specified), return 0 if done, -1 on 611 * error, otherwise the flag's retval. 612 */ 613int opt_next(void) 614{ 615 char *p; 616 const OPTIONS *o; 617 int ival; 618 long lval; 619 unsigned long ulval; 620 ossl_intmax_t imval; 621 ossl_uintmax_t umval; 622 623 /* Look at current arg; at end of the list? */ 624 arg = NULL; 625 p = argv[opt_index]; 626 if (p == NULL) 627 return 0; 628 629 /* If word doesn't start with a -, we're done. */ 630 if (*p != '-') 631 return 0; 632 633 /* Hit "--" ? We're done. */ 634 opt_index++; 635 if (strcmp(p, "--") == 0) 636 return 0; 637 638 /* Allow -nnn and --nnn */ 639 if (*++p == '-') 640 p++; 641 flag = p - 1; 642 643 /* If we have --flag=foo, snip it off */ 644 if ((arg = strchr(p, '=')) != NULL) 645 *arg++ = '\0'; 646 for (o = opts; o->name; ++o) { 647 /* If not this option, move on to the next one. */ 648 if (strcmp(p, o->name) != 0) 649 continue; 650 651 /* If it doesn't take a value, make sure none was given. */ 652 if (o->valtype == 0 || o->valtype == '-') { 653 if (arg) { 654 BIO_printf(bio_err, 655 "%s: Option -%s does not take a value\n", prog, p); 656 return -1; 657 } 658 return o->retval; 659 } 660 661 /* Want a value; get the next param if =foo not used. */ 662 if (arg == NULL) { 663 if (argv[opt_index] == NULL) { 664 BIO_printf(bio_err, 665 "%s: Option -%s needs a value\n", prog, o->name); 666 return -1; 667 } 668 arg = argv[opt_index++]; 669 } 670 671 /* Syntax-check value. */ 672 switch (o->valtype) { 673 default: 674 case 's': 675 /* Just a string. */ 676 break; 677 case '/': 678 if (app_isdir(arg) > 0) 679 break; 680 BIO_printf(bio_err, "%s: Not a directory: %s\n", prog, arg); 681 return -1; 682 case '<': 683 /* Input file. */ 684 break; 685 case '>': 686 /* Output file. */ 687 break; 688 case 'p': 689 case 'n': 690 if (!opt_int(arg, &ival) 691 || (o->valtype == 'p' && ival <= 0)) { 692 BIO_printf(bio_err, 693 "%s: Non-positive number \"%s\" for -%s\n", 694 prog, arg, o->name); 695 return -1; 696 } 697 break; 698 case 'M': 699 if (!opt_imax(arg, &imval)) { 700 BIO_printf(bio_err, 701 "%s: Invalid number \"%s\" for -%s\n", 702 prog, arg, o->name); 703 return -1; 704 } 705 break; 706 case 'U': 707 if (!opt_umax(arg, &umval)) { 708 BIO_printf(bio_err, 709 "%s: Invalid number \"%s\" for -%s\n", 710 prog, arg, o->name); 711 return -1; 712 } 713 break; 714 case 'l': 715 if (!opt_long(arg, &lval)) { 716 BIO_printf(bio_err, 717 "%s: Invalid number \"%s\" for -%s\n", 718 prog, arg, o->name); 719 return -1; 720 } 721 break; 722 case 'u': 723 if (!opt_ulong(arg, &ulval)) { 724 BIO_printf(bio_err, 725 "%s: Invalid number \"%s\" for -%s\n", 726 prog, arg, o->name); 727 return -1; 728 } 729 break; 730 case 'c': 731 case 'E': 732 case 'F': 733 case 'f': 734 if (opt_format(arg, 735 o->valtype == 'c' ? OPT_FMT_PDS : 736 o->valtype == 'E' ? OPT_FMT_PDE : 737 o->valtype == 'F' ? OPT_FMT_PEMDER 738 : OPT_FMT_ANY, &ival)) 739 break; 740 BIO_printf(bio_err, 741 "%s: Invalid format \"%s\" for -%s\n", 742 prog, arg, o->name); 743 return -1; 744 } 745 746 /* Return the flag value. */ 747 return o->retval; 748 } 749 if (unknown != NULL) { 750 dunno = p; 751 return unknown->retval; 752 } 753 BIO_printf(bio_err, "%s: Option unknown option -%s\n", prog, p); 754 return -1; 755} 756 757/* Return the most recent flag parameter. */ 758char *opt_arg(void) 759{ 760 return arg; 761} 762 763/* Return the most recent flag. */ 764char *opt_flag(void) 765{ 766 return flag; 767} 768 769/* Return the unknown option. */ 770char *opt_unknown(void) 771{ 772 return dunno; 773} 774 775/* Return the rest of the arguments after parsing flags. */ 776char **opt_rest(void) 777{ 778 return &argv[opt_index]; 779} 780 781/* How many items in remaining args? */ 782int opt_num_rest(void) 783{ 784 int i = 0; 785 char **pp; 786 787 for (pp = opt_rest(); *pp; pp++, i++) 788 continue; 789 return i; 790} 791 792/* Return a string describing the parameter type. */ 793static const char *valtype2param(const OPTIONS *o) 794{ 795 switch (o->valtype) { 796 case 0: 797 case '-': 798 return ""; 799 case 's': 800 return "val"; 801 case '/': 802 return "dir"; 803 case '<': 804 return "infile"; 805 case '>': 806 return "outfile"; 807 case 'p': 808 return "+int"; 809 case 'n': 810 return "int"; 811 case 'l': 812 return "long"; 813 case 'u': 814 return "ulong"; 815 case 'E': 816 return "PEM|DER|ENGINE"; 817 case 'F': 818 return "PEM|DER"; 819 case 'f': 820 return "format"; 821 case 'M': 822 return "intmax"; 823 case 'U': 824 return "uintmax"; 825 } 826 return "parm"; 827} 828 829void opt_help(const OPTIONS *list) 830{ 831 const OPTIONS *o; 832 int i; 833 int standard_prolog; 834 int width = 5; 835 char start[80 + 1]; 836 char *p; 837 const char *help; 838 839 /* Starts with its own help message? */ 840 standard_prolog = list[0].name != OPT_HELP_STR; 841 842 /* Find the widest help. */ 843 for (o = list; o->name; o++) { 844 if (o->name == OPT_MORE_STR) 845 continue; 846 i = 2 + (int)strlen(o->name); 847 if (o->valtype != '-') 848 i += 1 + strlen(valtype2param(o)); 849 if (i < MAX_OPT_HELP_WIDTH && i > width) 850 width = i; 851 assert(i < (int)sizeof(start)); 852 } 853 854 if (standard_prolog) 855 BIO_printf(bio_err, "Usage: %s [options]\nValid options are:\n", 856 prog); 857 858 /* Now let's print. */ 859 for (o = list; o->name; o++) { 860 help = o->helpstr ? o->helpstr : "(No additional info)"; 861 if (o->name == OPT_HELP_STR) { 862 BIO_printf(bio_err, help, prog); 863 continue; 864 } 865 866 /* Pad out prefix */ 867 memset(start, ' ', sizeof(start) - 1); 868 start[sizeof(start) - 1] = '\0'; 869 870 if (o->name == OPT_MORE_STR) { 871 /* Continuation of previous line; pad and print. */ 872 start[width] = '\0'; 873 BIO_printf(bio_err, "%s %s\n", start, help); 874 continue; 875 } 876 877 /* Build up the "-flag [param]" part. */ 878 p = start; 879 *p++ = ' '; 880 *p++ = '-'; 881 if (o->name[0]) 882 p += strlen(strcpy(p, o->name)); 883 else 884 *p++ = '*'; 885 if (o->valtype != '-') { 886 *p++ = ' '; 887 p += strlen(strcpy(p, valtype2param(o))); 888 } 889 *p = ' '; 890 if ((int)(p - start) >= MAX_OPT_HELP_WIDTH) { 891 *p = '\0'; 892 BIO_printf(bio_err, "%s\n", start); 893 memset(start, ' ', sizeof(start)); 894 } 895 start[width] = '\0'; 896 BIO_printf(bio_err, "%s %s\n", start, help); 897 } 898} 899