]> git.ipfire.org Git - thirdparty/openssl.git/blame - apps/lib/opt.c
Add option grouping capability to apps
[thirdparty/openssl.git] / apps / lib / opt.c
CommitLineData
846e33c7 1/*
48e5119a 2 * Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved.
7e1b7485 3 *
dffa7520 4 * Licensed under the Apache License 2.0 (the "License"). You may not use
846e33c7
RS
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
7e1b7485 8 */
a43ce58f
SL
9
10/*
11 * This file is also used by the test suite. Do not #include "apps.h".
12 */
13#include "opt.h"
14#include "fmt.h"
15#include "internal/nelem.h"
7e1b7485
RS
16#include <string.h>
17#if !defined(OPENSSL_SYS_MSDOS)
6b10d29c 18# include <unistd.h>
7e1b7485 19#endif
a3ed492f 20
7e1b7485
RS
21#include <stdlib.h>
22#include <errno.h>
23#include <ctype.h>
bd4850df 24#include <limits.h>
7e1b7485 25#include <openssl/bio.h>
5951e840 26#include <openssl/x509v3.h>
7e1b7485
RS
27
28#define MAX_OPT_HELP_WIDTH 30
29const char OPT_HELP_STR[] = "--";
30const char OPT_MORE_STR[] = "---";
4ed83891 31const char OPT_SECTION_STR[] = "----";
7e1b7485
RS
32
33/* Our state */
34static char **argv;
35static int argc;
36static int opt_index;
37static char *arg;
38static char *flag;
39static char *dunno;
40static const OPTIONS *unknown;
41static const OPTIONS *opts;
42static char prog[40];
43
44/*
45 * Return the simple name of the program; removing various platform gunk.
46 */
1fbab1dc 47#if defined(OPENSSL_SYS_WIN32)
7e1b7485
RS
48char *opt_progname(const char *argv0)
49{
45f13518 50 size_t i, n;
7e1b7485
RS
51 const char *p;
52 char *q;
53
54 /* find the last '/', '\' or ':' */
55 for (p = argv0 + strlen(argv0); --p > argv0;)
56 if (*p == '/' || *p == '\\' || *p == ':') {
57 p++;
58 break;
59 }
60
61 /* Strip off trailing nonsense. */
62 n = strlen(p);
63 if (n > 4 &&
a3ed492f 64 (strcmp(&p[n - 4], ".exe") == 0 || strcmp(&p[n - 4], ".EXE") == 0))
7e1b7485 65 n -= 4;
7e1b7485
RS
66
67 /* Copy over the name, in lowercase. */
cbe29648
RS
68 if (n > sizeof(prog) - 1)
69 n = sizeof(prog) - 1;
7e1b7485 70 for (q = prog, i = 0; i < n; i++, p++)
00dfbaad 71 *q++ = tolower((unsigned char)*p);
7e1b7485
RS
72 *q = '\0';
73 return prog;
74}
75
76#elif defined(OPENSSL_SYS_VMS)
77
78char *opt_progname(const char *argv0)
79{
80 const char *p, *q;
81
0ad69cd6 82 /* Find last special character sys:[foo.bar]openssl */
7e1b7485
RS
83 for (p = argv0 + strlen(argv0); --p > argv0;)
84 if (*p == ':' || *p == ']' || *p == '>') {
85 p++;
86 break;
87 }
88
89 q = strrchr(p, '.');
cbe29648
RS
90 strncpy(prog, p, sizeof(prog) - 1);
91 prog[sizeof(prog) - 1] = '\0';
92 if (q != NULL && q - p < sizeof(prog))
7e1b7485
RS
93 prog[q - p] = '\0';
94 return prog;
95}
96
97#else
98
99char *opt_progname(const char *argv0)
100{
101 const char *p;
102
103 /* Could use strchr, but this is like the ones above. */
104 for (p = argv0 + strlen(argv0); --p > argv0;)
105 if (*p == '/') {
106 p++;
107 break;
108 }
cbe29648
RS
109 strncpy(prog, p, sizeof(prog) - 1);
110 prog[sizeof(prog) - 1] = '\0';
7e1b7485
RS
111 return prog;
112}
113#endif
114
115char *opt_getprog(void)
116{
117 return prog;
118}
119
120/* Set up the arg parsing. */
121char *opt_init(int ac, char **av, const OPTIONS *o)
122{
123 /* Store state. */
124 argc = ac;
125 argv = av;
a43ce58f 126 opt_begin();
7e1b7485
RS
127 opts = o;
128 opt_progname(av[0]);
129 unknown = NULL;
130
131 for (; o->name; ++o) {
7e1b7485 132#ifndef NDEBUG
b286cb8e 133 const OPTIONS *next;
88806cfc 134 int duplicated, i;
7e1b7485
RS
135#endif
136
4ed83891
JS
137 if (o->name == OPT_HELP_STR || o->name == OPT_MORE_STR ||
138 o->name == OPT_SECTION_STR)
7e1b7485
RS
139 continue;
140#ifndef NDEBUG
141 i = o->valtype;
142
143 /* Make sure options are legit. */
a43ce58f
SL
144 OPENSSL_assert(o->name[0] != '-');
145 OPENSSL_assert(o->retval > 0);
03f887ca 146 switch (i) {
0c20802c
VD
147 case 0: case '-': case '/': case '<': case '>': case 'E': case 'F':
148 case 'M': case 'U': case 'f': case 'l': case 'n': case 'p': case 's':
f47e5647 149 case 'u': case 'c':
03f887ca
VD
150 break;
151 default:
a43ce58f 152 OPENSSL_assert(0);
03f887ca 153 }
7e1b7485
RS
154
155 /* Make sure there are no duplicates. */
88806cfc 156 for (next = o + 1; next->name; ++next) {
7e1b7485 157 /*
88806cfc 158 * Some compilers inline strcmp and the assert string is too long.
7e1b7485 159 */
88806cfc 160 duplicated = strcmp(o->name, next->name) == 0;
a43ce58f 161 OPENSSL_assert(!duplicated);
7e1b7485
RS
162 }
163#endif
164 if (o->name[0] == '\0') {
a43ce58f 165 OPENSSL_assert(unknown == NULL);
7e1b7485 166 unknown = o;
a43ce58f 167 OPENSSL_assert(unknown->valtype == 0 || unknown->valtype == '-');
7e1b7485
RS
168 }
169 }
170 return prog;
171}
172
173static OPT_PAIR formats[] = {
174 {"PEM/DER", OPT_FMT_PEMDER},
175 {"pkcs12", OPT_FMT_PKCS12},
176 {"smime", OPT_FMT_SMIME},
177 {"engine", OPT_FMT_ENGINE},
178 {"msblob", OPT_FMT_MSBLOB},
7e1b7485
RS
179 {"nss", OPT_FMT_NSS},
180 {"text", OPT_FMT_TEXT},
181 {"http", OPT_FMT_HTTP},
182 {"pvk", OPT_FMT_PVK},
183 {NULL}
184};
185
186/* Print an error message about a failed format parse. */
187int opt_format_error(const char *s, unsigned long flags)
188{
189 OPT_PAIR *ap;
190
2234212c 191 if (flags == OPT_FMT_PEMDER) {
a43ce58f
SL
192 opt_printf_stderr("%s: Bad format \"%s\"; must be pem or der\n",
193 prog, s);
2234212c 194 } else {
a43ce58f
SL
195 opt_printf_stderr("%s: Bad format \"%s\"; must be one of:\n",
196 prog, s);
7e1b7485
RS
197 for (ap = formats; ap->name; ap++)
198 if (flags & ap->retval)
a43ce58f 199 opt_printf_stderr(" %s\n", ap->name);
7e1b7485
RS
200 }
201 return 0;
202}
203
204/* Parse a format string, put it into *result; return 0 on failure, else 1. */
205int opt_format(const char *s, unsigned long flags, int *result)
206{
207 switch (*s) {
208 default:
209 return 0;
210 case 'D':
211 case 'd':
212 if ((flags & OPT_FMT_PEMDER) == 0)
213 return opt_format_error(s, flags);
214 *result = FORMAT_ASN1;
215 break;
216 case 'T':
217 case 't':
218 if ((flags & OPT_FMT_TEXT) == 0)
219 return opt_format_error(s, flags);
220 *result = FORMAT_TEXT;
221 break;
222 case 'N':
223 case 'n':
0bc2f365
RS
224 if ((flags & OPT_FMT_NSS) == 0)
225 return opt_format_error(s, flags);
226 if (strcmp(s, "NSS") != 0 && strcmp(s, "nss") != 0)
227 return opt_format_error(s, flags);
228 *result = FORMAT_NSS;
7e1b7485
RS
229 break;
230 case 'S':
231 case 's':
232 if ((flags & OPT_FMT_SMIME) == 0)
233 return opt_format_error(s, flags);
234 *result = FORMAT_SMIME;
235 break;
236 case 'M':
237 case 'm':
238 if ((flags & OPT_FMT_MSBLOB) == 0)
239 return opt_format_error(s, flags);
240 *result = FORMAT_MSBLOB;
241 break;
242 case 'E':
243 case 'e':
244 if ((flags & OPT_FMT_ENGINE) == 0)
245 return opt_format_error(s, flags);
246 *result = FORMAT_ENGINE;
247 break;
248 case 'H':
249 case 'h':
250 if ((flags & OPT_FMT_HTTP) == 0)
251 return opt_format_error(s, flags);
252 *result = FORMAT_HTTP;
253 break;
254 case '1':
255 if ((flags & OPT_FMT_PKCS12) == 0)
256 return opt_format_error(s, flags);
257 *result = FORMAT_PKCS12;
258 break;
259 case 'P':
260 case 'p':
261 if (s[1] == '\0' || strcmp(s, "PEM") == 0 || strcmp(s, "pem") == 0) {
262 if ((flags & OPT_FMT_PEMDER) == 0)
263 return opt_format_error(s, flags);
264 *result = FORMAT_PEM;
265 } else if (strcmp(s, "PVK") == 0 || strcmp(s, "pvk") == 0) {
266 if ((flags & OPT_FMT_PVK) == 0)
267 return opt_format_error(s, flags);
268 *result = FORMAT_PVK;
269 } else if (strcmp(s, "P12") == 0 || strcmp(s, "p12") == 0
270 || strcmp(s, "PKCS12") == 0 || strcmp(s, "pkcs12") == 0) {
271 if ((flags & OPT_FMT_PKCS12) == 0)
272 return opt_format_error(s, flags);
273 *result = FORMAT_PKCS12;
2234212c 274 } else {
7e1b7485 275 return 0;
2234212c 276 }
7e1b7485
RS
277 break;
278 }
279 return 1;
280}
281
282/* Parse a cipher name, put it in *EVP_CIPHER; return 0 on failure, else 1. */
283int opt_cipher(const char *name, const EVP_CIPHER **cipherp)
284{
285 *cipherp = EVP_get_cipherbyname(name);
2234212c 286 if (*cipherp != NULL)
7e1b7485 287 return 1;
a43ce58f 288 opt_printf_stderr("%s: Unrecognized flag %s\n", prog, name);
7e1b7485
RS
289 return 0;
290}
291
292/*
293 * Parse message digest name, put it in *EVP_MD; return 0 on failure, else 1.
294 */
295int opt_md(const char *name, const EVP_MD **mdp)
296{
297 *mdp = EVP_get_digestbyname(name);
2234212c 298 if (*mdp != NULL)
7e1b7485 299 return 1;
a43ce58f 300 opt_printf_stderr("%s: Unrecognized flag %s\n", prog, name);
7e1b7485
RS
301 return 0;
302}
303
304/* Look through a list of name/value pairs. */
305int opt_pair(const char *name, const OPT_PAIR* pairs, int *result)
306{
307 const OPT_PAIR *pp;
308
309 for (pp = pairs; pp->name; pp++)
310 if (strcmp(pp->name, name) == 0) {
311 *result = pp->retval;
312 return 1;
313 }
a43ce58f 314 opt_printf_stderr("%s: Value must be one of:\n", prog);
7e1b7485 315 for (pp = pairs; pp->name; pp++)
a43ce58f 316 opt_printf_stderr("\t%s\n", pp->name);
7e1b7485
RS
317 return 0;
318}
319
7e1b7485
RS
320/* Parse an int, put it into *result; return 0 on failure, else 1. */
321int opt_int(const char *value, int *result)
322{
bd4850df
RS
323 long l;
324
325 if (!opt_long(value, &l))
326 return 0;
327 *result = (int)l;
328 if (*result != l) {
a43ce58f
SL
329 opt_printf_stderr("%s: Value \"%s\" outside integer range\n",
330 prog, value);
7e1b7485
RS
331 return 0;
332 }
333 return 1;
334}
335
7447c49f
PY
336static void opt_number_error(const char *v)
337{
338 size_t i = 0;
339 struct strstr_pair_st {
340 char *prefix;
341 char *name;
342 } b[] = {
343 {"0x", "a hexadecimal"},
344 {"0X", "a hexadecimal"},
345 {"0", "an octal"}
346 };
347
348 for (i = 0; i < OSSL_NELEM(b); i++) {
349 if (strncmp(v, b[i].prefix, strlen(b[i].prefix)) == 0) {
a43ce58f
SL
350 opt_printf_stderr("%s: Can't parse \"%s\" as %s number\n",
351 prog, v, b[i].name);
7447c49f
PY
352 return;
353 }
354 }
a43ce58f 355 opt_printf_stderr("%s: Can't parse \"%s\" as a number\n", prog, v);
7447c49f
PY
356 return;
357}
358
7e1b7485
RS
359/* Parse a long, put it into *result; return 0 on failure, else 1. */
360int opt_long(const char *value, long *result)
361{
bd4850df
RS
362 int oerrno = errno;
363 long l;
364 char *endp;
365
c3a7e0c5 366 errno = 0;
bd4850df
RS
367 l = strtol(value, &endp, 0);
368 if (*endp
369 || endp == value
370 || ((l == LONG_MAX || l == LONG_MIN) && errno == ERANGE)
371 || (l == 0 && errno != 0)) {
7447c49f 372 opt_number_error(value);
bd4850df 373 errno = oerrno;
7e1b7485
RS
374 return 0;
375 }
bd4850df
RS
376 *result = l;
377 errno = oerrno;
7e1b7485
RS
378 return 1;
379}
380
d94a1a70 381#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && \
53f54696
SL
382 defined(INTMAX_MAX) && defined(UINTMAX_MAX) && \
383 !defined(OPENSSL_NO_INTTYPES_H)
03f887ca
VD
384
385/* Parse an intmax_t, put it into *result; return 0 on failure, else 1. */
386int opt_imax(const char *value, intmax_t *result)
387{
388 int oerrno = errno;
389 intmax_t m;
390 char *endp;
391
c3a7e0c5 392 errno = 0;
03f887ca
VD
393 m = strtoimax(value, &endp, 0);
394 if (*endp
395 || endp == value
396 || ((m == INTMAX_MAX || m == INTMAX_MIN) && errno == ERANGE)
397 || (m == 0 && errno != 0)) {
7447c49f 398 opt_number_error(value);
03f887ca
VD
399 errno = oerrno;
400 return 0;
401 }
402 *result = m;
403 errno = oerrno;
404 return 1;
405}
406
407/* Parse a uintmax_t, put it into *result; return 0 on failure, else 1. */
408int opt_umax(const char *value, uintmax_t *result)
409{
410 int oerrno = errno;
411 uintmax_t m;
412 char *endp;
413
c3a7e0c5 414 errno = 0;
03f887ca
VD
415 m = strtoumax(value, &endp, 0);
416 if (*endp
417 || endp == value
418 || (m == UINTMAX_MAX && errno == ERANGE)
419 || (m == 0 && errno != 0)) {
7447c49f 420 opt_number_error(value);
03f887ca
VD
421 errno = oerrno;
422 return 0;
423 }
424 *result = m;
425 errno = oerrno;
426 return 1;
427}
428#endif
429
7e1b7485
RS
430/*
431 * Parse an unsigned long, put it into *result; return 0 on failure, else 1.
432 */
433int opt_ulong(const char *value, unsigned long *result)
434{
bd4850df 435 int oerrno = errno;
7e1b7485 436 char *endptr;
bd4850df
RS
437 unsigned long l;
438
c3a7e0c5 439 errno = 0;
bd4850df
RS
440 l = strtoul(value, &endptr, 0);
441 if (*endptr
442 || endptr == value
443 || ((l == ULONG_MAX) && errno == ERANGE)
444 || (l == 0 && errno != 0)) {
7447c49f 445 opt_number_error(value);
bd4850df 446 errno = oerrno;
7e1b7485
RS
447 return 0;
448 }
bd4850df
RS
449 *result = l;
450 errno = oerrno;
7e1b7485
RS
451 return 1;
452}
453
454/*
455 * We pass opt as an int but cast it to "enum range" so that all the
456 * items in the OPT_V_ENUM enumeration are caught; this makes -Wswitch
457 * in gcc do the right thing.
458 */
459enum range { OPT_V_ENUM };
460
461int opt_verify(int opt, X509_VERIFY_PARAM *vpm)
462{
7e1b7485 463 int i;
03f887ca 464 ossl_intmax_t t = 0;
7e1b7485
RS
465 ASN1_OBJECT *otmp;
466 X509_PURPOSE *xptmp;
467 const X509_VERIFY_PARAM *vtmp;
468
a43ce58f
SL
469 OPENSSL_assert(vpm != NULL);
470 OPENSSL_assert(opt > OPT_V__FIRST);
471 OPENSSL_assert(opt < OPT_V__LAST);
7e1b7485
RS
472
473 switch ((enum range)opt) {
474 case OPT_V__FIRST:
475 case OPT_V__LAST:
476 return 0;
477 case OPT_V_POLICY:
478 otmp = OBJ_txt2obj(opt_arg(), 0);
479 if (otmp == NULL) {
a43ce58f 480 opt_printf_stderr("%s: Invalid Policy %s\n", prog, opt_arg());
7e1b7485
RS
481 return 0;
482 }
483 X509_VERIFY_PARAM_add0_policy(vpm, otmp);
484 break;
485 case OPT_V_PURPOSE:
0daccd4d 486 /* purpose name -> purpose index */
7e1b7485
RS
487 i = X509_PURPOSE_get_by_sname(opt_arg());
488 if (i < 0) {
a43ce58f 489 opt_printf_stderr("%s: Invalid purpose %s\n", prog, opt_arg());
7e1b7485
RS
490 return 0;
491 }
0daccd4d
VD
492
493 /* purpose index -> purpose object */
7e1b7485 494 xptmp = X509_PURPOSE_get0(i);
0daccd4d
VD
495
496 /* purpose object -> purpose value */
7e1b7485 497 i = X509_PURPOSE_get_id(xptmp);
0daccd4d
VD
498
499 if (!X509_VERIFY_PARAM_set_purpose(vpm, i)) {
a43ce58f
SL
500 opt_printf_stderr("%s: Internal error setting purpose %s\n",
501 prog, opt_arg());
0daccd4d
VD
502 return 0;
503 }
7e1b7485
RS
504 break;
505 case OPT_V_VERIFY_NAME:
506 vtmp = X509_VERIFY_PARAM_lookup(opt_arg());
507 if (vtmp == NULL) {
a43ce58f
SL
508 opt_printf_stderr("%s: Invalid verify name %s\n",
509 prog, opt_arg());
7e1b7485
RS
510 return 0;
511 }
512 X509_VERIFY_PARAM_set1(vpm, vtmp);
513 break;
514 case OPT_V_VERIFY_DEPTH:
515 i = atoi(opt_arg());
516 if (i >= 0)
517 X509_VERIFY_PARAM_set_depth(vpm, i);
518 break;
fbb82a60
VD
519 case OPT_V_VERIFY_AUTH_LEVEL:
520 i = atoi(opt_arg());
521 if (i >= 0)
522 X509_VERIFY_PARAM_set_auth_level(vpm, i);
523 break;
7e1b7485 524 case OPT_V_ATTIME:
03f887ca
VD
525 if (!opt_imax(opt_arg(), &t))
526 return 0;
527 if (t != (time_t)t) {
a43ce58f
SL
528 opt_printf_stderr("%s: epoch time out of range %s\n",
529 prog, opt_arg());
03f887ca
VD
530 return 0;
531 }
532 X509_VERIFY_PARAM_set_time(vpm, (time_t)t);
7e1b7485
RS
533 break;
534 case OPT_V_VERIFY_HOSTNAME:
535 if (!X509_VERIFY_PARAM_set1_host(vpm, opt_arg(), 0))
536 return 0;
537 break;
538 case OPT_V_VERIFY_EMAIL:
539 if (!X509_VERIFY_PARAM_set1_email(vpm, opt_arg(), 0))
540 return 0;
541 break;
542 case OPT_V_VERIFY_IP:
543 if (!X509_VERIFY_PARAM_set1_ip_asc(vpm, opt_arg()))
544 return 0;
545 break;
546 case OPT_V_IGNORE_CRITICAL:
547 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_IGNORE_CRITICAL);
548 break;
549 case OPT_V_ISSUER_CHECKS:
d33def66 550 /* NOP, deprecated */
7e1b7485
RS
551 break;
552 case OPT_V_CRL_CHECK:
553 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CRL_CHECK);
554 break;
555 case OPT_V_CRL_CHECK_ALL:
556 X509_VERIFY_PARAM_set_flags(vpm,
557 X509_V_FLAG_CRL_CHECK |
558 X509_V_FLAG_CRL_CHECK_ALL);
559 break;
560 case OPT_V_POLICY_CHECK:
561 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_POLICY_CHECK);
562 break;
563 case OPT_V_EXPLICIT_POLICY:
564 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_EXPLICIT_POLICY);
565 break;
566 case OPT_V_INHIBIT_ANY:
567 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_INHIBIT_ANY);
568 break;
569 case OPT_V_INHIBIT_MAP:
570 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_INHIBIT_MAP);
571 break;
572 case OPT_V_X509_STRICT:
573 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_X509_STRICT);
574 break;
575 case OPT_V_EXTENDED_CRL:
576 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_EXTENDED_CRL_SUPPORT);
577 break;
578 case OPT_V_USE_DELTAS:
579 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_USE_DELTAS);
580 break;
581 case OPT_V_POLICY_PRINT:
582 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NOTIFY_POLICY);
583 break;
584 case OPT_V_CHECK_SS_SIG:
585 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CHECK_SS_SIGNATURE);
586 break;
587 case OPT_V_TRUSTED_FIRST:
588 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_TRUSTED_FIRST);
589 break;
590 case OPT_V_SUITEB_128_ONLY:
591 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_128_LOS_ONLY);
592 break;
593 case OPT_V_SUITEB_128:
594 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_128_LOS);
595 break;
596 case OPT_V_SUITEB_192:
597 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_192_LOS);
598 break;
599 case OPT_V_PARTIAL_CHAIN:
600 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_PARTIAL_CHAIN);
601 break;
602 case OPT_V_NO_ALT_CHAINS:
603 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_ALT_CHAINS);
dccd20d1 604 break;
d35ff2c0
DW
605 case OPT_V_NO_CHECK_TIME:
606 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_CHECK_TIME);
dccd20d1 607 break;
a392ef20
RL
608 case OPT_V_ALLOW_PROXY_CERTS:
609 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_ALLOW_PROXY_CERTS);
610 break;
7e1b7485
RS
611 }
612 return 1;
613
614}
615
a43ce58f
SL
616void opt_begin(void)
617{
618 opt_index = 1;
619 arg = NULL;
620 flag = NULL;
621}
622
7e1b7485
RS
623/*
624 * Parse the next flag (and value if specified), return 0 if done, -1 on
625 * error, otherwise the flag's retval.
626 */
627int opt_next(void)
628{
96de2e59 629 char *p;
7e1b7485 630 const OPTIONS *o;
bd4850df 631 int ival;
03f887ca
VD
632 long lval;
633 unsigned long ulval;
634 ossl_intmax_t imval;
635 ossl_uintmax_t umval;
7e1b7485
RS
636
637 /* Look at current arg; at end of the list? */
638 arg = NULL;
639 p = argv[opt_index];
640 if (p == NULL)
641 return 0;
642
643 /* If word doesn't start with a -, we're done. */
644 if (*p != '-')
645 return 0;
646
647 /* Hit "--" ? We're done. */
648 opt_index++;
649 if (strcmp(p, "--") == 0)
650 return 0;
651
652 /* Allow -nnn and --nnn */
653 if (*++p == '-')
654 p++;
655 flag = p - 1;
656
657 /* If we have --flag=foo, snip it off */
658 if ((arg = strchr(p, '=')) != NULL)
659 *arg++ = '\0';
660 for (o = opts; o->name; ++o) {
661 /* If not this option, move on to the next one. */
662 if (strcmp(p, o->name) != 0)
663 continue;
664
665 /* If it doesn't take a value, make sure none was given. */
666 if (o->valtype == 0 || o->valtype == '-') {
667 if (arg) {
a43ce58f
SL
668 opt_printf_stderr("%s: Option -%s does not take a value\n",
669 prog, p);
7e1b7485
RS
670 return -1;
671 }
672 return o->retval;
673 }
674
675 /* Want a value; get the next param if =foo not used. */
676 if (arg == NULL) {
677 if (argv[opt_index] == NULL) {
a43ce58f
SL
678 opt_printf_stderr("%s: Option -%s needs a value\n",
679 prog, o->name);
7e1b7485
RS
680 return -1;
681 }
682 arg = argv[opt_index++];
683 }
684
685 /* Syntax-check value. */
7e1b7485
RS
686 switch (o->valtype) {
687 default:
688 case 's':
689 /* Just a string. */
690 break;
691 case '/':
a43ce58f 692 if (opt_isdir(arg) > 0)
7e1b7485 693 break;
a43ce58f 694 opt_printf_stderr("%s: Not a directory: %s\n", prog, arg);
7e1b7485
RS
695 return -1;
696 case '<':
697 /* Input file. */
4522e130 698 break;
7e1b7485
RS
699 case '>':
700 /* Output file. */
4522e130 701 break;
7e1b7485
RS
702 case 'p':
703 case 'n':
bd4850df
RS
704 if (!opt_int(arg, &ival)
705 || (o->valtype == 'p' && ival <= 0)) {
a43ce58f
SL
706 opt_printf_stderr("%s: Non-positive number \"%s\" for -%s\n",
707 prog, arg, o->name);
bd4850df 708 return -1;
7e1b7485 709 }
bd4850df 710 break;
03f887ca
VD
711 case 'M':
712 if (!opt_imax(arg, &imval)) {
a43ce58f
SL
713 opt_printf_stderr("%s: Invalid number \"%s\" for -%s\n",
714 prog, arg, o->name);
03f887ca
VD
715 return -1;
716 }
717 break;
718 case 'U':
719 if (!opt_umax(arg, &umval)) {
a43ce58f
SL
720 opt_printf_stderr("%s: Invalid number \"%s\" for -%s\n",
721 prog, arg, o->name);
03f887ca
VD
722 return -1;
723 }
724 break;
0c20802c 725 case 'l':
03f887ca 726 if (!opt_long(arg, &lval)) {
a43ce58f
SL
727 opt_printf_stderr("%s: Invalid number \"%s\" for -%s\n",
728 prog, arg, o->name);
03f887ca
VD
729 return -1;
730 }
731 break;
7e1b7485 732 case 'u':
03f887ca 733 if (!opt_ulong(arg, &ulval)) {
a43ce58f
SL
734 opt_printf_stderr("%s: Invalid number \"%s\" for -%s\n",
735 prog, arg, o->name);
bd4850df
RS
736 return -1;
737 }
738 break;
f47e5647 739 case 'c':
0c20802c 740 case 'E':
7e1b7485 741 case 'F':
0c20802c 742 case 'f':
7e1b7485 743 if (opt_format(arg,
f47e5647 744 o->valtype == 'c' ? OPT_FMT_PDS :
0c20802c 745 o->valtype == 'E' ? OPT_FMT_PDE :
7e1b7485 746 o->valtype == 'F' ? OPT_FMT_PEMDER
bd4850df 747 : OPT_FMT_ANY, &ival))
7e1b7485 748 break;
a43ce58f
SL
749 opt_printf_stderr("%s: Invalid format \"%s\" for -%s\n",
750 prog, arg, o->name);
7e1b7485
RS
751 return -1;
752 }
753
754 /* Return the flag value. */
755 return o->retval;
756 }
757 if (unknown != NULL) {
758 dunno = p;
759 return unknown->retval;
760 }
a43ce58f 761 opt_printf_stderr("%s: Option unknown option -%s\n", prog, p);
7e1b7485
RS
762 return -1;
763}
764
765/* Return the most recent flag parameter. */
766char *opt_arg(void)
767{
768 return arg;
769}
770
771/* Return the most recent flag. */
772char *opt_flag(void)
773{
774 return flag;
775}
776
777/* Return the unknown option. */
778char *opt_unknown(void)
779{
780 return dunno;
781}
782
783/* Return the rest of the arguments after parsing flags. */
784char **opt_rest(void)
785{
786 return &argv[opt_index];
787}
788
789/* How many items in remaining args? */
790int opt_num_rest(void)
791{
792 int i = 0;
793 char **pp;
794
795 for (pp = opt_rest(); *pp; pp++, i++)
796 continue;
797 return i;
798}
799
800/* Return a string describing the parameter type. */
801static const char *valtype2param(const OPTIONS *o)
802{
803 switch (o->valtype) {
6755ff11 804 case 0:
7e1b7485
RS
805 case '-':
806 return "";
807 case 's':
808 return "val";
809 case '/':
810 return "dir";
811 case '<':
812 return "infile";
813 case '>':
814 return "outfile";
815 case 'p':
0c20802c 816 return "+int";
7e1b7485 817 case 'n':
0c20802c
VD
818 return "int";
819 case 'l':
820 return "long";
7e1b7485 821 case 'u':
0c20802c
VD
822 return "ulong";
823 case 'E':
824 return "PEM|DER|ENGINE";
7e1b7485 825 case 'F':
0c20802c 826 return "PEM|DER";
7e1b7485
RS
827 case 'f':
828 return "format";
0c20802c
VD
829 case 'M':
830 return "intmax";
831 case 'U':
832 return "uintmax";
7e1b7485
RS
833 }
834 return "parm";
835}
836
4ed83891 837void opt_print(const OPTIONS *o, int width)
7e1b7485 838{
4ed83891 839 const char* help;
7e1b7485
RS
840 char start[80 + 1];
841 char *p;
7e1b7485 842
7e1b7485 843 help = o->helpstr ? o->helpstr : "(No additional info)";
4ed83891 844 if (o->name == OPT_HELP_STR || o->name == OPT_SECTION_STR) {
a43ce58f 845 opt_printf_stderr(help, prog);
4ed83891 846 return;
7e1b7485
RS
847 }
848
849 /* Pad out prefix */
16f8d4eb 850 memset(start, ' ', sizeof(start) - 1);
cbe29648 851 start[sizeof(start) - 1] = '\0';
7e1b7485
RS
852
853 if (o->name == OPT_MORE_STR) {
0ad69cd6 854 /* Continuation of previous line; pad and print. */
7e1b7485 855 start[width] = '\0';
a43ce58f 856 opt_printf_stderr("%s %s\n", start, help);
4ed83891 857 return;
7e1b7485
RS
858 }
859
860 /* Build up the "-flag [param]" part. */
861 p = start;
862 *p++ = ' ';
863 *p++ = '-';
864 if (o->name[0])
865 p += strlen(strcpy(p, o->name));
866 else
867 *p++ = '*';
868 if (o->valtype != '-') {
869 *p++ = ' ';
870 p += strlen(strcpy(p, valtype2param(o)));
871 }
872 *p = ' ';
873 if ((int)(p - start) >= MAX_OPT_HELP_WIDTH) {
874 *p = '\0';
a43ce58f 875 opt_printf_stderr("%s\n", start);
16f8d4eb 876 memset(start, ' ', sizeof(start));
7e1b7485
RS
877 }
878 start[width] = '\0';
a43ce58f 879 opt_printf_stderr("%s %s\n", start, help);
4ed83891
JS
880}
881
882void opt_help(const OPTIONS *list)
883{
884 const OPTIONS *o;
885 int i;
886 int standard_prolog;
887 int width = 5;
888 char start[80 + 1];
889
890 /* Starts with its own help message? */
891 standard_prolog = list[0].name != OPT_HELP_STR;
892
893 /* Find the widest help. */
894 for (o = list; o->name; o++) {
895 if (o->name == OPT_MORE_STR)
896 continue;
897 i = 2 + (int)strlen(o->name);
898 if (o->valtype != '-')
899 i += 1 + strlen(valtype2param(o));
900 if (i < MAX_OPT_HELP_WIDTH && i > width)
901 width = i;
902 OPENSSL_assert(i < (int)sizeof(start));
903 }
904
905 if (standard_prolog) {
906 opt_printf_stderr("Usage: %s [options]\n", prog);
907 if (list[0].name != OPT_SECTION_STR)
908 opt_printf_stderr("Valid options are:\n", prog);
909 }
910
911 /* Now let's print. */
912 for (o = list; o->name; o++) {
913 opt_print(o, width);
7e1b7485
RS
914 }
915}
a43ce58f
SL
916
917/* opt_isdir section */
918#ifdef _WIN32
919# include <windows.h>
920int opt_isdir(const char *name)
921{
922 DWORD attr;
923# if defined(UNICODE) || defined(_UNICODE)
924 size_t i, len_0 = strlen(name) + 1;
925 WCHAR tempname[MAX_PATH];
926
927 if (len_0 > MAX_PATH)
928 return -1;
929
930# if !defined(_WIN32_WCE) || _WIN32_WCE>=101
931 if (!MultiByteToWideChar(CP_ACP, 0, name, len_0, tempname, MAX_PATH))
932# endif
933 for (i = 0; i < len_0; i++)
934 tempname[i] = (WCHAR)name[i];
935
936 attr = GetFileAttributes(tempname);
937# else
938 attr = GetFileAttributes(name);
939# endif
940 if (attr == INVALID_FILE_ATTRIBUTES)
941 return -1;
942 return ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0);
943}
944#else
945# include <sys/stat.h>
946# ifndef S_ISDIR
947# if defined(_S_IFMT) && defined(_S_IFDIR)
948# define S_ISDIR(a) (((a) & _S_IFMT) == _S_IFDIR)
949# else
950# define S_ISDIR(a) (((a) & S_IFMT) == S_IFDIR)
951# endif
952# endif
953
954int opt_isdir(const char *name)
955{
956# if defined(S_ISDIR)
957 struct stat st;
958
959 if (stat(name, &st) == 0)
960 return S_ISDIR(st.st_mode);
961 else
962 return -1;
963# else
964 return -1;
965# endif
966}
967#endif