1 /*
2  * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
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
8  */
9 
10 #include "internal/e_os.h"
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include "internal/common.h"
15 #include <openssl/bio.h>
16 #include <openssl/crypto.h>
17 #include <openssl/trace.h>
18 #include <openssl/lhash.h>
19 #include <openssl/conf.h>
20 #include <openssl/x509.h>
21 #include <openssl/pem.h>
22 #include <openssl/ssl.h>
23 #ifndef OPENSSL_NO_ENGINE
24 # include <openssl/engine.h>
25 #endif
26 #include <openssl/err.h>
27 /* Needed to get the other O_xxx flags. */
28 #ifdef OPENSSL_SYS_VMS
29 # include <unixio.h>
30 #endif
31 #include "apps.h"
32 #include "progs.h"
33 
34 /*
35  * The LHASH callbacks ("hash" & "cmp") have been replaced by functions with
36  * the base prototypes (we cast each variable inside the function to the
37  * required type of "FUNCTION*"). This removes the necessity for
38  * macro-generated wrapper functions.
39  */
40 static LHASH_OF(FUNCTION) *prog_init(void);
41 static int do_cmd(LHASH_OF(FUNCTION) *prog, int argc, char *argv[]);
42 char *default_config_file = NULL;
43 
44 BIO *bio_in = NULL;
45 BIO *bio_out = NULL;
46 BIO *bio_err = NULL;
47 
warn_deprecated(const FUNCTION * fp)48 static void warn_deprecated(const FUNCTION *fp)
49 {
50     if (fp->deprecated_version != NULL)
51         BIO_printf(bio_err, "The command %s was deprecated in version %s.",
52                    fp->name, fp->deprecated_version);
53     else
54         BIO_printf(bio_err, "The command %s is deprecated.", fp->name);
55     if (strcmp(fp->deprecated_alternative, DEPRECATED_NO_ALTERNATIVE) != 0)
56         BIO_printf(bio_err, " Use '%s' instead.", fp->deprecated_alternative);
57     BIO_printf(bio_err, "\n");
58 }
59 
apps_startup(void)60 static int apps_startup(void)
61 {
62     const char *use_libctx = NULL;
63 #ifdef SIGPIPE
64     signal(SIGPIPE, SIG_IGN);
65 #endif
66 
67     /* Set non-default library initialisation settings */
68     if (!OPENSSL_init_ssl(OPENSSL_INIT_ENGINE_ALL_BUILTIN
69                           | OPENSSL_INIT_LOAD_CONFIG, NULL))
70         return 0;
71 
72     (void)setup_ui_method();
73     (void)setup_engine_loader();
74 
75     /*
76      * NOTE: This is an undocumented feature required for testing only.
77      * There are no guarantees that it will exist in future builds.
78      */
79     use_libctx = getenv("OPENSSL_TEST_LIBCTX");
80     if (use_libctx != NULL) {
81         /* Set this to "1" to create a global libctx */
82         if (strcmp(use_libctx, "1") == 0) {
83             if (app_create_libctx() == NULL)
84                 return 0;
85         }
86     }
87 
88     return 1;
89 }
90 
apps_shutdown(void)91 static void apps_shutdown(void)
92 {
93     app_providers_cleanup();
94     OSSL_LIB_CTX_free(app_get0_libctx());
95     destroy_engine_loader();
96     destroy_ui_method();
97 }
98 
99 
100 #ifndef OPENSSL_NO_TRACE
101 typedef struct tracedata_st {
102     BIO *bio;
103     unsigned int ingroup:1;
104 } tracedata;
105 
internal_trace_cb(const char * buf,size_t cnt,int category,int cmd,void * vdata)106 static size_t internal_trace_cb(const char *buf, size_t cnt,
107                                 int category, int cmd, void *vdata)
108 {
109     int ret = 0;
110     tracedata *trace_data = vdata;
111     char buffer[256], *hex;
112     CRYPTO_THREAD_ID tid;
113 
114     switch (cmd) {
115     case OSSL_TRACE_CTRL_BEGIN:
116         if (trace_data->ingroup) {
117             BIO_printf(bio_err, "ERROR: tracing already started\n");
118             return 0;
119         }
120         trace_data->ingroup = 1;
121 
122         tid = CRYPTO_THREAD_get_current_id();
123         hex = OPENSSL_buf2hexstr((const unsigned char *)&tid, sizeof(tid));
124         BIO_snprintf(buffer, sizeof(buffer), "TRACE[%s]:%s: ",
125                      hex == NULL ? "<null>" : hex,
126                      OSSL_trace_get_category_name(category));
127         OPENSSL_free(hex);
128         BIO_set_prefix(trace_data->bio, buffer);
129         break;
130     case OSSL_TRACE_CTRL_WRITE:
131         if (!trace_data->ingroup) {
132             BIO_printf(bio_err, "ERROR: writing when tracing not started\n");
133             return 0;
134         }
135         if (cnt > INT_MAX)
136             cnt = INT_MAX;
137 
138         ret = BIO_write(trace_data->bio, buf, (int)cnt);
139         break;
140     case OSSL_TRACE_CTRL_END:
141         if (!trace_data->ingroup) {
142             BIO_printf(bio_err, "ERROR: finishing when tracing not started\n");
143             return 0;
144         }
145         trace_data->ingroup = 0;
146 
147         BIO_set_prefix(trace_data->bio, NULL);
148 
149         break;
150     }
151 
152     return ret < 0 ? 0 : ret;
153 }
154 
155 DEFINE_STACK_OF(tracedata)
156 static STACK_OF(tracedata) *trace_data_stack;
157 
tracedata_free(tracedata * data)158 static void tracedata_free(tracedata *data)
159 {
160     BIO_free_all(data->bio);
161     OPENSSL_free(data);
162 }
163 
cleanup_trace(void)164 static void cleanup_trace(void)
165 {
166     sk_tracedata_pop_free(trace_data_stack, tracedata_free);
167 }
168 
setup_trace_category(int category)169 static void setup_trace_category(int category)
170 {
171     BIO *channel;
172     tracedata *trace_data;
173     BIO *bio = NULL;
174 
175     if (OSSL_trace_enabled(category))
176         return;
177 
178     bio = BIO_new(BIO_f_prefix());
179     channel = BIO_push(bio, dup_bio_err(FORMAT_TEXT));
180     trace_data = OPENSSL_zalloc(sizeof(*trace_data));
181 
182     if (trace_data == NULL
183         || bio == NULL
184         || (trace_data->bio = channel) == NULL
185         || OSSL_trace_set_callback(category, internal_trace_cb,
186                                    trace_data) == 0
187         || sk_tracedata_push(trace_data_stack, trace_data) == 0) {
188 
189         fprintf(stderr,
190                 "warning: unable to setup trace callback for category '%s'.\n",
191                 OSSL_trace_get_category_name(category));
192 
193         OSSL_trace_set_callback(category, NULL, NULL);
194         BIO_free_all(channel);
195         OPENSSL_free(trace_data);
196     }
197 }
198 
setup_trace(const char * str)199 static void setup_trace(const char *str)
200 {
201     char *val;
202 
203     /*
204      * We add this handler as early as possible to ensure it's executed
205      * as late as possible, i.e. after the TRACE code has done its cleanup
206      * (which happens last in OPENSSL_cleanup).
207      */
208     atexit(cleanup_trace);
209 
210     trace_data_stack = sk_tracedata_new_null();
211     val = OPENSSL_strdup(str);
212 
213     if (val != NULL) {
214         char *valp = val;
215         char *item;
216 
217         for (valp = val; (item = strtok(valp, ",")) != NULL; valp = NULL) {
218             int category = OSSL_trace_get_category_num(item);
219 
220             if (category == OSSL_TRACE_CATEGORY_ALL) {
221                 while (++category < OSSL_TRACE_CATEGORY_NUM)
222                     setup_trace_category(category);
223                 break;
224             } else if (category > 0) {
225                 setup_trace_category(category);
226             } else {
227                 fprintf(stderr,
228                         "warning: unknown trace category: '%s'.\n", item);
229             }
230         }
231     }
232 
233     OPENSSL_free(val);
234 }
235 #endif /* OPENSSL_NO_TRACE */
236 
237 static char *help_argv[] = { "help", NULL };
238 static char *version_argv[] = { "version", NULL };
239 
main(int argc,char * argv[])240 int main(int argc, char *argv[])
241 {
242     FUNCTION f, *fp;
243     LHASH_OF(FUNCTION) *prog = NULL;
244     char *pname;
245     const char *fname;
246     ARGS arg;
247     int global_help = 0;
248     int global_version = 0;
249     int ret = 0;
250     char *sec_mem_char = NULL;
251 #ifndef OPENSSL_NO_SECURE_MEMORY
252     char *sec_mem_minsize_char = NULL;
253 #endif
254 
255     arg.argv = NULL;
256     arg.size = 0;
257 
258     /* Set up some of the environment. */
259     bio_in = dup_bio_in(FORMAT_TEXT);
260     bio_out = dup_bio_out(FORMAT_TEXT);
261     bio_err = dup_bio_err(FORMAT_TEXT);
262 
263 #if defined(OPENSSL_SYS_VMS) && defined(__DECC)
264     argv = copy_argv(&argc, argv);
265 #elif defined(_WIN32)
266     /* Replace argv[] with UTF-8 encoded strings. */
267     win32_utf8argv(&argc, &argv);
268 #endif
269 
270 #ifndef OPENSSL_NO_TRACE
271     setup_trace(getenv("OPENSSL_TRACE"));
272 #endif
273 
274     sec_mem_char = getenv("OPENSSL_SEC_MEM");
275     if (sec_mem_char != NULL) {
276 #ifndef OPENSSL_NO_SECURE_MEMORY
277         long sec_mem = 0;
278         long sec_mem_minsize = 0;
279         char *end = NULL;
280 
281         errno = 0;
282         sec_mem = strtol(sec_mem_char, &end, 0);
283         if (errno != 0 || *end != 0 || end == sec_mem_char) {
284             BIO_printf(bio_err,
285                        "FATAL: could not convert OPENSSL_SEC_MEM (%s) to number\n",
286                        sec_mem_char);
287             ret = EXIT_FAILURE;
288             goto end;
289         }
290 
291         /*
292          * Try to fetch the minsize if given, if not use the default value.
293          */
294         sec_mem_minsize_char = getenv("OPENSSL_SEC_MEM_MINSIZE");
295         if (sec_mem_minsize_char != NULL) {
296             errno = 0;
297             sec_mem_minsize = strtol(sec_mem_minsize_char, &end, 0);
298             if (errno != 0 || *end != 0 || end == sec_mem_minsize_char) {
299                 BIO_printf(bio_err,
300                            "FATAL: could not convert OPENSSL_SEC_MEM_MINSIZE (%s) to number\n",
301                            sec_mem_minsize_char);
302                 ret = 1;
303                 goto end;
304             }
305         }
306 
307         ret = CRYPTO_secure_malloc_init(sec_mem, sec_mem_minsize);
308         if (ret != 1) {
309             BIO_printf(bio_err,
310                        "FATAL: could not initialize secure memory\n");
311             ERR_print_errors(bio_err);
312             ret = 1;
313             goto end;
314         }
315 #else
316         BIO_printf(bio_err,
317                    "FATAL: OPENSSL_SEC_MEM environment variable was set, but "
318                    "openssl was compiled without secure memory support.\n");
319 #endif
320     }
321 
322     if ((fname = "apps_startup", !apps_startup())
323             || (fname = "prog_init", (prog = prog_init()) == NULL)) {
324         BIO_printf(bio_err,
325                    "FATAL: Startup failure (dev note: %s()) for %s\n",
326                    fname, argv[0]);
327         ERR_print_errors(bio_err);
328         ret = 1;
329         goto end;
330     }
331     pname = opt_progname(argv[0]);
332 
333     default_config_file = CONF_get1_default_config_file();
334     if (default_config_file == NULL)
335         app_bail_out("%s: could not get default config file\n", pname);
336 
337     /* first check the program name */
338     f.name = pname;
339     fp = lh_FUNCTION_retrieve(prog, &f);
340     if (fp == NULL) {
341         /* We assume we've been called as 'openssl ...' */
342         global_help = argc > 1
343             && (strcmp(argv[1], "-help") == 0 || strcmp(argv[1], "--help") == 0
344                 || strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--h") == 0);
345         global_version = argc > 1
346             && (strcmp(argv[1], "-version") == 0 || strcmp(argv[1], "--version") == 0
347                 || strcmp(argv[1], "-v") == 0 || strcmp(argv[1], "--v") == 0);
348 
349         argc--;
350         argv++;
351         opt_appname(argc == 1 || global_help ? "help" : global_version ? "version" : argv[0]);
352     } else {
353         argv[0] = pname;
354     }
355 
356     /*
357      * If there's no command, assume "help". If there's an override for help
358      * or version run those, otherwise run the command given.
359      */
360     ret =  (argc == 0) || global_help
361             ? do_cmd(prog, 1, help_argv)
362             : global_version
363                 ? do_cmd(prog, 1, version_argv)
364                 : do_cmd(prog, argc, argv);
365 
366  end:
367     OPENSSL_free(default_config_file);
368     lh_FUNCTION_free(prog);
369     OPENSSL_free(arg.argv);
370     if (!app_RAND_write())
371         ret = EXIT_FAILURE;
372 
373     BIO_free(bio_in);
374     BIO_free_all(bio_out);
375     apps_shutdown();
376     BIO_free_all(bio_err);
377 #ifndef OPENSSL_NO_SECURE_MEMORY
378     CRYPTO_secure_malloc_done();
379 #endif
380     EXIT(ret);
381 }
382 
383 typedef enum HELP_CHOICE {
384     OPT_hERR = -1, OPT_hEOF = 0, OPT_hHELP
385 } HELP_CHOICE;
386 
387 const OPTIONS help_options[] = {
388     {OPT_HELP_STR, 1, '-', "Usage: help [options] [command]\n"},
389 
390     OPT_SECTION("General"),
391     {"help", OPT_hHELP, '-', "Display this summary"},
392 
393     OPT_PARAMETERS(),
394     {"command", 0, 0, "Name of command to display help (optional)"},
395     {NULL}
396 };
397 
help_main(int argc,char ** argv)398 int help_main(int argc, char **argv)
399 {
400     FUNCTION *fp;
401     int i, nl;
402     FUNC_TYPE tp;
403     char *prog;
404     HELP_CHOICE o;
405     DISPLAY_COLUMNS dc;
406     char *new_argv[3];
407 
408     prog = opt_init(argc, argv, help_options);
409     while ((o = opt_next()) != OPT_hEOF) {
410         switch (o) {
411         case OPT_hERR:
412         case OPT_hEOF:
413             BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
414             return 1;
415         case OPT_hHELP:
416             opt_help(help_options);
417             return 0;
418         }
419     }
420 
421     /* One optional argument, the command to get help for. */
422     if (opt_num_rest() == 1) {
423         new_argv[0] = opt_rest()[0];
424         new_argv[1] = "--help";
425         new_argv[2] = NULL;
426         return do_cmd(prog_init(), 2, new_argv);
427     }
428     if (!opt_check_rest_arg(NULL)) {
429         BIO_printf(bio_err, "Usage: %s\n", prog);
430         return 1;
431     }
432 
433     calculate_columns(functions, &dc);
434     BIO_printf(bio_err, "%s:\n\nStandard commands", prog);
435     i = 0;
436     tp = FT_none;
437     for (fp = functions; fp->name != NULL; fp++) {
438         nl = 0;
439         if (i++ % dc.columns == 0) {
440             BIO_printf(bio_err, "\n");
441             nl = 1;
442         }
443         if (fp->type != tp) {
444             tp = fp->type;
445             if (!nl)
446                 BIO_printf(bio_err, "\n");
447             if (tp == FT_md) {
448                 i = 1;
449                 BIO_printf(bio_err,
450                            "\nMessage Digest commands (see the `dgst' command for more details)\n");
451             } else if (tp == FT_cipher) {
452                 i = 1;
453                 BIO_printf(bio_err,
454                            "\nCipher commands (see the `enc' command for more details)\n");
455             }
456         }
457         BIO_printf(bio_err, "%-*s", dc.width, fp->name);
458     }
459     BIO_printf(bio_err, "\n\n");
460     return 0;
461 }
462 
do_cmd(LHASH_OF (FUNCTION)* prog,int argc,char * argv[])463 static int do_cmd(LHASH_OF(FUNCTION) *prog, int argc, char *argv[])
464 {
465     FUNCTION f, *fp;
466 
467     if (argc <= 0 || argv[0] == NULL)
468         return 0;
469     memset(&f, 0, sizeof(f));
470     f.name = argv[0];
471     fp = lh_FUNCTION_retrieve(prog, &f);
472     if (fp == NULL) {
473         if (EVP_get_digestbyname(argv[0])) {
474             f.type = FT_md;
475             f.func = dgst_main;
476             fp = &f;
477         } else if (EVP_get_cipherbyname(argv[0])) {
478             f.type = FT_cipher;
479             f.func = enc_main;
480             fp = &f;
481         }
482     }
483     if (fp != NULL) {
484         if (fp->deprecated_alternative != NULL)
485             warn_deprecated(fp);
486         return fp->func(argc, argv);
487     }
488     f.name = argv[0];
489     if (CHECK_AND_SKIP_PREFIX(f.name, "no-")) {
490         /*
491          * User is asking if foo is unsupported, by trying to "run" the
492          * no-foo command.  Strange.
493          */
494         if (lh_FUNCTION_retrieve(prog, &f) == NULL) {
495             BIO_printf(bio_out, "%s\n", argv[0]);
496             return 0;
497         }
498         BIO_printf(bio_out, "%s\n", argv[0] + 3);
499         return 1;
500     }
501 
502     BIO_printf(bio_err, "Invalid command '%s'; type \"help\" for a list.\n",
503                argv[0]);
504     return 1;
505 }
506 
function_cmp(const FUNCTION * a,const FUNCTION * b)507 static int function_cmp(const FUNCTION *a, const FUNCTION *b)
508 {
509     return strncmp(a->name, b->name, 8);
510 }
511 
function_hash(const FUNCTION * a)512 static unsigned long function_hash(const FUNCTION *a)
513 {
514     return OPENSSL_LH_strhash(a->name);
515 }
516 
SortFnByName(const void * _f1,const void * _f2)517 static int SortFnByName(const void *_f1, const void *_f2)
518 {
519     const FUNCTION *f1 = _f1;
520     const FUNCTION *f2 = _f2;
521 
522     if (f1->type != f2->type)
523         return f1->type - f2->type;
524     return strcmp(f1->name, f2->name);
525 }
526 
LHASH_OF(FUNCTION)527 static LHASH_OF(FUNCTION) *prog_init(void)
528 {
529     static LHASH_OF(FUNCTION) *ret = NULL;
530     static int prog_inited = 0;
531     FUNCTION *f;
532     size_t i;
533 
534     if (prog_inited)
535         return ret;
536 
537     prog_inited = 1;
538 
539     /* Sort alphabetically within category. For nicer help displays. */
540     for (i = 0, f = functions; f->name != NULL; ++f, ++i)
541         ;
542     qsort(functions, i, sizeof(*functions), SortFnByName);
543 
544     if ((ret = lh_FUNCTION_new(function_hash, function_cmp)) == NULL)
545         return NULL;
546 
547     for (f = functions; f->name != NULL; f++)
548         (void)lh_FUNCTION_insert(ret, f);
549     return ret;
550 }
551