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