1e71b7053SJung-uk Kim /*
25ac766abSJung-uk Kim * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
374664626SKris Kennaway *
4*b077aed3SPierre Pronchery * Licensed under the Apache License 2.0 (the "License"). You may not use
5e71b7053SJung-uk Kim * this file except in compliance with the License. You can obtain a copy
6e71b7053SJung-uk Kim * in the file LICENSE in the source distribution or at
7e71b7053SJung-uk Kim * https://www.openssl.org/source/license.html
85c87c606SMark Murray */
95c87c606SMark Murray
1074664626SKris Kennaway #include <stdio.h>
1174664626SKris Kennaway #include <string.h>
1274664626SKris Kennaway #include <stdlib.h>
1374664626SKris Kennaway #include <openssl/bio.h>
1474664626SKris Kennaway #include <openssl/crypto.h>
15*b077aed3SPierre Pronchery #include <openssl/trace.h>
1674664626SKris Kennaway #include <openssl/lhash.h>
1774664626SKris Kennaway #include <openssl/conf.h>
1874664626SKris Kennaway #include <openssl/x509.h>
1974664626SKris Kennaway #include <openssl/pem.h>
2074664626SKris Kennaway #include <openssl/ssl.h>
21fceca8a3SJacques Vidrine #ifndef OPENSSL_NO_ENGINE
225c87c606SMark Murray # include <openssl/engine.h>
23fceca8a3SJacques Vidrine #endif
2474664626SKris Kennaway #include <openssl/err.h>
25e71b7053SJung-uk Kim /* Needed to get the other O_xxx flags. */
26e71b7053SJung-uk Kim #ifdef OPENSSL_SYS_VMS
27e71b7053SJung-uk Kim # include <unixio.h>
281f13597dSJung-uk Kim #endif
29e71b7053SJung-uk Kim #include "apps.h"
30e71b7053SJung-uk Kim #include "progs.h"
31e71b7053SJung-uk Kim
326f9291ceSJung-uk Kim /*
336f9291ceSJung-uk Kim * The LHASH callbacks ("hash" & "cmp") have been replaced by functions with
346f9291ceSJung-uk Kim * the base prototypes (we cast each variable inside the function to the
356f9291ceSJung-uk Kim * required type of "FUNCTION*"). This removes the necessity for
366f9291ceSJung-uk Kim * macro-generated wrapper functions.
376f9291ceSJung-uk Kim */
381f13597dSJung-uk Kim static LHASH_OF(FUNCTION) *prog_init(void);
391f13597dSJung-uk Kim static int do_cmd(LHASH_OF(FUNCTION) *prog, int argc, char *argv[]);
4074664626SKris Kennaway char *default_config_file = NULL;
4174664626SKris Kennaway
42e71b7053SJung-uk Kim BIO *bio_in = NULL;
43e71b7053SJung-uk Kim BIO *bio_out = NULL;
4474664626SKris Kennaway BIO *bio_err = NULL;
45e71b7053SJung-uk Kim
warn_deprecated(const FUNCTION * fp)46*b077aed3SPierre Pronchery static void warn_deprecated(const FUNCTION *fp)
47e71b7053SJung-uk Kim {
48*b077aed3SPierre Pronchery if (fp->deprecated_version != NULL)
49*b077aed3SPierre Pronchery BIO_printf(bio_err, "The command %s was deprecated in version %s.",
50*b077aed3SPierre Pronchery fp->name, fp->deprecated_version);
51*b077aed3SPierre Pronchery else
52*b077aed3SPierre Pronchery BIO_printf(bio_err, "The command %s is deprecated.", fp->name);
53*b077aed3SPierre Pronchery if (strcmp(fp->deprecated_alternative, DEPRECATED_NO_ALTERNATIVE) != 0)
54*b077aed3SPierre Pronchery BIO_printf(bio_err, " Use '%s' instead.", fp->deprecated_alternative);
55*b077aed3SPierre Pronchery BIO_printf(bio_err, "\n");
56e71b7053SJung-uk Kim }
57e71b7053SJung-uk Kim
apps_startup(void)58e71b7053SJung-uk Kim static int apps_startup(void)
59e71b7053SJung-uk Kim {
60*b077aed3SPierre Pronchery const char *use_libctx = NULL;
61e71b7053SJung-uk Kim #ifdef SIGPIPE
62e71b7053SJung-uk Kim signal(SIGPIPE, SIG_IGN);
6374664626SKris Kennaway #endif
6474664626SKris Kennaway
65e71b7053SJung-uk Kim /* Set non-default library initialisation settings */
66e71b7053SJung-uk Kim if (!OPENSSL_init_ssl(OPENSSL_INIT_ENGINE_ALL_BUILTIN
67e71b7053SJung-uk Kim | OPENSSL_INIT_LOAD_CONFIG, NULL))
68e71b7053SJung-uk Kim return 0;
69e71b7053SJung-uk Kim
70*b077aed3SPierre Pronchery (void)setup_ui_method();
71*b077aed3SPierre Pronchery (void)setup_engine_loader();
72*b077aed3SPierre Pronchery
73*b077aed3SPierre Pronchery /*
74*b077aed3SPierre Pronchery * NOTE: This is an undocumented feature required for testing only.
75*b077aed3SPierre Pronchery * There are no guarantees that it will exist in future builds.
76*b077aed3SPierre Pronchery */
77*b077aed3SPierre Pronchery use_libctx = getenv("OPENSSL_TEST_LIBCTX");
78*b077aed3SPierre Pronchery if (use_libctx != NULL) {
79*b077aed3SPierre Pronchery /* Set this to "1" to create a global libctx */
80*b077aed3SPierre Pronchery if (strcmp(use_libctx, "1") == 0) {
81*b077aed3SPierre Pronchery if (app_create_libctx() == NULL)
82*b077aed3SPierre Pronchery return 0;
83*b077aed3SPierre Pronchery }
84*b077aed3SPierre Pronchery }
85e71b7053SJung-uk Kim
86e71b7053SJung-uk Kim return 1;
87e71b7053SJung-uk Kim }
88e71b7053SJung-uk Kim
apps_shutdown(void)89e71b7053SJung-uk Kim static void apps_shutdown(void)
905c87c606SMark Murray {
91*b077aed3SPierre Pronchery app_providers_cleanup();
92*b077aed3SPierre Pronchery OSSL_LIB_CTX_free(app_get0_libctx());
93*b077aed3SPierre Pronchery destroy_engine_loader();
94e71b7053SJung-uk Kim destroy_ui_method();
955c87c606SMark Murray }
965c87c606SMark Murray
97*b077aed3SPierre Pronchery
98*b077aed3SPierre Pronchery #ifndef OPENSSL_NO_TRACE
99*b077aed3SPierre Pronchery typedef struct tracedata_st {
100*b077aed3SPierre Pronchery BIO *bio;
101*b077aed3SPierre Pronchery unsigned int ingroup:1;
102*b077aed3SPierre Pronchery } tracedata;
103*b077aed3SPierre Pronchery
internal_trace_cb(const char * buf,size_t cnt,int category,int cmd,void * vdata)104*b077aed3SPierre Pronchery static size_t internal_trace_cb(const char *buf, size_t cnt,
105*b077aed3SPierre Pronchery int category, int cmd, void *vdata)
106e71b7053SJung-uk Kim {
107*b077aed3SPierre Pronchery int ret = 0;
108*b077aed3SPierre Pronchery tracedata *trace_data = vdata;
109*b077aed3SPierre Pronchery char buffer[256], *hex;
110*b077aed3SPierre Pronchery CRYPTO_THREAD_ID tid;
1115c87c606SMark Murray
112*b077aed3SPierre Pronchery switch (cmd) {
113*b077aed3SPierre Pronchery case OSSL_TRACE_CTRL_BEGIN:
114*b077aed3SPierre Pronchery if (trace_data->ingroup) {
115*b077aed3SPierre Pronchery BIO_printf(bio_err, "ERROR: tracing already started\n");
116*b077aed3SPierre Pronchery return 0;
117e71b7053SJung-uk Kim }
118*b077aed3SPierre Pronchery trace_data->ingroup = 1;
119*b077aed3SPierre Pronchery
120*b077aed3SPierre Pronchery tid = CRYPTO_THREAD_get_current_id();
121*b077aed3SPierre Pronchery hex = OPENSSL_buf2hexstr((const unsigned char *)&tid, sizeof(tid));
122*b077aed3SPierre Pronchery BIO_snprintf(buffer, sizeof(buffer), "TRACE[%s]:%s: ",
123*b077aed3SPierre Pronchery hex == NULL ? "<null>" : hex,
124*b077aed3SPierre Pronchery OSSL_trace_get_category_name(category));
125*b077aed3SPierre Pronchery OPENSSL_free(hex);
126*b077aed3SPierre Pronchery BIO_set_prefix(trace_data->bio, buffer);
127*b077aed3SPierre Pronchery break;
128*b077aed3SPierre Pronchery case OSSL_TRACE_CTRL_WRITE:
129*b077aed3SPierre Pronchery if (!trace_data->ingroup) {
130*b077aed3SPierre Pronchery BIO_printf(bio_err, "ERROR: writing when tracing not started\n");
131*b077aed3SPierre Pronchery return 0;
132*b077aed3SPierre Pronchery }
133*b077aed3SPierre Pronchery
134*b077aed3SPierre Pronchery ret = BIO_write(trace_data->bio, buf, cnt);
135*b077aed3SPierre Pronchery break;
136*b077aed3SPierre Pronchery case OSSL_TRACE_CTRL_END:
137*b077aed3SPierre Pronchery if (!trace_data->ingroup) {
138*b077aed3SPierre Pronchery BIO_printf(bio_err, "ERROR: finishing when tracing not started\n");
139*b077aed3SPierre Pronchery return 0;
140*b077aed3SPierre Pronchery }
141*b077aed3SPierre Pronchery trace_data->ingroup = 0;
142*b077aed3SPierre Pronchery
143*b077aed3SPierre Pronchery BIO_set_prefix(trace_data->bio, NULL);
144*b077aed3SPierre Pronchery
145*b077aed3SPierre Pronchery break;
146*b077aed3SPierre Pronchery }
147*b077aed3SPierre Pronchery
148*b077aed3SPierre Pronchery return ret < 0 ? 0 : ret;
149*b077aed3SPierre Pronchery }
150*b077aed3SPierre Pronchery
151*b077aed3SPierre Pronchery DEFINE_STACK_OF(tracedata)
152*b077aed3SPierre Pronchery static STACK_OF(tracedata) *trace_data_stack;
153*b077aed3SPierre Pronchery
tracedata_free(tracedata * data)154*b077aed3SPierre Pronchery static void tracedata_free(tracedata *data)
155*b077aed3SPierre Pronchery {
156*b077aed3SPierre Pronchery BIO_free_all(data->bio);
157*b077aed3SPierre Pronchery OPENSSL_free(data);
158*b077aed3SPierre Pronchery }
159*b077aed3SPierre Pronchery
STACK_OF(tracedata)160*b077aed3SPierre Pronchery static STACK_OF(tracedata) *trace_data_stack;
161*b077aed3SPierre Pronchery
162*b077aed3SPierre Pronchery static void cleanup_trace(void)
163*b077aed3SPierre Pronchery {
164*b077aed3SPierre Pronchery sk_tracedata_pop_free(trace_data_stack, tracedata_free);
165*b077aed3SPierre Pronchery }
166*b077aed3SPierre Pronchery
setup_trace_category(int category)167*b077aed3SPierre Pronchery static void setup_trace_category(int category)
168*b077aed3SPierre Pronchery {
169*b077aed3SPierre Pronchery BIO *channel;
170*b077aed3SPierre Pronchery tracedata *trace_data;
171*b077aed3SPierre Pronchery BIO *bio = NULL;
172*b077aed3SPierre Pronchery
173*b077aed3SPierre Pronchery if (OSSL_trace_enabled(category))
174*b077aed3SPierre Pronchery return;
175*b077aed3SPierre Pronchery
176*b077aed3SPierre Pronchery bio = BIO_new(BIO_f_prefix());
177*b077aed3SPierre Pronchery channel = BIO_push(bio, dup_bio_err(FORMAT_TEXT));
178*b077aed3SPierre Pronchery trace_data = OPENSSL_zalloc(sizeof(*trace_data));
179*b077aed3SPierre Pronchery
180*b077aed3SPierre Pronchery if (trace_data == NULL
181*b077aed3SPierre Pronchery || bio == NULL
182*b077aed3SPierre Pronchery || (trace_data->bio = channel) == NULL
183*b077aed3SPierre Pronchery || OSSL_trace_set_callback(category, internal_trace_cb,
184*b077aed3SPierre Pronchery trace_data) == 0
185*b077aed3SPierre Pronchery || sk_tracedata_push(trace_data_stack, trace_data) == 0) {
186*b077aed3SPierre Pronchery
187*b077aed3SPierre Pronchery fprintf(stderr,
188*b077aed3SPierre Pronchery "warning: unable to setup trace callback for category '%s'.\n",
189*b077aed3SPierre Pronchery OSSL_trace_get_category_name(category));
190*b077aed3SPierre Pronchery
191*b077aed3SPierre Pronchery OSSL_trace_set_callback(category, NULL, NULL);
192*b077aed3SPierre Pronchery BIO_free_all(channel);
193*b077aed3SPierre Pronchery }
194*b077aed3SPierre Pronchery }
195*b077aed3SPierre Pronchery
setup_trace(const char * str)196*b077aed3SPierre Pronchery static void setup_trace(const char *str)
197*b077aed3SPierre Pronchery {
198*b077aed3SPierre Pronchery char *val;
199*b077aed3SPierre Pronchery
200*b077aed3SPierre Pronchery /*
201*b077aed3SPierre Pronchery * We add this handler as early as possible to ensure it's executed
202*b077aed3SPierre Pronchery * as late as possible, i.e. after the TRACE code has done its cleanup
203*b077aed3SPierre Pronchery * (which happens last in OPENSSL_cleanup).
204*b077aed3SPierre Pronchery */
205*b077aed3SPierre Pronchery atexit(cleanup_trace);
206*b077aed3SPierre Pronchery
207*b077aed3SPierre Pronchery trace_data_stack = sk_tracedata_new_null();
208*b077aed3SPierre Pronchery val = OPENSSL_strdup(str);
209*b077aed3SPierre Pronchery
210*b077aed3SPierre Pronchery if (val != NULL) {
211*b077aed3SPierre Pronchery char *valp = val;
212*b077aed3SPierre Pronchery char *item;
213*b077aed3SPierre Pronchery
214*b077aed3SPierre Pronchery for (valp = val; (item = strtok(valp, ",")) != NULL; valp = NULL) {
215*b077aed3SPierre Pronchery int category = OSSL_trace_get_category_num(item);
216*b077aed3SPierre Pronchery
217*b077aed3SPierre Pronchery if (category == OSSL_TRACE_CATEGORY_ALL) {
218*b077aed3SPierre Pronchery while (++category < OSSL_TRACE_CATEGORY_NUM)
219*b077aed3SPierre Pronchery setup_trace_category(category);
220*b077aed3SPierre Pronchery break;
221*b077aed3SPierre Pronchery } else if (category > 0) {
222*b077aed3SPierre Pronchery setup_trace_category(category);
223*b077aed3SPierre Pronchery } else {
224*b077aed3SPierre Pronchery fprintf(stderr,
225*b077aed3SPierre Pronchery "warning: unknown trace category: '%s'.\n", item);
226*b077aed3SPierre Pronchery }
227*b077aed3SPierre Pronchery }
228*b077aed3SPierre Pronchery }
229*b077aed3SPierre Pronchery
230*b077aed3SPierre Pronchery OPENSSL_free(val);
231*b077aed3SPierre Pronchery }
232*b077aed3SPierre Pronchery #endif /* OPENSSL_NO_TRACE */
233*b077aed3SPierre Pronchery
234*b077aed3SPierre Pronchery static char *help_argv[] = { "help", NULL };
235e71b7053SJung-uk Kim
main(int argc,char * argv[])236e71b7053SJung-uk Kim int main(int argc, char *argv[])
23774664626SKris Kennaway {
23874664626SKris Kennaway FUNCTION f, *fp;
2391f13597dSJung-uk Kim LHASH_OF(FUNCTION) *prog = NULL;
240*b077aed3SPierre Pronchery char *pname;
241*b077aed3SPierre Pronchery const char *fname;
242e71b7053SJung-uk Kim ARGS arg;
243*b077aed3SPierre Pronchery int global_help = 0;
244*b077aed3SPierre Pronchery int ret = 0;
24574664626SKris Kennaway
246e71b7053SJung-uk Kim arg.argv = NULL;
247e71b7053SJung-uk Kim arg.size = 0;
2481f13597dSJung-uk Kim
249e71b7053SJung-uk Kim /* Set up some of the environment. */
250e71b7053SJung-uk Kim bio_in = dup_bio_in(FORMAT_TEXT);
251e71b7053SJung-uk Kim bio_out = dup_bio_out(FORMAT_TEXT);
252e71b7053SJung-uk Kim bio_err = dup_bio_err(FORMAT_TEXT);
253e71b7053SJung-uk Kim
254e71b7053SJung-uk Kim #if defined(OPENSSL_SYS_VMS) && defined(__DECC)
2555ac766abSJung-uk Kim argv = copy_argv(&argc, argv);
256e71b7053SJung-uk Kim #elif defined(_WIN32)
257*b077aed3SPierre Pronchery /* Replace argv[] with UTF-8 encoded strings. */
258e71b7053SJung-uk Kim win32_utf8argv(&argc, &argv);
259e71b7053SJung-uk Kim #endif
2601f13597dSJung-uk Kim
261*b077aed3SPierre Pronchery #ifndef OPENSSL_NO_TRACE
262*b077aed3SPierre Pronchery setup_trace(getenv("OPENSSL_TRACE"));
263*b077aed3SPierre Pronchery #endif
2645c87c606SMark Murray
265*b077aed3SPierre Pronchery if ((fname = "apps_startup", !apps_startup())
266*b077aed3SPierre Pronchery || (fname = "prog_init", (prog = prog_init()) == NULL)) {
267e71b7053SJung-uk Kim BIO_printf(bio_err,
268*b077aed3SPierre Pronchery "FATAL: Startup failure (dev note: %s()) for %s\n",
269*b077aed3SPierre Pronchery fname, argv[0]);
27017f01e99SJung-uk Kim ERR_print_errors(bio_err);
27117f01e99SJung-uk Kim ret = 1;
27217f01e99SJung-uk Kim goto end;
27317f01e99SJung-uk Kim }
274e71b7053SJung-uk Kim pname = opt_progname(argv[0]);
27574664626SKris Kennaway
276*b077aed3SPierre Pronchery default_config_file = CONF_get1_default_config_file();
277*b077aed3SPierre Pronchery if (default_config_file == NULL)
278*b077aed3SPierre Pronchery app_bail_out("%s: could not get default config file\n", pname);
279*b077aed3SPierre Pronchery
28074664626SKris Kennaway /* first check the program name */
28174664626SKris Kennaway f.name = pname;
2821f13597dSJung-uk Kim fp = lh_FUNCTION_retrieve(prog, &f);
283*b077aed3SPierre Pronchery if (fp == NULL) {
284*b077aed3SPierre Pronchery /* We assume we've been called as 'openssl ...' */
285*b077aed3SPierre Pronchery global_help = argc > 1
286*b077aed3SPierre Pronchery && (strcmp(argv[1], "-help") == 0 || strcmp(argv[1], "--help") == 0
287*b077aed3SPierre Pronchery || strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--h") == 0);
288e71b7053SJung-uk Kim argc--;
289e71b7053SJung-uk Kim argv++;
290*b077aed3SPierre Pronchery opt_appname(argc == 1 || global_help ? "help" : argv[0]);
291*b077aed3SPierre Pronchery } else {
292*b077aed3SPierre Pronchery argv[0] = pname;
29374664626SKris Kennaway }
29474664626SKris Kennaway
295*b077aed3SPierre Pronchery /* If there's a command, run with that, otherwise "help". */
296*b077aed3SPierre Pronchery ret = argc == 0 || global_help
297*b077aed3SPierre Pronchery ? do_cmd(prog, 1, help_argv)
298*b077aed3SPierre Pronchery : do_cmd(prog, argc, argv);
29974664626SKris Kennaway
30074664626SKris Kennaway end:
301e71b7053SJung-uk Kim OPENSSL_free(default_config_file);
3026f9291ceSJung-uk Kim lh_FUNCTION_free(prog);
303e71b7053SJung-uk Kim OPENSSL_free(arg.argv);
304*b077aed3SPierre Pronchery if (!app_RAND_write())
305*b077aed3SPierre Pronchery ret = EXIT_FAILURE;
30674664626SKris Kennaway
307e71b7053SJung-uk Kim BIO_free(bio_in);
308e71b7053SJung-uk Kim BIO_free_all(bio_out);
309751d2991SJung-uk Kim apps_shutdown();
310*b077aed3SPierre Pronchery BIO_free_all(bio_err);
311e71b7053SJung-uk Kim EXIT(ret);
3126f9291ceSJung-uk Kim }
313751d2991SJung-uk Kim
314e71b7053SJung-uk Kim typedef enum HELP_CHOICE {
315e71b7053SJung-uk Kim OPT_hERR = -1, OPT_hEOF = 0, OPT_hHELP
316e71b7053SJung-uk Kim } HELP_CHOICE;
317e71b7053SJung-uk Kim
318e71b7053SJung-uk Kim const OPTIONS help_options[] = {
319*b077aed3SPierre Pronchery {OPT_HELP_STR, 1, '-', "Usage: help [options] [command]\n"},
320*b077aed3SPierre Pronchery
321*b077aed3SPierre Pronchery OPT_SECTION("General"),
322e71b7053SJung-uk Kim {"help", OPT_hHELP, '-', "Display this summary"},
323*b077aed3SPierre Pronchery
324*b077aed3SPierre Pronchery OPT_PARAMETERS(),
325*b077aed3SPierre Pronchery {"command", 0, 0, "Name of command to display help (optional)"},
326e71b7053SJung-uk Kim {NULL}
327e71b7053SJung-uk Kim };
328e71b7053SJung-uk Kim
329e71b7053SJung-uk Kim
help_main(int argc,char ** argv)330e71b7053SJung-uk Kim int help_main(int argc, char **argv)
331e71b7053SJung-uk Kim {
332e71b7053SJung-uk Kim FUNCTION *fp;
333e71b7053SJung-uk Kim int i, nl;
334e71b7053SJung-uk Kim FUNC_TYPE tp;
335e71b7053SJung-uk Kim char *prog;
336e71b7053SJung-uk Kim HELP_CHOICE o;
337e71b7053SJung-uk Kim DISPLAY_COLUMNS dc;
338*b077aed3SPierre Pronchery char *new_argv[3];
339e71b7053SJung-uk Kim
340e71b7053SJung-uk Kim prog = opt_init(argc, argv, help_options);
341e71b7053SJung-uk Kim while ((o = opt_next()) != OPT_hEOF) {
342e71b7053SJung-uk Kim switch (o) {
343e71b7053SJung-uk Kim case OPT_hERR:
344e71b7053SJung-uk Kim case OPT_hEOF:
345e71b7053SJung-uk Kim BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
346e71b7053SJung-uk Kim return 1;
347e71b7053SJung-uk Kim case OPT_hHELP:
348e71b7053SJung-uk Kim opt_help(help_options);
349e71b7053SJung-uk Kim return 0;
350e71b7053SJung-uk Kim }
351e71b7053SJung-uk Kim }
352e71b7053SJung-uk Kim
353*b077aed3SPierre Pronchery /* One optional argument, the command to get help for. */
354e71b7053SJung-uk Kim if (opt_num_rest() == 1) {
355e71b7053SJung-uk Kim new_argv[0] = opt_rest()[0];
356e71b7053SJung-uk Kim new_argv[1] = "--help";
357e71b7053SJung-uk Kim new_argv[2] = NULL;
358e71b7053SJung-uk Kim return do_cmd(prog_init(), 2, new_argv);
359e71b7053SJung-uk Kim }
360e71b7053SJung-uk Kim if (opt_num_rest() != 0) {
361e71b7053SJung-uk Kim BIO_printf(bio_err, "Usage: %s\n", prog);
362e71b7053SJung-uk Kim return 1;
363e71b7053SJung-uk Kim }
364e71b7053SJung-uk Kim
365*b077aed3SPierre Pronchery calculate_columns(functions, &dc);
366*b077aed3SPierre Pronchery BIO_printf(bio_err, "%s:\n\nStandard commands", prog);
36774664626SKris Kennaway i = 0;
368e71b7053SJung-uk Kim tp = FT_none;
3696f9291ceSJung-uk Kim for (fp = functions; fp->name != NULL; fp++) {
37074664626SKris Kennaway nl = 0;
371e71b7053SJung-uk Kim if (i++ % dc.columns == 0) {
37274664626SKris Kennaway BIO_printf(bio_err, "\n");
37374664626SKris Kennaway nl = 1;
37474664626SKris Kennaway }
3756f9291ceSJung-uk Kim if (fp->type != tp) {
37674664626SKris Kennaway tp = fp->type;
3776f9291ceSJung-uk Kim if (!nl)
3786f9291ceSJung-uk Kim BIO_printf(bio_err, "\n");
379e71b7053SJung-uk Kim if (tp == FT_md) {
38074664626SKris Kennaway i = 1;
38174664626SKris Kennaway BIO_printf(bio_err,
38274664626SKris Kennaway "\nMessage Digest commands (see the `dgst' command for more details)\n");
383e71b7053SJung-uk Kim } else if (tp == FT_cipher) {
38474664626SKris Kennaway i = 1;
3856f9291ceSJung-uk Kim BIO_printf(bio_err,
3866f9291ceSJung-uk Kim "\nCipher commands (see the `enc' command for more details)\n");
38774664626SKris Kennaway }
38874664626SKris Kennaway }
389e71b7053SJung-uk Kim BIO_printf(bio_err, "%-*s", dc.width, fp->name);
39074664626SKris Kennaway }
39174664626SKris Kennaway BIO_printf(bio_err, "\n\n");
392e71b7053SJung-uk Kim return 0;
39374664626SKris Kennaway }
394e71b7053SJung-uk Kim
do_cmd(LHASH_OF (FUNCTION)* prog,int argc,char * argv[])395e71b7053SJung-uk Kim static int do_cmd(LHASH_OF(FUNCTION) *prog, int argc, char *argv[])
396e71b7053SJung-uk Kim {
397e71b7053SJung-uk Kim FUNCTION f, *fp;
398e71b7053SJung-uk Kim
399e71b7053SJung-uk Kim if (argc <= 0 || argv[0] == NULL)
400e71b7053SJung-uk Kim return 0;
401*b077aed3SPierre Pronchery memset(&f, 0, sizeof(f));
402e71b7053SJung-uk Kim f.name = argv[0];
403e71b7053SJung-uk Kim fp = lh_FUNCTION_retrieve(prog, &f);
404e71b7053SJung-uk Kim if (fp == NULL) {
405e71b7053SJung-uk Kim if (EVP_get_digestbyname(argv[0])) {
406e71b7053SJung-uk Kim f.type = FT_md;
407e71b7053SJung-uk Kim f.func = dgst_main;
408e71b7053SJung-uk Kim fp = &f;
409e71b7053SJung-uk Kim } else if (EVP_get_cipherbyname(argv[0])) {
410e71b7053SJung-uk Kim f.type = FT_cipher;
411e71b7053SJung-uk Kim f.func = enc_main;
412e71b7053SJung-uk Kim fp = &f;
413e71b7053SJung-uk Kim }
414e71b7053SJung-uk Kim }
415e71b7053SJung-uk Kim if (fp != NULL) {
416*b077aed3SPierre Pronchery if (fp->deprecated_alternative != NULL)
417*b077aed3SPierre Pronchery warn_deprecated(fp);
418e71b7053SJung-uk Kim return fp->func(argc, argv);
419e71b7053SJung-uk Kim }
420e71b7053SJung-uk Kim if ((strncmp(argv[0], "no-", 3)) == 0) {
421e71b7053SJung-uk Kim /*
422e71b7053SJung-uk Kim * User is asking if foo is unsupported, by trying to "run" the
423e71b7053SJung-uk Kim * no-foo command. Strange.
424e71b7053SJung-uk Kim */
425e71b7053SJung-uk Kim f.name = argv[0] + 3;
426e71b7053SJung-uk Kim if (lh_FUNCTION_retrieve(prog, &f) == NULL) {
427e71b7053SJung-uk Kim BIO_printf(bio_out, "%s\n", argv[0]);
428e71b7053SJung-uk Kim return 0;
429e71b7053SJung-uk Kim }
430e71b7053SJung-uk Kim BIO_printf(bio_out, "%s\n", argv[0] + 3);
431e71b7053SJung-uk Kim return 1;
432e71b7053SJung-uk Kim }
433e71b7053SJung-uk Kim
434e71b7053SJung-uk Kim BIO_printf(bio_err, "Invalid command '%s'; type \"help\" for a list.\n",
435e71b7053SJung-uk Kim argv[0]);
436e71b7053SJung-uk Kim return 1;
437e71b7053SJung-uk Kim }
438e71b7053SJung-uk Kim
function_cmp(const FUNCTION * a,const FUNCTION * b)439e71b7053SJung-uk Kim static int function_cmp(const FUNCTION * a, const FUNCTION * b)
440e71b7053SJung-uk Kim {
441e71b7053SJung-uk Kim return strncmp(a->name, b->name, 8);
442e71b7053SJung-uk Kim }
443e71b7053SJung-uk Kim
function_hash(const FUNCTION * a)444e71b7053SJung-uk Kim static unsigned long function_hash(const FUNCTION * a)
445e71b7053SJung-uk Kim {
446e71b7053SJung-uk Kim return OPENSSL_LH_strhash(a->name);
44774664626SKris Kennaway }
44874664626SKris Kennaway
SortFnByName(const void * _f1,const void * _f2)44974664626SKris Kennaway static int SortFnByName(const void *_f1, const void *_f2)
45074664626SKris Kennaway {
45174664626SKris Kennaway const FUNCTION *f1 = _f1;
45274664626SKris Kennaway const FUNCTION *f2 = _f2;
45374664626SKris Kennaway
45474664626SKris Kennaway if (f1->type != f2->type)
45574664626SKris Kennaway return f1->type - f2->type;
45674664626SKris Kennaway return strcmp(f1->name, f2->name);
45774664626SKris Kennaway }
45874664626SKris Kennaway
LHASH_OF(FUNCTION)4591f13597dSJung-uk Kim static LHASH_OF(FUNCTION) *prog_init(void)
4601f13597dSJung-uk Kim {
461e71b7053SJung-uk Kim static LHASH_OF(FUNCTION) *ret = NULL;
462e71b7053SJung-uk Kim static int prog_inited = 0;
46374664626SKris Kennaway FUNCTION *f;
4643b4e3dcbSSimon L. B. Nielsen size_t i;
46574664626SKris Kennaway
466e71b7053SJung-uk Kim if (prog_inited)
467e71b7053SJung-uk Kim return ret;
468e71b7053SJung-uk Kim
469e71b7053SJung-uk Kim prog_inited = 1;
470e71b7053SJung-uk Kim
471e71b7053SJung-uk Kim /* Sort alphabetically within category. For nicer help displays. */
472e71b7053SJung-uk Kim for (i = 0, f = functions; f->name != NULL; ++f, ++i)
473e71b7053SJung-uk Kim ;
474dee36b4fSJung-uk Kim qsort(functions, i, sizeof(*functions), SortFnByName);
47574664626SKris Kennaway
476e71b7053SJung-uk Kim if ((ret = lh_FUNCTION_new(function_hash, function_cmp)) == NULL)
477e71b7053SJung-uk Kim return NULL;
47874664626SKris Kennaway
47974664626SKris Kennaway for (f = functions; f->name != NULL; f++)
4801f13597dSJung-uk Kim (void)lh_FUNCTION_insert(ret, f);
481e71b7053SJung-uk Kim return ret;
48274664626SKris Kennaway }
483