• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
23 const char OPT_HELP_STR[] = "--";
24 const char OPT_MORE_STR[] = "---";
25 
26 /* Our state */
27 static char **argv;
28 static int argc;
29 static int opt_index;
30 static char *arg;
31 static char *flag;
32 static char *dunno;
33 static const OPTIONS *unknown;
34 static const OPTIONS *opts;
35 static char prog[40];
36 
37 /*
38  * Return the simple name of the program; removing various platform gunk.
39  */
40 #if defined(OPENSSL_SYS_WIN32)
opt_progname(const char * argv0)41 char *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 
opt_progname(const char * argv0)71 char *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 
opt_progname(const char * argv0)92 char *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 
opt_getprog(void)108 char *opt_getprog(void)
109 {
110     return prog;
111 }
112 
113 /* Set up the arg parsing. */
opt_init(int ac,char ** av,const OPTIONS * o)114 char *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 
165 static 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. */
opt_format_error(const char * s,unsigned long flags)179 int 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. */
opt_format(const char * s,unsigned long flags,int * result)197 int 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. */
opt_cipher(const char * name,const EVP_CIPHER ** cipherp)275 int 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  */
opt_md(const char * name,const EVP_MD ** mdp)287 int 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. */
opt_pair(const char * name,const OPT_PAIR * pairs,int * result)297 int 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. */
opt_int(const char * value,int * result)313 int 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 
opt_number_error(const char * v)328 static 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. */
opt_long(const char * value,long * result)353 int 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. */
opt_imax(const char * value,intmax_t * result)378 int 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. */
opt_umax(const char * value,uintmax_t * result)400 int 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  */
opt_ulong(const char * value,unsigned long * result)425 int 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  */
451 enum range { OPT_V_ENUM };
452 
opt_verify(int opt,X509_VERIFY_PARAM * vpm)453 int 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  */
opt_next(void)613 int 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. */
opt_arg(void)758 char *opt_arg(void)
759 {
760     return arg;
761 }
762 
763 /* Return the most recent flag. */
opt_flag(void)764 char *opt_flag(void)
765 {
766     return flag;
767 }
768 
769 /* Return the unknown option. */
opt_unknown(void)770 char *opt_unknown(void)
771 {
772     return dunno;
773 }
774 
775 /* Return the rest of the arguments after parsing flags. */
opt_rest(void)776 char **opt_rest(void)
777 {
778     return &argv[opt_index];
779 }
780 
781 /* How many items in remaining args? */
opt_num_rest(void)782 int 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. */
valtype2param(const OPTIONS * o)793 static 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 
opt_help(const OPTIONS * list)829 void 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