10Sstevel@tonic-gate /* crypto/engine/eng_dyn.c */
20Sstevel@tonic-gate /* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL
30Sstevel@tonic-gate * project 2001.
40Sstevel@tonic-gate */
50Sstevel@tonic-gate /* ====================================================================
60Sstevel@tonic-gate * Copyright (c) 1999-2001 The OpenSSL Project. All rights reserved.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without
90Sstevel@tonic-gate * modification, are permitted provided that the following conditions
100Sstevel@tonic-gate * are met:
110Sstevel@tonic-gate *
120Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright
130Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer.
140Sstevel@tonic-gate *
150Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright
160Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in
170Sstevel@tonic-gate * the documentation and/or other materials provided with the
180Sstevel@tonic-gate * distribution.
190Sstevel@tonic-gate *
200Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this
210Sstevel@tonic-gate * software must display the following acknowledgment:
220Sstevel@tonic-gate * "This product includes software developed by the OpenSSL Project
230Sstevel@tonic-gate * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
240Sstevel@tonic-gate *
250Sstevel@tonic-gate * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
260Sstevel@tonic-gate * endorse or promote products derived from this software without
270Sstevel@tonic-gate * prior written permission. For written permission, please contact
280Sstevel@tonic-gate * licensing@OpenSSL.org.
290Sstevel@tonic-gate *
300Sstevel@tonic-gate * 5. Products derived from this software may not be called "OpenSSL"
310Sstevel@tonic-gate * nor may "OpenSSL" appear in their names without prior written
320Sstevel@tonic-gate * permission of the OpenSSL Project.
330Sstevel@tonic-gate *
340Sstevel@tonic-gate * 6. Redistributions of any form whatsoever must retain the following
350Sstevel@tonic-gate * acknowledgment:
360Sstevel@tonic-gate * "This product includes software developed by the OpenSSL Project
370Sstevel@tonic-gate * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
380Sstevel@tonic-gate *
390Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
400Sstevel@tonic-gate * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
410Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
420Sstevel@tonic-gate * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
430Sstevel@tonic-gate * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
440Sstevel@tonic-gate * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
450Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
460Sstevel@tonic-gate * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
470Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
480Sstevel@tonic-gate * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
490Sstevel@tonic-gate * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
500Sstevel@tonic-gate * OF THE POSSIBILITY OF SUCH DAMAGE.
510Sstevel@tonic-gate * ====================================================================
520Sstevel@tonic-gate *
530Sstevel@tonic-gate * This product includes cryptographic software written by Eric Young
540Sstevel@tonic-gate * (eay@cryptsoft.com). This product includes software written by Tim
550Sstevel@tonic-gate * Hudson (tjh@cryptsoft.com).
560Sstevel@tonic-gate *
570Sstevel@tonic-gate */
580Sstevel@tonic-gate
590Sstevel@tonic-gate
600Sstevel@tonic-gate #include "eng_int.h"
610Sstevel@tonic-gate #include <openssl/dso.h>
620Sstevel@tonic-gate
630Sstevel@tonic-gate /* Shared libraries implementing ENGINEs for use by the "dynamic" ENGINE loader
640Sstevel@tonic-gate * should implement the hook-up functions with the following prototypes. */
650Sstevel@tonic-gate
660Sstevel@tonic-gate /* Our ENGINE handlers */
670Sstevel@tonic-gate static int dynamic_init(ENGINE *e);
680Sstevel@tonic-gate static int dynamic_finish(ENGINE *e);
69*2139Sjp161948 static int dynamic_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void));
700Sstevel@tonic-gate /* Predeclare our context type */
710Sstevel@tonic-gate typedef struct st_dynamic_data_ctx dynamic_data_ctx;
720Sstevel@tonic-gate /* The implementation for the important control command */
730Sstevel@tonic-gate static int dynamic_load(ENGINE *e, dynamic_data_ctx *ctx);
740Sstevel@tonic-gate
750Sstevel@tonic-gate #define DYNAMIC_CMD_SO_PATH ENGINE_CMD_BASE
760Sstevel@tonic-gate #define DYNAMIC_CMD_NO_VCHECK (ENGINE_CMD_BASE + 1)
770Sstevel@tonic-gate #define DYNAMIC_CMD_ID (ENGINE_CMD_BASE + 2)
780Sstevel@tonic-gate #define DYNAMIC_CMD_LIST_ADD (ENGINE_CMD_BASE + 3)
79*2139Sjp161948 #define DYNAMIC_CMD_DIR_LOAD (ENGINE_CMD_BASE + 4)
80*2139Sjp161948 #define DYNAMIC_CMD_DIR_ADD (ENGINE_CMD_BASE + 5)
81*2139Sjp161948 #define DYNAMIC_CMD_LOAD (ENGINE_CMD_BASE + 6)
820Sstevel@tonic-gate
830Sstevel@tonic-gate /* The constants used when creating the ENGINE */
840Sstevel@tonic-gate static const char *engine_dynamic_id = "dynamic";
850Sstevel@tonic-gate static const char *engine_dynamic_name = "Dynamic engine loading support";
860Sstevel@tonic-gate static const ENGINE_CMD_DEFN dynamic_cmd_defns[] = {
870Sstevel@tonic-gate {DYNAMIC_CMD_SO_PATH,
880Sstevel@tonic-gate "SO_PATH",
890Sstevel@tonic-gate "Specifies the path to the new ENGINE shared library",
900Sstevel@tonic-gate ENGINE_CMD_FLAG_STRING},
910Sstevel@tonic-gate {DYNAMIC_CMD_NO_VCHECK,
920Sstevel@tonic-gate "NO_VCHECK",
930Sstevel@tonic-gate "Specifies to continue even if version checking fails (boolean)",
940Sstevel@tonic-gate ENGINE_CMD_FLAG_NUMERIC},
950Sstevel@tonic-gate {DYNAMIC_CMD_ID,
960Sstevel@tonic-gate "ID",
970Sstevel@tonic-gate "Specifies an ENGINE id name for loading",
980Sstevel@tonic-gate ENGINE_CMD_FLAG_STRING},
990Sstevel@tonic-gate {DYNAMIC_CMD_LIST_ADD,
1000Sstevel@tonic-gate "LIST_ADD",
1010Sstevel@tonic-gate "Whether to add a loaded ENGINE to the internal list (0=no,1=yes,2=mandatory)",
1020Sstevel@tonic-gate ENGINE_CMD_FLAG_NUMERIC},
103*2139Sjp161948 {DYNAMIC_CMD_DIR_LOAD,
104*2139Sjp161948 "DIR_LOAD",
105*2139Sjp161948 "Specifies whether to load from 'DIR_ADD' directories (0=no,1=yes,2=mandatory)",
106*2139Sjp161948 ENGINE_CMD_FLAG_NUMERIC},
107*2139Sjp161948 {DYNAMIC_CMD_DIR_ADD,
108*2139Sjp161948 "DIR_ADD",
109*2139Sjp161948 "Adds a directory from which ENGINEs can be loaded",
110*2139Sjp161948 ENGINE_CMD_FLAG_STRING},
1110Sstevel@tonic-gate {DYNAMIC_CMD_LOAD,
1120Sstevel@tonic-gate "LOAD",
1130Sstevel@tonic-gate "Load up the ENGINE specified by other settings",
1140Sstevel@tonic-gate ENGINE_CMD_FLAG_NO_INPUT},
1150Sstevel@tonic-gate {0, NULL, NULL, 0}
1160Sstevel@tonic-gate };
1170Sstevel@tonic-gate static const ENGINE_CMD_DEFN dynamic_cmd_defns_empty[] = {
1180Sstevel@tonic-gate {0, NULL, NULL, 0}
1190Sstevel@tonic-gate };
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate /* Loading code stores state inside the ENGINE structure via the "ex_data"
1220Sstevel@tonic-gate * element. We load all our state into a single structure and use that as a
1230Sstevel@tonic-gate * single context in the "ex_data" stack. */
1240Sstevel@tonic-gate struct st_dynamic_data_ctx
1250Sstevel@tonic-gate {
1260Sstevel@tonic-gate /* The DSO object we load that supplies the ENGINE code */
1270Sstevel@tonic-gate DSO *dynamic_dso;
1280Sstevel@tonic-gate /* The function pointer to the version checking shared library function */
1290Sstevel@tonic-gate dynamic_v_check_fn v_check;
1300Sstevel@tonic-gate /* The function pointer to the engine-binding shared library function */
1310Sstevel@tonic-gate dynamic_bind_engine bind_engine;
1320Sstevel@tonic-gate /* The default name/path for loading the shared library */
1330Sstevel@tonic-gate const char *DYNAMIC_LIBNAME;
1340Sstevel@tonic-gate /* Whether to continue loading on a version check failure */
1350Sstevel@tonic-gate int no_vcheck;
1360Sstevel@tonic-gate /* If non-NULL, stipulates the 'id' of the ENGINE to be loaded */
1370Sstevel@tonic-gate const char *engine_id;
1380Sstevel@tonic-gate /* If non-zero, a successfully loaded ENGINE should be added to the internal
1390Sstevel@tonic-gate * ENGINE list. If 2, the add must succeed or the entire load should fail. */
1400Sstevel@tonic-gate int list_add_value;
1410Sstevel@tonic-gate /* The symbol name for the version checking function */
1420Sstevel@tonic-gate const char *DYNAMIC_F1;
1430Sstevel@tonic-gate /* The symbol name for the "initialise ENGINE structure" function */
1440Sstevel@tonic-gate const char *DYNAMIC_F2;
145*2139Sjp161948 /* Whether to never use 'dirs', use 'dirs' as a fallback, or only use
146*2139Sjp161948 * 'dirs' for loading. Default is to use 'dirs' as a fallback. */
147*2139Sjp161948 int dir_load;
148*2139Sjp161948 /* A stack of directories from which ENGINEs could be loaded */
149*2139Sjp161948 STACK *dirs;
1500Sstevel@tonic-gate };
1510Sstevel@tonic-gate
1520Sstevel@tonic-gate /* This is the "ex_data" index we obtain and reserve for use with our context
1530Sstevel@tonic-gate * structure. */
1540Sstevel@tonic-gate static int dynamic_ex_data_idx = -1;
1550Sstevel@tonic-gate
int_free_str(void * s)156*2139Sjp161948 static void int_free_str(void *s) { OPENSSL_free(s); }
1570Sstevel@tonic-gate /* Because our ex_data element may or may not get allocated depending on whether
1580Sstevel@tonic-gate * a "first-use" occurs before the ENGINE is freed, we have a memory leak
1590Sstevel@tonic-gate * problem to solve. We can't declare a "new" handler for the ex_data as we
1600Sstevel@tonic-gate * don't want a dynamic_data_ctx in *all* ENGINE structures of all types (this
1610Sstevel@tonic-gate * is a bug in the design of CRYPTO_EX_DATA). As such, we just declare a "free"
1620Sstevel@tonic-gate * handler and that will get called if an ENGINE is being destroyed and there
1630Sstevel@tonic-gate * was an ex_data element corresponding to our context type. */
dynamic_data_ctx_free_func(void * parent,void * ptr,CRYPTO_EX_DATA * ad,int idx,long argl,void * argp)1640Sstevel@tonic-gate static void dynamic_data_ctx_free_func(void *parent, void *ptr,
1650Sstevel@tonic-gate CRYPTO_EX_DATA *ad, int idx, long argl, void *argp)
1660Sstevel@tonic-gate {
1670Sstevel@tonic-gate if(ptr)
1680Sstevel@tonic-gate {
1690Sstevel@tonic-gate dynamic_data_ctx *ctx = (dynamic_data_ctx *)ptr;
1700Sstevel@tonic-gate if(ctx->dynamic_dso)
1710Sstevel@tonic-gate DSO_free(ctx->dynamic_dso);
1720Sstevel@tonic-gate if(ctx->DYNAMIC_LIBNAME)
1730Sstevel@tonic-gate OPENSSL_free((void*)ctx->DYNAMIC_LIBNAME);
1740Sstevel@tonic-gate if(ctx->engine_id)
1750Sstevel@tonic-gate OPENSSL_free((void*)ctx->engine_id);
176*2139Sjp161948 if(ctx->dirs)
177*2139Sjp161948 sk_pop_free(ctx->dirs, int_free_str);
1780Sstevel@tonic-gate OPENSSL_free(ctx);
1790Sstevel@tonic-gate }
1800Sstevel@tonic-gate }
1810Sstevel@tonic-gate
1820Sstevel@tonic-gate /* Construct the per-ENGINE context. We create it blindly and then use a lock to
1830Sstevel@tonic-gate * check for a race - if so, all but one of the threads "racing" will have
1840Sstevel@tonic-gate * wasted their time. The alternative involves creating everything inside the
1850Sstevel@tonic-gate * lock which is far worse. */
dynamic_set_data_ctx(ENGINE * e,dynamic_data_ctx ** ctx)1860Sstevel@tonic-gate static int dynamic_set_data_ctx(ENGINE *e, dynamic_data_ctx **ctx)
1870Sstevel@tonic-gate {
1880Sstevel@tonic-gate dynamic_data_ctx *c;
1890Sstevel@tonic-gate c = OPENSSL_malloc(sizeof(dynamic_data_ctx));
1900Sstevel@tonic-gate if(!c)
1910Sstevel@tonic-gate {
192*2139Sjp161948 ENGINEerr(ENGINE_F_DYNAMIC_SET_DATA_CTX,ERR_R_MALLOC_FAILURE);
1930Sstevel@tonic-gate return 0;
1940Sstevel@tonic-gate }
1950Sstevel@tonic-gate memset(c, 0, sizeof(dynamic_data_ctx));
1960Sstevel@tonic-gate c->dynamic_dso = NULL;
1970Sstevel@tonic-gate c->v_check = NULL;
1980Sstevel@tonic-gate c->bind_engine = NULL;
1990Sstevel@tonic-gate c->DYNAMIC_LIBNAME = NULL;
2000Sstevel@tonic-gate c->no_vcheck = 0;
2010Sstevel@tonic-gate c->engine_id = NULL;
2020Sstevel@tonic-gate c->list_add_value = 0;
2030Sstevel@tonic-gate c->DYNAMIC_F1 = "v_check";
2040Sstevel@tonic-gate c->DYNAMIC_F2 = "bind_engine";
205*2139Sjp161948 c->dir_load = 1;
206*2139Sjp161948 c->dirs = sk_new_null();
207*2139Sjp161948 if(!c->dirs)
208*2139Sjp161948 {
209*2139Sjp161948 ENGINEerr(ENGINE_F_DYNAMIC_SET_DATA_CTX,ERR_R_MALLOC_FAILURE);
210*2139Sjp161948 OPENSSL_free(c);
211*2139Sjp161948 return 0;
212*2139Sjp161948 }
2130Sstevel@tonic-gate CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
2140Sstevel@tonic-gate if((*ctx = (dynamic_data_ctx *)ENGINE_get_ex_data(e,
2150Sstevel@tonic-gate dynamic_ex_data_idx)) == NULL)
2160Sstevel@tonic-gate {
2170Sstevel@tonic-gate /* Good, we're the first */
2180Sstevel@tonic-gate ENGINE_set_ex_data(e, dynamic_ex_data_idx, c);
2190Sstevel@tonic-gate *ctx = c;
2200Sstevel@tonic-gate c = NULL;
2210Sstevel@tonic-gate }
2220Sstevel@tonic-gate CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
2230Sstevel@tonic-gate /* If we lost the race to set the context, c is non-NULL and *ctx is the
2240Sstevel@tonic-gate * context of the thread that won. */
2250Sstevel@tonic-gate if(c)
2260Sstevel@tonic-gate OPENSSL_free(c);
2270Sstevel@tonic-gate return 1;
2280Sstevel@tonic-gate }
2290Sstevel@tonic-gate
2300Sstevel@tonic-gate /* This function retrieves the context structure from an ENGINE's "ex_data", or
2310Sstevel@tonic-gate * if it doesn't exist yet, sets it up. */
dynamic_get_data_ctx(ENGINE * e)2320Sstevel@tonic-gate static dynamic_data_ctx *dynamic_get_data_ctx(ENGINE *e)
2330Sstevel@tonic-gate {
2340Sstevel@tonic-gate dynamic_data_ctx *ctx;
2350Sstevel@tonic-gate if(dynamic_ex_data_idx < 0)
2360Sstevel@tonic-gate {
2370Sstevel@tonic-gate /* Create and register the ENGINE ex_data, and associate our
2380Sstevel@tonic-gate * "free" function with it to ensure any allocated contexts get
2390Sstevel@tonic-gate * freed when an ENGINE goes underground. */
2400Sstevel@tonic-gate int new_idx = ENGINE_get_ex_new_index(0, NULL, NULL, NULL,
2410Sstevel@tonic-gate dynamic_data_ctx_free_func);
2420Sstevel@tonic-gate if(new_idx == -1)
2430Sstevel@tonic-gate {
2440Sstevel@tonic-gate ENGINEerr(ENGINE_F_DYNAMIC_GET_DATA_CTX,ENGINE_R_NO_INDEX);
2450Sstevel@tonic-gate return NULL;
2460Sstevel@tonic-gate }
2470Sstevel@tonic-gate CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
2480Sstevel@tonic-gate /* Avoid a race by checking again inside this lock */
2490Sstevel@tonic-gate if(dynamic_ex_data_idx < 0)
2500Sstevel@tonic-gate {
2510Sstevel@tonic-gate /* Good, someone didn't beat us to it */
2520Sstevel@tonic-gate dynamic_ex_data_idx = new_idx;
2530Sstevel@tonic-gate new_idx = -1;
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
2560Sstevel@tonic-gate /* In theory we could "give back" the index here if
2570Sstevel@tonic-gate * (new_idx>-1), but it's not possible and wouldn't gain us much
2580Sstevel@tonic-gate * if it were. */
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate ctx = (dynamic_data_ctx *)ENGINE_get_ex_data(e, dynamic_ex_data_idx);
2610Sstevel@tonic-gate /* Check if the context needs to be created */
2620Sstevel@tonic-gate if((ctx == NULL) && !dynamic_set_data_ctx(e, &ctx))
2630Sstevel@tonic-gate /* "set_data" will set errors if necessary */
2640Sstevel@tonic-gate return NULL;
2650Sstevel@tonic-gate return ctx;
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate
engine_dynamic(void)2680Sstevel@tonic-gate static ENGINE *engine_dynamic(void)
2690Sstevel@tonic-gate {
2700Sstevel@tonic-gate ENGINE *ret = ENGINE_new();
2710Sstevel@tonic-gate if(!ret)
2720Sstevel@tonic-gate return NULL;
2730Sstevel@tonic-gate if(!ENGINE_set_id(ret, engine_dynamic_id) ||
2740Sstevel@tonic-gate !ENGINE_set_name(ret, engine_dynamic_name) ||
2750Sstevel@tonic-gate !ENGINE_set_init_function(ret, dynamic_init) ||
2760Sstevel@tonic-gate !ENGINE_set_finish_function(ret, dynamic_finish) ||
2770Sstevel@tonic-gate !ENGINE_set_ctrl_function(ret, dynamic_ctrl) ||
2780Sstevel@tonic-gate !ENGINE_set_flags(ret, ENGINE_FLAGS_BY_ID_COPY) ||
2790Sstevel@tonic-gate !ENGINE_set_cmd_defns(ret, dynamic_cmd_defns))
2800Sstevel@tonic-gate {
2810Sstevel@tonic-gate ENGINE_free(ret);
2820Sstevel@tonic-gate return NULL;
2830Sstevel@tonic-gate }
2840Sstevel@tonic-gate return ret;
2850Sstevel@tonic-gate }
2860Sstevel@tonic-gate
ENGINE_load_dynamic(void)2870Sstevel@tonic-gate void ENGINE_load_dynamic(void)
2880Sstevel@tonic-gate {
2890Sstevel@tonic-gate ENGINE *toadd = engine_dynamic();
2900Sstevel@tonic-gate if(!toadd) return;
2910Sstevel@tonic-gate ENGINE_add(toadd);
2920Sstevel@tonic-gate /* If the "add" worked, it gets a structural reference. So either way,
2930Sstevel@tonic-gate * we release our just-created reference. */
2940Sstevel@tonic-gate ENGINE_free(toadd);
2950Sstevel@tonic-gate /* If the "add" didn't work, it was probably a conflict because it was
2960Sstevel@tonic-gate * already added (eg. someone calling ENGINE_load_blah then calling
2970Sstevel@tonic-gate * ENGINE_load_builtin_engines() perhaps). */
2980Sstevel@tonic-gate ERR_clear_error();
2990Sstevel@tonic-gate }
3000Sstevel@tonic-gate
dynamic_init(ENGINE * e)3010Sstevel@tonic-gate static int dynamic_init(ENGINE *e)
3020Sstevel@tonic-gate {
3030Sstevel@tonic-gate /* We always return failure - the "dyanamic" engine itself can't be used
3040Sstevel@tonic-gate * for anything. */
3050Sstevel@tonic-gate return 0;
3060Sstevel@tonic-gate }
3070Sstevel@tonic-gate
dynamic_finish(ENGINE * e)3080Sstevel@tonic-gate static int dynamic_finish(ENGINE *e)
3090Sstevel@tonic-gate {
3100Sstevel@tonic-gate /* This should never be called on account of "dynamic_init" always
3110Sstevel@tonic-gate * failing. */
3120Sstevel@tonic-gate return 0;
3130Sstevel@tonic-gate }
3140Sstevel@tonic-gate
dynamic_ctrl(ENGINE * e,int cmd,long i,void * p,void (* f)(void))315*2139Sjp161948 static int dynamic_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void))
3160Sstevel@tonic-gate {
3170Sstevel@tonic-gate dynamic_data_ctx *ctx = dynamic_get_data_ctx(e);
3180Sstevel@tonic-gate int initialised;
3190Sstevel@tonic-gate
3200Sstevel@tonic-gate if(!ctx)
3210Sstevel@tonic-gate {
3220Sstevel@tonic-gate ENGINEerr(ENGINE_F_DYNAMIC_CTRL,ENGINE_R_NOT_LOADED);
3230Sstevel@tonic-gate return 0;
3240Sstevel@tonic-gate }
3250Sstevel@tonic-gate initialised = ((ctx->dynamic_dso == NULL) ? 0 : 1);
3260Sstevel@tonic-gate /* All our control commands require the ENGINE to be uninitialised */
3270Sstevel@tonic-gate if(initialised)
3280Sstevel@tonic-gate {
3290Sstevel@tonic-gate ENGINEerr(ENGINE_F_DYNAMIC_CTRL,
3300Sstevel@tonic-gate ENGINE_R_ALREADY_LOADED);
3310Sstevel@tonic-gate return 0;
3320Sstevel@tonic-gate }
3330Sstevel@tonic-gate switch(cmd)
3340Sstevel@tonic-gate {
3350Sstevel@tonic-gate case DYNAMIC_CMD_SO_PATH:
3360Sstevel@tonic-gate /* a NULL 'p' or a string of zero-length is the same thing */
3370Sstevel@tonic-gate if(p && (strlen((const char *)p) < 1))
3380Sstevel@tonic-gate p = NULL;
3390Sstevel@tonic-gate if(ctx->DYNAMIC_LIBNAME)
3400Sstevel@tonic-gate OPENSSL_free((void*)ctx->DYNAMIC_LIBNAME);
3410Sstevel@tonic-gate if(p)
3420Sstevel@tonic-gate ctx->DYNAMIC_LIBNAME = BUF_strdup(p);
3430Sstevel@tonic-gate else
3440Sstevel@tonic-gate ctx->DYNAMIC_LIBNAME = NULL;
3450Sstevel@tonic-gate return (ctx->DYNAMIC_LIBNAME ? 1 : 0);
3460Sstevel@tonic-gate case DYNAMIC_CMD_NO_VCHECK:
3470Sstevel@tonic-gate ctx->no_vcheck = ((i == 0) ? 0 : 1);
3480Sstevel@tonic-gate return 1;
3490Sstevel@tonic-gate case DYNAMIC_CMD_ID:
3500Sstevel@tonic-gate /* a NULL 'p' or a string of zero-length is the same thing */
3510Sstevel@tonic-gate if(p && (strlen((const char *)p) < 1))
3520Sstevel@tonic-gate p = NULL;
3530Sstevel@tonic-gate if(ctx->engine_id)
3540Sstevel@tonic-gate OPENSSL_free((void*)ctx->engine_id);
3550Sstevel@tonic-gate if(p)
3560Sstevel@tonic-gate ctx->engine_id = BUF_strdup(p);
3570Sstevel@tonic-gate else
3580Sstevel@tonic-gate ctx->engine_id = NULL;
3590Sstevel@tonic-gate return (ctx->engine_id ? 1 : 0);
3600Sstevel@tonic-gate case DYNAMIC_CMD_LIST_ADD:
3610Sstevel@tonic-gate if((i < 0) || (i > 2))
3620Sstevel@tonic-gate {
3630Sstevel@tonic-gate ENGINEerr(ENGINE_F_DYNAMIC_CTRL,
3640Sstevel@tonic-gate ENGINE_R_INVALID_ARGUMENT);
3650Sstevel@tonic-gate return 0;
3660Sstevel@tonic-gate }
3670Sstevel@tonic-gate ctx->list_add_value = (int)i;
3680Sstevel@tonic-gate return 1;
3690Sstevel@tonic-gate case DYNAMIC_CMD_LOAD:
3700Sstevel@tonic-gate return dynamic_load(e, ctx);
371*2139Sjp161948 case DYNAMIC_CMD_DIR_LOAD:
372*2139Sjp161948 if((i < 0) || (i > 2))
373*2139Sjp161948 {
374*2139Sjp161948 ENGINEerr(ENGINE_F_DYNAMIC_CTRL,
375*2139Sjp161948 ENGINE_R_INVALID_ARGUMENT);
376*2139Sjp161948 return 0;
377*2139Sjp161948 }
378*2139Sjp161948 ctx->dir_load = (int)i;
379*2139Sjp161948 return 1;
380*2139Sjp161948 case DYNAMIC_CMD_DIR_ADD:
381*2139Sjp161948 /* a NULL 'p' or a string of zero-length is the same thing */
382*2139Sjp161948 if(!p || (strlen((const char *)p) < 1))
383*2139Sjp161948 {
384*2139Sjp161948 ENGINEerr(ENGINE_F_DYNAMIC_CTRL,
385*2139Sjp161948 ENGINE_R_INVALID_ARGUMENT);
386*2139Sjp161948 return 0;
387*2139Sjp161948 }
388*2139Sjp161948 {
389*2139Sjp161948 char *tmp_str = BUF_strdup(p);
390*2139Sjp161948 if(!tmp_str)
391*2139Sjp161948 {
392*2139Sjp161948 ENGINEerr(ENGINE_F_DYNAMIC_CTRL,
393*2139Sjp161948 ERR_R_MALLOC_FAILURE);
394*2139Sjp161948 return 0;
395*2139Sjp161948 }
396*2139Sjp161948 sk_insert(ctx->dirs, tmp_str, -1);
397*2139Sjp161948 }
398*2139Sjp161948 return 1;
3990Sstevel@tonic-gate default:
4000Sstevel@tonic-gate break;
4010Sstevel@tonic-gate }
4020Sstevel@tonic-gate ENGINEerr(ENGINE_F_DYNAMIC_CTRL,ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED);
4030Sstevel@tonic-gate return 0;
4040Sstevel@tonic-gate }
4050Sstevel@tonic-gate
int_load(dynamic_data_ctx * ctx)406*2139Sjp161948 static int int_load(dynamic_data_ctx *ctx)
407*2139Sjp161948 {
408*2139Sjp161948 int num, loop;
409*2139Sjp161948 /* Unless told not to, try a direct load */
410*2139Sjp161948 if((ctx->dir_load != 2) && (DSO_load(ctx->dynamic_dso,
411*2139Sjp161948 ctx->DYNAMIC_LIBNAME, NULL, 0)) != NULL)
412*2139Sjp161948 return 1;
413*2139Sjp161948 /* If we're not allowed to use 'dirs' or we have none, fail */
414*2139Sjp161948 if(!ctx->dir_load || ((num = sk_num(ctx->dirs)) < 1))
415*2139Sjp161948 return 0;
416*2139Sjp161948 for(loop = 0; loop < num; loop++)
417*2139Sjp161948 {
418*2139Sjp161948 const char *s = sk_value(ctx->dirs, loop);
419*2139Sjp161948 char *merge = DSO_merge(ctx->dynamic_dso, ctx->DYNAMIC_LIBNAME, s);
420*2139Sjp161948 if(!merge)
421*2139Sjp161948 return 0;
422*2139Sjp161948 if(DSO_load(ctx->dynamic_dso, merge, NULL, 0))
423*2139Sjp161948 {
424*2139Sjp161948 /* Found what we're looking for */
425*2139Sjp161948 OPENSSL_free(merge);
426*2139Sjp161948 return 1;
427*2139Sjp161948 }
428*2139Sjp161948 OPENSSL_free(merge);
429*2139Sjp161948 }
430*2139Sjp161948 return 0;
431*2139Sjp161948 }
432*2139Sjp161948
dynamic_load(ENGINE * e,dynamic_data_ctx * ctx)4330Sstevel@tonic-gate static int dynamic_load(ENGINE *e, dynamic_data_ctx *ctx)
4340Sstevel@tonic-gate {
4350Sstevel@tonic-gate ENGINE cpy;
4360Sstevel@tonic-gate dynamic_fns fns;
4370Sstevel@tonic-gate
438*2139Sjp161948 if(!ctx->dynamic_dso)
439*2139Sjp161948 ctx->dynamic_dso = DSO_new();
440*2139Sjp161948 if(!ctx->DYNAMIC_LIBNAME)
441*2139Sjp161948 {
442*2139Sjp161948 if(!ctx->engine_id)
443*2139Sjp161948 return 0;
444*2139Sjp161948 ctx->DYNAMIC_LIBNAME =
445*2139Sjp161948 DSO_convert_filename(ctx->dynamic_dso, ctx->engine_id);
446*2139Sjp161948 }
447*2139Sjp161948 if(!int_load(ctx))
4480Sstevel@tonic-gate {
4490Sstevel@tonic-gate ENGINEerr(ENGINE_F_DYNAMIC_LOAD,
4500Sstevel@tonic-gate ENGINE_R_DSO_NOT_FOUND);
451*2139Sjp161948 DSO_free(ctx->dynamic_dso);
452*2139Sjp161948 ctx->dynamic_dso = NULL;
4530Sstevel@tonic-gate return 0;
4540Sstevel@tonic-gate }
4550Sstevel@tonic-gate /* We have to find a bind function otherwise it'll always end badly */
4560Sstevel@tonic-gate if(!(ctx->bind_engine = (dynamic_bind_engine)DSO_bind_func(
4570Sstevel@tonic-gate ctx->dynamic_dso, ctx->DYNAMIC_F2)))
4580Sstevel@tonic-gate {
4590Sstevel@tonic-gate ctx->bind_engine = NULL;
4600Sstevel@tonic-gate DSO_free(ctx->dynamic_dso);
4610Sstevel@tonic-gate ctx->dynamic_dso = NULL;
4620Sstevel@tonic-gate ENGINEerr(ENGINE_F_DYNAMIC_LOAD,
4630Sstevel@tonic-gate ENGINE_R_DSO_FAILURE);
4640Sstevel@tonic-gate return 0;
4650Sstevel@tonic-gate }
4660Sstevel@tonic-gate /* Do we perform version checking? */
4670Sstevel@tonic-gate if(!ctx->no_vcheck)
4680Sstevel@tonic-gate {
4690Sstevel@tonic-gate unsigned long vcheck_res = 0;
4700Sstevel@tonic-gate /* Now we try to find a version checking function and decide how
4710Sstevel@tonic-gate * to cope with failure if/when it fails. */
4720Sstevel@tonic-gate ctx->v_check = (dynamic_v_check_fn)DSO_bind_func(
4730Sstevel@tonic-gate ctx->dynamic_dso, ctx->DYNAMIC_F1);
4740Sstevel@tonic-gate if(ctx->v_check)
4750Sstevel@tonic-gate vcheck_res = ctx->v_check(OSSL_DYNAMIC_VERSION);
4760Sstevel@tonic-gate /* We fail if the version checker veto'd the load *or* if it is
4770Sstevel@tonic-gate * deferring to us (by returning its version) and we think it is
4780Sstevel@tonic-gate * too old. */
4790Sstevel@tonic-gate if(vcheck_res < OSSL_DYNAMIC_OLDEST)
4800Sstevel@tonic-gate {
4810Sstevel@tonic-gate /* Fail */
4820Sstevel@tonic-gate ctx->bind_engine = NULL;
4830Sstevel@tonic-gate ctx->v_check = NULL;
4840Sstevel@tonic-gate DSO_free(ctx->dynamic_dso);
4850Sstevel@tonic-gate ctx->dynamic_dso = NULL;
4860Sstevel@tonic-gate ENGINEerr(ENGINE_F_DYNAMIC_LOAD,
4870Sstevel@tonic-gate ENGINE_R_VERSION_INCOMPATIBILITY);
4880Sstevel@tonic-gate return 0;
4890Sstevel@tonic-gate }
4900Sstevel@tonic-gate }
4910Sstevel@tonic-gate /* First binary copy the ENGINE structure so that we can roll back if
4920Sstevel@tonic-gate * the hand-over fails */
4930Sstevel@tonic-gate memcpy(&cpy, e, sizeof(ENGINE));
4940Sstevel@tonic-gate /* Provide the ERR, "ex_data", memory, and locking callbacks so the
4950Sstevel@tonic-gate * loaded library uses our state rather than its own. FIXME: As noted in
4960Sstevel@tonic-gate * engine.h, much of this would be simplified if each area of code
4970Sstevel@tonic-gate * provided its own "summary" structure of all related callbacks. It
4980Sstevel@tonic-gate * would also increase opaqueness. */
499*2139Sjp161948 fns.static_state = ENGINE_get_static_state();
5000Sstevel@tonic-gate fns.err_fns = ERR_get_implementation();
5010Sstevel@tonic-gate fns.ex_data_fns = CRYPTO_get_ex_data_implementation();
5020Sstevel@tonic-gate CRYPTO_get_mem_functions(&fns.mem_fns.malloc_cb,
5030Sstevel@tonic-gate &fns.mem_fns.realloc_cb,
5040Sstevel@tonic-gate &fns.mem_fns.free_cb);
5050Sstevel@tonic-gate fns.lock_fns.lock_locking_cb = CRYPTO_get_locking_callback();
5060Sstevel@tonic-gate fns.lock_fns.lock_add_lock_cb = CRYPTO_get_add_lock_callback();
5070Sstevel@tonic-gate fns.lock_fns.dynlock_create_cb = CRYPTO_get_dynlock_create_callback();
5080Sstevel@tonic-gate fns.lock_fns.dynlock_lock_cb = CRYPTO_get_dynlock_lock_callback();
5090Sstevel@tonic-gate fns.lock_fns.dynlock_destroy_cb = CRYPTO_get_dynlock_destroy_callback();
5100Sstevel@tonic-gate /* Now that we've loaded the dynamic engine, make sure no "dynamic"
5110Sstevel@tonic-gate * ENGINE elements will show through. */
5120Sstevel@tonic-gate engine_set_all_null(e);
5130Sstevel@tonic-gate
5140Sstevel@tonic-gate /* Try to bind the ENGINE onto our own ENGINE structure */
5150Sstevel@tonic-gate if(!ctx->bind_engine(e, ctx->engine_id, &fns))
5160Sstevel@tonic-gate {
5170Sstevel@tonic-gate ctx->bind_engine = NULL;
5180Sstevel@tonic-gate ctx->v_check = NULL;
5190Sstevel@tonic-gate DSO_free(ctx->dynamic_dso);
5200Sstevel@tonic-gate ctx->dynamic_dso = NULL;
5210Sstevel@tonic-gate ENGINEerr(ENGINE_F_DYNAMIC_LOAD,ENGINE_R_INIT_FAILED);
5220Sstevel@tonic-gate /* Copy the original ENGINE structure back */
5230Sstevel@tonic-gate memcpy(e, &cpy, sizeof(ENGINE));
5240Sstevel@tonic-gate return 0;
5250Sstevel@tonic-gate }
5260Sstevel@tonic-gate /* Do we try to add this ENGINE to the internal list too? */
5270Sstevel@tonic-gate if(ctx->list_add_value > 0)
5280Sstevel@tonic-gate {
5290Sstevel@tonic-gate if(!ENGINE_add(e))
5300Sstevel@tonic-gate {
5310Sstevel@tonic-gate /* Do we tolerate this or fail? */
5320Sstevel@tonic-gate if(ctx->list_add_value > 1)
5330Sstevel@tonic-gate {
5340Sstevel@tonic-gate /* Fail - NB: By this time, it's too late to
5350Sstevel@tonic-gate * rollback, and trying to do so allows the
5360Sstevel@tonic-gate * bind_engine() code to have created leaks. We
5370Sstevel@tonic-gate * just have to fail where we are, after the
5380Sstevel@tonic-gate * ENGINE has changed. */
5390Sstevel@tonic-gate ENGINEerr(ENGINE_F_DYNAMIC_LOAD,
5400Sstevel@tonic-gate ENGINE_R_CONFLICTING_ENGINE_ID);
5410Sstevel@tonic-gate return 0;
5420Sstevel@tonic-gate }
5430Sstevel@tonic-gate /* Tolerate */
5440Sstevel@tonic-gate ERR_clear_error();
5450Sstevel@tonic-gate }
5460Sstevel@tonic-gate }
5470Sstevel@tonic-gate return 1;
5480Sstevel@tonic-gate }
549