Import OpenSSL-0.9.8i.
[dragonfly.git] / crypto / openssl-0.9.7d / 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 BIO_snprintf(s,strlen(e->cmd_defns[idx].cmd_name) + 1,
164                                     "%s", e->cmd_defns[idx].cmd_name);
165         case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD:
166                 if(e->cmd_defns[idx].cmd_desc)
167                         return strlen(e->cmd_defns[idx].cmd_desc);
168                 return strlen(int_no_description);
169         case ENGINE_CTRL_GET_DESC_FROM_CMD:
170                 if(e->cmd_defns[idx].cmd_desc)
171                         return BIO_snprintf(s,
172                                             strlen(e->cmd_defns[idx].cmd_desc) + 1,
173                                             "%s", e->cmd_defns[idx].cmd_desc);
174                 return BIO_snprintf(s, strlen(int_no_description) + 1,"%s",
175                                     int_no_description);
176         case ENGINE_CTRL_GET_CMD_FLAGS:
177                 return e->cmd_defns[idx].cmd_flags;
178                 }
179         /* Shouldn't really be here ... */
180         ENGINEerr(ENGINE_F_INT_CTRL_HELPER,ENGINE_R_INTERNAL_LIST_ERROR);
181         return -1;
182         }
183
184 int ENGINE_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)())
185         {
186         int ctrl_exists, ref_exists;
187         if(e == NULL)
188                 {
189                 ENGINEerr(ENGINE_F_ENGINE_CTRL,ERR_R_PASSED_NULL_PARAMETER);
190                 return 0;
191                 }
192         CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
193         ref_exists = ((e->struct_ref > 0) ? 1 : 0);
194         CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
195         ctrl_exists = ((e->ctrl == NULL) ? 0 : 1);
196         if(!ref_exists)
197                 {
198                 ENGINEerr(ENGINE_F_ENGINE_CTRL,ENGINE_R_NO_REFERENCE);
199                 return 0;
200                 }
201         /* Intercept any "root-level" commands before trying to hand them on to
202          * ctrl() handlers. */
203         switch(cmd)
204                 {
205         case ENGINE_CTRL_HAS_CTRL_FUNCTION:
206                 return ctrl_exists;
207         case ENGINE_CTRL_GET_FIRST_CMD_TYPE:
208         case ENGINE_CTRL_GET_NEXT_CMD_TYPE:
209         case ENGINE_CTRL_GET_CMD_FROM_NAME:
210         case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD:
211         case ENGINE_CTRL_GET_NAME_FROM_CMD:
212         case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD:
213         case ENGINE_CTRL_GET_DESC_FROM_CMD:
214         case ENGINE_CTRL_GET_CMD_FLAGS:
215                 if(ctrl_exists && !(e->flags & ENGINE_FLAGS_MANUAL_CMD_CTRL))
216                         return int_ctrl_helper(e,cmd,i,p,f);
217                 if(!ctrl_exists)
218                         {
219                         ENGINEerr(ENGINE_F_ENGINE_CTRL,ENGINE_R_NO_CONTROL_FUNCTION);
220                         /* For these cmd-related functions, failure is indicated
221                          * by a -1 return value (because 0 is used as a valid
222                          * return in some places). */
223                         return -1;
224                         }
225         default:
226                 break;
227                 }
228         /* Anything else requires a ctrl() handler to exist. */
229         if(!ctrl_exists)
230                 {
231                 ENGINEerr(ENGINE_F_ENGINE_CTRL,ENGINE_R_NO_CONTROL_FUNCTION);
232                 return 0;
233                 }
234         return e->ctrl(e, cmd, i, p, f);
235         }
236
237 int ENGINE_cmd_is_executable(ENGINE *e, int cmd)
238         {
239         int flags;
240         if((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, cmd, NULL, NULL)) < 0)
241                 {
242                 ENGINEerr(ENGINE_F_ENGINE_CMD_IS_EXECUTABLE,
243                         ENGINE_R_INVALID_CMD_NUMBER);
244                 return 0;
245                 }
246         if(!(flags & ENGINE_CMD_FLAG_NO_INPUT) &&
247                         !(flags & ENGINE_CMD_FLAG_NUMERIC) &&
248                         !(flags & ENGINE_CMD_FLAG_STRING))
249                 return 0;
250         return 1;
251         }
252
253 int ENGINE_ctrl_cmd(ENGINE *e, const char *cmd_name,
254         long i, void *p, void (*f)(), int cmd_optional)
255         {
256         int num;
257
258         if((e == NULL) || (cmd_name == NULL))
259                 {
260                 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
261                         ERR_R_PASSED_NULL_PARAMETER);
262                 return 0;
263                 }
264         if((e->ctrl == NULL) || ((num = ENGINE_ctrl(e,
265                                         ENGINE_CTRL_GET_CMD_FROM_NAME,
266                                         0, (void *)cmd_name, NULL)) <= 0))
267                 {
268                 /* If the command didn't *have* to be supported, we fake
269                  * success. This allows certain settings to be specified for
270                  * multiple ENGINEs and only require a change of ENGINE id
271                  * (without having to selectively apply settings). Eg. changing
272                  * from a hardware device back to the regular software ENGINE
273                  * without editing the config file, etc. */
274                 if(cmd_optional)
275                         {
276                         ERR_clear_error();
277                         return 1;
278                         }
279                 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD,
280                         ENGINE_R_INVALID_CMD_NAME);
281                 return 0;
282                 }
283         /* Force the result of the control command to 0 or 1, for the reasons
284          * mentioned before. */
285         if (ENGINE_ctrl(e, num, i, p, f))
286                 return 1;
287         return 0;
288         }
289
290 int ENGINE_ctrl_cmd_string(ENGINE *e, const char *cmd_name, const char *arg,
291                                 int cmd_optional)
292         {
293         int num, flags;
294         long l;
295         char *ptr;
296         if((e == NULL) || (cmd_name == NULL))
297                 {
298                 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
299                         ERR_R_PASSED_NULL_PARAMETER);
300                 return 0;
301                 }
302         if((e->ctrl == NULL) || ((num = ENGINE_ctrl(e,
303                                         ENGINE_CTRL_GET_CMD_FROM_NAME,
304                                         0, (void *)cmd_name, NULL)) <= 0))
305                 {
306                 /* If the command didn't *have* to be supported, we fake
307                  * success. This allows certain settings to be specified for
308                  * multiple ENGINEs and only require a change of ENGINE id
309                  * (without having to selectively apply settings). Eg. changing
310                  * from a hardware device back to the regular software ENGINE
311                  * without editing the config file, etc. */
312                 if(cmd_optional)
313                         {
314                         ERR_clear_error();
315                         return 1;
316                         }
317                 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
318                         ENGINE_R_INVALID_CMD_NAME);
319                 return 0;
320                 }
321         if(!ENGINE_cmd_is_executable(e, num))
322                 {
323                 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
324                         ENGINE_R_CMD_NOT_EXECUTABLE);
325                 return 0;
326                 }
327         if((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num, NULL, NULL)) < 0)
328                 {
329                 /* Shouldn't happen, given that ENGINE_cmd_is_executable()
330                  * returned success. */
331                 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
332                         ENGINE_R_INTERNAL_LIST_ERROR);
333                 return 0;
334                 }
335         /* If the command takes no input, there must be no input. And vice
336          * versa. */
337         if(flags & ENGINE_CMD_FLAG_NO_INPUT)
338                 {
339                 if(arg != NULL)
340                         {
341                         ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
342                                 ENGINE_R_COMMAND_TAKES_NO_INPUT);
343                         return 0;
344                         }
345                 /* We deliberately force the result of ENGINE_ctrl() to 0 or 1
346                  * rather than returning it as "return data". This is to ensure
347                  * usage of these commands is consistent across applications and
348                  * that certain applications don't understand it one way, and
349                  * others another. */
350                 if(ENGINE_ctrl(e, num, 0, (void *)arg, NULL))
351                         return 1;
352                 return 0;
353                 }
354         /* So, we require input */
355         if(arg == NULL)
356                 {
357                 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
358                         ENGINE_R_COMMAND_TAKES_INPUT);
359                 return 0;
360                 }
361         /* If it takes string input, that's easy */
362         if(flags & ENGINE_CMD_FLAG_STRING)
363                 {
364                 /* Same explanation as above */
365                 if(ENGINE_ctrl(e, num, 0, (void *)arg, NULL))
366                         return 1;
367                 return 0;
368                 }
369         /* If it doesn't take numeric either, then it is unsupported for use in
370          * a config-setting situation, which is what this function is for. This
371          * should never happen though, because ENGINE_cmd_is_executable() was
372          * used. */
373         if(!(flags & ENGINE_CMD_FLAG_NUMERIC))
374                 {
375                 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
376                         ENGINE_R_INTERNAL_LIST_ERROR);
377                 return 0;
378                 }
379         l = strtol(arg, &ptr, 10);
380         if((arg == ptr) || (*ptr != '\0'))
381                 {
382                 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
383                         ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER);
384                 return 0;
385                 }
386         /* Force the result of the control command to 0 or 1, for the reasons
387          * mentioned before. */
388         if(ENGINE_ctrl(e, num, l, NULL, NULL))
389                 return 1;
390         return 0;
391         }