|
1 /* crypto/engine/eng_dyn.c */ |
|
2 /* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL |
|
3 * project 2001. |
|
4 */ |
|
5 /* ==================================================================== |
|
6 * Copyright (c) 1999-2001 The OpenSSL Project. All rights reserved. |
|
7 * |
|
8 * Redistribution and use in source and binary forms, with or without |
|
9 * modification, are permitted provided that the following conditions |
|
10 * are met: |
|
11 * |
|
12 * 1. Redistributions of source code must retain the above copyright |
|
13 * notice, this list of conditions and the following disclaimer. |
|
14 * |
|
15 * 2. Redistributions in binary form must reproduce the above copyright |
|
16 * notice, this list of conditions and the following disclaimer in |
|
17 * the documentation and/or other materials provided with the |
|
18 * distribution. |
|
19 * |
|
20 * 3. All advertising materials mentioning features or use of this |
|
21 * software must display the following acknowledgment: |
|
22 * "This product includes software developed by the OpenSSL Project |
|
23 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" |
|
24 * |
|
25 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to |
|
26 * endorse or promote products derived from this software without |
|
27 * prior written permission. For written permission, please contact |
|
28 * licensing@OpenSSL.org. |
|
29 * |
|
30 * 5. Products derived from this software may not be called "OpenSSL" |
|
31 * nor may "OpenSSL" appear in their names without prior written |
|
32 * permission of the OpenSSL Project. |
|
33 * |
|
34 * 6. Redistributions of any form whatsoever must retain the following |
|
35 * acknowledgment: |
|
36 * "This product includes software developed by the OpenSSL Project |
|
37 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" |
|
38 * |
|
39 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY |
|
40 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
42 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR |
|
43 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
|
45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
|
48 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
|
50 * OF THE POSSIBILITY OF SUCH DAMAGE. |
|
51 * ==================================================================== |
|
52 * |
|
53 * This product includes cryptographic software written by Eric Young |
|
54 * (eay@cryptsoft.com). This product includes software written by Tim |
|
55 * Hudson (tjh@cryptsoft.com). |
|
56 * |
|
57 */ |
|
58 |
|
59 /* |
|
60 © Portions copyright (c) 2006 Nokia Corporation. All rights reserved. |
|
61 */ |
|
62 |
|
63 |
|
64 #include "eng_int.h" |
|
65 #include <openssl/dso.h> |
|
66 #if (defined(SYMBIAN) && (defined(__WINSCW__) || defined(__WINS__))) |
|
67 #include "libcrypto_wsd_macros.h" |
|
68 #include "libcrypto_wsd.h" |
|
69 #endif |
|
70 |
|
71 /* Shared libraries implementing ENGINEs for use by the "dynamic" ENGINE loader |
|
72 * should implement the hook-up functions with the following prototypes. */ |
|
73 |
|
74 /* Our ENGINE handlers */ |
|
75 static int dynamic_init(ENGINE *e); |
|
76 static int dynamic_finish(ENGINE *e); |
|
77 static int dynamic_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void)); |
|
78 /* Predeclare our context type */ |
|
79 typedef struct st_dynamic_data_ctx dynamic_data_ctx; |
|
80 /* The implementation for the important control command */ |
|
81 static int dynamic_load(ENGINE *e, dynamic_data_ctx *ctx); |
|
82 |
|
83 #define DYNAMIC_CMD_SO_PATH ENGINE_CMD_BASE |
|
84 #define DYNAMIC_CMD_NO_VCHECK (ENGINE_CMD_BASE + 1) |
|
85 #define DYNAMIC_CMD_ID (ENGINE_CMD_BASE + 2) |
|
86 #define DYNAMIC_CMD_LIST_ADD (ENGINE_CMD_BASE + 3) |
|
87 #define DYNAMIC_CMD_DIR_LOAD (ENGINE_CMD_BASE + 4) |
|
88 #define DYNAMIC_CMD_DIR_ADD (ENGINE_CMD_BASE + 5) |
|
89 #define DYNAMIC_CMD_LOAD (ENGINE_CMD_BASE + 6) |
|
90 |
|
91 /* The constants used when creating the ENGINE */ |
|
92 #ifndef EMULATOR |
|
93 static const char *engine_dynamic_id = "dynamic"; |
|
94 static const char *engine_dynamic_name = "Dynamic engine loading support"; |
|
95 #else |
|
96 static const char *const engine_dynamic_id = "dynamic"; |
|
97 static const char *const engine_dynamic_name = "Dynamic engine loading support"; |
|
98 #endif |
|
99 static const ENGINE_CMD_DEFN dynamic_cmd_defns[] = { |
|
100 {DYNAMIC_CMD_SO_PATH, |
|
101 "SO_PATH", |
|
102 "Specifies the path to the new ENGINE shared library", |
|
103 ENGINE_CMD_FLAG_STRING}, |
|
104 {DYNAMIC_CMD_NO_VCHECK, |
|
105 "NO_VCHECK", |
|
106 "Specifies to continue even if version checking fails (boolean)", |
|
107 ENGINE_CMD_FLAG_NUMERIC}, |
|
108 {DYNAMIC_CMD_ID, |
|
109 "ID", |
|
110 "Specifies an ENGINE id name for loading", |
|
111 ENGINE_CMD_FLAG_STRING}, |
|
112 {DYNAMIC_CMD_LIST_ADD, |
|
113 "LIST_ADD", |
|
114 "Whether to add a loaded ENGINE to the internal list (0=no,1=yes,2=mandatory)", |
|
115 ENGINE_CMD_FLAG_NUMERIC}, |
|
116 {DYNAMIC_CMD_DIR_LOAD, |
|
117 "DIR_LOAD", |
|
118 "Specifies whether to load from 'DIR_ADD' directories (0=no,1=yes,2=mandatory)", |
|
119 ENGINE_CMD_FLAG_NUMERIC}, |
|
120 {DYNAMIC_CMD_DIR_ADD, |
|
121 "DIR_ADD", |
|
122 "Adds a directory from which ENGINEs can be loaded", |
|
123 ENGINE_CMD_FLAG_STRING}, |
|
124 {DYNAMIC_CMD_LOAD, |
|
125 "LOAD", |
|
126 "Load up the ENGINE specified by other settings", |
|
127 ENGINE_CMD_FLAG_NO_INPUT}, |
|
128 {0, NULL, NULL, 0} |
|
129 }; |
|
130 static const ENGINE_CMD_DEFN dynamic_cmd_defns_empty[] = { |
|
131 {0, NULL, NULL, 0} |
|
132 }; |
|
133 |
|
134 /* Loading code stores state inside the ENGINE structure via the "ex_data" |
|
135 * element. We load all our state into a single structure and use that as a |
|
136 * single context in the "ex_data" stack. */ |
|
137 struct st_dynamic_data_ctx |
|
138 { |
|
139 /* The DSO object we load that supplies the ENGINE code */ |
|
140 DSO *dynamic_dso; |
|
141 /* The function pointer to the version checking shared library function */ |
|
142 dynamic_v_check_fn v_check; |
|
143 /* The function pointer to the engine-binding shared library function */ |
|
144 dynamic_bind_engine bind_engine; |
|
145 /* The default name/path for loading the shared library */ |
|
146 const char *DYNAMIC_LIBNAME; |
|
147 /* Whether to continue loading on a version check failure */ |
|
148 int no_vcheck; |
|
149 /* If non-NULL, stipulates the 'id' of the ENGINE to be loaded */ |
|
150 const char *engine_id; |
|
151 /* If non-zero, a successfully loaded ENGINE should be added to the internal |
|
152 * ENGINE list. If 2, the add must succeed or the entire load should fail. */ |
|
153 int list_add_value; |
|
154 /* The symbol name for the version checking function */ |
|
155 const char *DYNAMIC_F1; |
|
156 /* The symbol name for the "initialise ENGINE structure" function */ |
|
157 const char *DYNAMIC_F2; |
|
158 /* Whether to never use 'dirs', use 'dirs' as a fallback, or only use |
|
159 * 'dirs' for loading. Default is to use 'dirs' as a fallback. */ |
|
160 int dir_load; |
|
161 /* A stack of directories from which ENGINEs could be loaded */ |
|
162 STACK *dirs; |
|
163 }; |
|
164 |
|
165 /* This is the "ex_data" index we obtain and reserve for use with our context |
|
166 * structure. */ |
|
167 #ifndef EMULATOR |
|
168 static int dynamic_ex_data_idx = -1; |
|
169 #else |
|
170 GET_STATIC_VAR_FROM_TLS(dynamic_ex_data_idx,eng_dyn,int) |
|
171 #define dynamic_ex_data_idx (*GET_WSD_VAR_NAME(dynamic_ex_data_idx,eng_dyn, s)()) |
|
172 #endif |
|
173 |
|
174 static void int_free_str(void *s) { OPENSSL_free(s); } |
|
175 /* Because our ex_data element may or may not get allocated depending on whether |
|
176 * a "first-use" occurs before the ENGINE is freed, we have a memory leak |
|
177 * problem to solve. We can't declare a "new" handler for the ex_data as we |
|
178 * don't want a dynamic_data_ctx in *all* ENGINE structures of all types (this |
|
179 * is a bug in the design of CRYPTO_EX_DATA). As such, we just declare a "free" |
|
180 * handler and that will get called if an ENGINE is being destroyed and there |
|
181 * was an ex_data element corresponding to our context type. */ |
|
182 static void dynamic_data_ctx_free_func(void *parent, void *ptr, |
|
183 CRYPTO_EX_DATA *ad, int idx, long argl, void *argp) |
|
184 { |
|
185 if(ptr) |
|
186 { |
|
187 dynamic_data_ctx *ctx = (dynamic_data_ctx *)ptr; |
|
188 if(ctx->dynamic_dso) |
|
189 DSO_free(ctx->dynamic_dso); |
|
190 if(ctx->DYNAMIC_LIBNAME) |
|
191 OPENSSL_free((void*)ctx->DYNAMIC_LIBNAME); |
|
192 if(ctx->engine_id) |
|
193 OPENSSL_free((void*)ctx->engine_id); |
|
194 if(ctx->dirs) |
|
195 sk_pop_free(ctx->dirs, int_free_str); |
|
196 OPENSSL_free(ctx); |
|
197 } |
|
198 } |
|
199 |
|
200 /* Construct the per-ENGINE context. We create it blindly and then use a lock to |
|
201 * check for a race - if so, all but one of the threads "racing" will have |
|
202 * wasted their time. The alternative involves creating everything inside the |
|
203 * lock which is far worse. */ |
|
204 static int dynamic_set_data_ctx(ENGINE *e, dynamic_data_ctx **ctx) |
|
205 { |
|
206 dynamic_data_ctx *c; |
|
207 c = OPENSSL_malloc(sizeof(dynamic_data_ctx)); |
|
208 if(!c) |
|
209 { |
|
210 ENGINEerr(ENGINE_F_DYNAMIC_SET_DATA_CTX,ERR_R_MALLOC_FAILURE); |
|
211 return 0; |
|
212 } |
|
213 memset(c, 0, sizeof(dynamic_data_ctx)); |
|
214 c->dynamic_dso = NULL; |
|
215 c->v_check = NULL; |
|
216 c->bind_engine = NULL; |
|
217 c->DYNAMIC_LIBNAME = NULL; |
|
218 c->no_vcheck = 0; |
|
219 c->engine_id = NULL; |
|
220 c->list_add_value = 0; |
|
221 c->DYNAMIC_F1 = "v_check"; |
|
222 c->DYNAMIC_F2 = "bind_engine"; |
|
223 c->dir_load = 1; |
|
224 c->dirs = sk_new_null(); |
|
225 if(!c->dirs) |
|
226 { |
|
227 ENGINEerr(ENGINE_F_DYNAMIC_SET_DATA_CTX,ERR_R_MALLOC_FAILURE); |
|
228 OPENSSL_free(c); |
|
229 return 0; |
|
230 } |
|
231 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); |
|
232 if((*ctx = (dynamic_data_ctx *)ENGINE_get_ex_data(e, |
|
233 dynamic_ex_data_idx)) == NULL) |
|
234 { |
|
235 /* Good, we're the first */ |
|
236 ENGINE_set_ex_data(e, dynamic_ex_data_idx, c); |
|
237 *ctx = c; |
|
238 c = NULL; |
|
239 } |
|
240 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); |
|
241 /* If we lost the race to set the context, c is non-NULL and *ctx is the |
|
242 * context of the thread that won. */ |
|
243 if(c) |
|
244 OPENSSL_free(c); |
|
245 return 1; |
|
246 } |
|
247 |
|
248 /* This function retrieves the context structure from an ENGINE's "ex_data", or |
|
249 * if it doesn't exist yet, sets it up. */ |
|
250 static dynamic_data_ctx *dynamic_get_data_ctx(ENGINE *e) |
|
251 { |
|
252 dynamic_data_ctx *ctx; |
|
253 if(dynamic_ex_data_idx < 0) |
|
254 { |
|
255 /* Create and register the ENGINE ex_data, and associate our |
|
256 * "free" function with it to ensure any allocated contexts get |
|
257 * freed when an ENGINE goes underground. */ |
|
258 int new_idx = ENGINE_get_ex_new_index(0, NULL, NULL, NULL, |
|
259 dynamic_data_ctx_free_func); |
|
260 if(new_idx == -1) |
|
261 { |
|
262 ENGINEerr(ENGINE_F_DYNAMIC_GET_DATA_CTX,ENGINE_R_NO_INDEX); |
|
263 return NULL; |
|
264 } |
|
265 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); |
|
266 /* Avoid a race by checking again inside this lock */ |
|
267 if(dynamic_ex_data_idx < 0) |
|
268 { |
|
269 /* Good, someone didn't beat us to it */ |
|
270 dynamic_ex_data_idx = new_idx; |
|
271 new_idx = -1; |
|
272 } |
|
273 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); |
|
274 /* In theory we could "give back" the index here if |
|
275 * (new_idx>-1), but it's not possible and wouldn't gain us much |
|
276 * if it were. */ |
|
277 } |
|
278 ctx = (dynamic_data_ctx *)ENGINE_get_ex_data(e, dynamic_ex_data_idx); |
|
279 /* Check if the context needs to be created */ |
|
280 if((ctx == NULL) && !dynamic_set_data_ctx(e, &ctx)) |
|
281 /* "set_data" will set errors if necessary */ |
|
282 return NULL; |
|
283 return ctx; |
|
284 } |
|
285 |
|
286 static ENGINE *engine_dynamic(void) |
|
287 { |
|
288 ENGINE *ret = ENGINE_new(); |
|
289 if(!ret) |
|
290 return NULL; |
|
291 if(!ENGINE_set_id(ret, engine_dynamic_id) || |
|
292 !ENGINE_set_name(ret, engine_dynamic_name) || |
|
293 !ENGINE_set_init_function(ret, dynamic_init) || |
|
294 !ENGINE_set_finish_function(ret, dynamic_finish) || |
|
295 !ENGINE_set_ctrl_function(ret, dynamic_ctrl) || |
|
296 !ENGINE_set_flags(ret, ENGINE_FLAGS_BY_ID_COPY) || |
|
297 !ENGINE_set_cmd_defns(ret, dynamic_cmd_defns)) |
|
298 { |
|
299 ENGINE_free(ret); |
|
300 return NULL; |
|
301 } |
|
302 return ret; |
|
303 } |
|
304 |
|
305 EXPORT_C void ENGINE_load_dynamic(void) |
|
306 { |
|
307 ENGINE *toadd = engine_dynamic(); |
|
308 if(!toadd) return; |
|
309 ENGINE_add(toadd); |
|
310 /* If the "add" worked, it gets a structural reference. So either way, |
|
311 * we release our just-created reference. */ |
|
312 ENGINE_free(toadd); |
|
313 /* If the "add" didn't work, it was probably a conflict because it was |
|
314 * already added (eg. someone calling ENGINE_load_blah then calling |
|
315 * ENGINE_load_builtin_engines() perhaps). */ |
|
316 ERR_clear_error(); |
|
317 } |
|
318 |
|
319 static int dynamic_init(ENGINE *e) |
|
320 { |
|
321 /* We always return failure - the "dyanamic" engine itself can't be used |
|
322 * for anything. */ |
|
323 return 0; |
|
324 } |
|
325 |
|
326 static int dynamic_finish(ENGINE *e) |
|
327 { |
|
328 /* This should never be called on account of "dynamic_init" always |
|
329 * failing. */ |
|
330 return 0; |
|
331 } |
|
332 |
|
333 static int dynamic_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void)) |
|
334 { |
|
335 dynamic_data_ctx *ctx = dynamic_get_data_ctx(e); |
|
336 int initialised; |
|
337 |
|
338 if(!ctx) |
|
339 { |
|
340 ENGINEerr(ENGINE_F_DYNAMIC_CTRL,ENGINE_R_NOT_LOADED); |
|
341 return 0; |
|
342 } |
|
343 initialised = ((ctx->dynamic_dso == NULL) ? 0 : 1); |
|
344 /* All our control commands require the ENGINE to be uninitialised */ |
|
345 if(initialised) |
|
346 { |
|
347 ENGINEerr(ENGINE_F_DYNAMIC_CTRL, |
|
348 ENGINE_R_ALREADY_LOADED); |
|
349 return 0; |
|
350 } |
|
351 switch(cmd) |
|
352 { |
|
353 case DYNAMIC_CMD_SO_PATH: |
|
354 /* a NULL 'p' or a string of zero-length is the same thing */ |
|
355 if(p && (strlen((const char *)p) < 1)) |
|
356 p = NULL; |
|
357 if(ctx->DYNAMIC_LIBNAME) |
|
358 OPENSSL_free((void*)ctx->DYNAMIC_LIBNAME); |
|
359 if(p) |
|
360 ctx->DYNAMIC_LIBNAME = BUF_strdup(p); |
|
361 else |
|
362 ctx->DYNAMIC_LIBNAME = NULL; |
|
363 return (ctx->DYNAMIC_LIBNAME ? 1 : 0); |
|
364 case DYNAMIC_CMD_NO_VCHECK: |
|
365 ctx->no_vcheck = ((i == 0) ? 0 : 1); |
|
366 return 1; |
|
367 case DYNAMIC_CMD_ID: |
|
368 /* a NULL 'p' or a string of zero-length is the same thing */ |
|
369 if(p && (strlen((const char *)p) < 1)) |
|
370 p = NULL; |
|
371 if(ctx->engine_id) |
|
372 OPENSSL_free((void*)ctx->engine_id); |
|
373 if(p) |
|
374 ctx->engine_id = BUF_strdup(p); |
|
375 else |
|
376 ctx->engine_id = NULL; |
|
377 return (ctx->engine_id ? 1 : 0); |
|
378 case DYNAMIC_CMD_LIST_ADD: |
|
379 if((i < 0) || (i > 2)) |
|
380 { |
|
381 ENGINEerr(ENGINE_F_DYNAMIC_CTRL, |
|
382 ENGINE_R_INVALID_ARGUMENT); |
|
383 return 0; |
|
384 } |
|
385 ctx->list_add_value = (int)i; |
|
386 return 1; |
|
387 case DYNAMIC_CMD_LOAD: |
|
388 return dynamic_load(e, ctx); |
|
389 case DYNAMIC_CMD_DIR_LOAD: |
|
390 if((i < 0) || (i > 2)) |
|
391 { |
|
392 ENGINEerr(ENGINE_F_DYNAMIC_CTRL, |
|
393 ENGINE_R_INVALID_ARGUMENT); |
|
394 return 0; |
|
395 } |
|
396 ctx->dir_load = (int)i; |
|
397 return 1; |
|
398 case DYNAMIC_CMD_DIR_ADD: |
|
399 /* a NULL 'p' or a string of zero-length is the same thing */ |
|
400 if(!p || (strlen((const char *)p) < 1)) |
|
401 { |
|
402 ENGINEerr(ENGINE_F_DYNAMIC_CTRL, |
|
403 ENGINE_R_INVALID_ARGUMENT); |
|
404 return 0; |
|
405 } |
|
406 { |
|
407 char *tmp_str = BUF_strdup(p); |
|
408 if(!tmp_str) |
|
409 { |
|
410 ENGINEerr(ENGINE_F_DYNAMIC_CTRL, |
|
411 ERR_R_MALLOC_FAILURE); |
|
412 return 0; |
|
413 } |
|
414 sk_insert(ctx->dirs, tmp_str, -1); |
|
415 } |
|
416 return 1; |
|
417 default: |
|
418 break; |
|
419 } |
|
420 ENGINEerr(ENGINE_F_DYNAMIC_CTRL,ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED); |
|
421 return 0; |
|
422 } |
|
423 |
|
424 static int int_load(dynamic_data_ctx *ctx) |
|
425 { |
|
426 int num, loop; |
|
427 /* Unless told not to, try a direct load */ |
|
428 if((ctx->dir_load != 2) && (DSO_load(ctx->dynamic_dso, |
|
429 ctx->DYNAMIC_LIBNAME, NULL, 0)) != NULL) |
|
430 return 1; |
|
431 /* If we're not allowed to use 'dirs' or we have none, fail */ |
|
432 if(!ctx->dir_load || ((num = sk_num(ctx->dirs)) < 1)) |
|
433 return 0; |
|
434 for(loop = 0; loop < num; loop++) |
|
435 { |
|
436 const char *s = sk_value(ctx->dirs, loop); |
|
437 char *merge = DSO_merge(ctx->dynamic_dso, ctx->DYNAMIC_LIBNAME, s); |
|
438 if(!merge) |
|
439 return 0; |
|
440 if(DSO_load(ctx->dynamic_dso, merge, NULL, 0)) |
|
441 { |
|
442 /* Found what we're looking for */ |
|
443 OPENSSL_free(merge); |
|
444 return 1; |
|
445 } |
|
446 OPENSSL_free(merge); |
|
447 } |
|
448 return 0; |
|
449 } |
|
450 |
|
451 static int dynamic_load(ENGINE *e, dynamic_data_ctx *ctx) |
|
452 { |
|
453 ENGINE cpy; |
|
454 dynamic_fns fns; |
|
455 |
|
456 if(!ctx->dynamic_dso) |
|
457 ctx->dynamic_dso = DSO_new(); |
|
458 if(!ctx->DYNAMIC_LIBNAME) |
|
459 { |
|
460 if(!ctx->engine_id) |
|
461 return 0; |
|
462 ctx->DYNAMIC_LIBNAME = |
|
463 DSO_convert_filename(ctx->dynamic_dso, ctx->engine_id); |
|
464 } |
|
465 if(!int_load(ctx)) |
|
466 { |
|
467 ENGINEerr(ENGINE_F_DYNAMIC_LOAD, |
|
468 ENGINE_R_DSO_NOT_FOUND); |
|
469 DSO_free(ctx->dynamic_dso); |
|
470 ctx->dynamic_dso = NULL; |
|
471 return 0; |
|
472 } |
|
473 /* We have to find a bind function otherwise it'll always end badly */ |
|
474 if(!(ctx->bind_engine = (dynamic_bind_engine)DSO_bind_func( |
|
475 ctx->dynamic_dso, ctx->DYNAMIC_F2))) |
|
476 { |
|
477 ctx->bind_engine = NULL; |
|
478 DSO_free(ctx->dynamic_dso); |
|
479 ctx->dynamic_dso = NULL; |
|
480 ENGINEerr(ENGINE_F_DYNAMIC_LOAD, |
|
481 ENGINE_R_DSO_FAILURE); |
|
482 return 0; |
|
483 } |
|
484 /* Do we perform version checking? */ |
|
485 if(!ctx->no_vcheck) |
|
486 { |
|
487 unsigned long vcheck_res = 0; |
|
488 /* Now we try to find a version checking function and decide how |
|
489 * to cope with failure if/when it fails. */ |
|
490 ctx->v_check = (dynamic_v_check_fn)DSO_bind_func( |
|
491 ctx->dynamic_dso, ctx->DYNAMIC_F1); |
|
492 if(ctx->v_check) |
|
493 vcheck_res = ctx->v_check(OSSL_DYNAMIC_VERSION); |
|
494 /* We fail if the version checker veto'd the load *or* if it is |
|
495 * deferring to us (by returning its version) and we think it is |
|
496 * too old. */ |
|
497 if(vcheck_res < OSSL_DYNAMIC_OLDEST) |
|
498 { |
|
499 /* Fail */ |
|
500 ctx->bind_engine = NULL; |
|
501 ctx->v_check = NULL; |
|
502 DSO_free(ctx->dynamic_dso); |
|
503 ctx->dynamic_dso = NULL; |
|
504 ENGINEerr(ENGINE_F_DYNAMIC_LOAD, |
|
505 ENGINE_R_VERSION_INCOMPATIBILITY); |
|
506 return 0; |
|
507 } |
|
508 } |
|
509 /* First binary copy the ENGINE structure so that we can roll back if |
|
510 * the hand-over fails */ |
|
511 memcpy(&cpy, e, sizeof(ENGINE)); |
|
512 /* Provide the ERR, "ex_data", memory, and locking callbacks so the |
|
513 * loaded library uses our state rather than its own. FIXME: As noted in |
|
514 * engine.h, much of this would be simplified if each area of code |
|
515 * provided its own "summary" structure of all related callbacks. It |
|
516 * would also increase opaqueness. */ |
|
517 fns.static_state = ENGINE_get_static_state(); |
|
518 fns.err_fns = ERR_get_implementation(); |
|
519 fns.ex_data_fns = CRYPTO_get_ex_data_implementation(); |
|
520 CRYPTO_get_mem_functions(&fns.mem_fns.malloc_cb, |
|
521 &fns.mem_fns.realloc_cb, |
|
522 &fns.mem_fns.free_cb); |
|
523 fns.lock_fns.lock_locking_cb = CRYPTO_get_locking_callback(); |
|
524 fns.lock_fns.lock_add_lock_cb = CRYPTO_get_add_lock_callback(); |
|
525 fns.lock_fns.dynlock_create_cb = CRYPTO_get_dynlock_create_callback(); |
|
526 fns.lock_fns.dynlock_lock_cb = CRYPTO_get_dynlock_lock_callback(); |
|
527 fns.lock_fns.dynlock_destroy_cb = CRYPTO_get_dynlock_destroy_callback(); |
|
528 /* Now that we've loaded the dynamic engine, make sure no "dynamic" |
|
529 * ENGINE elements will show through. */ |
|
530 engine_set_all_null(e); |
|
531 |
|
532 /* Try to bind the ENGINE onto our own ENGINE structure */ |
|
533 if(!ctx->bind_engine(e, ctx->engine_id, &fns)) |
|
534 { |
|
535 ctx->bind_engine = NULL; |
|
536 ctx->v_check = NULL; |
|
537 DSO_free(ctx->dynamic_dso); |
|
538 ctx->dynamic_dso = NULL; |
|
539 ENGINEerr(ENGINE_F_DYNAMIC_LOAD,ENGINE_R_INIT_FAILED); |
|
540 /* Copy the original ENGINE structure back */ |
|
541 memcpy(e, &cpy, sizeof(ENGINE)); |
|
542 return 0; |
|
543 } |
|
544 /* Do we try to add this ENGINE to the internal list too? */ |
|
545 if(ctx->list_add_value > 0) |
|
546 { |
|
547 if(!ENGINE_add(e)) |
|
548 { |
|
549 /* Do we tolerate this or fail? */ |
|
550 if(ctx->list_add_value > 1) |
|
551 { |
|
552 /* Fail - NB: By this time, it's too late to |
|
553 * rollback, and trying to do so allows the |
|
554 * bind_engine() code to have created leaks. We |
|
555 * just have to fail where we are, after the |
|
556 * ENGINE has changed. */ |
|
557 ENGINEerr(ENGINE_F_DYNAMIC_LOAD, |
|
558 ENGINE_R_CONFLICTING_ENGINE_ID); |
|
559 return 0; |
|
560 } |
|
561 /* Tolerate */ |
|
562 ERR_clear_error(); |
|
563 } |
|
564 } |
|
565 return 1; |
|
566 } |