xref: /freebsd/crypto/openssl/apps/lib/opt.c (revision b077aed33b7b6aefca7b17ddb250cf521f938613)
1*b077aed3SPierre Pronchery /*
2*b077aed3SPierre Pronchery  * Copyright 2015-2021 The OpenSSL Project Authors. All Rights Reserved.
3*b077aed3SPierre Pronchery  *
4*b077aed3SPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5*b077aed3SPierre Pronchery  * this file except in compliance with the License.  You can obtain a copy
6*b077aed3SPierre Pronchery  * in the file LICENSE in the source distribution or at
7*b077aed3SPierre Pronchery  * https://www.openssl.org/source/license.html
8*b077aed3SPierre Pronchery  */
9*b077aed3SPierre Pronchery 
10*b077aed3SPierre Pronchery /*
11*b077aed3SPierre Pronchery  * This file is also used by the test suite. Do not #include "apps.h".
12*b077aed3SPierre Pronchery  */
13*b077aed3SPierre Pronchery #include "opt.h"
14*b077aed3SPierre Pronchery #include "fmt.h"
15*b077aed3SPierre Pronchery #include "app_libctx.h"
16*b077aed3SPierre Pronchery #include "internal/nelem.h"
17*b077aed3SPierre Pronchery #include "internal/numbers.h"
18*b077aed3SPierre Pronchery #include <string.h>
19*b077aed3SPierre Pronchery #if !defined(OPENSSL_SYS_MSDOS)
20*b077aed3SPierre Pronchery # include <unistd.h>
21*b077aed3SPierre Pronchery #endif
22*b077aed3SPierre Pronchery 
23*b077aed3SPierre Pronchery #include <stdlib.h>
24*b077aed3SPierre Pronchery #include <errno.h>
25*b077aed3SPierre Pronchery #include <ctype.h>
26*b077aed3SPierre Pronchery #include <limits.h>
27*b077aed3SPierre Pronchery #include <openssl/err.h>
28*b077aed3SPierre Pronchery #include <openssl/bio.h>
29*b077aed3SPierre Pronchery #include <openssl/x509v3.h>
30*b077aed3SPierre Pronchery 
31*b077aed3SPierre Pronchery #define MAX_OPT_HELP_WIDTH 30
32*b077aed3SPierre Pronchery const char OPT_HELP_STR[] = "-H";
33*b077aed3SPierre Pronchery const char OPT_MORE_STR[] = "-M";
34*b077aed3SPierre Pronchery const char OPT_SECTION_STR[] = "-S";
35*b077aed3SPierre Pronchery const char OPT_PARAM_STR[] = "-P";
36*b077aed3SPierre Pronchery 
37*b077aed3SPierre Pronchery /* Our state */
38*b077aed3SPierre Pronchery static char **argv;
39*b077aed3SPierre Pronchery static int argc;
40*b077aed3SPierre Pronchery static int opt_index;
41*b077aed3SPierre Pronchery static char *arg;
42*b077aed3SPierre Pronchery static char *flag;
43*b077aed3SPierre Pronchery static char *dunno;
44*b077aed3SPierre Pronchery static const OPTIONS *unknown;
45*b077aed3SPierre Pronchery static const OPTIONS *opts;
46*b077aed3SPierre Pronchery static char prog[40];
47*b077aed3SPierre Pronchery 
48*b077aed3SPierre Pronchery /*
49*b077aed3SPierre Pronchery  * Return the simple name of the program; removing various platform gunk.
50*b077aed3SPierre Pronchery  */
51*b077aed3SPierre Pronchery #if defined(OPENSSL_SYS_WIN32)
52*b077aed3SPierre Pronchery 
53*b077aed3SPierre Pronchery const char *opt_path_end(const char *filename)
54*b077aed3SPierre Pronchery {
55*b077aed3SPierre Pronchery     const char *p;
56*b077aed3SPierre Pronchery 
57*b077aed3SPierre Pronchery     /* find the last '/', '\' or ':' */
58*b077aed3SPierre Pronchery     for (p = filename + strlen(filename); --p > filename; )
59*b077aed3SPierre Pronchery         if (*p == '/' || *p == '\\' || *p == ':') {
60*b077aed3SPierre Pronchery             p++;
61*b077aed3SPierre Pronchery             break;
62*b077aed3SPierre Pronchery         }
63*b077aed3SPierre Pronchery     return p;
64*b077aed3SPierre Pronchery }
65*b077aed3SPierre Pronchery 
66*b077aed3SPierre Pronchery char *opt_progname(const char *argv0)
67*b077aed3SPierre Pronchery {
68*b077aed3SPierre Pronchery     size_t i, n;
69*b077aed3SPierre Pronchery     const char *p;
70*b077aed3SPierre Pronchery     char *q;
71*b077aed3SPierre Pronchery 
72*b077aed3SPierre Pronchery     p = opt_path_end(argv0);
73*b077aed3SPierre Pronchery 
74*b077aed3SPierre Pronchery     /* Strip off trailing nonsense. */
75*b077aed3SPierre Pronchery     n = strlen(p);
76*b077aed3SPierre Pronchery     if (n > 4 &&
77*b077aed3SPierre Pronchery         (strcmp(&p[n - 4], ".exe") == 0 || strcmp(&p[n - 4], ".EXE") == 0))
78*b077aed3SPierre Pronchery         n -= 4;
79*b077aed3SPierre Pronchery 
80*b077aed3SPierre Pronchery     /* Copy over the name, in lowercase. */
81*b077aed3SPierre Pronchery     if (n > sizeof(prog) - 1)
82*b077aed3SPierre Pronchery         n = sizeof(prog) - 1;
83*b077aed3SPierre Pronchery     for (q = prog, i = 0; i < n; i++, p++)
84*b077aed3SPierre Pronchery         *q++ = tolower((unsigned char)*p);
85*b077aed3SPierre Pronchery     *q = '\0';
86*b077aed3SPierre Pronchery     return prog;
87*b077aed3SPierre Pronchery }
88*b077aed3SPierre Pronchery 
89*b077aed3SPierre Pronchery #elif defined(OPENSSL_SYS_VMS)
90*b077aed3SPierre Pronchery 
91*b077aed3SPierre Pronchery const char *opt_path_end(const char *filename)
92*b077aed3SPierre Pronchery {
93*b077aed3SPierre Pronchery     const char *p;
94*b077aed3SPierre Pronchery 
95*b077aed3SPierre Pronchery     /* Find last special character sys:[foo.bar]openssl */
96*b077aed3SPierre Pronchery     for (p = filename + strlen(filename); --p > filename;)
97*b077aed3SPierre Pronchery         if (*p == ':' || *p == ']' || *p == '>') {
98*b077aed3SPierre Pronchery             p++;
99*b077aed3SPierre Pronchery             break;
100*b077aed3SPierre Pronchery         }
101*b077aed3SPierre Pronchery     return p;
102*b077aed3SPierre Pronchery }
103*b077aed3SPierre Pronchery 
104*b077aed3SPierre Pronchery char *opt_progname(const char *argv0)
105*b077aed3SPierre Pronchery {
106*b077aed3SPierre Pronchery     const char *p, *q;
107*b077aed3SPierre Pronchery 
108*b077aed3SPierre Pronchery     /* Find last special character sys:[foo.bar]openssl */
109*b077aed3SPierre Pronchery     p = opt_path_end(argv0);
110*b077aed3SPierre Pronchery     q = strrchr(p, '.');
111*b077aed3SPierre Pronchery     if (prog != p)
112*b077aed3SPierre Pronchery         strncpy(prog, p, sizeof(prog) - 1);
113*b077aed3SPierre Pronchery     prog[sizeof(prog) - 1] = '\0';
114*b077aed3SPierre Pronchery     if (q != NULL && q - p < sizeof(prog))
115*b077aed3SPierre Pronchery         prog[q - p] = '\0';
116*b077aed3SPierre Pronchery     return prog;
117*b077aed3SPierre Pronchery }
118*b077aed3SPierre Pronchery 
119*b077aed3SPierre Pronchery #else
120*b077aed3SPierre Pronchery 
121*b077aed3SPierre Pronchery const char *opt_path_end(const char *filename)
122*b077aed3SPierre Pronchery {
123*b077aed3SPierre Pronchery     const char *p;
124*b077aed3SPierre Pronchery 
125*b077aed3SPierre Pronchery     /* Could use strchr, but this is like the ones above. */
126*b077aed3SPierre Pronchery     for (p = filename + strlen(filename); --p > filename;)
127*b077aed3SPierre Pronchery         if (*p == '/') {
128*b077aed3SPierre Pronchery             p++;
129*b077aed3SPierre Pronchery             break;
130*b077aed3SPierre Pronchery         }
131*b077aed3SPierre Pronchery     return p;
132*b077aed3SPierre Pronchery }
133*b077aed3SPierre Pronchery 
134*b077aed3SPierre Pronchery char *opt_progname(const char *argv0)
135*b077aed3SPierre Pronchery {
136*b077aed3SPierre Pronchery     const char *p;
137*b077aed3SPierre Pronchery 
138*b077aed3SPierre Pronchery     p = opt_path_end(argv0);
139*b077aed3SPierre Pronchery     if (prog != p)
140*b077aed3SPierre Pronchery         strncpy(prog, p, sizeof(prog) - 1);
141*b077aed3SPierre Pronchery     prog[sizeof(prog) - 1] = '\0';
142*b077aed3SPierre Pronchery     return prog;
143*b077aed3SPierre Pronchery }
144*b077aed3SPierre Pronchery #endif
145*b077aed3SPierre Pronchery 
146*b077aed3SPierre Pronchery char *opt_appname(const char *argv0)
147*b077aed3SPierre Pronchery {
148*b077aed3SPierre Pronchery     size_t len = strlen(prog);
149*b077aed3SPierre Pronchery 
150*b077aed3SPierre Pronchery     if (argv0 != NULL)
151*b077aed3SPierre Pronchery         BIO_snprintf(prog + len, sizeof(prog) - len - 1, " %s", argv0);
152*b077aed3SPierre Pronchery     return prog;
153*b077aed3SPierre Pronchery }
154*b077aed3SPierre Pronchery 
155*b077aed3SPierre Pronchery char *opt_getprog(void)
156*b077aed3SPierre Pronchery {
157*b077aed3SPierre Pronchery     return prog;
158*b077aed3SPierre Pronchery }
159*b077aed3SPierre Pronchery 
160*b077aed3SPierre Pronchery /* Set up the arg parsing. */
161*b077aed3SPierre Pronchery char *opt_init(int ac, char **av, const OPTIONS *o)
162*b077aed3SPierre Pronchery {
163*b077aed3SPierre Pronchery     /* Store state. */
164*b077aed3SPierre Pronchery     argc = ac;
165*b077aed3SPierre Pronchery     argv = av;
166*b077aed3SPierre Pronchery     opt_begin();
167*b077aed3SPierre Pronchery     opts = o;
168*b077aed3SPierre Pronchery     unknown = NULL;
169*b077aed3SPierre Pronchery 
170*b077aed3SPierre Pronchery     /* Make sure prog name is set for usage output */
171*b077aed3SPierre Pronchery     (void)opt_progname(argv[0]);
172*b077aed3SPierre Pronchery 
173*b077aed3SPierre Pronchery     /* Check all options up until the PARAM marker (if present) */
174*b077aed3SPierre Pronchery     for (; o->name != NULL && o->name != OPT_PARAM_STR; ++o) {
175*b077aed3SPierre Pronchery #ifndef NDEBUG
176*b077aed3SPierre Pronchery         const OPTIONS *next;
177*b077aed3SPierre Pronchery         int duplicated, i;
178*b077aed3SPierre Pronchery #endif
179*b077aed3SPierre Pronchery 
180*b077aed3SPierre Pronchery         if (o->name == OPT_HELP_STR
181*b077aed3SPierre Pronchery                 || o->name == OPT_MORE_STR
182*b077aed3SPierre Pronchery                 || o->name == OPT_SECTION_STR)
183*b077aed3SPierre Pronchery             continue;
184*b077aed3SPierre Pronchery #ifndef NDEBUG
185*b077aed3SPierre Pronchery         i = o->valtype;
186*b077aed3SPierre Pronchery 
187*b077aed3SPierre Pronchery         /* Make sure options are legit. */
188*b077aed3SPierre Pronchery         OPENSSL_assert(o->name[0] != '-');
189*b077aed3SPierre Pronchery         if (o->valtype == '.')
190*b077aed3SPierre Pronchery             OPENSSL_assert(o->retval == OPT_PARAM);
191*b077aed3SPierre Pronchery         else
192*b077aed3SPierre Pronchery             OPENSSL_assert(o->retval == OPT_DUP || o->retval > OPT_PARAM);
193*b077aed3SPierre Pronchery         switch (i) {
194*b077aed3SPierre Pronchery         case   0: case '-': case '.':
195*b077aed3SPierre Pronchery         case '/': case '<': case '>': case 'E': case 'F':
196*b077aed3SPierre Pronchery         case 'M': case 'U': case 'f': case 'l': case 'n': case 'p': case 's':
197*b077aed3SPierre Pronchery         case 'u': case 'c': case ':': case 'N':
198*b077aed3SPierre Pronchery             break;
199*b077aed3SPierre Pronchery         default:
200*b077aed3SPierre Pronchery             OPENSSL_assert(0);
201*b077aed3SPierre Pronchery         }
202*b077aed3SPierre Pronchery 
203*b077aed3SPierre Pronchery         /* Make sure there are no duplicates. */
204*b077aed3SPierre Pronchery         for (next = o + 1; next->name; ++next) {
205*b077aed3SPierre Pronchery             /*
206*b077aed3SPierre Pronchery              * Some compilers inline strcmp and the assert string is too long.
207*b077aed3SPierre Pronchery              */
208*b077aed3SPierre Pronchery             duplicated = next->retval != OPT_DUP
209*b077aed3SPierre Pronchery                 && strcmp(o->name, next->name) == 0;
210*b077aed3SPierre Pronchery             if (duplicated) {
211*b077aed3SPierre Pronchery                 opt_printf_stderr("%s: Internal error: duplicate option %s\n",
212*b077aed3SPierre Pronchery                                   prog, o->name);
213*b077aed3SPierre Pronchery                 OPENSSL_assert(!duplicated);
214*b077aed3SPierre Pronchery             }
215*b077aed3SPierre Pronchery         }
216*b077aed3SPierre Pronchery #endif
217*b077aed3SPierre Pronchery         if (o->name[0] == '\0') {
218*b077aed3SPierre Pronchery             OPENSSL_assert(unknown == NULL);
219*b077aed3SPierre Pronchery             unknown = o;
220*b077aed3SPierre Pronchery             OPENSSL_assert(unknown->valtype == 0 || unknown->valtype == '-');
221*b077aed3SPierre Pronchery         }
222*b077aed3SPierre Pronchery     }
223*b077aed3SPierre Pronchery     return prog;
224*b077aed3SPierre Pronchery }
225*b077aed3SPierre Pronchery 
226*b077aed3SPierre Pronchery static OPT_PAIR formats[] = {
227*b077aed3SPierre Pronchery     {"PEM/DER", OPT_FMT_PEMDER},
228*b077aed3SPierre Pronchery     {"pkcs12", OPT_FMT_PKCS12},
229*b077aed3SPierre Pronchery     {"smime", OPT_FMT_SMIME},
230*b077aed3SPierre Pronchery     {"engine", OPT_FMT_ENGINE},
231*b077aed3SPierre Pronchery     {"msblob", OPT_FMT_MSBLOB},
232*b077aed3SPierre Pronchery     {"nss", OPT_FMT_NSS},
233*b077aed3SPierre Pronchery     {"text", OPT_FMT_TEXT},
234*b077aed3SPierre Pronchery     {"http", OPT_FMT_HTTP},
235*b077aed3SPierre Pronchery     {"pvk", OPT_FMT_PVK},
236*b077aed3SPierre Pronchery     {NULL}
237*b077aed3SPierre Pronchery };
238*b077aed3SPierre Pronchery 
239*b077aed3SPierre Pronchery /* Print an error message about a failed format parse. */
240*b077aed3SPierre Pronchery static int opt_format_error(const char *s, unsigned long flags)
241*b077aed3SPierre Pronchery {
242*b077aed3SPierre Pronchery     OPT_PAIR *ap;
243*b077aed3SPierre Pronchery 
244*b077aed3SPierre Pronchery     if (flags == OPT_FMT_PEMDER) {
245*b077aed3SPierre Pronchery         opt_printf_stderr("%s: Bad format \"%s\"; must be pem or der\n",
246*b077aed3SPierre Pronchery                           prog, s);
247*b077aed3SPierre Pronchery     } else {
248*b077aed3SPierre Pronchery         opt_printf_stderr("%s: Bad format \"%s\"; must be one of:\n",
249*b077aed3SPierre Pronchery                           prog, s);
250*b077aed3SPierre Pronchery         for (ap = formats; ap->name; ap++)
251*b077aed3SPierre Pronchery             if (flags & ap->retval)
252*b077aed3SPierre Pronchery                 opt_printf_stderr("   %s\n", ap->name);
253*b077aed3SPierre Pronchery     }
254*b077aed3SPierre Pronchery     return 0;
255*b077aed3SPierre Pronchery }
256*b077aed3SPierre Pronchery 
257*b077aed3SPierre Pronchery /* Parse a format string, put it into *result; return 0 on failure, else 1. */
258*b077aed3SPierre Pronchery int opt_format(const char *s, unsigned long flags, int *result)
259*b077aed3SPierre Pronchery {
260*b077aed3SPierre Pronchery     switch (*s) {
261*b077aed3SPierre Pronchery     default:
262*b077aed3SPierre Pronchery         opt_printf_stderr("%s: Bad format \"%s\"\n", prog, s);
263*b077aed3SPierre Pronchery         return 0;
264*b077aed3SPierre Pronchery     case 'D':
265*b077aed3SPierre Pronchery     case 'd':
266*b077aed3SPierre Pronchery         if ((flags & OPT_FMT_PEMDER) == 0)
267*b077aed3SPierre Pronchery             return opt_format_error(s, flags);
268*b077aed3SPierre Pronchery         *result = FORMAT_ASN1;
269*b077aed3SPierre Pronchery         break;
270*b077aed3SPierre Pronchery     case 'T':
271*b077aed3SPierre Pronchery     case 't':
272*b077aed3SPierre Pronchery         if ((flags & OPT_FMT_TEXT) == 0)
273*b077aed3SPierre Pronchery             return opt_format_error(s, flags);
274*b077aed3SPierre Pronchery         *result = FORMAT_TEXT;
275*b077aed3SPierre Pronchery         break;
276*b077aed3SPierre Pronchery     case 'N':
277*b077aed3SPierre Pronchery     case 'n':
278*b077aed3SPierre Pronchery         if ((flags & OPT_FMT_NSS) == 0)
279*b077aed3SPierre Pronchery             return opt_format_error(s, flags);
280*b077aed3SPierre Pronchery         if (strcmp(s, "NSS") != 0 && strcmp(s, "nss") != 0)
281*b077aed3SPierre Pronchery             return opt_format_error(s, flags);
282*b077aed3SPierre Pronchery         *result = FORMAT_NSS;
283*b077aed3SPierre Pronchery         break;
284*b077aed3SPierre Pronchery     case 'S':
285*b077aed3SPierre Pronchery     case 's':
286*b077aed3SPierre Pronchery         if ((flags & OPT_FMT_SMIME) == 0)
287*b077aed3SPierre Pronchery             return opt_format_error(s, flags);
288*b077aed3SPierre Pronchery         *result = FORMAT_SMIME;
289*b077aed3SPierre Pronchery         break;
290*b077aed3SPierre Pronchery     case 'M':
291*b077aed3SPierre Pronchery     case 'm':
292*b077aed3SPierre Pronchery         if ((flags & OPT_FMT_MSBLOB) == 0)
293*b077aed3SPierre Pronchery             return opt_format_error(s, flags);
294*b077aed3SPierre Pronchery         *result = FORMAT_MSBLOB;
295*b077aed3SPierre Pronchery         break;
296*b077aed3SPierre Pronchery     case 'E':
297*b077aed3SPierre Pronchery     case 'e':
298*b077aed3SPierre Pronchery         if ((flags & OPT_FMT_ENGINE) == 0)
299*b077aed3SPierre Pronchery             return opt_format_error(s, flags);
300*b077aed3SPierre Pronchery         *result = FORMAT_ENGINE;
301*b077aed3SPierre Pronchery         break;
302*b077aed3SPierre Pronchery     case 'H':
303*b077aed3SPierre Pronchery     case 'h':
304*b077aed3SPierre Pronchery         if ((flags & OPT_FMT_HTTP) == 0)
305*b077aed3SPierre Pronchery             return opt_format_error(s, flags);
306*b077aed3SPierre Pronchery         *result = FORMAT_HTTP;
307*b077aed3SPierre Pronchery         break;
308*b077aed3SPierre Pronchery     case '1':
309*b077aed3SPierre Pronchery         if ((flags & OPT_FMT_PKCS12) == 0)
310*b077aed3SPierre Pronchery             return opt_format_error(s, flags);
311*b077aed3SPierre Pronchery         *result = FORMAT_PKCS12;
312*b077aed3SPierre Pronchery         break;
313*b077aed3SPierre Pronchery     case 'P':
314*b077aed3SPierre Pronchery     case 'p':
315*b077aed3SPierre Pronchery         if (s[1] == '\0' || strcmp(s, "PEM") == 0 || strcmp(s, "pem") == 0) {
316*b077aed3SPierre Pronchery             if ((flags & OPT_FMT_PEMDER) == 0)
317*b077aed3SPierre Pronchery                 return opt_format_error(s, flags);
318*b077aed3SPierre Pronchery             *result = FORMAT_PEM;
319*b077aed3SPierre Pronchery         } else if (strcmp(s, "PVK") == 0 || strcmp(s, "pvk") == 0) {
320*b077aed3SPierre Pronchery             if ((flags & OPT_FMT_PVK) == 0)
321*b077aed3SPierre Pronchery                 return opt_format_error(s, flags);
322*b077aed3SPierre Pronchery             *result = FORMAT_PVK;
323*b077aed3SPierre Pronchery         } else if (strcmp(s, "P12") == 0 || strcmp(s, "p12") == 0
324*b077aed3SPierre Pronchery                    || strcmp(s, "PKCS12") == 0 || strcmp(s, "pkcs12") == 0) {
325*b077aed3SPierre Pronchery             if ((flags & OPT_FMT_PKCS12) == 0)
326*b077aed3SPierre Pronchery                 return opt_format_error(s, flags);
327*b077aed3SPierre Pronchery             *result = FORMAT_PKCS12;
328*b077aed3SPierre Pronchery         } else {
329*b077aed3SPierre Pronchery             opt_printf_stderr("%s: Bad format \"%s\"\n", prog, s);
330*b077aed3SPierre Pronchery             return 0;
331*b077aed3SPierre Pronchery         }
332*b077aed3SPierre Pronchery         break;
333*b077aed3SPierre Pronchery     }
334*b077aed3SPierre Pronchery     return 1;
335*b077aed3SPierre Pronchery }
336*b077aed3SPierre Pronchery 
337*b077aed3SPierre Pronchery /* Return string representing the given format. */
338*b077aed3SPierre Pronchery static const char *format2str(int format)
339*b077aed3SPierre Pronchery {
340*b077aed3SPierre Pronchery     switch (format) {
341*b077aed3SPierre Pronchery     default:
342*b077aed3SPierre Pronchery         return "(undefined)";
343*b077aed3SPierre Pronchery     case FORMAT_PEM:
344*b077aed3SPierre Pronchery         return "PEM";
345*b077aed3SPierre Pronchery     case FORMAT_ASN1:
346*b077aed3SPierre Pronchery         return "DER";
347*b077aed3SPierre Pronchery     case FORMAT_TEXT:
348*b077aed3SPierre Pronchery         return "TEXT";
349*b077aed3SPierre Pronchery     case FORMAT_NSS:
350*b077aed3SPierre Pronchery         return "NSS";
351*b077aed3SPierre Pronchery     case FORMAT_SMIME:
352*b077aed3SPierre Pronchery         return "SMIME";
353*b077aed3SPierre Pronchery     case FORMAT_MSBLOB:
354*b077aed3SPierre Pronchery         return "MSBLOB";
355*b077aed3SPierre Pronchery     case FORMAT_ENGINE:
356*b077aed3SPierre Pronchery         return "ENGINE";
357*b077aed3SPierre Pronchery     case FORMAT_HTTP:
358*b077aed3SPierre Pronchery         return "HTTP";
359*b077aed3SPierre Pronchery     case FORMAT_PKCS12:
360*b077aed3SPierre Pronchery         return "P12";
361*b077aed3SPierre Pronchery     case FORMAT_PVK:
362*b077aed3SPierre Pronchery         return "PVK";
363*b077aed3SPierre Pronchery     }
364*b077aed3SPierre Pronchery }
365*b077aed3SPierre Pronchery 
366*b077aed3SPierre Pronchery /* Print an error message about unsuitable/unsupported format requested. */
367*b077aed3SPierre Pronchery void print_format_error(int format, unsigned long flags)
368*b077aed3SPierre Pronchery {
369*b077aed3SPierre Pronchery     (void)opt_format_error(format2str(format), flags);
370*b077aed3SPierre Pronchery }
371*b077aed3SPierre Pronchery 
372*b077aed3SPierre Pronchery /*
373*b077aed3SPierre Pronchery  * Parse a cipher name, put it in *cipherp after freeing what was there, if
374*b077aed3SPierre Pronchery  * cipherp is not NULL.  Return 0 on failure, else 1.
375*b077aed3SPierre Pronchery  */
376*b077aed3SPierre Pronchery int opt_cipher_silent(const char *name, EVP_CIPHER **cipherp)
377*b077aed3SPierre Pronchery {
378*b077aed3SPierre Pronchery     EVP_CIPHER *c;
379*b077aed3SPierre Pronchery 
380*b077aed3SPierre Pronchery     ERR_set_mark();
381*b077aed3SPierre Pronchery     if ((c = EVP_CIPHER_fetch(app_get0_libctx(), name,
382*b077aed3SPierre Pronchery                               app_get0_propq())) != NULL
383*b077aed3SPierre Pronchery         || (opt_legacy_okay()
384*b077aed3SPierre Pronchery             && (c = (EVP_CIPHER *)EVP_get_cipherbyname(name)) != NULL)) {
385*b077aed3SPierre Pronchery         ERR_pop_to_mark();
386*b077aed3SPierre Pronchery         if (cipherp != NULL) {
387*b077aed3SPierre Pronchery             EVP_CIPHER_free(*cipherp);
388*b077aed3SPierre Pronchery             *cipherp = c;
389*b077aed3SPierre Pronchery         } else {
390*b077aed3SPierre Pronchery             EVP_CIPHER_free(c);
391*b077aed3SPierre Pronchery         }
392*b077aed3SPierre Pronchery         return 1;
393*b077aed3SPierre Pronchery     }
394*b077aed3SPierre Pronchery     ERR_clear_last_mark();
395*b077aed3SPierre Pronchery     return 0;
396*b077aed3SPierre Pronchery }
397*b077aed3SPierre Pronchery 
398*b077aed3SPierre Pronchery int opt_cipher_any(const char *name, EVP_CIPHER **cipherp)
399*b077aed3SPierre Pronchery {
400*b077aed3SPierre Pronchery     int ret;
401*b077aed3SPierre Pronchery 
402*b077aed3SPierre Pronchery     if ((ret = opt_cipher_silent(name, cipherp)) == 0)
403*b077aed3SPierre Pronchery         opt_printf_stderr("%s: Unknown cipher: %s\n", prog, name);
404*b077aed3SPierre Pronchery     return ret;
405*b077aed3SPierre Pronchery }
406*b077aed3SPierre Pronchery 
407*b077aed3SPierre Pronchery int opt_cipher(const char *name, EVP_CIPHER **cipherp)
408*b077aed3SPierre Pronchery {
409*b077aed3SPierre Pronchery      int mode, ret = 0;
410*b077aed3SPierre Pronchery      unsigned long int flags;
411*b077aed3SPierre Pronchery      EVP_CIPHER *c = NULL;
412*b077aed3SPierre Pronchery 
413*b077aed3SPierre Pronchery      if (opt_cipher_any(name, &c)) {
414*b077aed3SPierre Pronchery         mode = EVP_CIPHER_get_mode(c);
415*b077aed3SPierre Pronchery         flags = EVP_CIPHER_get_flags(c);
416*b077aed3SPierre Pronchery         if (mode == EVP_CIPH_XTS_MODE) {
417*b077aed3SPierre Pronchery             opt_printf_stderr("%s XTS ciphers not supported\n", prog);
418*b077aed3SPierre Pronchery         } else if ((flags & EVP_CIPH_FLAG_AEAD_CIPHER) != 0) {
419*b077aed3SPierre Pronchery             opt_printf_stderr("%s: AEAD ciphers not supported\n", prog);
420*b077aed3SPierre Pronchery         } else {
421*b077aed3SPierre Pronchery             ret = 1;
422*b077aed3SPierre Pronchery             if (cipherp != NULL)
423*b077aed3SPierre Pronchery                 *cipherp = c;
424*b077aed3SPierre Pronchery         }
425*b077aed3SPierre Pronchery     }
426*b077aed3SPierre Pronchery     return ret;
427*b077aed3SPierre Pronchery }
428*b077aed3SPierre Pronchery 
429*b077aed3SPierre Pronchery /*
430*b077aed3SPierre Pronchery  * Parse message digest name, put it in *EVP_MD; return 0 on failure, else 1.
431*b077aed3SPierre Pronchery  */
432*b077aed3SPierre Pronchery int opt_md_silent(const char *name, EVP_MD **mdp)
433*b077aed3SPierre Pronchery {
434*b077aed3SPierre Pronchery     EVP_MD *md;
435*b077aed3SPierre Pronchery 
436*b077aed3SPierre Pronchery     ERR_set_mark();
437*b077aed3SPierre Pronchery     if ((md = EVP_MD_fetch(app_get0_libctx(), name, app_get0_propq())) != NULL
438*b077aed3SPierre Pronchery         || (opt_legacy_okay()
439*b077aed3SPierre Pronchery             && (md = (EVP_MD *)EVP_get_digestbyname(name)) != NULL)) {
440*b077aed3SPierre Pronchery         ERR_pop_to_mark();
441*b077aed3SPierre Pronchery         if (mdp != NULL) {
442*b077aed3SPierre Pronchery             EVP_MD_free(*mdp);
443*b077aed3SPierre Pronchery             *mdp = md;
444*b077aed3SPierre Pronchery         } else {
445*b077aed3SPierre Pronchery             EVP_MD_free(md);
446*b077aed3SPierre Pronchery         }
447*b077aed3SPierre Pronchery         return 1;
448*b077aed3SPierre Pronchery     }
449*b077aed3SPierre Pronchery     ERR_clear_last_mark();
450*b077aed3SPierre Pronchery     return 0;
451*b077aed3SPierre Pronchery }
452*b077aed3SPierre Pronchery 
453*b077aed3SPierre Pronchery int opt_md(const char *name, EVP_MD **mdp)
454*b077aed3SPierre Pronchery {
455*b077aed3SPierre Pronchery     int ret;
456*b077aed3SPierre Pronchery 
457*b077aed3SPierre Pronchery     if ((ret = opt_md_silent(name, mdp)) == 0)
458*b077aed3SPierre Pronchery         opt_printf_stderr("%s: Unknown option or message digest: %s\n", prog,
459*b077aed3SPierre Pronchery                           name != NULL ? name : "\"\"");
460*b077aed3SPierre Pronchery     return ret;
461*b077aed3SPierre Pronchery }
462*b077aed3SPierre Pronchery 
463*b077aed3SPierre Pronchery /* Look through a list of name/value pairs. */
464*b077aed3SPierre Pronchery int opt_pair(const char *name, const OPT_PAIR* pairs, int *result)
465*b077aed3SPierre Pronchery {
466*b077aed3SPierre Pronchery     const OPT_PAIR *pp;
467*b077aed3SPierre Pronchery 
468*b077aed3SPierre Pronchery     for (pp = pairs; pp->name; pp++)
469*b077aed3SPierre Pronchery         if (strcmp(pp->name, name) == 0) {
470*b077aed3SPierre Pronchery             *result = pp->retval;
471*b077aed3SPierre Pronchery             return 1;
472*b077aed3SPierre Pronchery         }
473*b077aed3SPierre Pronchery     opt_printf_stderr("%s: Value must be one of:\n", prog);
474*b077aed3SPierre Pronchery     for (pp = pairs; pp->name; pp++)
475*b077aed3SPierre Pronchery         opt_printf_stderr("\t%s\n", pp->name);
476*b077aed3SPierre Pronchery     return 0;
477*b077aed3SPierre Pronchery }
478*b077aed3SPierre Pronchery 
479*b077aed3SPierre Pronchery /* Look through a list of valid names */
480*b077aed3SPierre Pronchery int opt_string(const char *name, const char **options)
481*b077aed3SPierre Pronchery {
482*b077aed3SPierre Pronchery     const char **p;
483*b077aed3SPierre Pronchery 
484*b077aed3SPierre Pronchery     for (p = options; *p != NULL; p++)
485*b077aed3SPierre Pronchery         if (strcmp(*p, name) == 0)
486*b077aed3SPierre Pronchery             return 1;
487*b077aed3SPierre Pronchery     opt_printf_stderr("%s: Value must be one of:\n", prog);
488*b077aed3SPierre Pronchery     for (p = options; *p != NULL; p++)
489*b077aed3SPierre Pronchery         opt_printf_stderr("\t%s\n", *p);
490*b077aed3SPierre Pronchery     return 0;
491*b077aed3SPierre Pronchery }
492*b077aed3SPierre Pronchery 
493*b077aed3SPierre Pronchery /* Parse an int, put it into *result; return 0 on failure, else 1. */
494*b077aed3SPierre Pronchery int opt_int(const char *value, int *result)
495*b077aed3SPierre Pronchery {
496*b077aed3SPierre Pronchery     long l;
497*b077aed3SPierre Pronchery 
498*b077aed3SPierre Pronchery     if (!opt_long(value, &l))
499*b077aed3SPierre Pronchery         return 0;
500*b077aed3SPierre Pronchery     *result = (int)l;
501*b077aed3SPierre Pronchery     if (*result != l) {
502*b077aed3SPierre Pronchery         opt_printf_stderr("%s: Value \"%s\" outside integer range\n",
503*b077aed3SPierre Pronchery                           prog, value);
504*b077aed3SPierre Pronchery         return 0;
505*b077aed3SPierre Pronchery     }
506*b077aed3SPierre Pronchery     return 1;
507*b077aed3SPierre Pronchery }
508*b077aed3SPierre Pronchery 
509*b077aed3SPierre Pronchery /* Parse and return an integer, assuming range has been checked before. */
510*b077aed3SPierre Pronchery int opt_int_arg(void)
511*b077aed3SPierre Pronchery {
512*b077aed3SPierre Pronchery     int result = -1;
513*b077aed3SPierre Pronchery 
514*b077aed3SPierre Pronchery     (void)opt_int(arg, &result);
515*b077aed3SPierre Pronchery     return result;
516*b077aed3SPierre Pronchery }
517*b077aed3SPierre Pronchery 
518*b077aed3SPierre Pronchery static void opt_number_error(const char *v)
519*b077aed3SPierre Pronchery {
520*b077aed3SPierre Pronchery     size_t i = 0;
521*b077aed3SPierre Pronchery     struct strstr_pair_st {
522*b077aed3SPierre Pronchery         char *prefix;
523*b077aed3SPierre Pronchery         char *name;
524*b077aed3SPierre Pronchery     } b[] = {
525*b077aed3SPierre Pronchery         {"0x", "a hexadecimal"},
526*b077aed3SPierre Pronchery         {"0X", "a hexadecimal"},
527*b077aed3SPierre Pronchery         {"0", "an octal"}
528*b077aed3SPierre Pronchery     };
529*b077aed3SPierre Pronchery 
530*b077aed3SPierre Pronchery     for (i = 0; i < OSSL_NELEM(b); i++) {
531*b077aed3SPierre Pronchery         if (strncmp(v, b[i].prefix, strlen(b[i].prefix)) == 0) {
532*b077aed3SPierre Pronchery             opt_printf_stderr("%s: Can't parse \"%s\" as %s number\n",
533*b077aed3SPierre Pronchery                               prog, v, b[i].name);
534*b077aed3SPierre Pronchery             return;
535*b077aed3SPierre Pronchery         }
536*b077aed3SPierre Pronchery     }
537*b077aed3SPierre Pronchery     opt_printf_stderr("%s: Can't parse \"%s\" as a number\n", prog, v);
538*b077aed3SPierre Pronchery     return;
539*b077aed3SPierre Pronchery }
540*b077aed3SPierre Pronchery 
541*b077aed3SPierre Pronchery /* Parse a long, put it into *result; return 0 on failure, else 1. */
542*b077aed3SPierre Pronchery int opt_long(const char *value, long *result)
543*b077aed3SPierre Pronchery {
544*b077aed3SPierre Pronchery     int oerrno = errno;
545*b077aed3SPierre Pronchery     long l;
546*b077aed3SPierre Pronchery     char *endp;
547*b077aed3SPierre Pronchery 
548*b077aed3SPierre Pronchery     errno = 0;
549*b077aed3SPierre Pronchery     l = strtol(value, &endp, 0);
550*b077aed3SPierre Pronchery     if (*endp
551*b077aed3SPierre Pronchery             || endp == value
552*b077aed3SPierre Pronchery             || ((l == LONG_MAX || l == LONG_MIN) && errno == ERANGE)
553*b077aed3SPierre Pronchery             || (l == 0 && errno != 0)) {
554*b077aed3SPierre Pronchery         opt_number_error(value);
555*b077aed3SPierre Pronchery         errno = oerrno;
556*b077aed3SPierre Pronchery         return 0;
557*b077aed3SPierre Pronchery     }
558*b077aed3SPierre Pronchery     *result = l;
559*b077aed3SPierre Pronchery     errno = oerrno;
560*b077aed3SPierre Pronchery     return 1;
561*b077aed3SPierre Pronchery }
562*b077aed3SPierre Pronchery 
563*b077aed3SPierre Pronchery #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && \
564*b077aed3SPierre Pronchery     defined(INTMAX_MAX) && defined(UINTMAX_MAX) && \
565*b077aed3SPierre Pronchery     !defined(OPENSSL_NO_INTTYPES_H)
566*b077aed3SPierre Pronchery 
567*b077aed3SPierre Pronchery /* Parse an intmax_t, put it into *result; return 0 on failure, else 1. */
568*b077aed3SPierre Pronchery int opt_intmax(const char *value, ossl_intmax_t *result)
569*b077aed3SPierre Pronchery {
570*b077aed3SPierre Pronchery     int oerrno = errno;
571*b077aed3SPierre Pronchery     intmax_t m;
572*b077aed3SPierre Pronchery     char *endp;
573*b077aed3SPierre Pronchery 
574*b077aed3SPierre Pronchery     errno = 0;
575*b077aed3SPierre Pronchery     m = strtoimax(value, &endp, 0);
576*b077aed3SPierre Pronchery     if (*endp
577*b077aed3SPierre Pronchery             || endp == value
578*b077aed3SPierre Pronchery             || ((m == INTMAX_MAX || m == INTMAX_MIN)
579*b077aed3SPierre Pronchery                 && errno == ERANGE)
580*b077aed3SPierre Pronchery             || (m == 0 && errno != 0)) {
581*b077aed3SPierre Pronchery         opt_number_error(value);
582*b077aed3SPierre Pronchery         errno = oerrno;
583*b077aed3SPierre Pronchery         return 0;
584*b077aed3SPierre Pronchery     }
585*b077aed3SPierre Pronchery     /* Ensure that the value in |m| is never too big for |*result| */
586*b077aed3SPierre Pronchery     if (sizeof(m) > sizeof(*result)
587*b077aed3SPierre Pronchery         && (m < OSSL_INTMAX_MIN || m > OSSL_INTMAX_MAX)) {
588*b077aed3SPierre Pronchery         opt_number_error(value);
589*b077aed3SPierre Pronchery         return 0;
590*b077aed3SPierre Pronchery     }
591*b077aed3SPierre Pronchery     *result = (ossl_intmax_t)m;
592*b077aed3SPierre Pronchery     errno = oerrno;
593*b077aed3SPierre Pronchery     return 1;
594*b077aed3SPierre Pronchery }
595*b077aed3SPierre Pronchery 
596*b077aed3SPierre Pronchery /* Parse a uintmax_t, put it into *result; return 0 on failure, else 1. */
597*b077aed3SPierre Pronchery int opt_uintmax(const char *value, ossl_uintmax_t *result)
598*b077aed3SPierre Pronchery {
599*b077aed3SPierre Pronchery     int oerrno = errno;
600*b077aed3SPierre Pronchery     uintmax_t m;
601*b077aed3SPierre Pronchery     char *endp;
602*b077aed3SPierre Pronchery 
603*b077aed3SPierre Pronchery     errno = 0;
604*b077aed3SPierre Pronchery     m = strtoumax(value, &endp, 0);
605*b077aed3SPierre Pronchery     if (*endp
606*b077aed3SPierre Pronchery             || endp == value
607*b077aed3SPierre Pronchery             || (m == UINTMAX_MAX && errno == ERANGE)
608*b077aed3SPierre Pronchery             || (m == 0 && errno != 0)) {
609*b077aed3SPierre Pronchery         opt_number_error(value);
610*b077aed3SPierre Pronchery         errno = oerrno;
611*b077aed3SPierre Pronchery         return 0;
612*b077aed3SPierre Pronchery     }
613*b077aed3SPierre Pronchery     /* Ensure that the value in |m| is never too big for |*result| */
614*b077aed3SPierre Pronchery     if (sizeof(m) > sizeof(*result)
615*b077aed3SPierre Pronchery         && m > OSSL_UINTMAX_MAX) {
616*b077aed3SPierre Pronchery         opt_number_error(value);
617*b077aed3SPierre Pronchery         return 0;
618*b077aed3SPierre Pronchery     }
619*b077aed3SPierre Pronchery     *result = (ossl_intmax_t)m;
620*b077aed3SPierre Pronchery     errno = oerrno;
621*b077aed3SPierre Pronchery     return 1;
622*b077aed3SPierre Pronchery }
623*b077aed3SPierre Pronchery #else
624*b077aed3SPierre Pronchery /* Fallback implementations based on long */
625*b077aed3SPierre Pronchery int opt_intmax(const char *value, ossl_intmax_t *result)
626*b077aed3SPierre Pronchery {
627*b077aed3SPierre Pronchery     long m;
628*b077aed3SPierre Pronchery     int ret;
629*b077aed3SPierre Pronchery 
630*b077aed3SPierre Pronchery     if ((ret = opt_long(value, &m)))
631*b077aed3SPierre Pronchery         *result = m;
632*b077aed3SPierre Pronchery     return ret;
633*b077aed3SPierre Pronchery }
634*b077aed3SPierre Pronchery 
635*b077aed3SPierre Pronchery int opt_uintmax(const char *value, ossl_uintmax_t *result)
636*b077aed3SPierre Pronchery {
637*b077aed3SPierre Pronchery     unsigned long m;
638*b077aed3SPierre Pronchery     int ret;
639*b077aed3SPierre Pronchery 
640*b077aed3SPierre Pronchery     if ((ret = opt_ulong(value, &m)))
641*b077aed3SPierre Pronchery         *result = m;
642*b077aed3SPierre Pronchery     return ret;
643*b077aed3SPierre Pronchery }
644*b077aed3SPierre Pronchery #endif
645*b077aed3SPierre Pronchery 
646*b077aed3SPierre Pronchery /*
647*b077aed3SPierre Pronchery  * Parse an unsigned long, put it into *result; return 0 on failure, else 1.
648*b077aed3SPierre Pronchery  */
649*b077aed3SPierre Pronchery int opt_ulong(const char *value, unsigned long *result)
650*b077aed3SPierre Pronchery {
651*b077aed3SPierre Pronchery     int oerrno = errno;
652*b077aed3SPierre Pronchery     char *endptr;
653*b077aed3SPierre Pronchery     unsigned long l;
654*b077aed3SPierre Pronchery 
655*b077aed3SPierre Pronchery     errno = 0;
656*b077aed3SPierre Pronchery     l = strtoul(value, &endptr, 0);
657*b077aed3SPierre Pronchery     if (*endptr
658*b077aed3SPierre Pronchery             || endptr == value
659*b077aed3SPierre Pronchery             || ((l == ULONG_MAX) && errno == ERANGE)
660*b077aed3SPierre Pronchery             || (l == 0 && errno != 0)) {
661*b077aed3SPierre Pronchery         opt_number_error(value);
662*b077aed3SPierre Pronchery         errno = oerrno;
663*b077aed3SPierre Pronchery         return 0;
664*b077aed3SPierre Pronchery     }
665*b077aed3SPierre Pronchery     *result = l;
666*b077aed3SPierre Pronchery     errno = oerrno;
667*b077aed3SPierre Pronchery     return 1;
668*b077aed3SPierre Pronchery }
669*b077aed3SPierre Pronchery 
670*b077aed3SPierre Pronchery /*
671*b077aed3SPierre Pronchery  * We pass opt as an int but cast it to "enum range" so that all the
672*b077aed3SPierre Pronchery  * items in the OPT_V_ENUM enumeration are caught; this makes -Wswitch
673*b077aed3SPierre Pronchery  * in gcc do the right thing.
674*b077aed3SPierre Pronchery  */
675*b077aed3SPierre Pronchery enum range { OPT_V_ENUM };
676*b077aed3SPierre Pronchery 
677*b077aed3SPierre Pronchery int opt_verify(int opt, X509_VERIFY_PARAM *vpm)
678*b077aed3SPierre Pronchery {
679*b077aed3SPierre Pronchery     int i;
680*b077aed3SPierre Pronchery     ossl_intmax_t t = 0;
681*b077aed3SPierre Pronchery     ASN1_OBJECT *otmp;
682*b077aed3SPierre Pronchery     X509_PURPOSE *xptmp;
683*b077aed3SPierre Pronchery     const X509_VERIFY_PARAM *vtmp;
684*b077aed3SPierre Pronchery 
685*b077aed3SPierre Pronchery     OPENSSL_assert(vpm != NULL);
686*b077aed3SPierre Pronchery     OPENSSL_assert(opt > OPT_V__FIRST);
687*b077aed3SPierre Pronchery     OPENSSL_assert(opt < OPT_V__LAST);
688*b077aed3SPierre Pronchery 
689*b077aed3SPierre Pronchery     switch ((enum range)opt) {
690*b077aed3SPierre Pronchery     case OPT_V__FIRST:
691*b077aed3SPierre Pronchery     case OPT_V__LAST:
692*b077aed3SPierre Pronchery         return 0;
693*b077aed3SPierre Pronchery     case OPT_V_POLICY:
694*b077aed3SPierre Pronchery         otmp = OBJ_txt2obj(opt_arg(), 0);
695*b077aed3SPierre Pronchery         if (otmp == NULL) {
696*b077aed3SPierre Pronchery             opt_printf_stderr("%s: Invalid Policy %s\n", prog, opt_arg());
697*b077aed3SPierre Pronchery             return 0;
698*b077aed3SPierre Pronchery         }
699*b077aed3SPierre Pronchery         X509_VERIFY_PARAM_add0_policy(vpm, otmp);
700*b077aed3SPierre Pronchery         break;
701*b077aed3SPierre Pronchery     case OPT_V_PURPOSE:
702*b077aed3SPierre Pronchery         /* purpose name -> purpose index */
703*b077aed3SPierre Pronchery         i = X509_PURPOSE_get_by_sname(opt_arg());
704*b077aed3SPierre Pronchery         if (i < 0) {
705*b077aed3SPierre Pronchery             opt_printf_stderr("%s: Invalid purpose %s\n", prog, opt_arg());
706*b077aed3SPierre Pronchery             return 0;
707*b077aed3SPierre Pronchery         }
708*b077aed3SPierre Pronchery 
709*b077aed3SPierre Pronchery         /* purpose index -> purpose object */
710*b077aed3SPierre Pronchery         xptmp = X509_PURPOSE_get0(i);
711*b077aed3SPierre Pronchery 
712*b077aed3SPierre Pronchery         /* purpose object -> purpose value */
713*b077aed3SPierre Pronchery         i = X509_PURPOSE_get_id(xptmp);
714*b077aed3SPierre Pronchery 
715*b077aed3SPierre Pronchery         if (!X509_VERIFY_PARAM_set_purpose(vpm, i)) {
716*b077aed3SPierre Pronchery             opt_printf_stderr("%s: Internal error setting purpose %s\n",
717*b077aed3SPierre Pronchery                               prog, opt_arg());
718*b077aed3SPierre Pronchery             return 0;
719*b077aed3SPierre Pronchery         }
720*b077aed3SPierre Pronchery         break;
721*b077aed3SPierre Pronchery     case OPT_V_VERIFY_NAME:
722*b077aed3SPierre Pronchery         vtmp = X509_VERIFY_PARAM_lookup(opt_arg());
723*b077aed3SPierre Pronchery         if (vtmp == NULL) {
724*b077aed3SPierre Pronchery             opt_printf_stderr("%s: Invalid verify name %s\n",
725*b077aed3SPierre Pronchery                               prog, opt_arg());
726*b077aed3SPierre Pronchery             return 0;
727*b077aed3SPierre Pronchery         }
728*b077aed3SPierre Pronchery         X509_VERIFY_PARAM_set1(vpm, vtmp);
729*b077aed3SPierre Pronchery         break;
730*b077aed3SPierre Pronchery     case OPT_V_VERIFY_DEPTH:
731*b077aed3SPierre Pronchery         i = atoi(opt_arg());
732*b077aed3SPierre Pronchery         if (i >= 0)
733*b077aed3SPierre Pronchery             X509_VERIFY_PARAM_set_depth(vpm, i);
734*b077aed3SPierre Pronchery         break;
735*b077aed3SPierre Pronchery     case OPT_V_VERIFY_AUTH_LEVEL:
736*b077aed3SPierre Pronchery         i = atoi(opt_arg());
737*b077aed3SPierre Pronchery         if (i >= 0)
738*b077aed3SPierre Pronchery             X509_VERIFY_PARAM_set_auth_level(vpm, i);
739*b077aed3SPierre Pronchery         break;
740*b077aed3SPierre Pronchery     case OPT_V_ATTIME:
741*b077aed3SPierre Pronchery         if (!opt_intmax(opt_arg(), &t))
742*b077aed3SPierre Pronchery             return 0;
743*b077aed3SPierre Pronchery         if (t != (time_t)t) {
744*b077aed3SPierre Pronchery             opt_printf_stderr("%s: epoch time out of range %s\n",
745*b077aed3SPierre Pronchery                               prog, opt_arg());
746*b077aed3SPierre Pronchery             return 0;
747*b077aed3SPierre Pronchery         }
748*b077aed3SPierre Pronchery         X509_VERIFY_PARAM_set_time(vpm, (time_t)t);
749*b077aed3SPierre Pronchery         break;
750*b077aed3SPierre Pronchery     case OPT_V_VERIFY_HOSTNAME:
751*b077aed3SPierre Pronchery         if (!X509_VERIFY_PARAM_set1_host(vpm, opt_arg(), 0))
752*b077aed3SPierre Pronchery             return 0;
753*b077aed3SPierre Pronchery         break;
754*b077aed3SPierre Pronchery     case OPT_V_VERIFY_EMAIL:
755*b077aed3SPierre Pronchery         if (!X509_VERIFY_PARAM_set1_email(vpm, opt_arg(), 0))
756*b077aed3SPierre Pronchery             return 0;
757*b077aed3SPierre Pronchery         break;
758*b077aed3SPierre Pronchery     case OPT_V_VERIFY_IP:
759*b077aed3SPierre Pronchery         if (!X509_VERIFY_PARAM_set1_ip_asc(vpm, opt_arg()))
760*b077aed3SPierre Pronchery             return 0;
761*b077aed3SPierre Pronchery         break;
762*b077aed3SPierre Pronchery     case OPT_V_IGNORE_CRITICAL:
763*b077aed3SPierre Pronchery         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_IGNORE_CRITICAL);
764*b077aed3SPierre Pronchery         break;
765*b077aed3SPierre Pronchery     case OPT_V_ISSUER_CHECKS:
766*b077aed3SPierre Pronchery         /* NOP, deprecated */
767*b077aed3SPierre Pronchery         break;
768*b077aed3SPierre Pronchery     case OPT_V_CRL_CHECK:
769*b077aed3SPierre Pronchery         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CRL_CHECK);
770*b077aed3SPierre Pronchery         break;
771*b077aed3SPierre Pronchery     case OPT_V_CRL_CHECK_ALL:
772*b077aed3SPierre Pronchery         X509_VERIFY_PARAM_set_flags(vpm,
773*b077aed3SPierre Pronchery                                     X509_V_FLAG_CRL_CHECK |
774*b077aed3SPierre Pronchery                                     X509_V_FLAG_CRL_CHECK_ALL);
775*b077aed3SPierre Pronchery         break;
776*b077aed3SPierre Pronchery     case OPT_V_POLICY_CHECK:
777*b077aed3SPierre Pronchery         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_POLICY_CHECK);
778*b077aed3SPierre Pronchery         break;
779*b077aed3SPierre Pronchery     case OPT_V_EXPLICIT_POLICY:
780*b077aed3SPierre Pronchery         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_EXPLICIT_POLICY);
781*b077aed3SPierre Pronchery         break;
782*b077aed3SPierre Pronchery     case OPT_V_INHIBIT_ANY:
783*b077aed3SPierre Pronchery         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_INHIBIT_ANY);
784*b077aed3SPierre Pronchery         break;
785*b077aed3SPierre Pronchery     case OPT_V_INHIBIT_MAP:
786*b077aed3SPierre Pronchery         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_INHIBIT_MAP);
787*b077aed3SPierre Pronchery         break;
788*b077aed3SPierre Pronchery     case OPT_V_X509_STRICT:
789*b077aed3SPierre Pronchery         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_X509_STRICT);
790*b077aed3SPierre Pronchery         break;
791*b077aed3SPierre Pronchery     case OPT_V_EXTENDED_CRL:
792*b077aed3SPierre Pronchery         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_EXTENDED_CRL_SUPPORT);
793*b077aed3SPierre Pronchery         break;
794*b077aed3SPierre Pronchery     case OPT_V_USE_DELTAS:
795*b077aed3SPierre Pronchery         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_USE_DELTAS);
796*b077aed3SPierre Pronchery         break;
797*b077aed3SPierre Pronchery     case OPT_V_POLICY_PRINT:
798*b077aed3SPierre Pronchery         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NOTIFY_POLICY);
799*b077aed3SPierre Pronchery         break;
800*b077aed3SPierre Pronchery     case OPT_V_CHECK_SS_SIG:
801*b077aed3SPierre Pronchery         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CHECK_SS_SIGNATURE);
802*b077aed3SPierre Pronchery         break;
803*b077aed3SPierre Pronchery     case OPT_V_TRUSTED_FIRST:
804*b077aed3SPierre Pronchery         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_TRUSTED_FIRST);
805*b077aed3SPierre Pronchery         break;
806*b077aed3SPierre Pronchery     case OPT_V_SUITEB_128_ONLY:
807*b077aed3SPierre Pronchery         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_128_LOS_ONLY);
808*b077aed3SPierre Pronchery         break;
809*b077aed3SPierre Pronchery     case OPT_V_SUITEB_128:
810*b077aed3SPierre Pronchery         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_128_LOS);
811*b077aed3SPierre Pronchery         break;
812*b077aed3SPierre Pronchery     case OPT_V_SUITEB_192:
813*b077aed3SPierre Pronchery         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_192_LOS);
814*b077aed3SPierre Pronchery         break;
815*b077aed3SPierre Pronchery     case OPT_V_PARTIAL_CHAIN:
816*b077aed3SPierre Pronchery         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_PARTIAL_CHAIN);
817*b077aed3SPierre Pronchery         break;
818*b077aed3SPierre Pronchery     case OPT_V_NO_ALT_CHAINS:
819*b077aed3SPierre Pronchery         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_ALT_CHAINS);
820*b077aed3SPierre Pronchery         break;
821*b077aed3SPierre Pronchery     case OPT_V_NO_CHECK_TIME:
822*b077aed3SPierre Pronchery         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_CHECK_TIME);
823*b077aed3SPierre Pronchery         break;
824*b077aed3SPierre Pronchery     case OPT_V_ALLOW_PROXY_CERTS:
825*b077aed3SPierre Pronchery         X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_ALLOW_PROXY_CERTS);
826*b077aed3SPierre Pronchery         break;
827*b077aed3SPierre Pronchery     }
828*b077aed3SPierre Pronchery     return 1;
829*b077aed3SPierre Pronchery 
830*b077aed3SPierre Pronchery }
831*b077aed3SPierre Pronchery 
832*b077aed3SPierre Pronchery void opt_begin(void)
833*b077aed3SPierre Pronchery {
834*b077aed3SPierre Pronchery     opt_index = 1;
835*b077aed3SPierre Pronchery     arg = NULL;
836*b077aed3SPierre Pronchery     flag = NULL;
837*b077aed3SPierre Pronchery }
838*b077aed3SPierre Pronchery 
839*b077aed3SPierre Pronchery /*
840*b077aed3SPierre Pronchery  * Parse the next flag (and value if specified), return 0 if done, -1 on
841*b077aed3SPierre Pronchery  * error, otherwise the flag's retval.
842*b077aed3SPierre Pronchery  */
843*b077aed3SPierre Pronchery int opt_next(void)
844*b077aed3SPierre Pronchery {
845*b077aed3SPierre Pronchery     char *p;
846*b077aed3SPierre Pronchery     const OPTIONS *o;
847*b077aed3SPierre Pronchery     int ival;
848*b077aed3SPierre Pronchery     long lval;
849*b077aed3SPierre Pronchery     unsigned long ulval;
850*b077aed3SPierre Pronchery     ossl_intmax_t imval;
851*b077aed3SPierre Pronchery     ossl_uintmax_t umval;
852*b077aed3SPierre Pronchery 
853*b077aed3SPierre Pronchery     /* Look at current arg; at end of the list? */
854*b077aed3SPierre Pronchery     arg = NULL;
855*b077aed3SPierre Pronchery     p = argv[opt_index];
856*b077aed3SPierre Pronchery     if (p == NULL)
857*b077aed3SPierre Pronchery         return 0;
858*b077aed3SPierre Pronchery 
859*b077aed3SPierre Pronchery     /* If word doesn't start with a -, we're done. */
860*b077aed3SPierre Pronchery     if (*p != '-')
861*b077aed3SPierre Pronchery         return 0;
862*b077aed3SPierre Pronchery 
863*b077aed3SPierre Pronchery     /* Hit "--" ? We're done. */
864*b077aed3SPierre Pronchery     opt_index++;
865*b077aed3SPierre Pronchery     if (strcmp(p, "--") == 0)
866*b077aed3SPierre Pronchery         return 0;
867*b077aed3SPierre Pronchery 
868*b077aed3SPierre Pronchery     /* Allow -nnn and --nnn */
869*b077aed3SPierre Pronchery     if (*++p == '-')
870*b077aed3SPierre Pronchery         p++;
871*b077aed3SPierre Pronchery     flag = p - 1;
872*b077aed3SPierre Pronchery 
873*b077aed3SPierre Pronchery     /* If we have --flag=foo, snip it off */
874*b077aed3SPierre Pronchery     if ((arg = strchr(p, '=')) != NULL)
875*b077aed3SPierre Pronchery         *arg++ = '\0';
876*b077aed3SPierre Pronchery     for (o = opts; o->name; ++o) {
877*b077aed3SPierre Pronchery         /* If not this option, move on to the next one. */
878*b077aed3SPierre Pronchery         if (!(strcmp(p, "h") == 0 && strcmp(o->name, "help") == 0)
879*b077aed3SPierre Pronchery                 && strcmp(p, o->name) != 0)
880*b077aed3SPierre Pronchery             continue;
881*b077aed3SPierre Pronchery 
882*b077aed3SPierre Pronchery         /* If it doesn't take a value, make sure none was given. */
883*b077aed3SPierre Pronchery         if (o->valtype == 0 || o->valtype == '-') {
884*b077aed3SPierre Pronchery             if (arg) {
885*b077aed3SPierre Pronchery                 opt_printf_stderr("%s: Option -%s does not take a value\n",
886*b077aed3SPierre Pronchery                                   prog, p);
887*b077aed3SPierre Pronchery                 return -1;
888*b077aed3SPierre Pronchery             }
889*b077aed3SPierre Pronchery             return o->retval;
890*b077aed3SPierre Pronchery         }
891*b077aed3SPierre Pronchery 
892*b077aed3SPierre Pronchery         /* Want a value; get the next param if =foo not used. */
893*b077aed3SPierre Pronchery         if (arg == NULL) {
894*b077aed3SPierre Pronchery             if (argv[opt_index] == NULL) {
895*b077aed3SPierre Pronchery                 opt_printf_stderr("%s: Option -%s needs a value\n",
896*b077aed3SPierre Pronchery                                   prog, o->name);
897*b077aed3SPierre Pronchery                 return -1;
898*b077aed3SPierre Pronchery             }
899*b077aed3SPierre Pronchery             arg = argv[opt_index++];
900*b077aed3SPierre Pronchery         }
901*b077aed3SPierre Pronchery 
902*b077aed3SPierre Pronchery         /* Syntax-check value. */
903*b077aed3SPierre Pronchery         switch (o->valtype) {
904*b077aed3SPierre Pronchery         default:
905*b077aed3SPierre Pronchery         case 's':
906*b077aed3SPierre Pronchery         case ':':
907*b077aed3SPierre Pronchery             /* Just a string. */
908*b077aed3SPierre Pronchery             break;
909*b077aed3SPierre Pronchery         case '.':
910*b077aed3SPierre Pronchery             /* Parameters */
911*b077aed3SPierre Pronchery             break;
912*b077aed3SPierre Pronchery         case '/':
913*b077aed3SPierre Pronchery             if (opt_isdir(arg) > 0)
914*b077aed3SPierre Pronchery                 break;
915*b077aed3SPierre Pronchery             opt_printf_stderr("%s: Not a directory: %s\n", prog, arg);
916*b077aed3SPierre Pronchery             return -1;
917*b077aed3SPierre Pronchery         case '<':
918*b077aed3SPierre Pronchery             /* Input file. */
919*b077aed3SPierre Pronchery             break;
920*b077aed3SPierre Pronchery         case '>':
921*b077aed3SPierre Pronchery             /* Output file. */
922*b077aed3SPierre Pronchery             break;
923*b077aed3SPierre Pronchery         case 'p':
924*b077aed3SPierre Pronchery         case 'n':
925*b077aed3SPierre Pronchery         case 'N':
926*b077aed3SPierre Pronchery             if (!opt_int(arg, &ival))
927*b077aed3SPierre Pronchery                 return -1;
928*b077aed3SPierre Pronchery             if (o->valtype == 'p' && ival <= 0) {
929*b077aed3SPierre Pronchery                 opt_printf_stderr("%s: Non-positive number \"%s\" for option -%s\n",
930*b077aed3SPierre Pronchery                                   prog, arg, o->name);
931*b077aed3SPierre Pronchery                 return -1;
932*b077aed3SPierre Pronchery             }
933*b077aed3SPierre Pronchery             if (o->valtype == 'N' && ival < 0) {
934*b077aed3SPierre Pronchery                 opt_printf_stderr("%s: Negative number \"%s\" for option -%s\n",
935*b077aed3SPierre Pronchery                                   prog, arg, o->name);
936*b077aed3SPierre Pronchery                 return -1;
937*b077aed3SPierre Pronchery             }
938*b077aed3SPierre Pronchery             break;
939*b077aed3SPierre Pronchery         case 'M':
940*b077aed3SPierre Pronchery             if (!opt_intmax(arg, &imval))
941*b077aed3SPierre Pronchery                 return -1;
942*b077aed3SPierre Pronchery             break;
943*b077aed3SPierre Pronchery         case 'U':
944*b077aed3SPierre Pronchery             if (!opt_uintmax(arg, &umval))
945*b077aed3SPierre Pronchery                 return -1;
946*b077aed3SPierre Pronchery             break;
947*b077aed3SPierre Pronchery         case 'l':
948*b077aed3SPierre Pronchery             if (!opt_long(arg, &lval))
949*b077aed3SPierre Pronchery                 return -1;
950*b077aed3SPierre Pronchery             break;
951*b077aed3SPierre Pronchery         case 'u':
952*b077aed3SPierre Pronchery             if (!opt_ulong(arg, &ulval))
953*b077aed3SPierre Pronchery                 return -1;
954*b077aed3SPierre Pronchery             break;
955*b077aed3SPierre Pronchery         case 'c':
956*b077aed3SPierre Pronchery         case 'E':
957*b077aed3SPierre Pronchery         case 'F':
958*b077aed3SPierre Pronchery         case 'f':
959*b077aed3SPierre Pronchery             if (opt_format(arg,
960*b077aed3SPierre Pronchery                            o->valtype == 'c' ? OPT_FMT_PDS :
961*b077aed3SPierre Pronchery                            o->valtype == 'E' ? OPT_FMT_PDE :
962*b077aed3SPierre Pronchery                            o->valtype == 'F' ? OPT_FMT_PEMDER
963*b077aed3SPierre Pronchery                            : OPT_FMT_ANY, &ival))
964*b077aed3SPierre Pronchery                 break;
965*b077aed3SPierre Pronchery             opt_printf_stderr("%s: Invalid format \"%s\" for option -%s\n",
966*b077aed3SPierre Pronchery                               prog, arg, o->name);
967*b077aed3SPierre Pronchery             return -1;
968*b077aed3SPierre Pronchery         }
969*b077aed3SPierre Pronchery 
970*b077aed3SPierre Pronchery         /* Return the flag value. */
971*b077aed3SPierre Pronchery         return o->retval;
972*b077aed3SPierre Pronchery     }
973*b077aed3SPierre Pronchery     if (unknown != NULL) {
974*b077aed3SPierre Pronchery         dunno = p;
975*b077aed3SPierre Pronchery         return unknown->retval;
976*b077aed3SPierre Pronchery     }
977*b077aed3SPierre Pronchery     opt_printf_stderr("%s: Unknown option: -%s\n", prog, p);
978*b077aed3SPierre Pronchery     return -1;
979*b077aed3SPierre Pronchery }
980*b077aed3SPierre Pronchery 
981*b077aed3SPierre Pronchery /* Return the most recent flag parameter. */
982*b077aed3SPierre Pronchery char *opt_arg(void)
983*b077aed3SPierre Pronchery {
984*b077aed3SPierre Pronchery     return arg;
985*b077aed3SPierre Pronchery }
986*b077aed3SPierre Pronchery 
987*b077aed3SPierre Pronchery /* Return the most recent flag (option name including the preceding '-'). */
988*b077aed3SPierre Pronchery char *opt_flag(void)
989*b077aed3SPierre Pronchery {
990*b077aed3SPierre Pronchery     return flag;
991*b077aed3SPierre Pronchery }
992*b077aed3SPierre Pronchery 
993*b077aed3SPierre Pronchery /* Return the unknown option. */
994*b077aed3SPierre Pronchery char *opt_unknown(void)
995*b077aed3SPierre Pronchery {
996*b077aed3SPierre Pronchery     return dunno;
997*b077aed3SPierre Pronchery }
998*b077aed3SPierre Pronchery 
999*b077aed3SPierre Pronchery /* Return the rest of the arguments after parsing flags. */
1000*b077aed3SPierre Pronchery char **opt_rest(void)
1001*b077aed3SPierre Pronchery {
1002*b077aed3SPierre Pronchery     return &argv[opt_index];
1003*b077aed3SPierre Pronchery }
1004*b077aed3SPierre Pronchery 
1005*b077aed3SPierre Pronchery /* How many items in remaining args? */
1006*b077aed3SPierre Pronchery int opt_num_rest(void)
1007*b077aed3SPierre Pronchery {
1008*b077aed3SPierre Pronchery     int i = 0;
1009*b077aed3SPierre Pronchery     char **pp;
1010*b077aed3SPierre Pronchery 
1011*b077aed3SPierre Pronchery     for (pp = opt_rest(); *pp; pp++, i++)
1012*b077aed3SPierre Pronchery         continue;
1013*b077aed3SPierre Pronchery     return i;
1014*b077aed3SPierre Pronchery }
1015*b077aed3SPierre Pronchery 
1016*b077aed3SPierre Pronchery /* Return a string describing the parameter type. */
1017*b077aed3SPierre Pronchery static const char *valtype2param(const OPTIONS *o)
1018*b077aed3SPierre Pronchery {
1019*b077aed3SPierre Pronchery     switch (o->valtype) {
1020*b077aed3SPierre Pronchery     case 0:
1021*b077aed3SPierre Pronchery     case '-':
1022*b077aed3SPierre Pronchery         return "";
1023*b077aed3SPierre Pronchery     case ':':
1024*b077aed3SPierre Pronchery         return "uri";
1025*b077aed3SPierre Pronchery     case 's':
1026*b077aed3SPierre Pronchery         return "val";
1027*b077aed3SPierre Pronchery     case '/':
1028*b077aed3SPierre Pronchery         return "dir";
1029*b077aed3SPierre Pronchery     case '<':
1030*b077aed3SPierre Pronchery         return "infile";
1031*b077aed3SPierre Pronchery     case '>':
1032*b077aed3SPierre Pronchery         return "outfile";
1033*b077aed3SPierre Pronchery     case 'p':
1034*b077aed3SPierre Pronchery         return "+int";
1035*b077aed3SPierre Pronchery     case 'n':
1036*b077aed3SPierre Pronchery         return "int";
1037*b077aed3SPierre Pronchery     case 'l':
1038*b077aed3SPierre Pronchery         return "long";
1039*b077aed3SPierre Pronchery     case 'u':
1040*b077aed3SPierre Pronchery         return "ulong";
1041*b077aed3SPierre Pronchery     case 'E':
1042*b077aed3SPierre Pronchery         return "PEM|DER|ENGINE";
1043*b077aed3SPierre Pronchery     case 'F':
1044*b077aed3SPierre Pronchery         return "PEM|DER";
1045*b077aed3SPierre Pronchery     case 'f':
1046*b077aed3SPierre Pronchery         return "format";
1047*b077aed3SPierre Pronchery     case 'M':
1048*b077aed3SPierre Pronchery         return "intmax";
1049*b077aed3SPierre Pronchery     case 'N':
1050*b077aed3SPierre Pronchery         return "nonneg";
1051*b077aed3SPierre Pronchery     case 'U':
1052*b077aed3SPierre Pronchery         return "uintmax";
1053*b077aed3SPierre Pronchery     }
1054*b077aed3SPierre Pronchery     return "parm";
1055*b077aed3SPierre Pronchery }
1056*b077aed3SPierre Pronchery 
1057*b077aed3SPierre Pronchery static void opt_print(const OPTIONS *o, int doingparams, int width)
1058*b077aed3SPierre Pronchery {
1059*b077aed3SPierre Pronchery     const char* help;
1060*b077aed3SPierre Pronchery     char start[80 + 1];
1061*b077aed3SPierre Pronchery     char *p;
1062*b077aed3SPierre Pronchery 
1063*b077aed3SPierre Pronchery         help = o->helpstr ? o->helpstr : "(No additional info)";
1064*b077aed3SPierre Pronchery         if (o->name == OPT_HELP_STR) {
1065*b077aed3SPierre Pronchery             opt_printf_stderr(help, prog);
1066*b077aed3SPierre Pronchery             return;
1067*b077aed3SPierre Pronchery         }
1068*b077aed3SPierre Pronchery         if (o->name == OPT_SECTION_STR) {
1069*b077aed3SPierre Pronchery             opt_printf_stderr("\n");
1070*b077aed3SPierre Pronchery             opt_printf_stderr(help, prog);
1071*b077aed3SPierre Pronchery             return;
1072*b077aed3SPierre Pronchery         }
1073*b077aed3SPierre Pronchery         if (o->name == OPT_PARAM_STR) {
1074*b077aed3SPierre Pronchery             opt_printf_stderr("\nParameters:\n");
1075*b077aed3SPierre Pronchery             return;
1076*b077aed3SPierre Pronchery         }
1077*b077aed3SPierre Pronchery 
1078*b077aed3SPierre Pronchery         /* Pad out prefix */
1079*b077aed3SPierre Pronchery         memset(start, ' ', sizeof(start) - 1);
1080*b077aed3SPierre Pronchery         start[sizeof(start) - 1] = '\0';
1081*b077aed3SPierre Pronchery 
1082*b077aed3SPierre Pronchery         if (o->name == OPT_MORE_STR) {
1083*b077aed3SPierre Pronchery             /* Continuation of previous line; pad and print. */
1084*b077aed3SPierre Pronchery             start[width] = '\0';
1085*b077aed3SPierre Pronchery             opt_printf_stderr("%s  %s\n", start, help);
1086*b077aed3SPierre Pronchery             return;
1087*b077aed3SPierre Pronchery         }
1088*b077aed3SPierre Pronchery 
1089*b077aed3SPierre Pronchery         /* Build up the "-flag [param]" part. */
1090*b077aed3SPierre Pronchery         p = start;
1091*b077aed3SPierre Pronchery         *p++ = ' ';
1092*b077aed3SPierre Pronchery         if (!doingparams)
1093*b077aed3SPierre Pronchery             *p++ = '-';
1094*b077aed3SPierre Pronchery         if (o->name[0])
1095*b077aed3SPierre Pronchery             p += strlen(strcpy(p, o->name));
1096*b077aed3SPierre Pronchery         else
1097*b077aed3SPierre Pronchery             *p++ = '*';
1098*b077aed3SPierre Pronchery         if (o->valtype != '-') {
1099*b077aed3SPierre Pronchery             *p++ = ' ';
1100*b077aed3SPierre Pronchery             p += strlen(strcpy(p, valtype2param(o)));
1101*b077aed3SPierre Pronchery         }
1102*b077aed3SPierre Pronchery         *p = ' ';
1103*b077aed3SPierre Pronchery         if ((int)(p - start) >= MAX_OPT_HELP_WIDTH) {
1104*b077aed3SPierre Pronchery             *p = '\0';
1105*b077aed3SPierre Pronchery             opt_printf_stderr("%s\n", start);
1106*b077aed3SPierre Pronchery             memset(start, ' ', sizeof(start));
1107*b077aed3SPierre Pronchery         }
1108*b077aed3SPierre Pronchery         start[width] = '\0';
1109*b077aed3SPierre Pronchery         opt_printf_stderr("%s  %s\n", start, help);
1110*b077aed3SPierre Pronchery }
1111*b077aed3SPierre Pronchery 
1112*b077aed3SPierre Pronchery void opt_help(const OPTIONS *list)
1113*b077aed3SPierre Pronchery {
1114*b077aed3SPierre Pronchery     const OPTIONS *o;
1115*b077aed3SPierre Pronchery     int i, sawparams = 0, width = 5;
1116*b077aed3SPierre Pronchery     int standard_prolog;
1117*b077aed3SPierre Pronchery     char start[80 + 1];
1118*b077aed3SPierre Pronchery 
1119*b077aed3SPierre Pronchery     /* Starts with its own help message? */
1120*b077aed3SPierre Pronchery     standard_prolog = list[0].name != OPT_HELP_STR;
1121*b077aed3SPierre Pronchery 
1122*b077aed3SPierre Pronchery     /* Find the widest help. */
1123*b077aed3SPierre Pronchery     for (o = list; o->name; o++) {
1124*b077aed3SPierre Pronchery         if (o->name == OPT_MORE_STR)
1125*b077aed3SPierre Pronchery             continue;
1126*b077aed3SPierre Pronchery         i = 2 + (int)strlen(o->name);
1127*b077aed3SPierre Pronchery         if (o->valtype != '-')
1128*b077aed3SPierre Pronchery             i += 1 + strlen(valtype2param(o));
1129*b077aed3SPierre Pronchery         if (i < MAX_OPT_HELP_WIDTH && i > width)
1130*b077aed3SPierre Pronchery             width = i;
1131*b077aed3SPierre Pronchery         OPENSSL_assert(i < (int)sizeof(start));
1132*b077aed3SPierre Pronchery     }
1133*b077aed3SPierre Pronchery 
1134*b077aed3SPierre Pronchery     if (standard_prolog) {
1135*b077aed3SPierre Pronchery         opt_printf_stderr("Usage: %s [options]\n", prog);
1136*b077aed3SPierre Pronchery         if (list[0].name != OPT_SECTION_STR)
1137*b077aed3SPierre Pronchery             opt_printf_stderr("Valid options are:\n", prog);
1138*b077aed3SPierre Pronchery     }
1139*b077aed3SPierre Pronchery 
1140*b077aed3SPierre Pronchery     /* Now let's print. */
1141*b077aed3SPierre Pronchery     for (o = list; o->name; o++) {
1142*b077aed3SPierre Pronchery         if (o->name == OPT_PARAM_STR)
1143*b077aed3SPierre Pronchery             sawparams = 1;
1144*b077aed3SPierre Pronchery         opt_print(o, sawparams, width);
1145*b077aed3SPierre Pronchery     }
1146*b077aed3SPierre Pronchery }
1147*b077aed3SPierre Pronchery 
1148*b077aed3SPierre Pronchery /* opt_isdir section */
1149*b077aed3SPierre Pronchery #ifdef _WIN32
1150*b077aed3SPierre Pronchery # include <windows.h>
1151*b077aed3SPierre Pronchery int opt_isdir(const char *name)
1152*b077aed3SPierre Pronchery {
1153*b077aed3SPierre Pronchery     DWORD attr;
1154*b077aed3SPierre Pronchery # if defined(UNICODE) || defined(_UNICODE)
1155*b077aed3SPierre Pronchery     size_t i, len_0 = strlen(name) + 1;
1156*b077aed3SPierre Pronchery     WCHAR tempname[MAX_PATH];
1157*b077aed3SPierre Pronchery 
1158*b077aed3SPierre Pronchery     if (len_0 > MAX_PATH)
1159*b077aed3SPierre Pronchery         return -1;
1160*b077aed3SPierre Pronchery 
1161*b077aed3SPierre Pronchery #  if !defined(_WIN32_WCE) || _WIN32_WCE>=101
1162*b077aed3SPierre Pronchery     if (!MultiByteToWideChar(CP_ACP, 0, name, len_0, tempname, MAX_PATH))
1163*b077aed3SPierre Pronchery #  endif
1164*b077aed3SPierre Pronchery         for (i = 0; i < len_0; i++)
1165*b077aed3SPierre Pronchery             tempname[i] = (WCHAR)name[i];
1166*b077aed3SPierre Pronchery 
1167*b077aed3SPierre Pronchery     attr = GetFileAttributes(tempname);
1168*b077aed3SPierre Pronchery # else
1169*b077aed3SPierre Pronchery     attr = GetFileAttributes(name);
1170*b077aed3SPierre Pronchery # endif
1171*b077aed3SPierre Pronchery     if (attr == INVALID_FILE_ATTRIBUTES)
1172*b077aed3SPierre Pronchery         return -1;
1173*b077aed3SPierre Pronchery     return ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0);
1174*b077aed3SPierre Pronchery }
1175*b077aed3SPierre Pronchery #else
1176*b077aed3SPierre Pronchery # include <sys/stat.h>
1177*b077aed3SPierre Pronchery # ifndef S_ISDIR
1178*b077aed3SPierre Pronchery #  if defined(_S_IFMT) && defined(_S_IFDIR)
1179*b077aed3SPierre Pronchery #   define S_ISDIR(a)   (((a) & _S_IFMT) == _S_IFDIR)
1180*b077aed3SPierre Pronchery #  else
1181*b077aed3SPierre Pronchery #   define S_ISDIR(a)   (((a) & S_IFMT) == S_IFDIR)
1182*b077aed3SPierre Pronchery #  endif
1183*b077aed3SPierre Pronchery # endif
1184*b077aed3SPierre Pronchery 
1185*b077aed3SPierre Pronchery int opt_isdir(const char *name)
1186*b077aed3SPierre Pronchery {
1187*b077aed3SPierre Pronchery # if defined(S_ISDIR)
1188*b077aed3SPierre Pronchery     struct stat st;
1189*b077aed3SPierre Pronchery 
1190*b077aed3SPierre Pronchery     if (stat(name, &st) == 0)
1191*b077aed3SPierre Pronchery         return S_ISDIR(st.st_mode);
1192*b077aed3SPierre Pronchery     else
1193*b077aed3SPierre Pronchery         return -1;
1194*b077aed3SPierre Pronchery # else
1195*b077aed3SPierre Pronchery     return -1;
1196*b077aed3SPierre Pronchery # endif
1197*b077aed3SPierre Pronchery }
1198*b077aed3SPierre Pronchery #endif
1199