ssl/libcrypto/src/crypto/engine/eng_dyn.c
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     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 	}