DSO *DSO_load(DSO *dso, const char *filename, DSO_METHOD *meth, int flags) { DSO *ret; int allocated = 0; if(dso == NULL) { ret = DSO_new_method(meth); if(ret == NULL) { DSOerr(DSO_F_DSO_LOAD,ERR_R_MALLOC_FAILURE); goto err; } allocated = 1; /* Pass the provided flags to the new DSO object */ if(DSO_ctrl(ret, DSO_CTRL_SET_FLAGS, flags, NULL) < 0) { DSOerr(DSO_F_DSO_LOAD,DSO_R_CTRL_FAILED); goto err; } } else ret = dso; /* Don't load if we're currently already loaded */ if(ret->filename != NULL) { DSOerr(DSO_F_DSO_LOAD,DSO_R_DSO_ALREADY_LOADED); goto err; } /* filename can only be NULL if we were passed a dso that already has * one set. */ if(filename != NULL) if(!DSO_set_filename(ret, filename)) { DSOerr(DSO_F_DSO_LOAD,DSO_R_SET_FILENAME_FAILED); goto err; } filename = ret->filename; if(filename == NULL) { DSOerr(DSO_F_DSO_LOAD,DSO_R_NO_FILENAME); goto err; } if(ret->meth->dso_load == NULL) { DSOerr(DSO_F_DSO_LOAD,DSO_R_UNSUPPORTED); goto err; } if(!ret->meth->dso_load(ret)) { DSOerr(DSO_F_DSO_LOAD,DSO_R_LOAD_FAILED); goto err; } /* Load succeeded */ return(ret); err: if(allocated) DSO_free(ret); return(NULL); }
static int dynamic_load(ENGINE *e, dynamic_data_ctx *ctx) { ENGINE cpy; dynamic_fns fns; if (ctx->dynamic_dso == NULL) ctx->dynamic_dso = DSO_new(); if (ctx->dynamic_dso == NULL) return 0; if (!ctx->DYNAMIC_LIBNAME) { if (!ctx->engine_id) return 0; DSO_ctrl(ctx->dynamic_dso, DSO_CTRL_SET_FLAGS, DSO_FLAG_NAME_TRANSLATION_EXT_ONLY, NULL); ctx->DYNAMIC_LIBNAME = DSO_convert_filename(ctx->dynamic_dso, ctx->engine_id); } if (!int_load(ctx)) { ENGINEerr(ENGINE_F_DYNAMIC_LOAD, ENGINE_R_DSO_NOT_FOUND); DSO_free(ctx->dynamic_dso); ctx->dynamic_dso = NULL; return 0; } /* We have to find a bind function otherwise it'll always end badly */ if (! (ctx->bind_engine = (dynamic_bind_engine) DSO_bind_func(ctx->dynamic_dso, ctx->DYNAMIC_F2))) { ctx->bind_engine = NULL; DSO_free(ctx->dynamic_dso); ctx->dynamic_dso = NULL; ENGINEerr(ENGINE_F_DYNAMIC_LOAD, ENGINE_R_DSO_FAILURE); return 0; } /* Do we perform version checking? */ if (!ctx->no_vcheck) { unsigned long vcheck_res = 0; /* * Now we try to find a version checking function and decide how to * cope with failure if/when it fails. */ ctx->v_check = (dynamic_v_check_fn) DSO_bind_func(ctx->dynamic_dso, ctx->DYNAMIC_F1); if (ctx->v_check) vcheck_res = ctx->v_check(OSSL_DYNAMIC_VERSION); /* * We fail if the version checker veto'd the load *or* if it is * deferring to us (by returning its version) and we think it is too * old. */ if (vcheck_res < OSSL_DYNAMIC_OLDEST) { /* Fail */ ctx->bind_engine = NULL; ctx->v_check = NULL; DSO_free(ctx->dynamic_dso); ctx->dynamic_dso = NULL; ENGINEerr(ENGINE_F_DYNAMIC_LOAD, ENGINE_R_VERSION_INCOMPATIBILITY); return 0; } } /* * First binary copy the ENGINE structure so that we can roll back if the * hand-over fails */ memcpy(&cpy, e, sizeof(ENGINE)); /* * Provide the ERR, "ex_data", memory, and locking callbacks so the * loaded library uses our state rather than its own. FIXME: As noted in * engine.h, much of this would be simplified if each area of code * provided its own "summary" structure of all related callbacks. It * would also increase opaqueness. */ fns.static_state = ENGINE_get_static_state(); CRYPTO_get_mem_functions(&fns.mem_fns.malloc_fn, &fns.mem_fns.realloc_fn, &fns.mem_fns.free_fn); /* * Now that we've loaded the dynamic engine, make sure no "dynamic" * ENGINE elements will show through. */ engine_set_all_null(e); /* Try to bind the ENGINE onto our own ENGINE structure */ if (!ctx->bind_engine(e, ctx->engine_id, &fns)) { ctx->bind_engine = NULL; ctx->v_check = NULL; DSO_free(ctx->dynamic_dso); ctx->dynamic_dso = NULL; ENGINEerr(ENGINE_F_DYNAMIC_LOAD, ENGINE_R_INIT_FAILED); /* Copy the original ENGINE structure back */ memcpy(e, &cpy, sizeof(ENGINE)); return 0; } /* Do we try to add this ENGINE to the internal list too? */ if (ctx->list_add_value > 0) { if (!ENGINE_add(e)) { /* Do we tolerate this or fail? */ if (ctx->list_add_value > 1) { /* * Fail - NB: By this time, it's too late to rollback, and * trying to do so allows the bind_engine() code to have * created leaks. We just have to fail where we are, after * the ENGINE has changed. */ ENGINEerr(ENGINE_F_DYNAMIC_LOAD, ENGINE_R_CONFLICTING_ENGINE_ID); return 0; } /* Tolerate */ ERR_clear_error(); } } return 1; }
/* * Internal version that doesn't affect the store flags, and thereby avoid * locking. Direct callers must remember to set the store flags when * appropriate */ static int provider_activate(OSSL_PROVIDER *prov) { const OSSL_DISPATCH *provider_dispatch = NULL; if (prov->flag_initialized) return 1; /* * If the init function isn't set, it indicates that this provider is * a loadable module. */ if (prov->init_function == NULL) { if (prov->module == NULL) { char *allocated_path = NULL; const char *module_path = NULL; char *merged_path = NULL; const char *load_dir = ossl_safe_getenv("OPENSSL_MODULES"); if ((prov->module = DSO_new()) == NULL) { /* DSO_new() generates an error already */ return 0; } if (load_dir == NULL) load_dir = MODULESDIR; DSO_ctrl(prov->module, DSO_CTRL_SET_FLAGS, DSO_FLAG_NAME_TRANSLATION_EXT_ONLY, NULL); module_path = prov->path; if (module_path == NULL) module_path = allocated_path = DSO_convert_filename(prov->module, prov->name); if (module_path != NULL) merged_path = DSO_merge(prov->module, module_path, load_dir); if (merged_path == NULL || (DSO_load(prov->module, merged_path, NULL, 0)) == NULL) { DSO_free(prov->module); prov->module = NULL; } OPENSSL_free(merged_path); OPENSSL_free(allocated_path); } if (prov->module != NULL) prov->init_function = (OSSL_provider_init_fn *) DSO_bind_func(prov->module, "OSSL_provider_init"); } if (prov->init_function == NULL || !prov->init_function(prov, core_dispatch, &provider_dispatch)) { CRYPTOerr(CRYPTO_F_PROVIDER_ACTIVATE, ERR_R_INIT_FAIL); ERR_add_error_data(2, "name=", prov->name); DSO_free(prov->module); prov->module = NULL; return 0; } for (; provider_dispatch->function_id != 0; provider_dispatch++) { switch (provider_dispatch->function_id) { case OSSL_FUNC_PROVIDER_TEARDOWN: prov->teardown = OSSL_get_provider_teardown(provider_dispatch); break; case OSSL_FUNC_PROVIDER_GET_PARAM_TYPES: prov->get_param_types = OSSL_get_provider_get_param_types(provider_dispatch); break; case OSSL_FUNC_PROVIDER_GET_PARAMS: prov->get_params = OSSL_get_provider_get_params(provider_dispatch); break; case OSSL_FUNC_PROVIDER_QUERY_OPERATION: prov->query_operation = OSSL_get_provider_query_operation(provider_dispatch); break; } } /* With this flag set, this provider has become fully "loaded". */ prov->flag_initialized = 1; return 1; }