diff options
author | Dr. Stephen Henson <steve@openssl.org> | 2002-01-05 01:37:16 +0000 |
---|---|---|
committer | Dr. Stephen Henson <steve@openssl.org> | 2002-01-05 01:37:16 +0000 |
commit | bc37d996fcfd7f1c7c97728a563a40c0a251d908 (patch) | |
tree | 3bffb03f405fe2cf8b70c0e86c96d0bc7ab1b0d1 /crypto/conf/conf_mod.c | |
parent | 31cafe53c928e02d6351dc9a827e95bccd9b807d (diff) |
Experimental configuration code.
Incomplete, largely untested and subject to change/deletion.
Diffstat (limited to 'crypto/conf/conf_mod.c')
-rw-r--r-- | crypto/conf/conf_mod.c | 507 |
1 files changed, 507 insertions, 0 deletions
diff --git a/crypto/conf/conf_mod.c b/crypto/conf/conf_mod.c new file mode 100644 index 0000000000..cbbaf64f3c --- /dev/null +++ b/crypto/conf/conf_mod.c @@ -0,0 +1,507 @@ +/* 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 <stdio.h> +#include <openssl/crypto.h> +#include "cryptlib.h" +#include <openssl/conf.h> +#include <openssl/dso.h> +#include <openssl/x509.h> + + +#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; + } + |