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