1109998Smarkm/* apps/engine.c -*- mode: C; c-file-style: "eay" -*- */
2109998Smarkm/* Written by Richard Levitte <richard@levitte.org> for the OpenSSL
3109998Smarkm * project 2000.
4109998Smarkm */
5109998Smarkm/* ====================================================================
6109998Smarkm * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
7109998Smarkm *
8109998Smarkm * Redistribution and use in source and binary forms, with or without
9109998Smarkm * modification, are permitted provided that the following conditions
10109998Smarkm * are met:
11109998Smarkm *
12109998Smarkm * 1. Redistributions of source code must retain the above copyright
13109998Smarkm *    notice, this list of conditions and the following disclaimer.
14109998Smarkm *
15109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright
16109998Smarkm *    notice, this list of conditions and the following disclaimer in
17109998Smarkm *    the documentation and/or other materials provided with the
18109998Smarkm *    distribution.
19109998Smarkm *
20109998Smarkm * 3. All advertising materials mentioning features or use of this
21109998Smarkm *    software must display the following acknowledgment:
22109998Smarkm *    "This product includes software developed by the OpenSSL Project
23109998Smarkm *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24109998Smarkm *
25109998Smarkm * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26109998Smarkm *    endorse or promote products derived from this software without
27109998Smarkm *    prior written permission. For written permission, please contact
28109998Smarkm *    licensing@OpenSSL.org.
29109998Smarkm *
30109998Smarkm * 5. Products derived from this software may not be called "OpenSSL"
31109998Smarkm *    nor may "OpenSSL" appear in their names without prior written
32109998Smarkm *    permission of the OpenSSL Project.
33109998Smarkm *
34109998Smarkm * 6. Redistributions of any form whatsoever must retain the following
35109998Smarkm *    acknowledgment:
36109998Smarkm *    "This product includes software developed by the OpenSSL Project
37109998Smarkm *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38109998Smarkm *
39109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40109998Smarkm * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42109998Smarkm * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43109998Smarkm * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44109998Smarkm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45109998Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46109998Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48109998Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49109998Smarkm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50109998Smarkm * OF THE POSSIBILITY OF SUCH DAMAGE.
51109998Smarkm * ====================================================================
52109998Smarkm *
53109998Smarkm * This product includes cryptographic software written by Eric Young
54109998Smarkm * (eay@cryptsoft.com).  This product includes software written by Tim
55109998Smarkm * Hudson (tjh@cryptsoft.com).
56109998Smarkm *
57109998Smarkm */
58109998Smarkm
59111147Snectar
60109998Smarkm#include <stdio.h>
61109998Smarkm#include <stdlib.h>
62109998Smarkm#include <string.h>
63109998Smarkm#ifdef OPENSSL_NO_STDIO
64109998Smarkm#define APPS_WIN16
65109998Smarkm#endif
66109998Smarkm#include "apps.h"
67109998Smarkm#include <openssl/err.h>
68194206Ssimon#ifndef OPENSSL_NO_ENGINE
69109998Smarkm#include <openssl/engine.h>
70109998Smarkm#include <openssl/ssl.h>
71109998Smarkm
72109998Smarkm#undef PROG
73109998Smarkm#define PROG	engine_main
74109998Smarkm
75160814Ssimonstatic const char *engine_usage[]={
76109998Smarkm"usage: engine opts [engine ...]\n",
77109998Smarkm" -v[v[v[v]]] - verbose mode, for each engine, list its 'control commands'\n",
78109998Smarkm"               -vv will additionally display each command's description\n",
79109998Smarkm"               -vvv will also add the input flags for each command\n",
80109998Smarkm"               -vvvv will also show internal input flags\n",
81109998Smarkm" -c          - for each engine, also list the capabilities\n",
82160814Ssimon" -t[t]       - for each engine, check that they are really available\n",
83160814Ssimon"               -tt will display error trace for unavailable engines\n",
84109998Smarkm" -pre <cmd>  - runs command 'cmd' against the ENGINE before any attempts\n",
85109998Smarkm"               to load it (if -t is used)\n",
86109998Smarkm" -post <cmd> - runs command 'cmd' against the ENGINE after loading it\n",
87109998Smarkm"               (only used if -t is also provided)\n",
88109998Smarkm" NB: -pre and -post will be applied to all ENGINEs supplied on the command\n",
89109998Smarkm" line, or all supported ENGINEs if none are specified.\n",
90109998Smarkm" Eg. '-pre \"SO_PATH:/lib/libdriver.so\"' calls command \"SO_PATH\" with\n",
91109998Smarkm" argument \"/lib/libdriver.so\".\n",
92109998SmarkmNULL
93109998Smarkm};
94109998Smarkm
95238405Sjkimstatic void identity(char *ptr)
96109998Smarkm	{
97109998Smarkm	return;
98109998Smarkm	}
99109998Smarkm
100109998Smarkmstatic int append_buf(char **buf, const char *s, int *size, int step)
101109998Smarkm	{
102109998Smarkm	int l = strlen(s);
103109998Smarkm
104109998Smarkm	if (*buf == NULL)
105109998Smarkm		{
106109998Smarkm		*size = step;
107109998Smarkm		*buf = OPENSSL_malloc(*size);
108109998Smarkm		if (*buf == NULL)
109109998Smarkm			return 0;
110109998Smarkm		**buf = '\0';
111109998Smarkm		}
112109998Smarkm
113109998Smarkm	if (**buf != '\0')
114109998Smarkm		l += 2;		/* ", " */
115109998Smarkm
116109998Smarkm	if (strlen(*buf) + strlen(s) >= (unsigned int)*size)
117109998Smarkm		{
118109998Smarkm		*size += step;
119109998Smarkm		*buf = OPENSSL_realloc(*buf, *size);
120109998Smarkm		}
121109998Smarkm
122109998Smarkm	if (*buf == NULL)
123109998Smarkm		return 0;
124109998Smarkm
125109998Smarkm	if (**buf != '\0')
126127128Snectar		BUF_strlcat(*buf, ", ", *size);
127127128Snectar	BUF_strlcat(*buf, s, *size);
128109998Smarkm
129109998Smarkm	return 1;
130109998Smarkm	}
131109998Smarkm
132109998Smarkmstatic int util_flags(BIO *bio_out, unsigned int flags, const char *indent)
133109998Smarkm	{
134109998Smarkm	int started = 0, err = 0;
135109998Smarkm	/* Indent before displaying input flags */
136109998Smarkm	BIO_printf(bio_out, "%s%s(input flags): ", indent, indent);
137109998Smarkm	if(flags == 0)
138109998Smarkm		{
139109998Smarkm		BIO_printf(bio_out, "<no flags>\n");
140109998Smarkm		return 1;
141109998Smarkm		}
142109998Smarkm        /* If the object is internal, mark it in a way that shows instead of
143109998Smarkm         * having it part of all the other flags, even if it really is. */
144109998Smarkm	if(flags & ENGINE_CMD_FLAG_INTERNAL)
145109998Smarkm		{
146109998Smarkm		BIO_printf(bio_out, "[Internal] ");
147109998Smarkm		}
148109998Smarkm
149109998Smarkm	if(flags & ENGINE_CMD_FLAG_NUMERIC)
150109998Smarkm		{
151109998Smarkm		BIO_printf(bio_out, "NUMERIC");
152109998Smarkm		started = 1;
153109998Smarkm		}
154109998Smarkm	/* Now we check that no combinations of the mutually exclusive NUMERIC,
155109998Smarkm	 * STRING, and NO_INPUT flags have been used. Future flags that can be
156109998Smarkm	 * OR'd together with these would need to added after these to preserve
157109998Smarkm	 * the testing logic. */
158109998Smarkm	if(flags & ENGINE_CMD_FLAG_STRING)
159109998Smarkm		{
160109998Smarkm		if(started)
161109998Smarkm			{
162109998Smarkm			BIO_printf(bio_out, "|");
163109998Smarkm			err = 1;
164109998Smarkm			}
165109998Smarkm		BIO_printf(bio_out, "STRING");
166109998Smarkm		started = 1;
167109998Smarkm		}
168109998Smarkm	if(flags & ENGINE_CMD_FLAG_NO_INPUT)
169109998Smarkm		{
170109998Smarkm		if(started)
171109998Smarkm			{
172109998Smarkm			BIO_printf(bio_out, "|");
173109998Smarkm			err = 1;
174109998Smarkm			}
175109998Smarkm		BIO_printf(bio_out, "NO_INPUT");
176109998Smarkm		started = 1;
177109998Smarkm		}
178109998Smarkm	/* Check for unknown flags */
179109998Smarkm	flags = flags & ~ENGINE_CMD_FLAG_NUMERIC &
180109998Smarkm			~ENGINE_CMD_FLAG_STRING &
181109998Smarkm			~ENGINE_CMD_FLAG_NO_INPUT &
182109998Smarkm			~ENGINE_CMD_FLAG_INTERNAL;
183109998Smarkm	if(flags)
184109998Smarkm		{
185109998Smarkm		if(started) BIO_printf(bio_out, "|");
186109998Smarkm		BIO_printf(bio_out, "<0x%04X>", flags);
187109998Smarkm		}
188109998Smarkm	if(err)
189109998Smarkm		BIO_printf(bio_out, "  <illegal flags!>");
190109998Smarkm	BIO_printf(bio_out, "\n");
191109998Smarkm	return 1;
192109998Smarkm	}
193109998Smarkm
194109998Smarkmstatic int util_verbose(ENGINE *e, int verbose, BIO *bio_out, const char *indent)
195109998Smarkm	{
196109998Smarkm	static const int line_wrap = 78;
197109998Smarkm	int num;
198109998Smarkm	int ret = 0;
199109998Smarkm	char *name = NULL;
200109998Smarkm	char *desc = NULL;
201109998Smarkm	int flags;
202109998Smarkm	int xpos = 0;
203238405Sjkim	STACK_OF(OPENSSL_STRING) *cmds = NULL;
204109998Smarkm	if(!ENGINE_ctrl(e, ENGINE_CTRL_HAS_CTRL_FUNCTION, 0, NULL, NULL) ||
205109998Smarkm			((num = ENGINE_ctrl(e, ENGINE_CTRL_GET_FIRST_CMD_TYPE,
206109998Smarkm					0, NULL, NULL)) <= 0))
207109998Smarkm		{
208109998Smarkm#if 0
209109998Smarkm		BIO_printf(bio_out, "%s<no control commands>\n", indent);
210109998Smarkm#endif
211109998Smarkm		return 1;
212109998Smarkm		}
213109998Smarkm
214238405Sjkim	cmds = sk_OPENSSL_STRING_new_null();
215109998Smarkm
216109998Smarkm	if(!cmds)
217109998Smarkm		goto err;
218109998Smarkm	do {
219109998Smarkm		int len;
220109998Smarkm		/* Get the command input flags */
221109998Smarkm		if((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num,
222109998Smarkm					NULL, NULL)) < 0)
223109998Smarkm			goto err;
224109998Smarkm                if (!(flags & ENGINE_CMD_FLAG_INTERNAL) || verbose >= 4)
225109998Smarkm                        {
226109998Smarkm                        /* Get the command name */
227109998Smarkm                        if((len = ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_LEN_FROM_CMD, num,
228109998Smarkm                                NULL, NULL)) <= 0)
229109998Smarkm                                goto err;
230109998Smarkm                        if((name = OPENSSL_malloc(len + 1)) == NULL)
231109998Smarkm                                goto err;
232109998Smarkm                        if(ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_FROM_CMD, num, name,
233109998Smarkm                                NULL) <= 0)
234109998Smarkm                                goto err;
235109998Smarkm                        /* Get the command description */
236109998Smarkm                        if((len = ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_LEN_FROM_CMD, num,
237109998Smarkm                                NULL, NULL)) < 0)
238109998Smarkm                                goto err;
239109998Smarkm                        if(len > 0)
240109998Smarkm                                {
241109998Smarkm                                if((desc = OPENSSL_malloc(len + 1)) == NULL)
242109998Smarkm                                        goto err;
243109998Smarkm                                if(ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_FROM_CMD, num, desc,
244109998Smarkm                                        NULL) <= 0)
245109998Smarkm                                        goto err;
246109998Smarkm                                }
247109998Smarkm                        /* Now decide on the output */
248109998Smarkm                        if(xpos == 0)
249109998Smarkm                                /* Do an indent */
250194206Ssimon                                xpos = BIO_puts(bio_out, indent);
251109998Smarkm                        else
252109998Smarkm                                /* Otherwise prepend a ", " */
253109998Smarkm                                xpos += BIO_printf(bio_out, ", ");
254109998Smarkm                        if(verbose == 1)
255109998Smarkm                                {
256109998Smarkm                                /* We're just listing names, comma-delimited */
257109998Smarkm                                if((xpos > (int)strlen(indent)) &&
258109998Smarkm					(xpos + (int)strlen(name) > line_wrap))
259109998Smarkm                                        {
260109998Smarkm                                        BIO_printf(bio_out, "\n");
261194206Ssimon                                        xpos = BIO_puts(bio_out, indent);
262109998Smarkm                                        }
263109998Smarkm                                xpos += BIO_printf(bio_out, "%s", name);
264109998Smarkm                                }
265109998Smarkm                        else
266109998Smarkm                                {
267109998Smarkm                                /* We're listing names plus descriptions */
268109998Smarkm                                BIO_printf(bio_out, "%s: %s\n", name,
269109998Smarkm                                        (desc == NULL) ? "<no description>" : desc);
270109998Smarkm                                /* ... and sometimes input flags */
271109998Smarkm                                if((verbose >= 3) && !util_flags(bio_out, flags,
272109998Smarkm                                        indent))
273109998Smarkm                                        goto err;
274109998Smarkm                                xpos = 0;
275109998Smarkm                                }
276109998Smarkm                        }
277109998Smarkm		OPENSSL_free(name); name = NULL;
278109998Smarkm		if(desc) { OPENSSL_free(desc); desc = NULL; }
279109998Smarkm		/* Move to the next command */
280109998Smarkm		num = ENGINE_ctrl(e, ENGINE_CTRL_GET_NEXT_CMD_TYPE,
281109998Smarkm					num, NULL, NULL);
282109998Smarkm		} while(num > 0);
283109998Smarkm	if(xpos > 0)
284109998Smarkm		BIO_printf(bio_out, "\n");
285109998Smarkm	ret = 1;
286109998Smarkmerr:
287238405Sjkim	if(cmds) sk_OPENSSL_STRING_pop_free(cmds, identity);
288109998Smarkm	if(name) OPENSSL_free(name);
289109998Smarkm	if(desc) OPENSSL_free(desc);
290109998Smarkm	return ret;
291109998Smarkm	}
292109998Smarkm
293238405Sjkimstatic void util_do_cmds(ENGINE *e, STACK_OF(OPENSSL_STRING) *cmds,
294238405Sjkim			BIO *bio_out, const char *indent)
295109998Smarkm	{
296238405Sjkim	int loop, res, num = sk_OPENSSL_STRING_num(cmds);
297238405Sjkim
298109998Smarkm	if(num < 0)
299109998Smarkm		{
300109998Smarkm		BIO_printf(bio_out, "[Error]: internal stack error\n");
301109998Smarkm		return;
302109998Smarkm		}
303109998Smarkm	for(loop = 0; loop < num; loop++)
304109998Smarkm		{
305109998Smarkm		char buf[256];
306109998Smarkm		const char *cmd, *arg;
307238405Sjkim		cmd = sk_OPENSSL_STRING_value(cmds, loop);
308109998Smarkm		res = 1; /* assume success */
309109998Smarkm		/* Check if this command has no ":arg" */
310109998Smarkm		if((arg = strstr(cmd, ":")) == NULL)
311109998Smarkm			{
312109998Smarkm			if(!ENGINE_ctrl_cmd_string(e, cmd, NULL, 0))
313109998Smarkm				res = 0;
314109998Smarkm			}
315109998Smarkm		else
316109998Smarkm			{
317109998Smarkm			if((int)(arg - cmd) > 254)
318109998Smarkm				{
319109998Smarkm				BIO_printf(bio_out,"[Error]: command name too long\n");
320109998Smarkm				return;
321109998Smarkm				}
322109998Smarkm			memcpy(buf, cmd, (int)(arg - cmd));
323109998Smarkm			buf[arg-cmd] = '\0';
324109998Smarkm			arg++; /* Move past the ":" */
325109998Smarkm			/* Call the command with the argument */
326109998Smarkm			if(!ENGINE_ctrl_cmd_string(e, buf, arg, 0))
327109998Smarkm				res = 0;
328109998Smarkm			}
329109998Smarkm		if(res)
330109998Smarkm			BIO_printf(bio_out, "[Success]: %s\n", cmd);
331109998Smarkm		else
332109998Smarkm			{
333109998Smarkm			BIO_printf(bio_out, "[Failure]: %s\n", cmd);
334109998Smarkm			ERR_print_errors(bio_out);
335109998Smarkm			}
336109998Smarkm		}
337109998Smarkm	}
338109998Smarkm
339109998Smarkmint MAIN(int, char **);
340109998Smarkm
341109998Smarkmint MAIN(int argc, char **argv)
342109998Smarkm	{
343109998Smarkm	int ret=1,i;
344160814Ssimon	const char **pp;
345160814Ssimon	int verbose=0, list_cap=0, test_avail=0, test_avail_noise = 0;
346109998Smarkm	ENGINE *e;
347238405Sjkim	STACK_OF(OPENSSL_STRING) *engines = sk_OPENSSL_STRING_new_null();
348238405Sjkim	STACK_OF(OPENSSL_STRING) *pre_cmds = sk_OPENSSL_STRING_new_null();
349238405Sjkim	STACK_OF(OPENSSL_STRING) *post_cmds = sk_OPENSSL_STRING_new_null();
350109998Smarkm	int badops=1;
351109998Smarkm	BIO *bio_out=NULL;
352109998Smarkm	const char *indent = "     ";
353109998Smarkm
354109998Smarkm	apps_startup();
355109998Smarkm	SSL_load_error_strings();
356109998Smarkm
357109998Smarkm	if (bio_err == NULL)
358109998Smarkm		bio_err=BIO_new_fp(stderr,BIO_NOCLOSE);
359109998Smarkm
360109998Smarkm	if (!load_config(bio_err, NULL))
361109998Smarkm		goto end;
362109998Smarkm	bio_out=BIO_new_fp(stdout,BIO_NOCLOSE);
363109998Smarkm#ifdef OPENSSL_SYS_VMS
364109998Smarkm	{
365109998Smarkm	BIO *tmpbio = BIO_new(BIO_f_linebuffer());
366109998Smarkm	bio_out = BIO_push(tmpbio, bio_out);
367109998Smarkm	}
368109998Smarkm#endif
369109998Smarkm
370109998Smarkm	argc--;
371109998Smarkm	argv++;
372109998Smarkm	while (argc >= 1)
373109998Smarkm		{
374109998Smarkm		if (strncmp(*argv,"-v",2) == 0)
375109998Smarkm			{
376109998Smarkm			if(strspn(*argv + 1, "v") < strlen(*argv + 1))
377109998Smarkm				goto skip_arg_loop;
378109998Smarkm			if((verbose=strlen(*argv + 1)) > 4)
379109998Smarkm				goto skip_arg_loop;
380109998Smarkm			}
381109998Smarkm		else if (strcmp(*argv,"-c") == 0)
382109998Smarkm			list_cap=1;
383160814Ssimon		else if (strncmp(*argv,"-t",2) == 0)
384160814Ssimon			{
385109998Smarkm			test_avail=1;
386160814Ssimon			if(strspn(*argv + 1, "t") < strlen(*argv + 1))
387160814Ssimon				goto skip_arg_loop;
388160814Ssimon			if((test_avail_noise = strlen(*argv + 1) - 1) > 1)
389160814Ssimon				goto skip_arg_loop;
390160814Ssimon			}
391109998Smarkm		else if (strcmp(*argv,"-pre") == 0)
392109998Smarkm			{
393109998Smarkm			argc--; argv++;
394160814Ssimon			if (argc == 0)
395160814Ssimon				goto skip_arg_loop;
396238405Sjkim			sk_OPENSSL_STRING_push(pre_cmds,*argv);
397109998Smarkm			}
398109998Smarkm		else if (strcmp(*argv,"-post") == 0)
399109998Smarkm			{
400109998Smarkm			argc--; argv++;
401160814Ssimon			if (argc == 0)
402160814Ssimon				goto skip_arg_loop;
403238405Sjkim			sk_OPENSSL_STRING_push(post_cmds,*argv);
404109998Smarkm			}
405109998Smarkm		else if ((strncmp(*argv,"-h",2) == 0) ||
406109998Smarkm				(strcmp(*argv,"-?") == 0))
407109998Smarkm			goto skip_arg_loop;
408109998Smarkm		else
409238405Sjkim			sk_OPENSSL_STRING_push(engines,*argv);
410109998Smarkm		argc--;
411109998Smarkm		argv++;
412109998Smarkm		}
413109998Smarkm	/* Looks like everything went OK */
414109998Smarkm	badops = 0;
415109998Smarkmskip_arg_loop:
416109998Smarkm
417109998Smarkm	if (badops)
418109998Smarkm		{
419109998Smarkm		for (pp=engine_usage; (*pp != NULL); pp++)
420109998Smarkm			BIO_printf(bio_err,"%s",*pp);
421109998Smarkm		goto end;
422109998Smarkm		}
423109998Smarkm
424238405Sjkim	if (sk_OPENSSL_STRING_num(engines) == 0)
425109998Smarkm		{
426109998Smarkm		for(e = ENGINE_get_first(); e != NULL; e = ENGINE_get_next(e))
427109998Smarkm			{
428238405Sjkim			sk_OPENSSL_STRING_push(engines,(char *)ENGINE_get_id(e));
429109998Smarkm			}
430109998Smarkm		}
431109998Smarkm
432238405Sjkim	for (i=0; i<sk_OPENSSL_STRING_num(engines); i++)
433109998Smarkm		{
434238405Sjkim		const char *id = sk_OPENSSL_STRING_value(engines,i);
435109998Smarkm		if ((e = ENGINE_by_id(id)) != NULL)
436109998Smarkm			{
437109998Smarkm			const char *name = ENGINE_get_name(e);
438109998Smarkm			/* Do "id" first, then "name". Easier to auto-parse. */
439109998Smarkm			BIO_printf(bio_out, "(%s) %s\n", id, name);
440109998Smarkm			util_do_cmds(e, pre_cmds, bio_out, indent);
441109998Smarkm			if (strcmp(ENGINE_get_id(e), id) != 0)
442109998Smarkm				{
443109998Smarkm				BIO_printf(bio_out, "Loaded: (%s) %s\n",
444109998Smarkm					ENGINE_get_id(e), ENGINE_get_name(e));
445109998Smarkm				}
446109998Smarkm			if (list_cap)
447109998Smarkm				{
448109998Smarkm				int cap_size = 256;
449109998Smarkm				char *cap_buf = NULL;
450109998Smarkm				int k,n;
451109998Smarkm				const int *nids;
452109998Smarkm				ENGINE_CIPHERS_PTR fn_c;
453109998Smarkm				ENGINE_DIGESTS_PTR fn_d;
454238405Sjkim				ENGINE_PKEY_METHS_PTR fn_pk;
455109998Smarkm
456109998Smarkm				if (ENGINE_get_RSA(e) != NULL
457109998Smarkm					&& !append_buf(&cap_buf, "RSA",
458109998Smarkm						&cap_size, 256))
459109998Smarkm					goto end;
460109998Smarkm				if (ENGINE_get_DSA(e) != NULL
461109998Smarkm					&& !append_buf(&cap_buf, "DSA",
462109998Smarkm						&cap_size, 256))
463109998Smarkm					goto end;
464109998Smarkm				if (ENGINE_get_DH(e) != NULL
465109998Smarkm					&& !append_buf(&cap_buf, "DH",
466109998Smarkm						&cap_size, 256))
467109998Smarkm					goto end;
468109998Smarkm				if (ENGINE_get_RAND(e) != NULL
469109998Smarkm					&& !append_buf(&cap_buf, "RAND",
470109998Smarkm						&cap_size, 256))
471109998Smarkm					goto end;
472109998Smarkm
473109998Smarkm				fn_c = ENGINE_get_ciphers(e);
474109998Smarkm				if(!fn_c) goto skip_ciphers;
475109998Smarkm				n = fn_c(e, NULL, &nids, 0);
476109998Smarkm				for(k=0 ; k < n ; ++k)
477109998Smarkm					if(!append_buf(&cap_buf,
478109998Smarkm						       OBJ_nid2sn(nids[k]),
479109998Smarkm						       &cap_size, 256))
480109998Smarkm						goto end;
481109998Smarkm
482109998Smarkmskip_ciphers:
483109998Smarkm				fn_d = ENGINE_get_digests(e);
484109998Smarkm				if(!fn_d) goto skip_digests;
485109998Smarkm				n = fn_d(e, NULL, &nids, 0);
486109998Smarkm				for(k=0 ; k < n ; ++k)
487109998Smarkm					if(!append_buf(&cap_buf,
488109998Smarkm						       OBJ_nid2sn(nids[k]),
489109998Smarkm						       &cap_size, 256))
490109998Smarkm						goto end;
491109998Smarkm
492109998Smarkmskip_digests:
493238405Sjkim				fn_pk = ENGINE_get_pkey_meths(e);
494238405Sjkim				if(!fn_pk) goto skip_pmeths;
495238405Sjkim				n = fn_pk(e, NULL, &nids, 0);
496238405Sjkim				for(k=0 ; k < n ; ++k)
497238405Sjkim					if(!append_buf(&cap_buf,
498238405Sjkim						       OBJ_nid2sn(nids[k]),
499238405Sjkim						       &cap_size, 256))
500238405Sjkim						goto end;
501238405Sjkimskip_pmeths:
502109998Smarkm				if (cap_buf && (*cap_buf != '\0'))
503109998Smarkm					BIO_printf(bio_out, " [%s]\n", cap_buf);
504109998Smarkm
505109998Smarkm				OPENSSL_free(cap_buf);
506109998Smarkm				}
507109998Smarkm			if(test_avail)
508109998Smarkm				{
509109998Smarkm				BIO_printf(bio_out, "%s", indent);
510109998Smarkm				if (ENGINE_init(e))
511109998Smarkm					{
512109998Smarkm					BIO_printf(bio_out, "[ available ]\n");
513109998Smarkm					util_do_cmds(e, post_cmds, bio_out, indent);
514109998Smarkm					ENGINE_finish(e);
515109998Smarkm					}
516109998Smarkm				else
517109998Smarkm					{
518109998Smarkm					BIO_printf(bio_out, "[ unavailable ]\n");
519160814Ssimon					if(test_avail_noise)
520160814Ssimon						ERR_print_errors_fp(stdout);
521109998Smarkm					ERR_clear_error();
522109998Smarkm					}
523109998Smarkm				}
524109998Smarkm			if((verbose > 0) && !util_verbose(e, verbose, bio_out, indent))
525109998Smarkm				goto end;
526109998Smarkm			ENGINE_free(e);
527109998Smarkm			}
528109998Smarkm		else
529109998Smarkm			ERR_print_errors(bio_err);
530109998Smarkm		}
531109998Smarkm
532109998Smarkm	ret=0;
533109998Smarkmend:
534160814Ssimon
535109998Smarkm	ERR_print_errors(bio_err);
536238405Sjkim	sk_OPENSSL_STRING_pop_free(engines, identity);
537238405Sjkim	sk_OPENSSL_STRING_pop_free(pre_cmds, identity);
538238405Sjkim	sk_OPENSSL_STRING_pop_free(post_cmds, identity);
539109998Smarkm	if (bio_out != NULL) BIO_free_all(bio_out);
540109998Smarkm	apps_shutdown();
541109998Smarkm	OPENSSL_EXIT(ret);
542109998Smarkm	}
543120631Snectar#else
544120631Snectar
545120631Snectar# if PEDANTIC
546120631Snectarstatic void *dummy=&dummy;
547120631Snectar# endif
548120631Snectar
549111147Snectar#endif
550