1109998Smarkm/* crypto/engine/eng_dyn.c */ 2280304Sjkim/* 3280304Sjkim * Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL project 4280304Sjkim * 2001. 5109998Smarkm */ 6109998Smarkm/* ==================================================================== 7109998Smarkm * Copyright (c) 1999-2001 The OpenSSL Project. All rights reserved. 8109998Smarkm * 9109998Smarkm * Redistribution and use in source and binary forms, with or without 10109998Smarkm * modification, are permitted provided that the following conditions 11109998Smarkm * are met: 12109998Smarkm * 13109998Smarkm * 1. Redistributions of source code must retain the above copyright 14280304Sjkim * notice, this list of conditions and the following disclaimer. 15109998Smarkm * 16109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright 17109998Smarkm * notice, this list of conditions and the following disclaimer in 18109998Smarkm * the documentation and/or other materials provided with the 19109998Smarkm * distribution. 20109998Smarkm * 21109998Smarkm * 3. All advertising materials mentioning features or use of this 22109998Smarkm * software must display the following acknowledgment: 23109998Smarkm * "This product includes software developed by the OpenSSL Project 24109998Smarkm * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 25109998Smarkm * 26109998Smarkm * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 27109998Smarkm * endorse or promote products derived from this software without 28109998Smarkm * prior written permission. For written permission, please contact 29109998Smarkm * licensing@OpenSSL.org. 30109998Smarkm * 31109998Smarkm * 5. Products derived from this software may not be called "OpenSSL" 32109998Smarkm * nor may "OpenSSL" appear in their names without prior written 33109998Smarkm * permission of the OpenSSL Project. 34109998Smarkm * 35109998Smarkm * 6. Redistributions of any form whatsoever must retain the following 36109998Smarkm * acknowledgment: 37109998Smarkm * "This product includes software developed by the OpenSSL Project 38109998Smarkm * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 39109998Smarkm * 40109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 41109998Smarkm * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43109998Smarkm * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44109998Smarkm * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45109998Smarkm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46109998Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47109998Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49109998Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50109998Smarkm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51109998Smarkm * OF THE POSSIBILITY OF SUCH DAMAGE. 52109998Smarkm * ==================================================================== 53109998Smarkm * 54109998Smarkm * This product includes cryptographic software written by Eric Young 55109998Smarkm * (eay@cryptsoft.com). This product includes software written by Tim 56109998Smarkm * Hudson (tjh@cryptsoft.com). 57109998Smarkm * 58109998Smarkm */ 59109998Smarkm 60109998Smarkm#include "eng_int.h" 61109998Smarkm#include <openssl/dso.h> 62109998Smarkm 63280304Sjkim/* 64280304Sjkim * Shared libraries implementing ENGINEs for use by the "dynamic" ENGINE 65280304Sjkim * loader should implement the hook-up functions with the following 66280304Sjkim * prototypes. 67280304Sjkim */ 68109998Smarkm 69109998Smarkm/* Our ENGINE handlers */ 70109998Smarkmstatic int dynamic_init(ENGINE *e); 71109998Smarkmstatic int dynamic_finish(ENGINE *e); 72280304Sjkimstatic int dynamic_ctrl(ENGINE *e, int cmd, long i, void *p, 73280304Sjkim void (*f) (void)); 74109998Smarkm/* Predeclare our context type */ 75109998Smarkmtypedef struct st_dynamic_data_ctx dynamic_data_ctx; 76109998Smarkm/* The implementation for the important control command */ 77109998Smarkmstatic int dynamic_load(ENGINE *e, dynamic_data_ctx *ctx); 78109998Smarkm 79280304Sjkim#define DYNAMIC_CMD_SO_PATH ENGINE_CMD_BASE 80280304Sjkim#define DYNAMIC_CMD_NO_VCHECK (ENGINE_CMD_BASE + 1) 81280304Sjkim#define DYNAMIC_CMD_ID (ENGINE_CMD_BASE + 2) 82280304Sjkim#define DYNAMIC_CMD_LIST_ADD (ENGINE_CMD_BASE + 3) 83280304Sjkim#define DYNAMIC_CMD_DIR_LOAD (ENGINE_CMD_BASE + 4) 84280304Sjkim#define DYNAMIC_CMD_DIR_ADD (ENGINE_CMD_BASE + 5) 85280304Sjkim#define DYNAMIC_CMD_LOAD (ENGINE_CMD_BASE + 6) 86109998Smarkm 87109998Smarkm/* The constants used when creating the ENGINE */ 88109998Smarkmstatic const char *engine_dynamic_id = "dynamic"; 89109998Smarkmstatic const char *engine_dynamic_name = "Dynamic engine loading support"; 90109998Smarkmstatic const ENGINE_CMD_DEFN dynamic_cmd_defns[] = { 91280304Sjkim {DYNAMIC_CMD_SO_PATH, 92280304Sjkim "SO_PATH", 93280304Sjkim "Specifies the path to the new ENGINE shared library", 94280304Sjkim ENGINE_CMD_FLAG_STRING}, 95280304Sjkim {DYNAMIC_CMD_NO_VCHECK, 96280304Sjkim "NO_VCHECK", 97280304Sjkim "Specifies to continue even if version checking fails (boolean)", 98280304Sjkim ENGINE_CMD_FLAG_NUMERIC}, 99280304Sjkim {DYNAMIC_CMD_ID, 100280304Sjkim "ID", 101280304Sjkim "Specifies an ENGINE id name for loading", 102280304Sjkim ENGINE_CMD_FLAG_STRING}, 103280304Sjkim {DYNAMIC_CMD_LIST_ADD, 104280304Sjkim "LIST_ADD", 105280304Sjkim "Whether to add a loaded ENGINE to the internal list (0=no,1=yes,2=mandatory)", 106280304Sjkim ENGINE_CMD_FLAG_NUMERIC}, 107280304Sjkim {DYNAMIC_CMD_DIR_LOAD, 108280304Sjkim "DIR_LOAD", 109280304Sjkim "Specifies whether to load from 'DIR_ADD' directories (0=no,1=yes,2=mandatory)", 110280304Sjkim ENGINE_CMD_FLAG_NUMERIC}, 111280304Sjkim {DYNAMIC_CMD_DIR_ADD, 112280304Sjkim "DIR_ADD", 113280304Sjkim "Adds a directory from which ENGINEs can be loaded", 114280304Sjkim ENGINE_CMD_FLAG_STRING}, 115280304Sjkim {DYNAMIC_CMD_LOAD, 116280304Sjkim "LOAD", 117280304Sjkim "Load up the ENGINE specified by other settings", 118280304Sjkim ENGINE_CMD_FLAG_NO_INPUT}, 119280304Sjkim {0, NULL, NULL, 0} 120280304Sjkim}; 121109998Smarkm 122280304Sjkim/* 123280304Sjkim * Loading code stores state inside the ENGINE structure via the "ex_data" 124109998Smarkm * element. We load all our state into a single structure and use that as a 125280304Sjkim * single context in the "ex_data" stack. 126280304Sjkim */ 127280304Sjkimstruct st_dynamic_data_ctx { 128280304Sjkim /* The DSO object we load that supplies the ENGINE code */ 129280304Sjkim DSO *dynamic_dso; 130280304Sjkim /* 131280304Sjkim * The function pointer to the version checking shared library function 132280304Sjkim */ 133280304Sjkim dynamic_v_check_fn v_check; 134280304Sjkim /* 135280304Sjkim * The function pointer to the engine-binding shared library function 136280304Sjkim */ 137280304Sjkim dynamic_bind_engine bind_engine; 138280304Sjkim /* The default name/path for loading the shared library */ 139280304Sjkim const char *DYNAMIC_LIBNAME; 140280304Sjkim /* Whether to continue loading on a version check failure */ 141280304Sjkim int no_vcheck; 142280304Sjkim /* If non-NULL, stipulates the 'id' of the ENGINE to be loaded */ 143280304Sjkim const char *engine_id; 144280304Sjkim /* 145280304Sjkim * If non-zero, a successfully loaded ENGINE should be added to the 146280304Sjkim * internal ENGINE list. If 2, the add must succeed or the entire load 147280304Sjkim * should fail. 148280304Sjkim */ 149280304Sjkim int list_add_value; 150280304Sjkim /* The symbol name for the version checking function */ 151280304Sjkim const char *DYNAMIC_F1; 152280304Sjkim /* The symbol name for the "initialise ENGINE structure" function */ 153280304Sjkim const char *DYNAMIC_F2; 154280304Sjkim /* 155280304Sjkim * Whether to never use 'dirs', use 'dirs' as a fallback, or only use 156280304Sjkim * 'dirs' for loading. Default is to use 'dirs' as a fallback. 157280304Sjkim */ 158280304Sjkim int dir_load; 159280304Sjkim /* A stack of directories from which ENGINEs could be loaded */ 160280304Sjkim STACK_OF(OPENSSL_STRING) *dirs; 161280304Sjkim}; 162109998Smarkm 163280304Sjkim/* 164280304Sjkim * This is the "ex_data" index we obtain and reserve for use with our context 165280304Sjkim * structure. 166280304Sjkim */ 167109998Smarkmstatic int dynamic_ex_data_idx = -1; 168109998Smarkm 169280304Sjkimstatic void int_free_str(char *s) 170280304Sjkim{ 171280304Sjkim OPENSSL_free(s); 172280304Sjkim} 173280304Sjkim 174280304Sjkim/* 175280304Sjkim * Because our ex_data element may or may not get allocated depending on 176280304Sjkim * whether a "first-use" occurs before the ENGINE is freed, we have a memory 177280304Sjkim * leak problem to solve. We can't declare a "new" handler for the ex_data as 178280304Sjkim * we don't want a dynamic_data_ctx in *all* ENGINE structures of all types 179280304Sjkim * (this is a bug in the design of CRYPTO_EX_DATA). As such, we just declare 180280304Sjkim * a "free" handler and that will get called if an ENGINE is being destroyed 181280304Sjkim * and there was an ex_data element corresponding to our context type. 182280304Sjkim */ 183109998Smarkmstatic void dynamic_data_ctx_free_func(void *parent, void *ptr, 184280304Sjkim CRYPTO_EX_DATA *ad, int idx, long argl, 185280304Sjkim void *argp) 186280304Sjkim{ 187280304Sjkim if (ptr) { 188280304Sjkim dynamic_data_ctx *ctx = (dynamic_data_ctx *)ptr; 189280304Sjkim if (ctx->dynamic_dso) 190280304Sjkim DSO_free(ctx->dynamic_dso); 191280304Sjkim if (ctx->DYNAMIC_LIBNAME) 192280304Sjkim OPENSSL_free((void *)ctx->DYNAMIC_LIBNAME); 193280304Sjkim if (ctx->engine_id) 194280304Sjkim OPENSSL_free((void *)ctx->engine_id); 195280304Sjkim if (ctx->dirs) 196280304Sjkim sk_OPENSSL_STRING_pop_free(ctx->dirs, int_free_str); 197280304Sjkim OPENSSL_free(ctx); 198280304Sjkim } 199280304Sjkim} 200109998Smarkm 201280304Sjkim/* 202280304Sjkim * Construct the per-ENGINE context. We create it blindly and then use a lock 203280304Sjkim * to check for a race - if so, all but one of the threads "racing" will have 204109998Smarkm * wasted their time. The alternative involves creating everything inside the 205280304Sjkim * lock which is far worse. 206280304Sjkim */ 207109998Smarkmstatic int dynamic_set_data_ctx(ENGINE *e, dynamic_data_ctx **ctx) 208280304Sjkim{ 209280304Sjkim dynamic_data_ctx *c; 210280304Sjkim c = OPENSSL_malloc(sizeof(dynamic_data_ctx)); 211280304Sjkim if (!c) { 212280304Sjkim ENGINEerr(ENGINE_F_DYNAMIC_SET_DATA_CTX, ERR_R_MALLOC_FAILURE); 213280304Sjkim return 0; 214280304Sjkim } 215280304Sjkim memset(c, 0, sizeof(dynamic_data_ctx)); 216280304Sjkim c->dynamic_dso = NULL; 217280304Sjkim c->v_check = NULL; 218280304Sjkim c->bind_engine = NULL; 219280304Sjkim c->DYNAMIC_LIBNAME = NULL; 220280304Sjkim c->no_vcheck = 0; 221280304Sjkim c->engine_id = NULL; 222280304Sjkim c->list_add_value = 0; 223280304Sjkim c->DYNAMIC_F1 = "v_check"; 224280304Sjkim c->DYNAMIC_F2 = "bind_engine"; 225280304Sjkim c->dir_load = 1; 226280304Sjkim c->dirs = sk_OPENSSL_STRING_new_null(); 227280304Sjkim if (!c->dirs) { 228280304Sjkim ENGINEerr(ENGINE_F_DYNAMIC_SET_DATA_CTX, ERR_R_MALLOC_FAILURE); 229280304Sjkim OPENSSL_free(c); 230280304Sjkim return 0; 231280304Sjkim } 232280304Sjkim CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 233280304Sjkim if ((*ctx = (dynamic_data_ctx *)ENGINE_get_ex_data(e, 234280304Sjkim dynamic_ex_data_idx)) 235280304Sjkim == NULL) { 236280304Sjkim /* Good, we're the first */ 237280304Sjkim ENGINE_set_ex_data(e, dynamic_ex_data_idx, c); 238280304Sjkim *ctx = c; 239280304Sjkim c = NULL; 240280304Sjkim } 241280304Sjkim CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 242280304Sjkim /* 243280304Sjkim * If we lost the race to set the context, c is non-NULL and *ctx is the 244280304Sjkim * context of the thread that won. 245280304Sjkim */ 246280304Sjkim if (c) 247280304Sjkim OPENSSL_free(c); 248280304Sjkim return 1; 249280304Sjkim} 250109998Smarkm 251280304Sjkim/* 252280304Sjkim * This function retrieves the context structure from an ENGINE's "ex_data", 253280304Sjkim * or if it doesn't exist yet, sets it up. 254280304Sjkim */ 255109998Smarkmstatic dynamic_data_ctx *dynamic_get_data_ctx(ENGINE *e) 256280304Sjkim{ 257280304Sjkim dynamic_data_ctx *ctx; 258280304Sjkim if (dynamic_ex_data_idx < 0) { 259280304Sjkim /* 260280304Sjkim * Create and register the ENGINE ex_data, and associate our "free" 261280304Sjkim * function with it to ensure any allocated contexts get freed when 262280304Sjkim * an ENGINE goes underground. 263280304Sjkim */ 264280304Sjkim int new_idx = ENGINE_get_ex_new_index(0, NULL, NULL, NULL, 265280304Sjkim dynamic_data_ctx_free_func); 266280304Sjkim if (new_idx == -1) { 267280304Sjkim ENGINEerr(ENGINE_F_DYNAMIC_GET_DATA_CTX, ENGINE_R_NO_INDEX); 268280304Sjkim return NULL; 269280304Sjkim } 270280304Sjkim CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 271280304Sjkim /* Avoid a race by checking again inside this lock */ 272280304Sjkim if (dynamic_ex_data_idx < 0) { 273280304Sjkim /* Good, someone didn't beat us to it */ 274280304Sjkim dynamic_ex_data_idx = new_idx; 275280304Sjkim new_idx = -1; 276280304Sjkim } 277280304Sjkim CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 278280304Sjkim /* 279280304Sjkim * In theory we could "give back" the index here if (new_idx>-1), but 280280304Sjkim * it's not possible and wouldn't gain us much if it were. 281280304Sjkim */ 282280304Sjkim } 283280304Sjkim ctx = (dynamic_data_ctx *)ENGINE_get_ex_data(e, dynamic_ex_data_idx); 284280304Sjkim /* Check if the context needs to be created */ 285280304Sjkim if ((ctx == NULL) && !dynamic_set_data_ctx(e, &ctx)) 286280304Sjkim /* "set_data" will set errors if necessary */ 287280304Sjkim return NULL; 288280304Sjkim return ctx; 289280304Sjkim} 290109998Smarkm 291109998Smarkmstatic ENGINE *engine_dynamic(void) 292280304Sjkim{ 293280304Sjkim ENGINE *ret = ENGINE_new(); 294280304Sjkim if (!ret) 295280304Sjkim return NULL; 296280304Sjkim if (!ENGINE_set_id(ret, engine_dynamic_id) || 297280304Sjkim !ENGINE_set_name(ret, engine_dynamic_name) || 298280304Sjkim !ENGINE_set_init_function(ret, dynamic_init) || 299280304Sjkim !ENGINE_set_finish_function(ret, dynamic_finish) || 300280304Sjkim !ENGINE_set_ctrl_function(ret, dynamic_ctrl) || 301280304Sjkim !ENGINE_set_flags(ret, ENGINE_FLAGS_BY_ID_COPY) || 302280304Sjkim !ENGINE_set_cmd_defns(ret, dynamic_cmd_defns)) { 303280304Sjkim ENGINE_free(ret); 304280304Sjkim return NULL; 305280304Sjkim } 306280304Sjkim return ret; 307280304Sjkim} 308109998Smarkm 309109998Smarkmvoid ENGINE_load_dynamic(void) 310280304Sjkim{ 311280304Sjkim ENGINE *toadd = engine_dynamic(); 312280304Sjkim if (!toadd) 313280304Sjkim return; 314280304Sjkim ENGINE_add(toadd); 315280304Sjkim /* 316280304Sjkim * If the "add" worked, it gets a structural reference. So either way, we 317280304Sjkim * release our just-created reference. 318280304Sjkim */ 319280304Sjkim ENGINE_free(toadd); 320280304Sjkim /* 321280304Sjkim * If the "add" didn't work, it was probably a conflict because it was 322280304Sjkim * already added (eg. someone calling ENGINE_load_blah then calling 323280304Sjkim * ENGINE_load_builtin_engines() perhaps). 324280304Sjkim */ 325280304Sjkim ERR_clear_error(); 326280304Sjkim} 327109998Smarkm 328109998Smarkmstatic int dynamic_init(ENGINE *e) 329280304Sjkim{ 330280304Sjkim /* 331280304Sjkim * We always return failure - the "dyanamic" engine itself can't be used 332280304Sjkim * for anything. 333280304Sjkim */ 334280304Sjkim return 0; 335280304Sjkim} 336109998Smarkm 337109998Smarkmstatic int dynamic_finish(ENGINE *e) 338280304Sjkim{ 339280304Sjkim /* 340280304Sjkim * This should never be called on account of "dynamic_init" always 341280304Sjkim * failing. 342280304Sjkim */ 343280304Sjkim return 0; 344280304Sjkim} 345109998Smarkm 346280304Sjkimstatic int dynamic_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void)) 347280304Sjkim{ 348280304Sjkim dynamic_data_ctx *ctx = dynamic_get_data_ctx(e); 349280304Sjkim int initialised; 350109998Smarkm 351280304Sjkim if (!ctx) { 352280304Sjkim ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_NOT_LOADED); 353280304Sjkim return 0; 354280304Sjkim } 355280304Sjkim initialised = ((ctx->dynamic_dso == NULL) ? 0 : 1); 356280304Sjkim /* All our control commands require the ENGINE to be uninitialised */ 357280304Sjkim if (initialised) { 358280304Sjkim ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_ALREADY_LOADED); 359280304Sjkim return 0; 360280304Sjkim } 361280304Sjkim switch (cmd) { 362280304Sjkim case DYNAMIC_CMD_SO_PATH: 363280304Sjkim /* a NULL 'p' or a string of zero-length is the same thing */ 364280304Sjkim if (p && (strlen((const char *)p) < 1)) 365280304Sjkim p = NULL; 366280304Sjkim if (ctx->DYNAMIC_LIBNAME) 367280304Sjkim OPENSSL_free((void *)ctx->DYNAMIC_LIBNAME); 368280304Sjkim if (p) 369280304Sjkim ctx->DYNAMIC_LIBNAME = BUF_strdup(p); 370280304Sjkim else 371280304Sjkim ctx->DYNAMIC_LIBNAME = NULL; 372280304Sjkim return (ctx->DYNAMIC_LIBNAME ? 1 : 0); 373280304Sjkim case DYNAMIC_CMD_NO_VCHECK: 374280304Sjkim ctx->no_vcheck = ((i == 0) ? 0 : 1); 375280304Sjkim return 1; 376280304Sjkim case DYNAMIC_CMD_ID: 377280304Sjkim /* a NULL 'p' or a string of zero-length is the same thing */ 378280304Sjkim if (p && (strlen((const char *)p) < 1)) 379280304Sjkim p = NULL; 380280304Sjkim if (ctx->engine_id) 381280304Sjkim OPENSSL_free((void *)ctx->engine_id); 382280304Sjkim if (p) 383280304Sjkim ctx->engine_id = BUF_strdup(p); 384280304Sjkim else 385280304Sjkim ctx->engine_id = NULL; 386280304Sjkim return (ctx->engine_id ? 1 : 0); 387280304Sjkim case DYNAMIC_CMD_LIST_ADD: 388280304Sjkim if ((i < 0) || (i > 2)) { 389280304Sjkim ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_INVALID_ARGUMENT); 390280304Sjkim return 0; 391280304Sjkim } 392280304Sjkim ctx->list_add_value = (int)i; 393280304Sjkim return 1; 394280304Sjkim case DYNAMIC_CMD_LOAD: 395280304Sjkim return dynamic_load(e, ctx); 396280304Sjkim case DYNAMIC_CMD_DIR_LOAD: 397280304Sjkim if ((i < 0) || (i > 2)) { 398280304Sjkim ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_INVALID_ARGUMENT); 399280304Sjkim return 0; 400280304Sjkim } 401280304Sjkim ctx->dir_load = (int)i; 402280304Sjkim return 1; 403280304Sjkim case DYNAMIC_CMD_DIR_ADD: 404280304Sjkim /* a NULL 'p' or a string of zero-length is the same thing */ 405280304Sjkim if (!p || (strlen((const char *)p) < 1)) { 406280304Sjkim ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_INVALID_ARGUMENT); 407280304Sjkim return 0; 408280304Sjkim } 409280304Sjkim { 410280304Sjkim char *tmp_str = BUF_strdup(p); 411280304Sjkim if (!tmp_str) { 412280304Sjkim ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ERR_R_MALLOC_FAILURE); 413280304Sjkim return 0; 414280304Sjkim } 415280304Sjkim sk_OPENSSL_STRING_insert(ctx->dirs, tmp_str, -1); 416280304Sjkim } 417280304Sjkim return 1; 418280304Sjkim default: 419280304Sjkim break; 420280304Sjkim } 421280304Sjkim ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED); 422280304Sjkim return 0; 423280304Sjkim} 424280304Sjkim 425160814Ssimonstatic int int_load(dynamic_data_ctx *ctx) 426280304Sjkim{ 427280304Sjkim int num, loop; 428280304Sjkim /* Unless told not to, try a direct load */ 429280304Sjkim if ((ctx->dir_load != 2) && (DSO_load(ctx->dynamic_dso, 430280304Sjkim ctx->DYNAMIC_LIBNAME, NULL, 431280304Sjkim 0)) != NULL) 432280304Sjkim return 1; 433280304Sjkim /* If we're not allowed to use 'dirs' or we have none, fail */ 434280304Sjkim if (!ctx->dir_load || (num = sk_OPENSSL_STRING_num(ctx->dirs)) < 1) 435280304Sjkim return 0; 436280304Sjkim for (loop = 0; loop < num; loop++) { 437280304Sjkim const char *s = sk_OPENSSL_STRING_value(ctx->dirs, loop); 438280304Sjkim char *merge = DSO_merge(ctx->dynamic_dso, ctx->DYNAMIC_LIBNAME, s); 439280304Sjkim if (!merge) 440280304Sjkim return 0; 441280304Sjkim if (DSO_load(ctx->dynamic_dso, merge, NULL, 0)) { 442280304Sjkim /* Found what we're looking for */ 443280304Sjkim OPENSSL_free(merge); 444280304Sjkim return 1; 445280304Sjkim } 446280304Sjkim OPENSSL_free(merge); 447280304Sjkim } 448280304Sjkim return 0; 449280304Sjkim} 450160814Ssimon 451109998Smarkmstatic int dynamic_load(ENGINE *e, dynamic_data_ctx *ctx) 452280304Sjkim{ 453280304Sjkim ENGINE cpy; 454280304Sjkim dynamic_fns fns; 455109998Smarkm 456280304Sjkim if (!ctx->dynamic_dso) 457280304Sjkim ctx->dynamic_dso = DSO_new(); 458280304Sjkim if (!ctx->DYNAMIC_LIBNAME) { 459280304Sjkim if (!ctx->engine_id) 460280304Sjkim return 0; 461280304Sjkim ctx->DYNAMIC_LIBNAME = 462280304Sjkim DSO_convert_filename(ctx->dynamic_dso, ctx->engine_id); 463280304Sjkim } 464280304Sjkim if (!int_load(ctx)) { 465280304Sjkim ENGINEerr(ENGINE_F_DYNAMIC_LOAD, ENGINE_R_DSO_NOT_FOUND); 466280304Sjkim DSO_free(ctx->dynamic_dso); 467280304Sjkim ctx->dynamic_dso = NULL; 468280304Sjkim return 0; 469280304Sjkim } 470280304Sjkim /* We have to find a bind function otherwise it'll always end badly */ 471280304Sjkim if (! 472280304Sjkim (ctx->bind_engine = 473280304Sjkim (dynamic_bind_engine) DSO_bind_func(ctx->dynamic_dso, 474280304Sjkim ctx->DYNAMIC_F2))) { 475280304Sjkim ctx->bind_engine = NULL; 476280304Sjkim DSO_free(ctx->dynamic_dso); 477280304Sjkim ctx->dynamic_dso = NULL; 478280304Sjkim ENGINEerr(ENGINE_F_DYNAMIC_LOAD, ENGINE_R_DSO_FAILURE); 479280304Sjkim return 0; 480280304Sjkim } 481280304Sjkim /* Do we perform version checking? */ 482280304Sjkim if (!ctx->no_vcheck) { 483280304Sjkim unsigned long vcheck_res = 0; 484280304Sjkim /* 485280304Sjkim * Now we try to find a version checking function and decide how to 486280304Sjkim * cope with failure if/when it fails. 487280304Sjkim */ 488280304Sjkim ctx->v_check = 489280304Sjkim (dynamic_v_check_fn) DSO_bind_func(ctx->dynamic_dso, 490280304Sjkim ctx->DYNAMIC_F1); 491280304Sjkim if (ctx->v_check) 492280304Sjkim vcheck_res = ctx->v_check(OSSL_DYNAMIC_VERSION); 493280304Sjkim /* 494280304Sjkim * We fail if the version checker veto'd the load *or* if it is 495280304Sjkim * deferring to us (by returning its version) and we think it is too 496280304Sjkim * old. 497280304Sjkim */ 498280304Sjkim if (vcheck_res < OSSL_DYNAMIC_OLDEST) { 499280304Sjkim /* Fail */ 500280304Sjkim ctx->bind_engine = NULL; 501280304Sjkim ctx->v_check = NULL; 502280304Sjkim DSO_free(ctx->dynamic_dso); 503280304Sjkim ctx->dynamic_dso = NULL; 504280304Sjkim ENGINEerr(ENGINE_F_DYNAMIC_LOAD, 505280304Sjkim ENGINE_R_VERSION_INCOMPATIBILITY); 506280304Sjkim return 0; 507280304Sjkim } 508280304Sjkim } 509280304Sjkim /* 510280304Sjkim * First binary copy the ENGINE structure so that we can roll back if the 511280304Sjkim * hand-over fails 512280304Sjkim */ 513280304Sjkim memcpy(&cpy, e, sizeof(ENGINE)); 514280304Sjkim /* 515280304Sjkim * Provide the ERR, "ex_data", memory, and locking callbacks so the 516280304Sjkim * loaded library uses our state rather than its own. FIXME: As noted in 517280304Sjkim * engine.h, much of this would be simplified if each area of code 518280304Sjkim * provided its own "summary" structure of all related callbacks. It 519280304Sjkim * would also increase opaqueness. 520280304Sjkim */ 521280304Sjkim fns.static_state = ENGINE_get_static_state(); 522280304Sjkim fns.err_fns = ERR_get_implementation(); 523280304Sjkim fns.ex_data_fns = CRYPTO_get_ex_data_implementation(); 524280304Sjkim CRYPTO_get_mem_functions(&fns.mem_fns.malloc_cb, 525280304Sjkim &fns.mem_fns.realloc_cb, &fns.mem_fns.free_cb); 526280304Sjkim fns.lock_fns.lock_locking_cb = CRYPTO_get_locking_callback(); 527280304Sjkim fns.lock_fns.lock_add_lock_cb = CRYPTO_get_add_lock_callback(); 528280304Sjkim fns.lock_fns.dynlock_create_cb = CRYPTO_get_dynlock_create_callback(); 529280304Sjkim fns.lock_fns.dynlock_lock_cb = CRYPTO_get_dynlock_lock_callback(); 530280304Sjkim fns.lock_fns.dynlock_destroy_cb = CRYPTO_get_dynlock_destroy_callback(); 531280304Sjkim /* 532280304Sjkim * Now that we've loaded the dynamic engine, make sure no "dynamic" 533280304Sjkim * ENGINE elements will show through. 534280304Sjkim */ 535280304Sjkim engine_set_all_null(e); 536109998Smarkm 537280304Sjkim /* Try to bind the ENGINE onto our own ENGINE structure */ 538280304Sjkim if (!ctx->bind_engine(e, ctx->engine_id, &fns)) { 539280304Sjkim ctx->bind_engine = NULL; 540280304Sjkim ctx->v_check = NULL; 541280304Sjkim DSO_free(ctx->dynamic_dso); 542280304Sjkim ctx->dynamic_dso = NULL; 543280304Sjkim ENGINEerr(ENGINE_F_DYNAMIC_LOAD, ENGINE_R_INIT_FAILED); 544280304Sjkim /* Copy the original ENGINE structure back */ 545280304Sjkim memcpy(e, &cpy, sizeof(ENGINE)); 546280304Sjkim return 0; 547280304Sjkim } 548280304Sjkim /* Do we try to add this ENGINE to the internal list too? */ 549280304Sjkim if (ctx->list_add_value > 0) { 550280304Sjkim if (!ENGINE_add(e)) { 551280304Sjkim /* Do we tolerate this or fail? */ 552280304Sjkim if (ctx->list_add_value > 1) { 553280304Sjkim /* 554280304Sjkim * Fail - NB: By this time, it's too late to rollback, and 555280304Sjkim * trying to do so allows the bind_engine() code to have 556280304Sjkim * created leaks. We just have to fail where we are, after 557280304Sjkim * the ENGINE has changed. 558280304Sjkim */ 559280304Sjkim ENGINEerr(ENGINE_F_DYNAMIC_LOAD, 560280304Sjkim ENGINE_R_CONFLICTING_ENGINE_ID); 561280304Sjkim return 0; 562280304Sjkim } 563280304Sjkim /* Tolerate */ 564280304Sjkim ERR_clear_error(); 565280304Sjkim } 566280304Sjkim } 567280304Sjkim return 1; 568280304Sjkim} 569