X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=apps%2Fengine.c;h=1a22d5dee9224df23e7e5cc79c02040c85eae08c;hp=ca5618b1a69c66619fd5824b4a912190a6e16bfc;hb=bb3e67f3157cc44f20c1d3b96611126d4660d225;hpb=11c0f1201c2b26fc056fcb189b7d375d7163ffd0;ds=inline diff --git a/apps/engine.c b/apps/engine.c index ca5618b1a6..1a22d5dee9 100644 --- a/apps/engine.c +++ b/apps/engine.c @@ -59,7 +59,7 @@ #include #include #include -#ifdef NO_STDIO +#ifdef OPENSSL_NO_STDIO #define APPS_WIN16 #endif #include "apps.h" @@ -72,12 +72,21 @@ static char *engine_usage[]={ "usage: engine opts [engine ...]\n", -" -v - verbose mode, a textual listing of the engines in OpenSSL\n", -#if 0 +" -v[v[v[v]]] - verbose mode, for each engine, list its 'control commands'\n", +" -vv will additionally display each command's description\n", +" -vvv will also add the input flags for each command\n", +" -vvvv will also show internal input flags\n", " -c - for each engine, also list the capabilities\n", -#endif -" -t - for each engine, check that they are really available\n", -" -l - load all built-in engines\n", +" -t[t] - for each engine, check that they are really available\n", +" -tt will display error trace for unavailable engines\n", +" -pre - runs command 'cmd' against the ENGINE before any attempts\n", +" to load it (if -t is used)\n", +" -post - runs command 'cmd' against the ENGINE after loading it\n", +" (only used if -t is also provided)\n", +" NB: -pre and -post will be applied to all ENGINEs supplied on the command\n", +" line, or all supported ENGINEs if none are specified.\n", +" Eg. '-pre \"SO_PATH:/lib/libdriver.so\"' calls command \"SO_PATH\" with\n", +" argument \"/lib/libdriver.so\".\n", NULL }; @@ -86,7 +95,7 @@ static void identity(void *ptr) return; } -static int append_buf(char **buf, char *s, int *size, int step) +static int append_buf(char **buf, const char *s, int *size, int step) { int l = strlen(s); @@ -102,7 +111,7 @@ static int append_buf(char **buf, char *s, int *size, int step) if (**buf != '\0') l += 2; /* ", " */ - if (strlen(*buf) + strlen(s) >= *size) + if (strlen(*buf) + strlen(s) >= (unsigned int)*size) { *size += step; *buf = OPENSSL_realloc(*buf, *size); @@ -118,25 +127,241 @@ static int append_buf(char **buf, char *s, int *size, int step) return 1; } +static int util_flags(BIO *bio_out, unsigned int flags, const char *indent) + { + int started = 0, err = 0; + /* Indent before displaying input flags */ + BIO_printf(bio_out, "%s%s(input flags): ", indent, indent); + if(flags == 0) + { + BIO_printf(bio_out, "\n"); + return 1; + } + /* If the object is internal, mark it in a way that shows instead of + * having it part of all the other flags, even if it really is. */ + if(flags & ENGINE_CMD_FLAG_INTERNAL) + { + BIO_printf(bio_out, "[Internal] "); + } + + if(flags & ENGINE_CMD_FLAG_NUMERIC) + { + if(started) + { + BIO_printf(bio_out, "|"); + err = 1; + } + BIO_printf(bio_out, "NUMERIC"); + started = 1; + } + /* Now we check that no combinations of the mutually exclusive NUMERIC, + * STRING, and NO_INPUT flags have been used. Future flags that can be + * OR'd together with these would need to added after these to preserve + * the testing logic. */ + if(flags & ENGINE_CMD_FLAG_STRING) + { + if(started) + { + BIO_printf(bio_out, "|"); + err = 1; + } + BIO_printf(bio_out, "STRING"); + started = 1; + } + if(flags & ENGINE_CMD_FLAG_NO_INPUT) + { + if(started) + { + BIO_printf(bio_out, "|"); + err = 1; + } + BIO_printf(bio_out, "NO_INPUT"); + started = 1; + } + /* Check for unknown flags */ + flags = flags & ~ENGINE_CMD_FLAG_NUMERIC & + ~ENGINE_CMD_FLAG_STRING & + ~ENGINE_CMD_FLAG_NO_INPUT & + ~ENGINE_CMD_FLAG_INTERNAL; + if(flags) + { + if(started) BIO_printf(bio_out, "|"); + BIO_printf(bio_out, "<0x%04X>", flags); + } + if(err) + BIO_printf(bio_out, " "); + BIO_printf(bio_out, "\n"); + return 1; + } + +static int util_verbose(ENGINE *e, int verbose, BIO *bio_out, const char *indent) + { + static const int line_wrap = 78; + int num; + int ret = 0; + char *name = NULL; + char *desc = NULL; + int flags; + int xpos = 0; + STACK *cmds = NULL; + if(!ENGINE_ctrl(e, ENGINE_CTRL_HAS_CTRL_FUNCTION, 0, NULL, NULL) || + ((num = ENGINE_ctrl(e, ENGINE_CTRL_GET_FIRST_CMD_TYPE, + 0, NULL, NULL)) <= 0)) + { +#if 0 + BIO_printf(bio_out, "%s\n", indent); +#endif + return 1; + } + + cmds = sk_new_null(); + + if(!cmds) + goto err; + do { + int len; + /* Get the command input flags */ + if((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num, + NULL, NULL)) < 0) + goto err; + if (!(flags & ENGINE_CMD_FLAG_INTERNAL) || verbose >= 4) + { + /* Get the command name */ + if((len = ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_LEN_FROM_CMD, num, + NULL, NULL)) <= 0) + goto err; + if((name = OPENSSL_malloc(len + 1)) == NULL) + goto err; + if(ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_FROM_CMD, num, name, + NULL) <= 0) + goto err; + /* Get the command description */ + if((len = ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_LEN_FROM_CMD, num, + NULL, NULL)) < 0) + goto err; + if(len > 0) + { + if((desc = OPENSSL_malloc(len + 1)) == NULL) + goto err; + if(ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_FROM_CMD, num, desc, + NULL) <= 0) + goto err; + } + /* Now decide on the output */ + if(xpos == 0) + /* Do an indent */ + xpos = BIO_printf(bio_out, indent); + else + /* Otherwise prepend a ", " */ + xpos += BIO_printf(bio_out, ", "); + if(verbose == 1) + { + /* We're just listing names, comma-delimited */ + if((xpos > (int)strlen(indent)) && + (xpos + (int)strlen(name) > line_wrap)) + { + BIO_printf(bio_out, "\n"); + xpos = BIO_printf(bio_out, indent); + } + xpos += BIO_printf(bio_out, "%s", name); + } + else + { + /* We're listing names plus descriptions */ + BIO_printf(bio_out, "%s: %s\n", name, + (desc == NULL) ? "" : desc); + /* ... and sometimes input flags */ + if((verbose >= 3) && !util_flags(bio_out, flags, + indent)) + goto err; + xpos = 0; + } + } + OPENSSL_free(name); name = NULL; + if(desc) { OPENSSL_free(desc); desc = NULL; } + /* Move to the next command */ + num = ENGINE_ctrl(e, ENGINE_CTRL_GET_NEXT_CMD_TYPE, + num, NULL, NULL); + } while(num > 0); + if(xpos > 0) + BIO_printf(bio_out, "\n"); + ret = 1; +err: + if(cmds) sk_pop_free(cmds, identity); + if(name) OPENSSL_free(name); + if(desc) OPENSSL_free(desc); + return ret; + } + +static void util_do_cmds(ENGINE *e, STACK *cmds, BIO *bio_out, const char *indent) + { + int loop, res, num = sk_num(cmds); + if(num < 0) + { + BIO_printf(bio_out, "[Error]: internal stack error\n"); + return; + } + for(loop = 0; loop < num; loop++) + { + char buf[256]; + const char *cmd, *arg; + cmd = sk_value(cmds, loop); + res = 1; /* assume success */ + /* Check if this command has no ":arg" */ + if((arg = strstr(cmd, ":")) == NULL) + { + if(!ENGINE_ctrl_cmd_string(e, cmd, NULL, 0)) + res = 0; + } + else + { + if((int)(arg - cmd) > 254) + { + BIO_printf(bio_out,"[Error]: command name too long\n"); + return; + } + memcpy(buf, cmd, (int)(arg - cmd)); + buf[arg-cmd] = '\0'; + arg++; /* Move past the ":" */ + /* Call the command with the argument */ + if(!ENGINE_ctrl_cmd_string(e, buf, arg, 0)) + res = 0; + } + if(res) + BIO_printf(bio_out, "[Success]: %s\n", cmd); + else + { + BIO_printf(bio_out, "[Failure]: %s\n", cmd); + ERR_print_errors(bio_out); + } + } + } + int MAIN(int, char **); int MAIN(int argc, char **argv) { int ret=1,i; char **pp; - int verbose=0, list_cap=0, test_avail=0; + int verbose=0, list_cap=0, test_avail=0, test_avail_noise = 0; ENGINE *e; STACK *engines = sk_new_null(); - int badops=0; + STACK *pre_cmds = sk_new_null(); + STACK *post_cmds = sk_new_null(); + int badops=1; BIO *bio_out=NULL; + const char *indent = " "; apps_startup(); SSL_load_error_strings(); if (bio_err == NULL) bio_err=BIO_new_fp(stderr,BIO_NOCLOSE); + + if (!load_config(bio_err, NULL)) + goto end; bio_out=BIO_new_fp(stdout,BIO_NOCLOSE); -#ifdef VMS +#ifdef OPENSSL_SYS_VMS { BIO *tmpbio = BIO_new(BIO_f_linebuffer()); bio_out = BIO_push(tmpbio, bio_out); @@ -147,27 +372,44 @@ int MAIN(int argc, char **argv) argv++; while (argc >= 1) { - if (strcmp(*argv,"-v") == 0) - verbose=1; + if (strncmp(*argv,"-v",2) == 0) + { + if(strspn(*argv + 1, "v") < strlen(*argv + 1)) + goto skip_arg_loop; + if((verbose=strlen(*argv + 1)) > 4) + goto skip_arg_loop; + } else if (strcmp(*argv,"-c") == 0) list_cap=1; - else if (strcmp(*argv,"-t") == 0) + else if (strncmp(*argv,"-t",2) == 0) + { test_avail=1; - else if (strcmp(*argv,"-l") == 0) - ENGINE_load_builtin_engines(); - else if ((strncmp(*argv,"-h",2) == 0) || - (strcmp(*argv,"-?") == 0)) + if(strspn(*argv + 1, "t") < strlen(*argv + 1)) + goto skip_arg_loop; + if((test_avail_noise = strlen(*argv + 1) - 1) > 1) + goto skip_arg_loop; + } + else if (strcmp(*argv,"-pre") == 0) { - badops=1; - break; + argc--; argv++; + sk_push(pre_cmds,*argv); } - else + else if (strcmp(*argv,"-post") == 0) { - sk_push(engines,*argv); + argc--; argv++; + sk_push(post_cmds,*argv); } + else if ((strncmp(*argv,"-h",2) == 0) || + (strcmp(*argv,"-?") == 0)) + goto skip_arg_loop; + else + sk_push(engines,*argv); argc--; argv++; } + /* Looks like everything went OK */ + badops = 0; +skip_arg_loop: if (badops) { @@ -190,26 +432,22 @@ int MAIN(int argc, char **argv) if ((e = ENGINE_by_id(id)) != NULL) { const char *name = ENGINE_get_name(e); - BIO_printf(bio_out, "%s (%s)", name, id); - if (list_cap || test_avail) - BIO_printf(bio_out, ":"); - if (test_avail) + /* Do "id" first, then "name". Easier to auto-parse. */ + BIO_printf(bio_out, "(%s) %s\n", id, name); + util_do_cmds(e, pre_cmds, bio_out, indent); + if (strcmp(ENGINE_get_id(e), id) != 0) { - if (ENGINE_init(e)) - { - BIO_printf(bio_out, " available"); - ENGINE_finish(e); - } - else - { - BIO_printf(bio_out, " unavailable"); - ERR_clear_error(); - } + BIO_printf(bio_out, "Loaded: (%s) %s\n", + ENGINE_get_id(e), ENGINE_get_name(e)); } if (list_cap) { int cap_size = 256; char *cap_buf = NULL; + int k,n; + const int *nids; + ENGINE_CIPHERS_PTR fn_c; + ENGINE_DIGESTS_PTR fn_d; if (ENGINE_get_RSA(e) != NULL && !append_buf(&cap_buf, "RSA", @@ -228,12 +466,51 @@ int MAIN(int argc, char **argv) &cap_size, 256)) goto end; - if (*cap_buf != '\0') - BIO_printf(bio_out, " [%s]", cap_buf); + fn_c = ENGINE_get_ciphers(e); + if(!fn_c) goto skip_ciphers; + n = fn_c(e, NULL, &nids, 0); + for(k=0 ; k < n ; ++k) + if(!append_buf(&cap_buf, + OBJ_nid2sn(nids[k]), + &cap_size, 256)) + goto end; + +skip_ciphers: + fn_d = ENGINE_get_digests(e); + if(!fn_d) goto skip_digests; + n = fn_d(e, NULL, &nids, 0); + for(k=0 ; k < n ; ++k) + if(!append_buf(&cap_buf, + OBJ_nid2sn(nids[k]), + &cap_size, 256)) + goto end; + +skip_digests: + if (cap_buf && (*cap_buf != '\0')) + BIO_printf(bio_out, " [%s]\n", cap_buf); OPENSSL_free(cap_buf); } - BIO_printf(bio_out, "\n"); + if(test_avail) + { + BIO_printf(bio_out, "%s", indent); + if (ENGINE_init(e)) + { + BIO_printf(bio_out, "[ available ]\n"); + util_do_cmds(e, post_cmds, bio_out, indent); + ENGINE_finish(e); + } + else + { + BIO_printf(bio_out, "[ unavailable ]\n"); + if(test_avail_noise) + ERR_print_errors_fp(stdout); + ERR_clear_error(); + } + } + if((verbose > 0) && !util_verbose(e, verbose, bio_out, indent)) + goto end; + ENGINE_free(e); } else ERR_print_errors(bio_err); @@ -243,6 +520,9 @@ int MAIN(int argc, char **argv) end: ERR_print_errors(bio_err); sk_pop_free(engines, identity); + sk_pop_free(pre_cmds, identity); + sk_pop_free(post_cmds, identity); if (bio_out != NULL) BIO_free_all(bio_out); - EXIT(ret); + apps_shutdown(); + OPENSSL_EXIT(ret); }