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