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