xref: /onnv-gate/usr/src/common/openssl/crypto/engine/eng_ctrl.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /* crypto/engine/eng_ctrl.c */
2*0Sstevel@tonic-gate /* ====================================================================
3*0Sstevel@tonic-gate  * Copyright (c) 1999-2001 The OpenSSL Project.  All rights reserved.
4*0Sstevel@tonic-gate  *
5*0Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
6*0Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
7*0Sstevel@tonic-gate  * are met:
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
10*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
11*0Sstevel@tonic-gate  *
12*0Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
13*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in
14*0Sstevel@tonic-gate  *    the documentation and/or other materials provided with the
15*0Sstevel@tonic-gate  *    distribution.
16*0Sstevel@tonic-gate  *
17*0Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this
18*0Sstevel@tonic-gate  *    software must display the following acknowledgment:
19*0Sstevel@tonic-gate  *    "This product includes software developed by the OpenSSL Project
20*0Sstevel@tonic-gate  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
21*0Sstevel@tonic-gate  *
22*0Sstevel@tonic-gate  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23*0Sstevel@tonic-gate  *    endorse or promote products derived from this software without
24*0Sstevel@tonic-gate  *    prior written permission. For written permission, please contact
25*0Sstevel@tonic-gate  *    licensing@OpenSSL.org.
26*0Sstevel@tonic-gate  *
27*0Sstevel@tonic-gate  * 5. Products derived from this software may not be called "OpenSSL"
28*0Sstevel@tonic-gate  *    nor may "OpenSSL" appear in their names without prior written
29*0Sstevel@tonic-gate  *    permission of the OpenSSL Project.
30*0Sstevel@tonic-gate  *
31*0Sstevel@tonic-gate  * 6. Redistributions of any form whatsoever must retain the following
32*0Sstevel@tonic-gate  *    acknowledgment:
33*0Sstevel@tonic-gate  *    "This product includes software developed by the OpenSSL Project
34*0Sstevel@tonic-gate  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
35*0Sstevel@tonic-gate  *
36*0Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37*0Sstevel@tonic-gate  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38*0Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39*0Sstevel@tonic-gate  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
40*0Sstevel@tonic-gate  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41*0Sstevel@tonic-gate  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42*0Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43*0Sstevel@tonic-gate  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44*0Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45*0Sstevel@tonic-gate  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46*0Sstevel@tonic-gate  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47*0Sstevel@tonic-gate  * OF THE POSSIBILITY OF SUCH DAMAGE.
48*0Sstevel@tonic-gate  * ====================================================================
49*0Sstevel@tonic-gate  *
50*0Sstevel@tonic-gate  * This product includes cryptographic software written by Eric Young
51*0Sstevel@tonic-gate  * (eay@cryptsoft.com).  This product includes software written by Tim
52*0Sstevel@tonic-gate  * Hudson (tjh@cryptsoft.com).
53*0Sstevel@tonic-gate  *
54*0Sstevel@tonic-gate  */
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate #include <openssl/crypto.h>
57*0Sstevel@tonic-gate #include "cryptlib.h"
58*0Sstevel@tonic-gate #include "eng_int.h"
59*0Sstevel@tonic-gate #include <openssl/engine.h>
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate /* When querying a ENGINE-specific control command's 'description', this string
62*0Sstevel@tonic-gate  * is used if the ENGINE_CMD_DEFN has cmd_desc set to NULL. */
63*0Sstevel@tonic-gate static const char *int_no_description = "";
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate /* These internal functions handle 'CMD'-related control commands when the
66*0Sstevel@tonic-gate  * ENGINE in question has asked us to take care of it (ie. the ENGINE did not
67*0Sstevel@tonic-gate  * set the ENGINE_FLAGS_MANUAL_CMD_CTRL flag. */
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate static int int_ctrl_cmd_is_null(const ENGINE_CMD_DEFN *defn)
70*0Sstevel@tonic-gate 	{
71*0Sstevel@tonic-gate 	if((defn->cmd_num == 0) || (defn->cmd_name == NULL))
72*0Sstevel@tonic-gate 		return 1;
73*0Sstevel@tonic-gate 	return 0;
74*0Sstevel@tonic-gate 	}
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate static int int_ctrl_cmd_by_name(const ENGINE_CMD_DEFN *defn, const char *s)
77*0Sstevel@tonic-gate 	{
78*0Sstevel@tonic-gate 	int idx = 0;
79*0Sstevel@tonic-gate 	while(!int_ctrl_cmd_is_null(defn) && (strcmp(defn->cmd_name, s) != 0))
80*0Sstevel@tonic-gate 		{
81*0Sstevel@tonic-gate 		idx++;
82*0Sstevel@tonic-gate 		defn++;
83*0Sstevel@tonic-gate 		}
84*0Sstevel@tonic-gate 	if(int_ctrl_cmd_is_null(defn))
85*0Sstevel@tonic-gate 		/* The given name wasn't found */
86*0Sstevel@tonic-gate 		return -1;
87*0Sstevel@tonic-gate 	return idx;
88*0Sstevel@tonic-gate 	}
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate static int int_ctrl_cmd_by_num(const ENGINE_CMD_DEFN *defn, unsigned int num)
91*0Sstevel@tonic-gate 	{
92*0Sstevel@tonic-gate 	int idx = 0;
93*0Sstevel@tonic-gate 	/* NB: It is stipulated that 'cmd_defn' lists are ordered by cmd_num. So
94*0Sstevel@tonic-gate 	 * our searches don't need to take any longer than necessary. */
95*0Sstevel@tonic-gate 	while(!int_ctrl_cmd_is_null(defn) && (defn->cmd_num < num))
96*0Sstevel@tonic-gate 		{
97*0Sstevel@tonic-gate 		idx++;
98*0Sstevel@tonic-gate 		defn++;
99*0Sstevel@tonic-gate 		}
100*0Sstevel@tonic-gate 	if(defn->cmd_num == num)
101*0Sstevel@tonic-gate 		return idx;
102*0Sstevel@tonic-gate 	/* The given cmd_num wasn't found */
103*0Sstevel@tonic-gate 	return -1;
104*0Sstevel@tonic-gate 	}
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate static int int_ctrl_helper(ENGINE *e, int cmd, long i, void *p, void (*f)())
107*0Sstevel@tonic-gate 	{
108*0Sstevel@tonic-gate 	int idx;
109*0Sstevel@tonic-gate 	char *s = (char *)p;
110*0Sstevel@tonic-gate 	/* Take care of the easy one first (eg. it requires no searches) */
111*0Sstevel@tonic-gate 	if(cmd == ENGINE_CTRL_GET_FIRST_CMD_TYPE)
112*0Sstevel@tonic-gate 		{
113*0Sstevel@tonic-gate 		if((e->cmd_defns == NULL) || int_ctrl_cmd_is_null(e->cmd_defns))
114*0Sstevel@tonic-gate 			return 0;
115*0Sstevel@tonic-gate 		return e->cmd_defns->cmd_num;
116*0Sstevel@tonic-gate 		}
117*0Sstevel@tonic-gate 	/* One or two commands require that "p" be a valid string buffer */
118*0Sstevel@tonic-gate 	if((cmd == ENGINE_CTRL_GET_CMD_FROM_NAME) ||
119*0Sstevel@tonic-gate 			(cmd == ENGINE_CTRL_GET_NAME_FROM_CMD) ||
120*0Sstevel@tonic-gate 			(cmd == ENGINE_CTRL_GET_DESC_FROM_CMD))
121*0Sstevel@tonic-gate 		{
122*0Sstevel@tonic-gate 		if(s == NULL)
123*0Sstevel@tonic-gate 			{
124*0Sstevel@tonic-gate 			ENGINEerr(ENGINE_F_INT_CTRL_HELPER,
125*0Sstevel@tonic-gate 				ERR_R_PASSED_NULL_PARAMETER);
126*0Sstevel@tonic-gate 			return -1;
127*0Sstevel@tonic-gate 			}
128*0Sstevel@tonic-gate 		}
129*0Sstevel@tonic-gate 	/* Now handle cmd_name -> cmd_num conversion */
130*0Sstevel@tonic-gate 	if(cmd == ENGINE_CTRL_GET_CMD_FROM_NAME)
131*0Sstevel@tonic-gate 		{
132*0Sstevel@tonic-gate 		if((e->cmd_defns == NULL) || ((idx = int_ctrl_cmd_by_name(
133*0Sstevel@tonic-gate 						e->cmd_defns, s)) < 0))
134*0Sstevel@tonic-gate 			{
135*0Sstevel@tonic-gate 			ENGINEerr(ENGINE_F_INT_CTRL_HELPER,
136*0Sstevel@tonic-gate 				ENGINE_R_INVALID_CMD_NAME);
137*0Sstevel@tonic-gate 			return -1;
138*0Sstevel@tonic-gate 			}
139*0Sstevel@tonic-gate 		return e->cmd_defns[idx].cmd_num;
140*0Sstevel@tonic-gate 		}
141*0Sstevel@tonic-gate 	/* For the rest of the commands, the 'long' argument must specify a
142*0Sstevel@tonic-gate 	 * valie command number - so we need to conduct a search. */
143*0Sstevel@tonic-gate 	if((e->cmd_defns == NULL) || ((idx = int_ctrl_cmd_by_num(e->cmd_defns,
144*0Sstevel@tonic-gate 					(unsigned int)i)) < 0))
145*0Sstevel@tonic-gate 		{
146*0Sstevel@tonic-gate 		ENGINEerr(ENGINE_F_INT_CTRL_HELPER,
147*0Sstevel@tonic-gate 			ENGINE_R_INVALID_CMD_NUMBER);
148*0Sstevel@tonic-gate 		return -1;
149*0Sstevel@tonic-gate 		}
150*0Sstevel@tonic-gate 	/* Now the logic splits depending on command type */
151*0Sstevel@tonic-gate 	switch(cmd)
152*0Sstevel@tonic-gate 		{
153*0Sstevel@tonic-gate 	case ENGINE_CTRL_GET_NEXT_CMD_TYPE:
154*0Sstevel@tonic-gate 		idx++;
155*0Sstevel@tonic-gate 		if(int_ctrl_cmd_is_null(e->cmd_defns + idx))
156*0Sstevel@tonic-gate 			/* end-of-list */
157*0Sstevel@tonic-gate 			return 0;
158*0Sstevel@tonic-gate 		else
159*0Sstevel@tonic-gate 			return e->cmd_defns[idx].cmd_num;
160*0Sstevel@tonic-gate 	case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD:
161*0Sstevel@tonic-gate 		return strlen(e->cmd_defns[idx].cmd_name);
162*0Sstevel@tonic-gate 	case ENGINE_CTRL_GET_NAME_FROM_CMD:
163*0Sstevel@tonic-gate 		return BIO_snprintf(s,strlen(e->cmd_defns[idx].cmd_name) + 1,
164*0Sstevel@tonic-gate 				    "%s", e->cmd_defns[idx].cmd_name);
165*0Sstevel@tonic-gate 	case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD:
166*0Sstevel@tonic-gate 		if(e->cmd_defns[idx].cmd_desc)
167*0Sstevel@tonic-gate 			return strlen(e->cmd_defns[idx].cmd_desc);
168*0Sstevel@tonic-gate 		return strlen(int_no_description);
169*0Sstevel@tonic-gate 	case ENGINE_CTRL_GET_DESC_FROM_CMD:
170*0Sstevel@tonic-gate 		if(e->cmd_defns[idx].cmd_desc)
171*0Sstevel@tonic-gate 			return BIO_snprintf(s,
172*0Sstevel@tonic-gate 					    strlen(e->cmd_defns[idx].cmd_desc) + 1,
173*0Sstevel@tonic-gate 					    "%s", e->cmd_defns[idx].cmd_desc);
174*0Sstevel@tonic-gate 		return BIO_snprintf(s, strlen(int_no_description) + 1,"%s",
175*0Sstevel@tonic-gate 				    int_no_description);
176*0Sstevel@tonic-gate 	case ENGINE_CTRL_GET_CMD_FLAGS:
177*0Sstevel@tonic-gate 		return e->cmd_defns[idx].cmd_flags;
178*0Sstevel@tonic-gate 		}
179*0Sstevel@tonic-gate 	/* Shouldn't really be here ... */
180*0Sstevel@tonic-gate 	ENGINEerr(ENGINE_F_INT_CTRL_HELPER,ENGINE_R_INTERNAL_LIST_ERROR);
181*0Sstevel@tonic-gate 	return -1;
182*0Sstevel@tonic-gate 	}
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate int ENGINE_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)())
185*0Sstevel@tonic-gate 	{
186*0Sstevel@tonic-gate 	int ctrl_exists, ref_exists;
187*0Sstevel@tonic-gate 	if(e == NULL)
188*0Sstevel@tonic-gate 		{
189*0Sstevel@tonic-gate 		ENGINEerr(ENGINE_F_ENGINE_CTRL,ERR_R_PASSED_NULL_PARAMETER);
190*0Sstevel@tonic-gate 		return 0;
191*0Sstevel@tonic-gate 		}
192*0Sstevel@tonic-gate 	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
193*0Sstevel@tonic-gate 	ref_exists = ((e->struct_ref > 0) ? 1 : 0);
194*0Sstevel@tonic-gate 	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
195*0Sstevel@tonic-gate 	ctrl_exists = ((e->ctrl == NULL) ? 0 : 1);
196*0Sstevel@tonic-gate 	if(!ref_exists)
197*0Sstevel@tonic-gate 		{
198*0Sstevel@tonic-gate 		ENGINEerr(ENGINE_F_ENGINE_CTRL,ENGINE_R_NO_REFERENCE);
199*0Sstevel@tonic-gate 		return 0;
200*0Sstevel@tonic-gate 		}
201*0Sstevel@tonic-gate 	/* Intercept any "root-level" commands before trying to hand them on to
202*0Sstevel@tonic-gate 	 * ctrl() handlers. */
203*0Sstevel@tonic-gate 	switch(cmd)
204*0Sstevel@tonic-gate 		{
205*0Sstevel@tonic-gate 	case ENGINE_CTRL_HAS_CTRL_FUNCTION:
206*0Sstevel@tonic-gate 		return ctrl_exists;
207*0Sstevel@tonic-gate 	case ENGINE_CTRL_GET_FIRST_CMD_TYPE:
208*0Sstevel@tonic-gate 	case ENGINE_CTRL_GET_NEXT_CMD_TYPE:
209*0Sstevel@tonic-gate 	case ENGINE_CTRL_GET_CMD_FROM_NAME:
210*0Sstevel@tonic-gate 	case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD:
211*0Sstevel@tonic-gate 	case ENGINE_CTRL_GET_NAME_FROM_CMD:
212*0Sstevel@tonic-gate 	case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD:
213*0Sstevel@tonic-gate 	case ENGINE_CTRL_GET_DESC_FROM_CMD:
214*0Sstevel@tonic-gate 	case ENGINE_CTRL_GET_CMD_FLAGS:
215*0Sstevel@tonic-gate 		if(ctrl_exists && !(e->flags & ENGINE_FLAGS_MANUAL_CMD_CTRL))
216*0Sstevel@tonic-gate 			return int_ctrl_helper(e,cmd,i,p,f);
217*0Sstevel@tonic-gate 		if(!ctrl_exists)
218*0Sstevel@tonic-gate 			{
219*0Sstevel@tonic-gate 			ENGINEerr(ENGINE_F_ENGINE_CTRL,ENGINE_R_NO_CONTROL_FUNCTION);
220*0Sstevel@tonic-gate 			/* For these cmd-related functions, failure is indicated
221*0Sstevel@tonic-gate 			 * by a -1 return value (because 0 is used as a valid
222*0Sstevel@tonic-gate 			 * return in some places). */
223*0Sstevel@tonic-gate 			return -1;
224*0Sstevel@tonic-gate 			}
225*0Sstevel@tonic-gate 	default:
226*0Sstevel@tonic-gate 		break;
227*0Sstevel@tonic-gate 		}
228*0Sstevel@tonic-gate 	/* Anything else requires a ctrl() handler to exist. */
229*0Sstevel@tonic-gate 	if(!ctrl_exists)
230*0Sstevel@tonic-gate 		{
231*0Sstevel@tonic-gate 		ENGINEerr(ENGINE_F_ENGINE_CTRL,ENGINE_R_NO_CONTROL_FUNCTION);
232*0Sstevel@tonic-gate 		return 0;
233*0Sstevel@tonic-gate 		}
234*0Sstevel@tonic-gate 	return e->ctrl(e, cmd, i, p, f);
235*0Sstevel@tonic-gate 	}
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate int ENGINE_cmd_is_executable(ENGINE *e, int cmd)
238*0Sstevel@tonic-gate 	{
239*0Sstevel@tonic-gate 	int flags;
240*0Sstevel@tonic-gate 	if((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, cmd, NULL, NULL)) < 0)
241*0Sstevel@tonic-gate 		{
242*0Sstevel@tonic-gate 		ENGINEerr(ENGINE_F_ENGINE_CMD_IS_EXECUTABLE,
243*0Sstevel@tonic-gate 			ENGINE_R_INVALID_CMD_NUMBER);
244*0Sstevel@tonic-gate 		return 0;
245*0Sstevel@tonic-gate 		}
246*0Sstevel@tonic-gate 	if(!(flags & ENGINE_CMD_FLAG_NO_INPUT) &&
247*0Sstevel@tonic-gate 			!(flags & ENGINE_CMD_FLAG_NUMERIC) &&
248*0Sstevel@tonic-gate 			!(flags & ENGINE_CMD_FLAG_STRING))
249*0Sstevel@tonic-gate 		return 0;
250*0Sstevel@tonic-gate 	return 1;
251*0Sstevel@tonic-gate 	}
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate int ENGINE_ctrl_cmd(ENGINE *e, const char *cmd_name,
254*0Sstevel@tonic-gate         long i, void *p, void (*f)(), int cmd_optional)
255*0Sstevel@tonic-gate         {
256*0Sstevel@tonic-gate 	int num;
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate 	if((e == NULL) || (cmd_name == NULL))
259*0Sstevel@tonic-gate 		{
260*0Sstevel@tonic-gate 		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
261*0Sstevel@tonic-gate 			ERR_R_PASSED_NULL_PARAMETER);
262*0Sstevel@tonic-gate 		return 0;
263*0Sstevel@tonic-gate 		}
264*0Sstevel@tonic-gate 	if((e->ctrl == NULL) || ((num = ENGINE_ctrl(e,
265*0Sstevel@tonic-gate 					ENGINE_CTRL_GET_CMD_FROM_NAME,
266*0Sstevel@tonic-gate 					0, (void *)cmd_name, NULL)) <= 0))
267*0Sstevel@tonic-gate 		{
268*0Sstevel@tonic-gate 		/* If the command didn't *have* to be supported, we fake
269*0Sstevel@tonic-gate 		 * success. This allows certain settings to be specified for
270*0Sstevel@tonic-gate 		 * multiple ENGINEs and only require a change of ENGINE id
271*0Sstevel@tonic-gate 		 * (without having to selectively apply settings). Eg. changing
272*0Sstevel@tonic-gate 		 * from a hardware device back to the regular software ENGINE
273*0Sstevel@tonic-gate 		 * without editing the config file, etc. */
274*0Sstevel@tonic-gate 		if(cmd_optional)
275*0Sstevel@tonic-gate 			{
276*0Sstevel@tonic-gate 			ERR_clear_error();
277*0Sstevel@tonic-gate 			return 1;
278*0Sstevel@tonic-gate 			}
279*0Sstevel@tonic-gate 		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD,
280*0Sstevel@tonic-gate 			ENGINE_R_INVALID_CMD_NAME);
281*0Sstevel@tonic-gate 		return 0;
282*0Sstevel@tonic-gate 		}
283*0Sstevel@tonic-gate 	/* Force the result of the control command to 0 or 1, for the reasons
284*0Sstevel@tonic-gate 	 * mentioned before. */
285*0Sstevel@tonic-gate         if (ENGINE_ctrl(e, num, i, p, f))
286*0Sstevel@tonic-gate                 return 1;
287*0Sstevel@tonic-gate         return 0;
288*0Sstevel@tonic-gate         }
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate int ENGINE_ctrl_cmd_string(ENGINE *e, const char *cmd_name, const char *arg,
291*0Sstevel@tonic-gate 				int cmd_optional)
292*0Sstevel@tonic-gate 	{
293*0Sstevel@tonic-gate 	int num, flags;
294*0Sstevel@tonic-gate 	long l;
295*0Sstevel@tonic-gate 	char *ptr;
296*0Sstevel@tonic-gate 	if((e == NULL) || (cmd_name == NULL))
297*0Sstevel@tonic-gate 		{
298*0Sstevel@tonic-gate 		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
299*0Sstevel@tonic-gate 			ERR_R_PASSED_NULL_PARAMETER);
300*0Sstevel@tonic-gate 		return 0;
301*0Sstevel@tonic-gate 		}
302*0Sstevel@tonic-gate 	if((e->ctrl == NULL) || ((num = ENGINE_ctrl(e,
303*0Sstevel@tonic-gate 					ENGINE_CTRL_GET_CMD_FROM_NAME,
304*0Sstevel@tonic-gate 					0, (void *)cmd_name, NULL)) <= 0))
305*0Sstevel@tonic-gate 		{
306*0Sstevel@tonic-gate 		/* If the command didn't *have* to be supported, we fake
307*0Sstevel@tonic-gate 		 * success. This allows certain settings to be specified for
308*0Sstevel@tonic-gate 		 * multiple ENGINEs and only require a change of ENGINE id
309*0Sstevel@tonic-gate 		 * (without having to selectively apply settings). Eg. changing
310*0Sstevel@tonic-gate 		 * from a hardware device back to the regular software ENGINE
311*0Sstevel@tonic-gate 		 * without editing the config file, etc. */
312*0Sstevel@tonic-gate 		if(cmd_optional)
313*0Sstevel@tonic-gate 			{
314*0Sstevel@tonic-gate 			ERR_clear_error();
315*0Sstevel@tonic-gate 			return 1;
316*0Sstevel@tonic-gate 			}
317*0Sstevel@tonic-gate 		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
318*0Sstevel@tonic-gate 			ENGINE_R_INVALID_CMD_NAME);
319*0Sstevel@tonic-gate 		return 0;
320*0Sstevel@tonic-gate 		}
321*0Sstevel@tonic-gate 	if(!ENGINE_cmd_is_executable(e, num))
322*0Sstevel@tonic-gate 		{
323*0Sstevel@tonic-gate 		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
324*0Sstevel@tonic-gate 			ENGINE_R_CMD_NOT_EXECUTABLE);
325*0Sstevel@tonic-gate 		return 0;
326*0Sstevel@tonic-gate 		}
327*0Sstevel@tonic-gate 	if((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num, NULL, NULL)) < 0)
328*0Sstevel@tonic-gate 		{
329*0Sstevel@tonic-gate 		/* Shouldn't happen, given that ENGINE_cmd_is_executable()
330*0Sstevel@tonic-gate 		 * returned success. */
331*0Sstevel@tonic-gate 		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
332*0Sstevel@tonic-gate 			ENGINE_R_INTERNAL_LIST_ERROR);
333*0Sstevel@tonic-gate 		return 0;
334*0Sstevel@tonic-gate 		}
335*0Sstevel@tonic-gate 	/* If the command takes no input, there must be no input. And vice
336*0Sstevel@tonic-gate 	 * versa. */
337*0Sstevel@tonic-gate 	if(flags & ENGINE_CMD_FLAG_NO_INPUT)
338*0Sstevel@tonic-gate 		{
339*0Sstevel@tonic-gate 		if(arg != NULL)
340*0Sstevel@tonic-gate 			{
341*0Sstevel@tonic-gate 			ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
342*0Sstevel@tonic-gate 				ENGINE_R_COMMAND_TAKES_NO_INPUT);
343*0Sstevel@tonic-gate 			return 0;
344*0Sstevel@tonic-gate 			}
345*0Sstevel@tonic-gate 		/* We deliberately force the result of ENGINE_ctrl() to 0 or 1
346*0Sstevel@tonic-gate 		 * rather than returning it as "return data". This is to ensure
347*0Sstevel@tonic-gate 		 * usage of these commands is consistent across applications and
348*0Sstevel@tonic-gate 		 * that certain applications don't understand it one way, and
349*0Sstevel@tonic-gate 		 * others another. */
350*0Sstevel@tonic-gate 		if(ENGINE_ctrl(e, num, 0, (void *)arg, NULL))
351*0Sstevel@tonic-gate 			return 1;
352*0Sstevel@tonic-gate 		return 0;
353*0Sstevel@tonic-gate 		}
354*0Sstevel@tonic-gate 	/* So, we require input */
355*0Sstevel@tonic-gate 	if(arg == NULL)
356*0Sstevel@tonic-gate 		{
357*0Sstevel@tonic-gate 		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
358*0Sstevel@tonic-gate 			ENGINE_R_COMMAND_TAKES_INPUT);
359*0Sstevel@tonic-gate 		return 0;
360*0Sstevel@tonic-gate 		}
361*0Sstevel@tonic-gate 	/* If it takes string input, that's easy */
362*0Sstevel@tonic-gate 	if(flags & ENGINE_CMD_FLAG_STRING)
363*0Sstevel@tonic-gate 		{
364*0Sstevel@tonic-gate 		/* Same explanation as above */
365*0Sstevel@tonic-gate 		if(ENGINE_ctrl(e, num, 0, (void *)arg, NULL))
366*0Sstevel@tonic-gate 			return 1;
367*0Sstevel@tonic-gate 		return 0;
368*0Sstevel@tonic-gate 		}
369*0Sstevel@tonic-gate 	/* If it doesn't take numeric either, then it is unsupported for use in
370*0Sstevel@tonic-gate 	 * a config-setting situation, which is what this function is for. This
371*0Sstevel@tonic-gate 	 * should never happen though, because ENGINE_cmd_is_executable() was
372*0Sstevel@tonic-gate 	 * used. */
373*0Sstevel@tonic-gate 	if(!(flags & ENGINE_CMD_FLAG_NUMERIC))
374*0Sstevel@tonic-gate 		{
375*0Sstevel@tonic-gate 		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
376*0Sstevel@tonic-gate 			ENGINE_R_INTERNAL_LIST_ERROR);
377*0Sstevel@tonic-gate 		return 0;
378*0Sstevel@tonic-gate 		}
379*0Sstevel@tonic-gate 	l = strtol(arg, &ptr, 10);
380*0Sstevel@tonic-gate 	if((arg == ptr) || (*ptr != '\0'))
381*0Sstevel@tonic-gate 		{
382*0Sstevel@tonic-gate 		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
383*0Sstevel@tonic-gate 			ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER);
384*0Sstevel@tonic-gate 		return 0;
385*0Sstevel@tonic-gate 		}
386*0Sstevel@tonic-gate 	/* Force the result of the control command to 0 or 1, for the reasons
387*0Sstevel@tonic-gate 	 * mentioned before. */
388*0Sstevel@tonic-gate 	if(ENGINE_ctrl(e, num, l, NULL, NULL))
389*0Sstevel@tonic-gate 		return 1;
390*0Sstevel@tonic-gate 	return 0;
391*0Sstevel@tonic-gate 	}
392