Maximize time_t when intmax_t is available
[openssl.git] / apps / opt.c
1 /* ====================================================================
2  * Copyright (c) 2015 The OpenSSL Project.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in
13  *    the documentation and/or other materials provided with the
14  *    distribution.
15  *
16  * 3. All advertising materials mentioning features or use of this
17  *    software must display the following acknowledgment:
18  *    "This product includes software developed by the OpenSSL Project
19  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
20  *
21  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
22  *    endorse or promote products derived from this software without
23  *    prior written permission. For written permission, please contact
24  *    licensing@OpenSSL.org.
25  *
26  * 5. Products derived from this software may not be called "OpenSSL"
27  *    nor may "OpenSSL" appear in their names without prior written
28  *    permission of the OpenSSL Project.
29  *
30  * 6. Redistributions of any form whatsoever must retain the following
31  *    acknowledgment:
32  *    "This product includes software developed by the OpenSSL Project
33  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
36  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
44  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
46  * OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  */
49
50 /* #define COMPILE_STANDALONE_TEST_DRIVER  */
51 #include "apps.h"
52 #include <string.h>
53 #if !defined(OPENSSL_SYS_MSDOS)
54 # include OPENSSL_UNISTD
55 #endif
56
57 #include <stdlib.h>
58 #include <errno.h>
59 #include <ctype.h>
60 #include <limits.h>
61 #include <openssl/bio.h>
62
63 #define MAX_OPT_HELP_WIDTH 30
64 const char OPT_HELP_STR[] = "--";
65 const char OPT_MORE_STR[] = "---";
66
67 /* Our state */
68 static char **argv;
69 static int argc;
70 static int opt_index;
71 static char *arg;
72 static char *flag;
73 static char *dunno;
74 static const OPTIONS *unknown;
75 static const OPTIONS *opts;
76 static char prog[40];
77
78 #if !defined(INTMAX_MAX) || !defined(UINTMAX_MAX)
79 #define opt_imax opt_long
80 #define opt_umax opt_ulong
81 #endif
82
83 /*
84  * Return the simple name of the program; removing various platform gunk.
85  */
86 #if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_NETWARE)
87 char *opt_progname(const char *argv0)
88 {
89     size_t i, n;
90     const char *p;
91     char *q;
92
93     /* find the last '/', '\' or ':' */
94     for (p = argv0 + strlen(argv0); --p > argv0;)
95         if (*p == '/' || *p == '\\' || *p == ':') {
96             p++;
97             break;
98         }
99
100     /* Strip off trailing nonsense. */
101     n = strlen(p);
102     if (n > 4 &&
103         (strcmp(&p[n - 4], ".exe") == 0 || strcmp(&p[n - 4], ".EXE") == 0))
104         n -= 4;
105 #if defined(OPENSSL_SYS_NETWARE)
106     if (n > 4 &&
107         (strcmp(&p[n - 4], ".nlm") == 0 || strcmp(&p[n - 4], ".NLM") == 0))
108         n -= 4;
109 #endif
110
111     /* Copy over the name, in lowercase. */
112     if (n > sizeof prog - 1)
113         n = sizeof prog - 1;
114     for (q = prog, i = 0; i < n; i++, p++)
115         *q++ = isupper(*p) ? tolower(*p) : *p;
116     *q = '\0';
117     return prog;
118 }
119
120 #elif defined(OPENSSL_SYS_VMS)
121
122 char *opt_progname(const char *argv0)
123 {
124     const char *p, *q;
125
126     /* Find last special charcter sys:[foo.bar]openssl */
127     for (p = argv0 + strlen(argv0); --p > argv0;)
128         if (*p == ':' || *p == ']' || *p == '>') {
129             p++;
130             break;
131         }
132
133     q = strrchr(p, '.');
134     strncpy(prog, p, sizeof prog - 1);
135     prog[sizeof prog - 1] = '\0';
136     if (q != NULL && q - p < sizeof prog)
137         prog[q - p] = '\0';
138     return prog;
139 }
140
141 #else
142
143 char *opt_progname(const char *argv0)
144 {
145     const char *p;
146
147     /* Could use strchr, but this is like the ones above. */
148     for (p = argv0 + strlen(argv0); --p > argv0;)
149         if (*p == '/') {
150             p++;
151             break;
152         }
153     strncpy(prog, p, sizeof prog - 1);
154     prog[sizeof prog - 1] = '\0';
155     return prog;
156 }
157 #endif
158
159 char *opt_getprog(void)
160 {
161     return prog;
162 }
163
164 /* Set up the arg parsing. */
165 char *opt_init(int ac, char **av, const OPTIONS *o)
166 {
167     /* Store state. */
168     argc = ac;
169     argv = av;
170     opt_index = 1;
171     opts = o;
172     opt_progname(av[0]);
173     unknown = NULL;
174
175     for (; o->name; ++o) {
176         const OPTIONS *next;
177 #ifndef NDEBUG
178         int duplicated, i;
179 #endif
180
181         if (o->name == OPT_HELP_STR || o->name == OPT_MORE_STR)
182             continue;
183 #ifndef NDEBUG
184         i = o->valtype;
185
186         /* Make sure options are legit. */
187         assert(o->name[0] != '-');
188         assert(o->retval > 0);
189         switch (i) {
190         case   0: case '-': case '/': case '<': case '>': case 'F': case 'M':
191         case 'L': case 'U': case 'f': case 'n': case 'p': case 's': case 'u':
192             break;
193         default:
194             assert(0);
195         }
196
197         /* Make sure there are no duplicates. */
198         for (next = o + 1; next->name; ++next) {
199             /*
200              * Some compilers inline strcmp and the assert string is too long.
201              */
202             duplicated = strcmp(o->name, next->name) == 0;
203             assert(!duplicated);
204         }
205 #endif
206         if (o->name[0] == '\0') {
207             assert(unknown == NULL);
208             unknown = o;
209             assert(unknown->valtype == 0 || unknown->valtype == '-');
210         }
211     }
212     return prog;
213 }
214
215 static OPT_PAIR formats[] = {
216     {"PEM/DER", OPT_FMT_PEMDER},
217     {"pkcs12", OPT_FMT_PKCS12},
218     {"smime", OPT_FMT_SMIME},
219     {"engine", OPT_FMT_ENGINE},
220     {"msblob", OPT_FMT_MSBLOB},
221     {"netscape", OPT_FMT_NETSCAPE},
222     {"nss", OPT_FMT_NSS},
223     {"text", OPT_FMT_TEXT},
224     {"http", OPT_FMT_HTTP},
225     {"pvk", OPT_FMT_PVK},
226     {NULL}
227 };
228
229 /* Print an error message about a failed format parse. */
230 int opt_format_error(const char *s, unsigned long flags)
231 {
232     OPT_PAIR *ap;
233
234     if (flags == OPT_FMT_PEMDER)
235         BIO_printf(bio_err, "%s: Bad format \"%s\"; must be pem or der\n",
236                    prog, s);
237     else {
238         BIO_printf(bio_err, "%s: Bad format \"%s\"; must be one of:\n",
239                    prog, s);
240         for (ap = formats; ap->name; ap++)
241             if (flags & ap->retval)
242                 BIO_printf(bio_err, "   %s\n", ap->name);
243     }
244     return 0;
245 }
246
247 /* Parse a format string, put it into *result; return 0 on failure, else 1. */
248 int opt_format(const char *s, unsigned long flags, int *result)
249 {
250     switch (*s) {
251     default:
252         return 0;
253     case 'D':
254     case 'd':
255         if ((flags & OPT_FMT_PEMDER) == 0)
256             return opt_format_error(s, flags);
257         *result = FORMAT_ASN1;
258         break;
259     case 'T':
260     case 't':
261         if ((flags & OPT_FMT_TEXT) == 0)
262             return opt_format_error(s, flags);
263         *result = FORMAT_TEXT;
264         break;
265     case 'N':
266     case 'n':
267         if ((flags & OPT_FMT_NSS) == 0)
268             return opt_format_error(s, flags);
269         if (strcmp(s, "NSS") != 0 && strcmp(s, "nss") != 0)
270             return opt_format_error(s, flags);
271         *result = FORMAT_NSS;
272         break;
273     case 'S':
274     case 's':
275         if ((flags & OPT_FMT_SMIME) == 0)
276             return opt_format_error(s, flags);
277         *result = FORMAT_SMIME;
278         break;
279     case 'M':
280     case 'm':
281         if ((flags & OPT_FMT_MSBLOB) == 0)
282             return opt_format_error(s, flags);
283         *result = FORMAT_MSBLOB;
284         break;
285     case 'E':
286     case 'e':
287         if ((flags & OPT_FMT_ENGINE) == 0)
288             return opt_format_error(s, flags);
289         *result = FORMAT_ENGINE;
290         break;
291     case 'H':
292     case 'h':
293         if ((flags & OPT_FMT_HTTP) == 0)
294             return opt_format_error(s, flags);
295         *result = FORMAT_HTTP;
296         break;
297     case '1':
298         if ((flags & OPT_FMT_PKCS12) == 0)
299             return opt_format_error(s, flags);
300         *result = FORMAT_PKCS12;
301         break;
302     case 'P':
303     case 'p':
304         if (s[1] == '\0' || strcmp(s, "PEM") == 0 || strcmp(s, "pem") == 0) {
305             if ((flags & OPT_FMT_PEMDER) == 0)
306                 return opt_format_error(s, flags);
307             *result = FORMAT_PEM;
308         } else if (strcmp(s, "PVK") == 0 || strcmp(s, "pvk") == 0) {
309             if ((flags & OPT_FMT_PVK) == 0)
310                 return opt_format_error(s, flags);
311             *result = FORMAT_PVK;
312         } else if (strcmp(s, "P12") == 0 || strcmp(s, "p12") == 0
313                    || strcmp(s, "PKCS12") == 0 || strcmp(s, "pkcs12") == 0) {
314             if ((flags & OPT_FMT_PKCS12) == 0)
315                 return opt_format_error(s, flags);
316             *result = FORMAT_PKCS12;
317         } else
318             return 0;
319         break;
320     }
321     return 1;
322 }
323
324 /* Parse a cipher name, put it in *EVP_CIPHER; return 0 on failure, else 1. */
325 int opt_cipher(const char *name, const EVP_CIPHER **cipherp)
326 {
327     *cipherp = EVP_get_cipherbyname(name);
328     if (*cipherp)
329         return 1;
330     BIO_printf(bio_err, "%s: Unknown cipher %s\n", prog, name);
331     return 0;
332 }
333
334 /*
335  * Parse message digest name, put it in *EVP_MD; return 0 on failure, else 1.
336  */
337 int opt_md(const char *name, const EVP_MD **mdp)
338 {
339     *mdp = EVP_get_digestbyname(name);
340     if (*mdp)
341         return 1;
342     BIO_printf(bio_err, "%s: Unknown digest %s\n", prog, name);
343     return 0;
344 }
345
346 /* Look through a list of name/value pairs. */
347 int opt_pair(const char *name, const OPT_PAIR* pairs, int *result)
348 {
349     const OPT_PAIR *pp;
350
351     for (pp = pairs; pp->name; pp++)
352         if (strcmp(pp->name, name) == 0) {
353             *result = pp->retval;
354             return 1;
355         }
356     BIO_printf(bio_err, "%s: Value must be one of:\n", prog);
357     for (pp = pairs; pp->name; pp++)
358         BIO_printf(bio_err, "\t%s\n", pp->name);
359     return 0;
360 }
361
362 /* Parse an int, put it into *result; return 0 on failure, else 1. */
363 int opt_int(const char *value, int *result)
364 {
365     long l;
366
367     if (!opt_long(value, &l))
368         return 0;
369     *result = (int)l;
370     if (*result != l) {
371         BIO_printf(bio_err, "%s: Value \"%s\" outside integer range\n",
372                    prog, value);
373         return 0;
374     }
375     return 1;
376 }
377
378 /* Parse a long, put it into *result; return 0 on failure, else 1. */
379 int opt_long(const char *value, long *result)
380 {
381     int oerrno = errno;
382     long l;
383     char *endp;
384
385     l = strtol(value, &endp, 0);
386     if (*endp
387             || endp == value
388             || ((l == LONG_MAX || l == LONG_MIN) && errno == ERANGE)
389             || (l == 0 && errno != 0)) {
390         BIO_printf(bio_err, "%s: Can't parse \"%s\" as a number\n",
391                    prog, value);
392         errno = oerrno;
393         return 0;
394     }
395     *result = l;
396     errno = oerrno;
397     return 1;
398 }
399
400 #if defined(INTMAX_MAX) && defined(UINTMAX_MAX)
401
402 /* Parse an intmax_t, put it into *result; return 0 on failure, else 1. */
403 int opt_imax(const char *value, intmax_t *result)
404 {
405     int oerrno = errno;
406     intmax_t m;
407     char *endp;
408
409     m = strtoimax(value, &endp, 0);
410     if (*endp
411             || endp == value
412             || ((m == INTMAX_MAX || m == INTMAX_MIN) && errno == ERANGE)
413             || (m == 0 && errno != 0)) {
414         BIO_printf(bio_err, "%s: Can't parse \"%s\" as a number\n",
415                    prog, value);
416         errno = oerrno;
417         return 0;
418     }
419     *result = m;
420     errno = oerrno;
421     return 1;
422 }
423
424 /* Parse a uintmax_t, put it into *result; return 0 on failure, else 1. */
425 int opt_umax(const char *value, uintmax_t *result)
426 {
427     int oerrno = errno;
428     uintmax_t m;
429     char *endp;
430
431     m = strtoumax(value, &endp, 0);
432     if (*endp
433             || endp == value
434             || (m == UINTMAX_MAX && errno == ERANGE)
435             || (m == 0 && errno != 0)) {
436         BIO_printf(bio_err, "%s: Can't parse \"%s\" as a number\n",
437                    prog, value);
438         errno = oerrno;
439         return 0;
440     }
441     *result = m;
442     errno = oerrno;
443     return 1;
444 }
445 #endif
446
447 /*
448  * Parse an unsigned long, put it into *result; return 0 on failure, else 1.
449  */
450 int opt_ulong(const char *value, unsigned long *result)
451 {
452     int oerrno = errno;
453     char *endptr;
454     unsigned long l;
455
456     l = strtoul(value, &endptr, 0);
457     if (*endptr
458             || endptr == value
459             || ((l == ULONG_MAX) && errno == ERANGE)
460             || (l == 0 && errno != 0)) {
461         BIO_printf(bio_err, "%s: Can't parse \"%s\" as an unsigned number\n",
462                    prog, value);
463         errno = oerrno;
464         return 0;
465     }
466     *result = l;
467     errno = oerrno;
468     return 1;
469 }
470
471 /*
472  * We pass opt as an int but cast it to "enum range" so that all the
473  * items in the OPT_V_ENUM enumeration are caught; this makes -Wswitch
474  * in gcc do the right thing.
475  */
476 enum range { OPT_V_ENUM };
477
478 int opt_verify(int opt, X509_VERIFY_PARAM *vpm)
479 {
480     int i;
481     ossl_intmax_t t = 0;
482     ASN1_OBJECT *otmp;
483     X509_PURPOSE *xptmp;
484     const X509_VERIFY_PARAM *vtmp;
485
486     assert(vpm != NULL);
487     assert(opt > OPT_V__FIRST);
488     assert(opt < OPT_V__LAST);
489
490     switch ((enum range)opt) {
491     case OPT_V__FIRST:
492     case OPT_V__LAST:
493         return 0;
494     case OPT_V_POLICY:
495         otmp = OBJ_txt2obj(opt_arg(), 0);
496         if (otmp == NULL) {
497             BIO_printf(bio_err, "%s: Invalid Policy %s\n", prog, opt_arg());
498             return 0;
499         }
500         X509_VERIFY_PARAM_add0_policy(vpm, otmp);
501         break;
502     case OPT_V_PURPOSE:
503         i = X509_PURPOSE_get_by_sname(opt_arg());
504         if (i < 0) {
505             BIO_printf(bio_err, "%s: Invalid purpose %s\n", prog, opt_arg());
506             return 0;
507         }
508         xptmp = X509_PURPOSE_get0(i);
509         i = X509_PURPOSE_get_id(xptmp);
510         X509_VERIFY_PARAM_set_purpose(vpm, i);
511         break;
512     case OPT_V_VERIFY_NAME:
513         vtmp = X509_VERIFY_PARAM_lookup(opt_arg());
514         if (vtmp == NULL) {
515             BIO_printf(bio_err, "%s: Invalid verify name %s\n",
516                        prog, opt_arg());
517             return 0;
518         }
519         X509_VERIFY_PARAM_set1(vpm, vtmp);
520         break;
521     case OPT_V_VERIFY_DEPTH:
522         i = atoi(opt_arg());
523         if (i >= 0)
524             X509_VERIFY_PARAM_set_depth(vpm, i);
525         break;
526     case OPT_V_ATTIME:
527         if (!opt_imax(opt_arg(), &t))
528             return 0;
529         if (t != (time_t)t) {
530             BIO_printf(bio_err, "%s: epoch time out of range %s\n",
531                        prog, opt_arg());
532             return 0;
533         }
534         X509_VERIFY_PARAM_set_time(vpm, (time_t)t);
535         break;
536     case OPT_V_VERIFY_HOSTNAME:
537         if (!X509_VERIFY_PARAM_set1_host(vpm, opt_arg(), 0))
538             return 0;
539         break;
540     case OPT_V_VERIFY_EMAIL:
541         if (!X509_VERIFY_PARAM_set1_email(vpm, opt_arg(), 0))
542             return 0;
543         break;
544     case OPT_V_VERIFY_IP:
545         if (!X509_VERIFY_PARAM_set1_ip_asc(vpm, opt_arg()))
546             return 0;
547         break;
548     case OPT_V_IGNORE_CRITICAL:
549         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_IGNORE_CRITICAL);
550         break;
551     case OPT_V_ISSUER_CHECKS:
552         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CB_ISSUER_CHECK);
553         break;
554     case OPT_V_CRL_CHECK:
555         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CRL_CHECK);
556         break;
557     case OPT_V_CRL_CHECK_ALL:
558         X509_VERIFY_PARAM_set_flags(vpm,
559                                     X509_V_FLAG_CRL_CHECK |
560                                     X509_V_FLAG_CRL_CHECK_ALL);
561         break;
562     case OPT_V_POLICY_CHECK:
563         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_POLICY_CHECK);
564         break;
565     case OPT_V_EXPLICIT_POLICY:
566         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_EXPLICIT_POLICY);
567         break;
568     case OPT_V_INHIBIT_ANY:
569         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_INHIBIT_ANY);
570         break;
571     case OPT_V_INHIBIT_MAP:
572         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_INHIBIT_MAP);
573         break;
574     case OPT_V_X509_STRICT:
575         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_X509_STRICT);
576         break;
577     case OPT_V_EXTENDED_CRL:
578         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_EXTENDED_CRL_SUPPORT);
579         break;
580     case OPT_V_USE_DELTAS:
581         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_USE_DELTAS);
582         break;
583     case OPT_V_POLICY_PRINT:
584         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NOTIFY_POLICY);
585         break;
586     case OPT_V_CHECK_SS_SIG:
587         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CHECK_SS_SIGNATURE);
588         break;
589     case OPT_V_TRUSTED_FIRST:
590         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_TRUSTED_FIRST);
591         break;
592     case OPT_V_SUITEB_128_ONLY:
593         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_128_LOS_ONLY);
594         break;
595     case OPT_V_SUITEB_128:
596         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_128_LOS);
597         break;
598     case OPT_V_SUITEB_192:
599         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_192_LOS);
600         break;
601     case OPT_V_PARTIAL_CHAIN:
602         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_PARTIAL_CHAIN);
603         break;
604     case OPT_V_NO_ALT_CHAINS:
605         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_ALT_CHAINS);
606         break;
607     case OPT_V_NO_CHECK_TIME:
608         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_CHECK_TIME);
609         break;
610     }
611     return 1;
612
613 }
614
615 /*
616  * Parse the next flag (and value if specified), return 0 if done, -1 on
617  * error, otherwise the flag's retval.
618  */
619 int opt_next(void)
620 {
621     char *p;
622     const OPTIONS *o;
623     int ival;
624     long lval;
625     unsigned long ulval;
626     ossl_intmax_t imval;
627     ossl_uintmax_t umval;
628
629     /* Look at current arg; at end of the list? */
630     arg = NULL;
631     p = argv[opt_index];
632     if (p == NULL)
633         return 0;
634
635     /* If word doesn't start with a -, we're done. */
636     if (*p != '-')
637         return 0;
638
639     /* Hit "--" ? We're done. */
640     opt_index++;
641     if (strcmp(p, "--") == 0)
642         return 0;
643
644     /* Allow -nnn and --nnn */
645     if (*++p == '-')
646         p++;
647     flag = p - 1;
648
649     /* If we have --flag=foo, snip it off */
650     if ((arg = strchr(p, '=')) != NULL)
651         *arg++ = '\0';
652     for (o = opts; o->name; ++o) {
653         /* If not this option, move on to the next one. */
654         if (strcmp(p, o->name) != 0)
655             continue;
656
657         /* If it doesn't take a value, make sure none was given. */
658         if (o->valtype == 0 || o->valtype == '-') {
659             if (arg) {
660                 BIO_printf(bio_err,
661                            "%s: Option -%s does not take a value\n", prog, p);
662                 return -1;
663             }
664             return o->retval;
665         }
666
667         /* Want a value; get the next param if =foo not used. */
668         if (arg == NULL) {
669             if (argv[opt_index] == NULL) {
670                 BIO_printf(bio_err,
671                            "%s: Option -%s needs a value\n", prog, o->name);
672                 return -1;
673             }
674             arg = argv[opt_index++];
675         }
676
677         /* Syntax-check value. */
678         switch (o->valtype) {
679         default:
680         case 's':
681             /* Just a string. */
682             break;
683         case '/':
684             if (app_isdir(arg) >= 0)
685                 break;
686             BIO_printf(bio_err, "%s: Not a directory: %s\n", prog, arg);
687             return -1;
688         case '<':
689             /* Input file. */
690             if (strcmp(arg, "-") == 0 || app_access(arg, R_OK) >= 0)
691                 break;
692             BIO_printf(bio_err,
693                        "%s: Cannot open input file %s, %s\n",
694                        prog, arg, strerror(errno));
695             return -1;
696         case '>':
697             /* Output file. */
698             if (strcmp(arg, "-") == 0 || app_access(arg, W_OK) >= 0 || errno == ENOENT)
699                 break;
700             BIO_printf(bio_err,
701                        "%s: Cannot open output file %s, %s\n",
702                        prog, arg, strerror(errno));
703             return -1;
704         case 'p':
705         case 'n':
706             if (!opt_int(arg, &ival)
707                     || (o->valtype == 'p' && ival <= 0)) {
708                 BIO_printf(bio_err,
709                            "%s: Non-positive number \"%s\" for -%s\n",
710                            prog, arg, o->name);
711                 return -1;
712             }
713             break;
714         case 'M':
715             if (!opt_imax(arg, &imval)) {
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_umax(arg, &umval)) {
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 'L':
731             if (!opt_long(arg, &lval)) {
732                 BIO_printf(bio_err,
733                            "%s: Invalid number \"%s\" for -%s\n",
734                            prog, arg, o->name);
735                 return -1;
736             }
737             break;
738         case 'u':
739             if (!opt_ulong(arg, &ulval)) {
740                 BIO_printf(bio_err,
741                            "%s: Invalid number \"%s\" for -%s\n",
742                            prog, arg, o->name);
743                 return -1;
744             }
745             break;
746         case 'f':
747         case 'F':
748             if (opt_format(arg,
749                            o->valtype == 'F' ? OPT_FMT_PEMDER
750                            : OPT_FMT_ANY, &ival))
751                 break;
752             BIO_printf(bio_err,
753                        "%s: Invalid format \"%s\" for -%s\n",
754                        prog, arg, o->name);
755             return -1;
756         }
757
758         /* Return the flag value. */
759         return o->retval;
760     }
761     if (unknown != NULL) {
762         dunno = p;
763         return unknown->retval;
764     }
765     BIO_printf(bio_err, "%s: Option unknown option -%s\n", prog, p);
766     return -1;
767 }
768
769 /* Return the most recent flag parameter. */
770 char *opt_arg(void)
771 {
772     return arg;
773 }
774
775 /* Return the most recent flag. */
776 char *opt_flag(void)
777 {
778     return flag;
779 }
780
781 /* Return the unknown option. */
782 char *opt_unknown(void)
783 {
784     return dunno;
785 }
786
787 /* Return the rest of the arguments after parsing flags. */
788 char **opt_rest(void)
789 {
790     return &argv[opt_index];
791 }
792
793 /* How many items in remaining args? */
794 int opt_num_rest(void)
795 {
796     int i = 0;
797     char **pp;
798
799     for (pp = opt_rest(); *pp; pp++, i++)
800         continue;
801     return i;
802 }
803
804 /* Return a string describing the parameter type. */
805 static const char *valtype2param(const OPTIONS *o)
806 {
807     switch (o->valtype) {
808     case '-':
809         return "";
810     case 's':
811         return "val";
812     case '/':
813         return "dir";
814     case '<':
815         return "infile";
816     case '>':
817         return "outfile";
818     case 'p':
819         return "pnum";
820     case 'n':
821         return "num";
822     case 'u':
823         return "unum";
824     case 'F':
825         return "der/pem";
826     case 'f':
827         return "format";
828     }
829     return "parm";
830 }
831
832 void opt_help(const OPTIONS *list)
833 {
834     const OPTIONS *o;
835     int i;
836     int standard_prolog;
837     int width = 5;
838     char start[80 + 1];
839     char *p;
840     const char *help;
841
842     /* Starts with its own help message? */
843     standard_prolog = list[0].name != OPT_HELP_STR;
844
845     /* Find the widest help. */
846     for (o = list; o->name; o++) {
847         if (o->name == OPT_MORE_STR)
848             continue;
849         i = 2 + (int)strlen(o->name);
850         if (o->valtype != '-')
851             i += 1 + strlen(valtype2param(o));
852         if (i < MAX_OPT_HELP_WIDTH && i > width)
853             width = i;
854         assert(i < (int)sizeof start);
855     }
856
857     if (standard_prolog)
858         BIO_printf(bio_err, "Usage: %s [options]\nValid options are:\n",
859                    prog);
860
861     /* Now let's print. */
862     for (o = list; o->name; o++) {
863         help = o->helpstr ? o->helpstr : "(No additional info)";
864         if (o->name == OPT_HELP_STR) {
865             BIO_printf(bio_err, help, prog);
866             continue;
867         }
868
869         /* Pad out prefix */
870         memset(start, ' ', sizeof(start) - 1);
871         start[sizeof start - 1] = '\0';
872
873         if (o->name == OPT_MORE_STR) {
874             /* Continuation of previous line; padd and print. */
875             start[width] = '\0';
876             BIO_printf(bio_err, "%s  %s\n", start, help);
877             continue;
878         }
879
880         /* Build up the "-flag [param]" part. */
881         p = start;
882         *p++ = ' ';
883         *p++ = '-';
884         if (o->name[0])
885             p += strlen(strcpy(p, o->name));
886         else
887             *p++ = '*';
888         if (o->valtype != '-') {
889             *p++ = ' ';
890             p += strlen(strcpy(p, valtype2param(o)));
891         }
892         *p = ' ';
893         if ((int)(p - start) >= MAX_OPT_HELP_WIDTH) {
894             *p = '\0';
895             BIO_printf(bio_err, "%s\n", start);
896             memset(start, ' ', sizeof(start));
897         }
898         start[width] = '\0';
899         BIO_printf(bio_err, "%s  %s\n", start, help);
900     }
901 }
902
903 #ifdef COMPILE_STANDALONE_TEST_DRIVER
904 # include <sys/stat.h>
905
906 typedef enum OPTION_choice {
907     OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
908     OPT_IN, OPT_INFORM, OPT_OUT, OPT_COUNT, OPT_U, OPT_FLAG,
909     OPT_STR, OPT_NOTUSED
910 } OPTION_CHOICE;
911
912 static OPTIONS options[] = {
913     {OPT_HELP_STR, 1, '-', "Usage: %s flags\n"},
914     {OPT_HELP_STR, 1, '-', "Valid options are:\n"},
915     {"help", OPT_HELP, '-', "Display this summary"},
916     {"in", OPT_IN, '<', "input file"},
917     {OPT_MORE_STR, 1, '-', "more detail about input"},
918     {"inform", OPT_INFORM, 'f', "input file format; defaults to pem"},
919     {"out", OPT_OUT, '>', "output file"},
920     {"count", OPT_COUNT, 'p', "a counter greater than zero"},
921     {"u", OPT_U, 'u', "an unsigned number"},
922     {"flag", OPT_FLAG, 0, "just some flag"},
923     {"str", OPT_STR, 's', "the magic word"},
924     {"areallyverylongoption", OPT_HELP, '-', "long way for help"},
925     {NULL}
926 };
927
928 BIO *bio_err;
929
930 int app_isdir(const char *name)
931 {
932     struct stat sb;
933
934     return name != NULL && stat(name, &sb) >= 0 && S_ISDIR(sb.st_mode);
935 }
936
937 int main(int ac, char **av)
938 {
939     OPTION_CHOICE o;
940     char **rest;
941     char *prog;
942
943     bio_err = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT);
944
945     prog = opt_init(ac, av, options);
946     while ((o = opt_next()) != OPT_EOF) {
947         switch (c) {
948         case OPT_NOTUSED:
949         case OPT_EOF:
950         case OPT_ERR:
951             printf("%s: Usage error; try -help.\n", prog);
952             return 1;
953         case OPT_HELP:
954             opt_help(options);
955             return 0;
956         case OPT_IN:
957             printf("in %s\n", opt_arg());
958             break;
959         case OPT_INFORM:
960             printf("inform %s\n", opt_arg());
961             break;
962         case OPT_OUT:
963             printf("out %s\n", opt_arg());
964             break;
965         case OPT_COUNT:
966             printf("count %s\n", opt_arg());
967             break;
968         case OPT_U:
969             printf("u %s\n", opt_arg());
970             break;
971         case OPT_FLAG:
972             printf("flag\n");
973             break;
974         case OPT_STR:
975             printf("str %s\n", opt_arg());
976             break;
977         }
978     }
979     argc = opt_num_rest();
980     argv = opt_rest();
981
982     printf("args = %d\n", argc);
983     if (argc)
984         while (*argv)
985             printf("  %s\n", *argv++);
986     return 0;
987 }
988 #endif