/* conf_mod.c */ /* Written by Stephen Henson (shenson@bigfoot.com) for the OpenSSL * project 2001. */ /* ==================================================================== * Copyright (c) 2001 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" * * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * licensing@OpenSSL.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written * permission of the OpenSSL Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" * * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). * */ #include #include #include "cryptlib.h" #include #include #include #define DSO_mod_init_name "OPENSSL_init" #define DSO_mod_finish_name "OPENSSL_finish" /* This structure contains a data about supported modules. * entries in this table correspond to either dynamic or * static modules. */ struct conf_module_st { /* DSO of this module or NULL if static */ DSO *dso; /* Name of the module */ char *name; /* Init function */ conf_init_func *init; /* Finish function */ conf_finish_func *finish; /* Number of successfully initialized modules */ int links; void *usr_data; }; /* This structure contains information about modules that have been * successfully initialized. There may be more than one entry for a * given module. */ struct conf_imodule_st { CONF_MODULE *pmod; char *name; char *value; unsigned long flags; void *usr_data; }; static STACK_OF(CONF_MODULE) *supported_modules = NULL; static STACK_OF(CONF_IMODULE) *initialized_modules = NULL; static void module_free(CONF_MODULE *md); static void module_finish(CONF_IMODULE *imod); static int module_run(CONF *cnf, char *name, char *value, unsigned long flags); static CONF_MODULE *module_add(DSO *dso, char *name, conf_init_func *ifunc, conf_finish_func *ffunc); static CONF_MODULE *module_find(char *name); static int module_init(CONF_MODULE *pmod, char *name, char *value, CONF *cnf); static CONF_MODULE *module_load_dso(CONF *cnf, char *name, char *value, unsigned long flags); /* Main function: load modules from a CONF structure */ int CONF_modules_load(CONF *cnf, char *appname, unsigned long flags) { STACK_OF(CONF_VALUE) *values; CONF_VALUE *vl; char *vsection; int ret, i; if (!cnf || !appname) return 1; vsection = NCONF_get_string(cnf, NULL, appname); if (!vsection) { ERR_clear_error(); return 1; } values = NCONF_get_section(cnf, vsection); if (!values) return 0; for (i = 0; i < sk_CONF_VALUE_num(values); i++) { vl = sk_CONF_VALUE_value(values, i); ret = module_run(cnf, vl->name, vl->value, flags); if (ret <= 0) if(!(flags & CONF_MFLAGS_IGNORE_ERRORS)) return ret; } return 1; } int CONF_modules_load_file(char *filename, char *appname, unsigned long flags) { CONF *conf = NULL; int ret = 0; conf = NCONF_new(NULL); if (!conf) goto err; if (NCONF_load(conf, filename, NULL) <= 0) goto err; ret = CONF_modules_load(conf, appname, flags); err: NCONF_free(conf); return ret; } static int module_run(CONF *cnf, char *name, char *value, unsigned long flags) { CONF_MODULE *md; int ret; md = module_find(name); /* Module not found: try to load DSO */ if (!md) md = module_load_dso(cnf, name, value, flags); if (!md) { if (!(flags & CONF_MFLAGS_SILENT)) { CONFerr(CONF_F_MODULE_RUN, CONF_R_UNKNOWN_MODULE_NAME); ERR_add_error_data(2, "module=", name); } return -1; } ret = module_init(md, name, value, cnf); if (ret <= 0) { if (!(flags & CONF_MFLAGS_SILENT)) { char rcode[10]; CONFerr(CONF_F_CONF_MODULES_LOAD, CONF_R_MODULE_INITIALIZATION_ERROR); sprintf(rcode, "%-8d", ret); ERR_add_error_data(6, "module=", name, ", value=", value, ", retcode=", rcode); } } return ret; } /* Load a module from a DSO */ static CONF_MODULE *module_load_dso(CONF *cnf, char *name, char *value, unsigned long flags) { DSO *dso = NULL; conf_init_func *ifunc; conf_finish_func *ffunc; char *path = NULL; int errcode = 0; CONF_MODULE *md; /* Look for alternative path in module section */ path = NCONF_get_string(cnf, value, "path"); if (!path) { ERR_get_error(); path = name; } dso = DSO_load(NULL, path, NULL, 0); if (!dso) { errcode = CONF_R_ERROR_LOADING_DSO; goto err; } ifunc = (conf_init_func *)DSO_bind_func(dso, DSO_mod_init_name); if (!ifunc) { errcode = CONF_R_MISSING_INIT_FUNCTION; goto err; } ffunc = (conf_finish_func *)DSO_bind_func(dso, DSO_mod_finish_name); if (!ffunc) { errcode = CONF_R_MISSING_FINISH_FUNCTION; goto err; } /* All OK, add module */ md = module_add(dso, name, ifunc, ffunc); if (!md) goto err; return md; err: if (dso) DSO_free(dso); CONFerr(CONF_F_MODULE_LOAD_DSO, errcode); ERR_add_error_data(4, "module=", name, ", path=", path); return NULL; } /* add module to list */ static CONF_MODULE *module_add(DSO *dso, char *name, conf_init_func *ifunc, conf_finish_func *ffunc) { CONF_MODULE *tmod = NULL; if (supported_modules == NULL) supported_modules = sk_CONF_MODULE_new_null(); if (supported_modules == NULL) return NULL; tmod = OPENSSL_malloc(sizeof(CONF_MODULE)); if (tmod == NULL) return NULL; tmod->dso = dso; tmod->name = BUF_strdup(name); tmod->init = ifunc; tmod->finish = ffunc; tmod->links = 0; if (!sk_CONF_MODULE_push(supported_modules, tmod)) { OPENSSL_free(tmod); return NULL; } return tmod; } /* Find a module from the list. We allow module names of the * form modname.XXXX to just search for modname to allow the * same module to be initialized more than once. */ static CONF_MODULE *module_find(char *name) { CONF_MODULE *tmod; int i, nchar; char *p; p = strrchr(name, '.'); if (p) nchar = p - name; else nchar = strlen(name); for (i = 0; i < sk_CONF_MODULE_num(supported_modules); i++) { tmod = sk_CONF_MODULE_value(supported_modules, i); if (!strncmp(tmod->name, name, nchar)) return tmod; } return NULL; } /* initialize a module */ static int module_init(CONF_MODULE *pmod, char *name, char *value, CONF *cnf) { int ret, init_called = 0; CONF_IMODULE *imod = NULL; /* Otherwise add initialized module to list */ imod = OPENSSL_malloc(sizeof(CONF_IMODULE)); if (!imod) goto err; imod->pmod = pmod; imod->name = BUF_strdup(name); imod->value = BUF_strdup(value); imod->usr_data = NULL; if (!imod->name || !imod->value) goto memerr; /* Try to initialize module */ if(pmod->init) { ret = pmod->init(imod, cnf); init_called = 1; /* Error occurred, exit */ if (ret <= 0) goto err; } if (initialized_modules == NULL) initialized_modules = sk_CONF_IMODULE_new_null(); if (!initialized_modules) goto err; if (!sk_CONF_IMODULE_push(initialized_modules, imod)) goto err; pmod->links++; return ret; err: CONFerr(CONF_F_MODULE_INIT, ERR_R_MALLOC_FAILURE); /* We've started the module so we'd better finish it */ if (pmod->finish && init_called) pmod->finish(imod); memerr: if (imod) { if (imod->name) OPENSSL_free(imod->name); if (imod->value) OPENSSL_free(imod->value); OPENSSL_free(imod); } return -1; } /* Unload any dynamic modules that have a link count of zero: * i.e. have no active initialized modules. If 'all' is set * then all modules are unloaded including static ones. */ void CONF_modules_unload(int all) { int i; CONF_MODULE *md; /* unload modules in reverse order */ for (i = sk_CONF_MODULE_num(supported_modules) - 1; i >= 0; i--) { md = sk_CONF_MODULE_value(supported_modules, i); /* If static or in use and 'all' not set ignore it */ if (((md->links > 0) || !md->dso) && !all) continue; /* Since we're working in reverse this is OK */ sk_CONF_MODULE_delete(supported_modules, i); module_free(md); } if (sk_CONF_MODULE_num(supported_modules) == 0) { sk_CONF_MODULE_free(supported_modules); supported_modules = NULL; } } /* unload a single module */ static void module_free(CONF_MODULE *md) { if (md->dso) DSO_free(md->dso); OPENSSL_free(md->name); OPENSSL_free(md); } /* finish and free up all modules instances */ void CONF_modules_finish(void) { CONF_IMODULE *imod; while (sk_CONF_IMODULE_num(initialized_modules) > 0) { imod = sk_CONF_IMODULE_pop(initialized_modules); module_finish(imod); } sk_CONF_IMODULE_free(initialized_modules); initialized_modules = NULL; } /* finish a module instance */ static void module_finish(CONF_IMODULE *imod) { imod->pmod->finish(imod); imod->pmod->links--; OPENSSL_free(imod->name); OPENSSL_free(imod->value); OPENSSL_free(imod); } /* Add a static module to OpenSSL */ int CONF_module_add(char *name, conf_init_func *ifunc, conf_finish_func *ffunc) { if (module_add(NULL, name, ifunc, ffunc)) return 1; else return 0; } void CONF_modules_free(void) { CONF_modules_finish(); CONF_modules_unload(1); } /* Utility functions */ char *CONF_imodule_get_name(CONF_IMODULE *md) { return md->name; } char *CONF_imodule_get_value(CONF_IMODULE *md) { return md->value; } void *CONF_imodule_get_usr_data(CONF_IMODULE *md) { return md->usr_data; } void CONF_imodule_set_usr_data(CONF_IMODULE *md, void *usr_data) { md->usr_data = usr_data; } CONF_MODULE *CONF_imodule_get_module(CONF_IMODULE *md) { return md->pmod; } unsigned long CONF_imodule_get_flags(CONF_IMODULE *md) { return md->flags; } void CONF_imodule_set_flags(CONF_IMODULE *md, unsigned long flags) { md->flags = flags; } void *CONF_module_get_usr_data(CONF_MODULE *pmod) { return pmod->usr_data; } void CONF_module_set_usr_data(CONF_MODULE *pmod, void *usr_data) { pmod->usr_data = usr_data; }