X-Git-Url: https://git.openssl.org/gitweb/?a=blobdiff_plain;f=apps%2Fopenssl.c;h=6b2c2b9c6ba7512ce8979e1b2c5e14783da9556f;hb=914f97eecc9166fbfdb50c2d04e2b9f9d0c52198;hp=fceb458542a6685db73d485aa5d6483ab5960f79;hpb=f3b3d7f0033080f86ede5a53e8af2fb313091b5a;p=openssl.git diff --git a/apps/openssl.c b/apps/openssl.c index fceb458542..6b2c2b9c6b 100644 --- a/apps/openssl.c +++ b/apps/openssl.c @@ -1,17 +1,19 @@ /* - * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ +#include #include #include #include #include #include +#include #include #include #include @@ -21,29 +23,12 @@ # include #endif #include -#ifdef OPENSSL_FIPS -# include -#endif -#define USE_SOCKETS /* needed for the _O_BINARY defs in the MS world */ -#include "s_apps.h" /* Needed to get the other O_xxx flags. */ #ifdef OPENSSL_SYS_VMS # include #endif -#define INCLUDE_FUNCTION_TABLE #include "apps.h" - - -#ifdef OPENSSL_NO_CAMELLIA -# define FORMAT "%-15s" -# define COLUMNS 5 -#else -# define FORMAT "%-18s" -# define COLUMNS 4 -#endif - -/* Special sentinel to exit the program. */ -#define EXIT_THE_PROGRAM (-1) +#include "progs.h" /* * The LHASH callbacks ("hash" & "cmp") have been replaced by functions with @@ -53,84 +38,209 @@ */ static LHASH_OF(FUNCTION) *prog_init(void); static int do_cmd(LHASH_OF(FUNCTION) *prog, int argc, char *argv[]); -static void list_pkey(void); -static void list_type(FUNC_TYPE ft); -static void list_disabled(void); char *default_config_file = NULL; -static CONF *config = NULL; BIO *bio_in = NULL; BIO *bio_out = NULL; BIO *bio_err = NULL; -static int apps_startup() +static void warn_deprecated(const FUNCTION *fp) { + if (fp->deprecated_version != NULL) + BIO_printf(bio_err, "The command %s was deprecated in version %s.", + fp->name, fp->deprecated_version); + else + BIO_printf(bio_err, "The command %s is deprecated.", fp->name); + if (strcmp(fp->deprecated_alternative, DEPRECATED_NO_ALTERNATIVE) != 0) + BIO_printf(bio_err, " Use '%s' instead.", fp->deprecated_alternative); + BIO_printf(bio_err, "\n"); +} + +static int apps_startup(void) +{ + const char *use_libctx = NULL; #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); #endif /* Set non-default library initialisation settings */ - if (!OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_ALL_BUILTIN - | OPENSSL_INIT_LOAD_CONFIG, NULL)) + if (!OPENSSL_init_ssl(OPENSSL_INIT_ENGINE_ALL_BUILTIN + | OPENSSL_INIT_LOAD_CONFIG, NULL)) return 0; -#ifndef OPENSSL_NO_UI setup_ui_method(); -#endif + + /* + * NOTE: This is an undocumented feature required for testing only. + * There are no guarantees that it will exist in future builds. + */ + use_libctx = getenv("OPENSSL_TEST_LIBCTX"); + if (use_libctx != NULL) { + /* Set this to "1" to create a global libctx */ + if (strcmp(use_libctx, "1") == 0) { + if (app_create_libctx() == NULL) + return 0; + } + } return 1; } -static void apps_shutdown() +static void apps_shutdown(void) { -#ifndef OPENSSL_NO_UI + app_providers_cleanup(); + OPENSSL_CTX_free(app_get0_libctx()); destroy_ui_method(); -#endif } -static char *make_config_name() + +#ifndef OPENSSL_NO_TRACE +typedef struct tracedata_st { + BIO *bio; + unsigned int ingroup:1; +} tracedata; + +static size_t internal_trace_cb(const char *buf, size_t cnt, + int category, int cmd, void *vdata) { - const char *t; - size_t len; - char *p; - - if ((t = getenv("OPENSSL_CONF")) != NULL) - return OPENSSL_strdup(t); - - t = X509_get_default_cert_area(); - len = strlen(t) + 1 + strlen(OPENSSL_CONF) + 1; - p = app_malloc(len, "config filename buffer"); - strcpy(p, t); -#ifndef OPENSSL_SYS_VMS - strcat(p, "/"); -#endif - strcat(p, OPENSSL_CONF); + int ret = 0; + tracedata *trace_data = vdata; + char buffer[256], *hex; + CRYPTO_THREAD_ID tid; + + switch (cmd) { + case OSSL_TRACE_CTRL_BEGIN: + if (!ossl_assert(!trace_data->ingroup)) + return 0; + trace_data->ingroup = 1; + + tid = CRYPTO_THREAD_get_current_id(); + hex = OPENSSL_buf2hexstr((const unsigned char *)&tid, sizeof(tid)); + BIO_snprintf(buffer, sizeof(buffer), "TRACE[%s]:%s: ", + hex == NULL ? "" : hex, + OSSL_trace_get_category_name(category)); + OPENSSL_free(hex); + BIO_set_prefix(trace_data->bio, buffer); + break; + case OSSL_TRACE_CTRL_WRITE: + if (!ossl_assert(trace_data->ingroup)) + return 0; + + ret = BIO_write(trace_data->bio, buf, cnt); + break; + case OSSL_TRACE_CTRL_END: + if (!ossl_assert(trace_data->ingroup)) + return 0; + trace_data->ingroup = 0; + + BIO_set_prefix(trace_data->bio, NULL); + + break; + } - return p; + return ret < 0 ? 0 : ret; } +DEFINE_STACK_OF(tracedata) +static STACK_OF(tracedata) *trace_data_stack; + +static void tracedata_free(tracedata *data) +{ + BIO_free_all(data->bio); + OPENSSL_free(data); +} + +static STACK_OF(tracedata) *trace_data_stack; + +static void cleanup_trace(void) +{ + sk_tracedata_pop_free(trace_data_stack, tracedata_free); +} + +static void setup_trace_category(int category) +{ + BIO *channel; + tracedata *trace_data; + + if (OSSL_trace_enabled(category)) + return; + + channel = BIO_push(BIO_new(BIO_f_prefix()), dup_bio_err(FORMAT_TEXT)); + trace_data = OPENSSL_zalloc(sizeof(*trace_data)); + + if (trace_data == NULL + || (trace_data->bio = channel) == NULL + || OSSL_trace_set_callback(category, internal_trace_cb, + trace_data) == 0 + || sk_tracedata_push(trace_data_stack, trace_data) == 0) { + + fprintf(stderr, + "warning: unable to setup trace callback for category '%s'.\n", + OSSL_trace_get_category_name(category)); + + OSSL_trace_set_callback(category, NULL, NULL); + BIO_free_all(channel); + } +} + +static void setup_trace(const char *str) +{ + char *val; + + /* + * We add this handler as early as possible to ensure it's executed + * as late as possible, i.e. after the TRACE code has done its cleanup + * (which happens last in OPENSSL_cleanup). + */ + atexit(cleanup_trace); + + trace_data_stack = sk_tracedata_new_null(); + val = OPENSSL_strdup(str); + + if (val != NULL) { + char *valp = val; + char *item; + + for (valp = val; (item = strtok(valp, ",")) != NULL; valp = NULL) { + int category = OSSL_trace_get_category_num(item); + + if (category == OSSL_TRACE_CATEGORY_ALL) { + while (++category < OSSL_TRACE_CATEGORY_NUM) + setup_trace_category(category); + break; + } else if (category > 0) { + setup_trace_category(category); + } else { + fprintf(stderr, + "warning: unknown trace category: '%s'.\n", item); + } + } + } + + OPENSSL_free(val); +} +#endif /* OPENSSL_NO_TRACE */ + +static char *help_argv[] = { "help", NULL }; + int main(int argc, char *argv[]) { FUNCTION f, *fp; LHASH_OF(FUNCTION) *prog = NULL; - char **copied_argv = NULL; - char *p, *pname; - char buf[1024]; - const char *prompt; + char *pname; ARGS arg; - int first, n, i, ret = 0; + int ret = 0; arg.argv = NULL; arg.size = 0; /* Set up some of the environment. */ - default_config_file = make_config_name(); bio_in = dup_bio_in(FORMAT_TEXT); bio_out = dup_bio_out(FORMAT_TEXT); bio_err = dup_bio_err(FORMAT_TEXT); #if defined(OPENSSL_SYS_VMS) && defined(__DECC) - copied_argv = argv = copy_argv(&argc, argv); + argv = copy_argv(&argc, argv); #elif defined(_WIN32) /* * Replace argv[] with UTF-8 encoded strings. @@ -138,267 +248,71 @@ int main(int argc, char *argv[]) win32_utf8argv(&argc, &argv); #endif - p = getenv("OPENSSL_DEBUG_MEMORY"); - if (p != NULL && strcmp(p, "on") == 0) - CRYPTO_set_mem_debug(1); - CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); - - if (getenv("OPENSSL_FIPS")) { -#ifdef OPENSSL_FIPS - if (!FIPS_mode_set(1)) { - ERR_print_errors(bio_err); - return 1; - } -#else - BIO_printf(bio_err, "FIPS mode not supported.\n"); - return 1; +#ifndef OPENSSL_NO_TRACE + setup_trace(getenv("OPENSSL_TRACE")); #endif - } - if (!apps_startup()) + if (!apps_startup()) { + BIO_printf(bio_err, + "FATAL: Startup failure (dev note: apps_startup() failed)\n"); + ERR_print_errors(bio_err); + ret = 1; goto end; + } prog = prog_init(); + if (prog == NULL) { + BIO_printf(bio_err, + "FATAL: Startup failure (dev note: prog_init() failed)\n"); + ERR_print_errors(bio_err); + ret = 1; + goto end; + } pname = opt_progname(argv[0]); + default_config_file = CONF_get1_default_config_file(); + if (default_config_file == NULL) + app_bail_out("%s: could not get default config file\n", pname); + /* first check the program name */ f.name = pname; fp = lh_FUNCTION_retrieve(prog, &f); - if (fp != NULL) { - argv[0] = pname; - ret = fp->func(argc, argv); - goto end; - } - - /* If there is stuff on the command line, run with that. */ - if (argc != 1) { + if (fp == NULL) { + /* We assume we've been called as 'openssl cmd' */ argc--; argv++; - ret = do_cmd(prog, argc, argv); - if (ret < 0) - ret = 0; - goto end; } - /* ok, lets enter interactive mode */ - for (;;) { - ret = 0; - /* Read a line, continue reading if line ends with \ */ - for (p = buf, n = sizeof buf, i = 0, first = 1; n > 0; first = 0) { - prompt = first ? "OpenSSL> " : "> "; - p[0] = '\0'; -#ifndef READLINE - fputs(prompt, stdout); - fflush(stdout); - if (!fgets(p, n, stdin)) - goto end; - if (p[0] == '\0') - goto end; - i = strlen(p); - if (i <= 1) - break; - if (p[i - 2] != '\\') - break; - i -= 2; - p += i; - n -= i; -#else - { - extern char *readline(const char *); - extern void add_history(const char *cp); - char *text; - - text = readline(prompt); - if (text == NULL) - goto end; - i = strlen(text); - if (i == 0 || i > n) - break; - if (text[i - 1] != '\\') { - p += strlen(strcpy(p, text)); - free(text); - add_history(buf); - break; - } - - text[i - 1] = '\0'; - p += strlen(strcpy(p, text)); - free(text); - n -= i; - } -#endif - } - - if (!chopup_args(&arg, buf)) { - BIO_printf(bio_err, "Can't parse (no memory?)\n"); - break; - } + /* If there's a command, run with that, otherwise "help". */ + ret = argc > 0 + ? do_cmd(prog, argc, argv) + : do_cmd(prog, 1, help_argv); - ret = do_cmd(prog, arg.argc, arg.argv); - if (ret == EXIT_THE_PROGRAM) { - ret = 0; - goto end; - } - if (ret != 0) - BIO_printf(bio_err, "error in %s\n", arg.argv[0]); - (void)BIO_flush(bio_out); - (void)BIO_flush(bio_err); - } - ret = 1; end: - OPENSSL_free(copied_argv); OPENSSL_free(default_config_file); - NCONF_free(config); - config = NULL; lh_FUNCTION_free(prog); OPENSSL_free(arg.argv); + app_RAND_write(); BIO_free(bio_in); BIO_free_all(bio_out); apps_shutdown(); -#ifndef OPENSSL_NO_CRYPTO_MDEBUG - if (CRYPTO_mem_leaks(bio_err) <= 0) - ret = 1; -#endif BIO_free(bio_err); EXIT(ret); } -OPTIONS exit_options[] = { - {NULL} -}; - -static void list_cipher_fn(const EVP_CIPHER *c, - const char *from, const char *to, void *arg) -{ - if (c) - BIO_printf(arg, "%s\n", EVP_CIPHER_name(c)); - else { - if (!from) - from = ""; - if (!to) - to = ""; - BIO_printf(arg, "%s => %s\n", from, to); - } -} - -static void list_md_fn(const EVP_MD *m, - const char *from, const char *to, void *arg) -{ - if (m) - BIO_printf(arg, "%s\n", EVP_MD_name(m)); - else { - if (!from) - from = ""; - if (!to) - to = ""; - BIO_printf((BIO *)arg, "%s => %s\n", from, to); - } -} - -static void list_missing_help(void) -{ - const FUNCTION *fp; - const OPTIONS *o; - - for (fp = functions; fp->name != NULL; fp++) { - if ((o = fp->help) == NULL) { - BIO_printf(bio_out, "%s *\n", fp->name); - continue; - } - for ( ; o->name != NULL; o++) { - if (o->helpstr == NULL) - BIO_printf(bio_out, "%s %s\n", fp->name, o->name); - } - } -} - - -/* Unified enum for help and list commands. */ -typedef enum HELPLIST_CHOICE { - OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, - OPT_COMMANDS, OPT_DIGEST_COMMANDS, - OPT_DIGEST_ALGORITHMS, OPT_CIPHER_COMMANDS, OPT_CIPHER_ALGORITHMS, - OPT_PK_ALGORITHMS, OPT_DISABLED, OPT_MISSING_HELP -} HELPLIST_CHOICE; - -OPTIONS list_options[] = { - {"help", OPT_HELP, '-', "Display this summary"}, - {"commands", OPT_COMMANDS, '-', "List of standard commands"}, - {"digest-commands", OPT_DIGEST_COMMANDS, '-', - "List of message digest commands"}, - {"digest-algorithms", OPT_DIGEST_ALGORITHMS, '-', - "List of message digest algorithms"}, - {"cipher-commands", OPT_CIPHER_COMMANDS, '-', "List of cipher commands"}, - {"cipher-algorithms", OPT_CIPHER_ALGORITHMS, '-', - "List of cipher algorithms"}, - {"public-key-algorithms", OPT_PK_ALGORITHMS, '-', - "List of public key algorithms"}, - {"disabled", OPT_DISABLED, '-', - "List of disabled features"}, - {"missing-help", OPT_MISSING_HELP, '-', - "List missing detailed help strings"}, - {NULL} -}; - -int list_main(int argc, char **argv) -{ - char *prog; - HELPLIST_CHOICE o; - int done = 0; - - prog = opt_init(argc, argv, list_options); - while ((o = opt_next()) != OPT_EOF) { - switch (o) { - case OPT_EOF: /* Never hit, but suppresses warning */ - case OPT_ERR: - BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); - return 1; - case OPT_HELP: - opt_help(list_options); - break; - case OPT_COMMANDS: - list_type(FT_general); - break; - case OPT_DIGEST_COMMANDS: - list_type(FT_md); - break; - case OPT_DIGEST_ALGORITHMS: - EVP_MD_do_all_sorted(list_md_fn, bio_out); - break; - case OPT_CIPHER_COMMANDS: - list_type(FT_cipher); - break; - case OPT_CIPHER_ALGORITHMS: - EVP_CIPHER_do_all_sorted(list_cipher_fn, bio_out); - break; - case OPT_PK_ALGORITHMS: - list_pkey(); - break; - case OPT_DISABLED: - list_disabled(); - break; - case OPT_MISSING_HELP: - list_missing_help(); - break; - } - done = 1; - } - - if (!done) { - BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); - return 1; - } - - return 0; -} - typedef enum HELP_CHOICE { OPT_hERR = -1, OPT_hEOF = 0, OPT_hHELP } HELP_CHOICE; -OPTIONS help_options[] = { +const OPTIONS help_options[] = { + {OPT_HELP_STR, 1, '-', "Usage: help [options] [command]\n"}, + + OPT_SECTION("General"), {"help", OPT_hHELP, '-', "Display this summary"}, + + OPT_PARAMETERS(), + {"command", 0, 0, "Name of command to display help (optional)"}, {NULL} }; @@ -410,6 +324,8 @@ int help_main(int argc, char **argv) FUNC_TYPE tp; char *prog; HELP_CHOICE o; + DISPLAY_COLUMNS dc; + char *new_argv[3]; prog = opt_init(argc, argv, help_options); while ((o = opt_next()) != OPT_hEOF) { @@ -424,17 +340,24 @@ int help_main(int argc, char **argv) } } + if (opt_num_rest() == 1) { + new_argv[0] = opt_rest()[0]; + new_argv[1] = "--help"; + new_argv[2] = NULL; + return do_cmd(prog_init(), 2, new_argv); + } if (opt_num_rest() != 0) { BIO_printf(bio_err, "Usage: %s\n", prog); return 1; } - BIO_printf(bio_err, "\nStandard commands"); + calculate_columns(functions, &dc); + BIO_printf(bio_err, "Standard commands"); i = 0; tp = FT_none; for (fp = functions; fp->name != NULL; fp++) { nl = 0; - if (((i++) % COLUMNS) == 0) { + if (i++ % dc.columns == 0) { BIO_printf(bio_err, "\n"); nl = 1; } @@ -452,37 +375,18 @@ int help_main(int argc, char **argv) "\nCipher commands (see the `enc' command for more details)\n"); } } - BIO_printf(bio_err, FORMAT, fp->name); + BIO_printf(bio_err, "%-*s", dc.width, fp->name); } BIO_printf(bio_err, "\n\n"); return 0; } -int exit_main(int argc, char **argv) -{ - return EXIT_THE_PROGRAM; -} - -static void list_type(FUNC_TYPE ft) -{ - FUNCTION *fp; - int i = 0; - - for (fp = functions; fp->name != NULL; fp++) - if (fp->type == ft) { - if ((i++ % COLUMNS) == 0) - BIO_printf(bio_out, "\n"); - BIO_printf(bio_out, FORMAT, fp->name); - } - BIO_printf(bio_out, "\n"); -} - static int do_cmd(LHASH_OF(FUNCTION) *prog, int argc, char *argv[]) { FUNCTION f, *fp; if (argc <= 0 || argv[0] == NULL) - return (0); + return 0; f.name = argv[0]; fp = lh_FUNCTION_retrieve(prog, &f); if (fp == NULL) { @@ -497,7 +401,9 @@ static int do_cmd(LHASH_OF(FUNCTION) *prog, int argc, char *argv[]) } } if (fp != NULL) { - return (fp->func(argc, argv)); + if (fp->deprecated_alternative != NULL) + warn_deprecated(fp); + return fp->func(argc, argv); } if ((strncmp(argv[0], "no-", 3)) == 0) { /* @@ -507,48 +413,15 @@ static int do_cmd(LHASH_OF(FUNCTION) *prog, int argc, char *argv[]) f.name = argv[0] + 3; if (lh_FUNCTION_retrieve(prog, &f) == NULL) { BIO_printf(bio_out, "%s\n", argv[0]); - return (0); + return 0; } BIO_printf(bio_out, "%s\n", argv[0] + 3); return 1; } - if (strcmp(argv[0], "quit") == 0 || strcmp(argv[0], "q") == 0 || - strcmp(argv[0], "exit") == 0 || strcmp(argv[0], "bye") == 0) - /* Special value to mean "exit the program. */ - return EXIT_THE_PROGRAM; BIO_printf(bio_err, "Invalid command '%s'; type \"help\" for a list.\n", argv[0]); - return (1); -} - -static void list_pkey(void) -{ - int i; - - for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) { - const EVP_PKEY_ASN1_METHOD *ameth; - int pkey_id, pkey_base_id, pkey_flags; - const char *pinfo, *pem_str; - ameth = EVP_PKEY_asn1_get0(i); - EVP_PKEY_asn1_get0_info(&pkey_id, &pkey_base_id, &pkey_flags, - &pinfo, &pem_str, ameth); - if (pkey_flags & ASN1_PKEY_ALIAS) { - BIO_printf(bio_out, "Name: %s\n", OBJ_nid2ln(pkey_id)); - BIO_printf(bio_out, "\tAlias for: %s\n", - OBJ_nid2ln(pkey_base_id)); - } else { - BIO_printf(bio_out, "Name: %s\n", pinfo); - BIO_printf(bio_out, "\tType: %s Algorithm\n", - pkey_flags & ASN1_PKEY_DYNAMIC ? - "External" : "Builtin"); - BIO_printf(bio_out, "\tOID: %s\n", OBJ_nid2ln(pkey_id)); - if (pem_str == NULL) - pem_str = "(none)"; - BIO_printf(bio_out, "\tPEM string: %s\n", pem_str); - } - - } + return 1; } static int function_cmp(const FUNCTION * a, const FUNCTION * b) @@ -571,157 +444,27 @@ static int SortFnByName(const void *_f1, const void *_f2) return strcmp(f1->name, f2->name); } -static void list_disabled(void) -{ - BIO_puts(bio_out, "Disabled algorithms:\n"); -#ifdef OPENSSL_NO_BF - BIO_puts(bio_out, "BF\n"); -#endif -#ifndef OPENSSL_NO_BLAKE2 - BIO_puts(bio_out, "BLAKE2\n"); -#endif -#ifdef OPENSSL_NO_CAMELLIA - BIO_puts(bio_out, "CAMELLIA\n"); -#endif -#ifdef OPENSSL_NO_CAST - BIO_puts(bio_out, "CAST\n"); -#endif -#ifdef OPENSSL_NO_CMAC - BIO_puts(bio_out, "CMAC\n"); -#endif -#ifdef OPENSSL_NO_CMS - BIO_puts(bio_out, "CMS\n"); -#endif -#ifdef OPENSSL_NO_COMP - BIO_puts(bio_out, "COMP\n"); -#endif -#ifdef OPENSSL_NO_DES - BIO_puts(bio_out, "DES\n"); -#endif -#ifdef OPENSSL_NO_DGRAM - BIO_puts(bio_out, "DGRAM\n"); -#endif -#ifdef OPENSSL_NO_DH - BIO_puts(bio_out, "DH\n"); -#endif -#ifdef OPENSSL_NO_DSA - BIO_puts(bio_out, "DSA\n"); -#endif -#if defined(OPENSSL_NO_DTLS) - BIO_puts(bio_out, "DTLS\n"); -#endif -#if defined(OPENSSL_NO_DTLS1) - BIO_puts(bio_out, "DTLS1\n"); -#endif -#if defined(OPENSSL_NO_DTLS1_2) - BIO_puts(bio_out, "DTLS1_2\n"); -#endif -#ifdef OPENSSL_NO_EC - BIO_puts(bio_out, "EC\n"); -#endif -#ifdef OPENSSL_NO_EC2M - BIO_puts(bio_out, "EC2M\n"); -#endif -#ifdef OPENSSL_NO_ENGINE - BIO_puts(bio_out, "ENGINE\n"); -#endif -#ifdef OPENSSL_NO_GOST - BIO_puts(bio_out, "GOST\n"); -#endif -#ifdef OPENSSL_NO_HEARTBEATS - BIO_puts(bio_out, "HEARTBEATS\n"); -#endif -#ifdef OPENSSL_NO_IDEA - BIO_puts(bio_out, "IDEA\n"); -#endif -#ifdef OPENSSL_NO_MD2 - BIO_puts(bio_out, "MD2\n"); -#endif -#ifdef OPENSSL_NO_MD4 - BIO_puts(bio_out, "MD4\n"); -#endif -#ifdef OPENSSL_NO_MD5 - BIO_puts(bio_out, "MD5\n"); -#endif -#ifdef OPENSSL_NO_MDC2 - BIO_puts(bio_out, "MDC2\n"); -#endif -#ifdef OPENSSL_NO_OCB - BIO_puts(bio_out, "OCB\n"); -#endif -#ifdef OPENSSL_NO_OCSP - BIO_puts(bio_out, "OCSP\n"); -#endif -#ifdef OPENSSL_NO_PSK - BIO_puts(bio_out, "PSK\n"); -#endif -#ifdef OPENSSL_NO_RC2 - BIO_puts(bio_out, "RC2\n"); -#endif -#ifdef OPENSSL_NO_RC4 - BIO_puts(bio_out, "RC4\n"); -#endif -#ifdef OPENSSL_NO_RC5 - BIO_puts(bio_out, "RC5\n"); -#endif -#ifdef OPENSSL_NO_RMD160 - BIO_puts(bio_out, "RMD160\n"); -#endif -#ifdef OPENSSL_NO_RSA - BIO_puts(bio_out, "RSA\n"); -#endif -#ifdef OPENSSL_NO_SCRYPT - BIO_puts(bio_out, "SCRYPT\n"); -#endif -#ifdef OPENSSL_NO_SCTP - BIO_puts(bio_out, "SCTP\n"); -#endif -#ifdef OPENSSL_NO_SEED - BIO_puts(bio_out, "SEED\n"); -#endif -#ifdef OPENSSL_NO_SOCK - BIO_puts(bio_out, "SOCK\n"); -#endif -#ifdef OPENSSL_NO_SRP - BIO_puts(bio_out, "SRP\n"); -#endif -#ifdef OPENSSL_NO_SRTP - BIO_puts(bio_out, "SRTP\n"); -#endif -#ifdef OPENSSL_NO_SSL3 - BIO_puts(bio_out, "SSL3\n"); -#endif -#ifdef OPENSSL_NO_TLS1 - BIO_puts(bio_out, "TLS1\n"); -#endif -#ifdef OPENSSL_NO_TLS1_1 - BIO_puts(bio_out, "TLS1_1\n"); -#endif -#ifdef OPENSSL_NO_TLS1_2 - BIO_puts(bio_out, "TLS1_2\n"); -#endif -#ifdef OPENSSL_NO_WHIRLPOOL - BIO_puts(bio_out, "WHIRLPOOL\n"); -#endif -#ifndef ZLIB - BIO_puts(bio_out, "ZLIB\n"); -#endif -} - static LHASH_OF(FUNCTION) *prog_init(void) { - LHASH_OF(FUNCTION) *ret; + static LHASH_OF(FUNCTION) *ret = NULL; + static int prog_inited = 0; FUNCTION *f; size_t i; + if (prog_inited) + return ret; + + prog_inited = 1; + /* Sort alphabetically within category. For nicer help displays. */ - for (i = 0, f = functions; f->name != NULL; ++f, ++i) ; + for (i = 0, f = functions; f->name != NULL; ++f, ++i) + ; qsort(functions, i, sizeof(*functions), SortFnByName); if ((ret = lh_FUNCTION_new(function_hash, function_cmp)) == NULL) - return (NULL); + return NULL; for (f = functions; f->name != NULL; f++) (void)lh_FUNCTION_insert(ret, f); - return (ret); + return ret; }