1*2a59c28fStb /* $OpenBSD: conf_mod.c,v 1.40 2024/10/10 06:51:22 tb Exp $ */ 2e6841c1dSdjm /* Written by Stephen Henson (steve@openssl.org) for the OpenSSL 3da347917Sbeck * project 2001. 4da347917Sbeck */ 5da347917Sbeck /* ==================================================================== 6da347917Sbeck * Copyright (c) 2001 The OpenSSL Project. All rights reserved. 7da347917Sbeck * 8da347917Sbeck * Redistribution and use in source and binary forms, with or without 9da347917Sbeck * modification, are permitted provided that the following conditions 10da347917Sbeck * are met: 11da347917Sbeck * 12da347917Sbeck * 1. Redistributions of source code must retain the above copyright 13da347917Sbeck * notice, this list of conditions and the following disclaimer. 14da347917Sbeck * 15da347917Sbeck * 2. Redistributions in binary form must reproduce the above copyright 16da347917Sbeck * notice, this list of conditions and the following disclaimer in 17da347917Sbeck * the documentation and/or other materials provided with the 18da347917Sbeck * distribution. 19da347917Sbeck * 20da347917Sbeck * 3. All advertising materials mentioning features or use of this 21da347917Sbeck * software must display the following acknowledgment: 22da347917Sbeck * "This product includes software developed by the OpenSSL Project 23da347917Sbeck * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 24da347917Sbeck * 25da347917Sbeck * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26da347917Sbeck * endorse or promote products derived from this software without 27da347917Sbeck * prior written permission. For written permission, please contact 28da347917Sbeck * licensing@OpenSSL.org. 29da347917Sbeck * 30da347917Sbeck * 5. Products derived from this software may not be called "OpenSSL" 31da347917Sbeck * nor may "OpenSSL" appear in their names without prior written 32da347917Sbeck * permission of the OpenSSL Project. 33da347917Sbeck * 34da347917Sbeck * 6. Redistributions of any form whatsoever must retain the following 35da347917Sbeck * acknowledgment: 36da347917Sbeck * "This product includes software developed by the OpenSSL Project 37da347917Sbeck * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 38da347917Sbeck * 39da347917Sbeck * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40da347917Sbeck * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41da347917Sbeck * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42da347917Sbeck * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43da347917Sbeck * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44da347917Sbeck * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45da347917Sbeck * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46da347917Sbeck * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47da347917Sbeck * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48da347917Sbeck * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49da347917Sbeck * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50da347917Sbeck * OF THE POSSIBILITY OF SUCH DAMAGE. 51da347917Sbeck * ==================================================================== 52da347917Sbeck * 53da347917Sbeck * This product includes cryptographic software written by Eric Young 54da347917Sbeck * (eay@cryptsoft.com). This product includes software written by Tim 55da347917Sbeck * Hudson (tjh@cryptsoft.com). 56da347917Sbeck * 57da347917Sbeck */ 58da347917Sbeck 59da347917Sbeck #include <ctype.h> 60a8913c44Sjsing #include <stdio.h> 61a8913c44Sjsing #include <string.h> 62a8913c44Sjsing #include <unistd.h> 63a8913c44Sjsing 64da347917Sbeck #include <openssl/conf.h> 65b6ab114eSjsing #include <openssl/crypto.h> 66b6ab114eSjsing #include <openssl/err.h> 67da347917Sbeck #include <openssl/x509.h> 68da347917Sbeck 69e0656bc1Stb /* This structure contains data about supported modules. */ 7044486fcbSjsing struct conf_module_st { 71da347917Sbeck /* Name of the module */ 72da347917Sbeck char *name; 73da347917Sbeck /* Init function */ 74da347917Sbeck conf_init_func *init; 75da347917Sbeck /* Finish function */ 76da347917Sbeck conf_finish_func *finish; 77da347917Sbeck /* Number of successfully initialized modules */ 78da347917Sbeck int links; 79da347917Sbeck }; 80da347917Sbeck 81da347917Sbeck 82da347917Sbeck /* This structure contains information about modules that have been 83da347917Sbeck * successfully initialized. There may be more than one entry for a 84da347917Sbeck * given module. 85da347917Sbeck */ 86da347917Sbeck 8744486fcbSjsing struct conf_imodule_st { 88482e134aStb CONF_MODULE *mod; 89da347917Sbeck char *value; 90da347917Sbeck }; 91da347917Sbeck 92da347917Sbeck static STACK_OF(CONF_MODULE) *supported_modules = NULL; 93da347917Sbeck static STACK_OF(CONF_IMODULE) *initialized_modules = NULL; 94da347917Sbeck 95511ac327Stb static void module_free(CONF_MODULE *mod); 961d022c02Stb static void imodule_free(CONF_IMODULE *imod); 97da347917Sbeck static void module_finish(CONF_IMODULE *imod); 98da347917Sbeck static int module_run(const CONF *cnf, char *name, char *value, 99da347917Sbeck unsigned long flags); 1003cdf45a4Stb static int module_add(const char *name, conf_init_func *ifunc, 101e0656bc1Stb conf_finish_func *ffunc); 102da347917Sbeck static CONF_MODULE *module_find(char *name); 1035c82b5ecStb static int module_init(CONF_MODULE *mod, char *name, char *value, 104da347917Sbeck const CONF *cnf); 105da347917Sbeck 106da347917Sbeck /* Main function: load modules from a CONF structure */ 107da347917Sbeck 10844486fcbSjsing int 10944486fcbSjsing CONF_modules_load(const CONF *cnf, const char *appname, unsigned long flags) 110da347917Sbeck { 111da347917Sbeck STACK_OF(CONF_VALUE) *values; 112da347917Sbeck CONF_VALUE *vl; 1134fcf65c5Sdjm char *vsection = NULL; 114da347917Sbeck 115da347917Sbeck int ret, i; 116da347917Sbeck 117da347917Sbeck if (!cnf) 118da347917Sbeck return 1; 119da347917Sbeck 1204fcf65c5Sdjm if (appname) 121da347917Sbeck vsection = NCONF_get_string(cnf, NULL, appname); 122da347917Sbeck 1234fcf65c5Sdjm if (!appname || (!vsection && (flags & CONF_MFLAGS_DEFAULT_SECTION))) 1244fcf65c5Sdjm vsection = NCONF_get_string(cnf, NULL, "openssl_conf"); 1254fcf65c5Sdjm 12644486fcbSjsing if (!vsection) { 127da347917Sbeck ERR_clear_error(); 128da347917Sbeck return 1; 129da347917Sbeck } 130da347917Sbeck 131da347917Sbeck values = NCONF_get_section(cnf, vsection); 132da347917Sbeck 133da347917Sbeck if (!values) 134da347917Sbeck return 0; 135da347917Sbeck 13644486fcbSjsing for (i = 0; i < sk_CONF_VALUE_num(values); i++) { 137da347917Sbeck vl = sk_CONF_VALUE_value(values, i); 138da347917Sbeck ret = module_run(cnf, vl->name, vl->value, flags); 139da347917Sbeck if (ret <= 0) 140da347917Sbeck if (!(flags & CONF_MFLAGS_IGNORE_ERRORS)) 141da347917Sbeck return ret; 142da347917Sbeck } 143da347917Sbeck 144da347917Sbeck return 1; 145da347917Sbeck } 146bbdd77aaSbeck LCRYPTO_ALIAS(CONF_modules_load); 147da347917Sbeck 14844486fcbSjsing int 14944486fcbSjsing CONF_modules_load_file(const char *filename, const char *appname, 150da347917Sbeck unsigned long flags) 151da347917Sbeck { 152da347917Sbeck char *file = NULL; 153da347917Sbeck CONF *conf = NULL; 154da347917Sbeck int ret = 0; 155da347917Sbeck conf = NCONF_new(NULL); 156da347917Sbeck if (!conf) 157da347917Sbeck goto err; 158da347917Sbeck 15944486fcbSjsing if (filename == NULL) { 160da347917Sbeck file = CONF_get1_default_config_file(); 161da347917Sbeck if (!file) 162da347917Sbeck goto err; 16344486fcbSjsing } else 164da347917Sbeck file = (char *)filename; 165da347917Sbeck 16644486fcbSjsing if (NCONF_load(conf, file, NULL) <= 0) { 167da347917Sbeck if ((flags & CONF_MFLAGS_IGNORE_MISSING_FILE) && 16844486fcbSjsing (ERR_GET_REASON(ERR_peek_last_error()) == 16944486fcbSjsing CONF_R_NO_SUCH_FILE)) { 170da347917Sbeck ERR_clear_error(); 171da347917Sbeck ret = 1; 172da347917Sbeck } 173da347917Sbeck goto err; 174da347917Sbeck } 175da347917Sbeck 176da347917Sbeck ret = CONF_modules_load(conf, appname, flags); 177da347917Sbeck 178da347917Sbeck err: 179da347917Sbeck if (filename == NULL) 1806f3a6cb1Sbeck free(file); 181da347917Sbeck NCONF_free(conf); 182da347917Sbeck 183da347917Sbeck return ret; 184da347917Sbeck } 185bbdd77aaSbeck LCRYPTO_ALIAS(CONF_modules_load_file); 186da347917Sbeck 18744486fcbSjsing static int 18844486fcbSjsing module_run(const CONF *cnf, char *name, char *value, unsigned long flags) 189da347917Sbeck { 190511ac327Stb CONF_MODULE *mod; 191da347917Sbeck int ret; 192da347917Sbeck 193511ac327Stb if ((mod = module_find(name)) == NULL) { 19444486fcbSjsing if (!(flags & CONF_MFLAGS_SILENT)) { 1955067ae9fSbeck CONFerror(CONF_R_UNKNOWN_MODULE_NAME); 1960f637b92Sbeck ERR_asprintf_error_data("module=%s", name); 197da347917Sbeck } 198da347917Sbeck return -1; 199da347917Sbeck } 200da347917Sbeck 201511ac327Stb ret = module_init(mod, name, value, cnf); 202da347917Sbeck 20344486fcbSjsing if (ret <= 0) { 20444486fcbSjsing if (!(flags & CONF_MFLAGS_SILENT)) { 2055067ae9fSbeck CONFerror(CONF_R_MODULE_INITIALIZATION_ERROR); 2060f637b92Sbeck ERR_asprintf_error_data 2070f637b92Sbeck ("module=%s, value=%s, retcode=%-8d", 2080f637b92Sbeck name, value, ret); 209da347917Sbeck } 210da347917Sbeck } 211da347917Sbeck 212da347917Sbeck return ret; 213da347917Sbeck } 214da347917Sbeck 2153cdf45a4Stb static int 216e0656bc1Stb module_add(const char *name, conf_init_func *ifunc, conf_finish_func *ffunc) 217da347917Sbeck { 218fee7a564Stb CONF_MODULE *mod = NULL; 2193cdf45a4Stb int ret = 0; 22044486fcbSjsing 22169442892Sbeck if (name == NULL) 2223cdf45a4Stb goto err; 2233cdf45a4Stb 224da347917Sbeck if (supported_modules == NULL) 225da347917Sbeck supported_modules = sk_CONF_MODULE_new_null(); 226da347917Sbeck if (supported_modules == NULL) 2273cdf45a4Stb goto err; 228da347917Sbeck 229fee7a564Stb if ((mod = calloc(1, sizeof(*mod))) == NULL) 2303cdf45a4Stb goto err; 231fee7a564Stb if ((mod->name = strdup(name)) == NULL) 2323cdf45a4Stb goto err; 233fee7a564Stb mod->init = ifunc; 234fee7a564Stb mod->finish = ffunc; 235da347917Sbeck 236fee7a564Stb if (!sk_CONF_MODULE_push(supported_modules, mod)) 2373cdf45a4Stb goto err; 238fee7a564Stb mod = NULL; 239da347917Sbeck 2403cdf45a4Stb ret = 1; 2413cdf45a4Stb 2423cdf45a4Stb err: 243fee7a564Stb module_free(mod); 2443cdf45a4Stb 2453cdf45a4Stb return ret; 246da347917Sbeck } 247da347917Sbeck 248da347917Sbeck /* Find a module from the list. We allow module names of the 249da347917Sbeck * form modname.XXXX to just search for modname to allow the 250da347917Sbeck * same module to be initialized more than once. 251da347917Sbeck */ 252da347917Sbeck 25344486fcbSjsing static CONF_MODULE * 25444486fcbSjsing module_find(char *name) 255da347917Sbeck { 256fee7a564Stb CONF_MODULE *mod; 257da347917Sbeck int i, nchar; 258da347917Sbeck char *p; 25944486fcbSjsing 260da347917Sbeck p = strrchr(name, '.'); 261da347917Sbeck 262da347917Sbeck if (p) 263da347917Sbeck nchar = p - name; 264da347917Sbeck else 265da347917Sbeck nchar = strlen(name); 266da347917Sbeck 26744486fcbSjsing for (i = 0; i < sk_CONF_MODULE_num(supported_modules); i++) { 268fee7a564Stb mod = sk_CONF_MODULE_value(supported_modules, i); 269fee7a564Stb if (!strncmp(mod->name, name, nchar)) 270fee7a564Stb return mod; 271da347917Sbeck } 272da347917Sbeck 273da347917Sbeck return NULL; 274da347917Sbeck } 275da347917Sbeck 276da347917Sbeck /* initialize a module */ 27744486fcbSjsing static int 2785c82b5ecStb module_init(CONF_MODULE *mod, char *name, char *value, const CONF *cnf) 279da347917Sbeck { 280da347917Sbeck CONF_IMODULE *imod = NULL; 28196025fd0Stb int need_finish = 0; 28296025fd0Stb int ret = -1; 283da347917Sbeck 28496025fd0Stb if (name == NULL || value == NULL) 28596025fd0Stb goto err; 28696025fd0Stb 28796025fd0Stb if ((imod = calloc(1, sizeof(*imod))) == NULL) 288da347917Sbeck goto err; 289da347917Sbeck 2905c82b5ecStb imod->mod = mod; 291da347917Sbeck 29296025fd0Stb if ((imod->value = strdup(value)) == NULL) 29396025fd0Stb goto err; 294da347917Sbeck 29596025fd0Stb if (mod->init != NULL) { 29696025fd0Stb need_finish = 1; 29796025fd0Stb if (mod->init(imod, cnf) <= 0) 298da347917Sbeck goto err; 299da347917Sbeck } 300da347917Sbeck 30196025fd0Stb if (initialized_modules == NULL) 302da347917Sbeck initialized_modules = sk_CONF_IMODULE_new_null(); 30396025fd0Stb if (initialized_modules == NULL) 304da347917Sbeck goto err; 305da347917Sbeck 30696025fd0Stb if (!sk_CONF_IMODULE_push(initialized_modules, imod)) 307da347917Sbeck goto err; 30896025fd0Stb imod = NULL; 30996025fd0Stb need_finish = 0; 310da347917Sbeck 3115c82b5ecStb mod->links++; 312da347917Sbeck 31396025fd0Stb ret = 1; 314da347917Sbeck 315da347917Sbeck err: 31696025fd0Stb if (need_finish && mod->finish != NULL) 3175c82b5ecStb mod->finish(imod); 318da347917Sbeck 31996025fd0Stb imodule_free(imod); 320da347917Sbeck 32196025fd0Stb return ret; 322da347917Sbeck } 323da347917Sbeck 324da347917Sbeck /* Unload any dynamic modules that have a link count of zero: 325da347917Sbeck * i.e. have no active initialized modules. If 'all' is set 326da347917Sbeck * then all modules are unloaded including static ones. 327da347917Sbeck */ 328da347917Sbeck 32944486fcbSjsing void 33044486fcbSjsing CONF_modules_unload(int all) 331da347917Sbeck { 332da347917Sbeck int i; 333511ac327Stb CONF_MODULE *mod; 33444486fcbSjsing 335da347917Sbeck CONF_modules_finish(); 33644486fcbSjsing 337da347917Sbeck /* unload modules in reverse order */ 33844486fcbSjsing for (i = sk_CONF_MODULE_num(supported_modules) - 1; i >= 0; i--) { 339511ac327Stb mod = sk_CONF_MODULE_value(supported_modules, i); 340e0656bc1Stb if (!all) 341da347917Sbeck continue; 342da347917Sbeck /* Since we're working in reverse this is OK */ 3434fcf65c5Sdjm (void)sk_CONF_MODULE_delete(supported_modules, i); 344511ac327Stb module_free(mod); 345da347917Sbeck } 34644486fcbSjsing if (sk_CONF_MODULE_num(supported_modules) == 0) { 347da347917Sbeck sk_CONF_MODULE_free(supported_modules); 348da347917Sbeck supported_modules = NULL; 349da347917Sbeck } 350da347917Sbeck } 351bbdd77aaSbeck LCRYPTO_ALIAS(CONF_modules_unload); 352da347917Sbeck 353da347917Sbeck /* unload a single module */ 35444486fcbSjsing static void 355511ac327Stb module_free(CONF_MODULE *mod) 356da347917Sbeck { 357511ac327Stb if (mod == NULL) 358f06d1561Stb return; 359f06d1561Stb 360511ac327Stb free(mod->name); 361511ac327Stb free(mod); 362da347917Sbeck } 363da347917Sbeck 3641d022c02Stb static void 3651d022c02Stb imodule_free(CONF_IMODULE *imod) 3661d022c02Stb { 3671d022c02Stb if (imod == NULL) 3681d022c02Stb return; 3691d022c02Stb 3701d022c02Stb free(imod->value); 3711d022c02Stb free(imod); 3721d022c02Stb } 3731d022c02Stb 374da347917Sbeck /* finish and free up all modules instances */ 375da347917Sbeck 37644486fcbSjsing void 37744486fcbSjsing CONF_modules_finish(void) 378da347917Sbeck { 379da347917Sbeck CONF_IMODULE *imod; 38044486fcbSjsing 38144486fcbSjsing while (sk_CONF_IMODULE_num(initialized_modules) > 0) { 382da347917Sbeck imod = sk_CONF_IMODULE_pop(initialized_modules); 383da347917Sbeck module_finish(imod); 384da347917Sbeck } 385da347917Sbeck sk_CONF_IMODULE_free(initialized_modules); 386da347917Sbeck initialized_modules = NULL; 387da347917Sbeck } 388bbdd77aaSbeck LCRYPTO_ALIAS(CONF_modules_finish); 389da347917Sbeck 390da347917Sbeck /* finish a module instance */ 391da347917Sbeck 39244486fcbSjsing static void 39344486fcbSjsing module_finish(CONF_IMODULE *imod) 394da347917Sbeck { 395482e134aStb if (imod->mod->finish) 396482e134aStb imod->mod->finish(imod); 397482e134aStb imod->mod->links--; 3981d022c02Stb 3991d022c02Stb imodule_free(imod); 400da347917Sbeck } 401da347917Sbeck 402da347917Sbeck /* Add a static module to OpenSSL */ 403da347917Sbeck 40444486fcbSjsing int 405e0656bc1Stb CONF_module_add(const char *name, conf_init_func *ifunc, conf_finish_func *ffunc) 406da347917Sbeck { 4073cdf45a4Stb return module_add(name, ifunc, ffunc); 408da347917Sbeck } 409da347917Sbeck 41044486fcbSjsing void 41144486fcbSjsing CONF_modules_free(void) 412da347917Sbeck { 413da347917Sbeck CONF_modules_finish(); 414da347917Sbeck CONF_modules_unload(1); 415da347917Sbeck } 416bbdd77aaSbeck LCRYPTO_ALIAS(CONF_modules_free); 417da347917Sbeck 41844486fcbSjsing const char * 4191d159ddeStb CONF_imodule_get_value(const CONF_IMODULE *imod) 420da347917Sbeck { 4211d159ddeStb return imod->value; 422da347917Sbeck } 423da347917Sbeck 4241297a291Sderaadt char * 4251297a291Sderaadt CONF_get1_default_config_file(void) 426da347917Sbeck { 42775eb8854Sderaadt char *file = NULL; 428da347917Sbeck 42944486fcbSjsing if (asprintf(&file, "%s/openssl.cnf", 43044486fcbSjsing X509_get_default_cert_area()) == -1) 431e1962626Sderaadt return (NULL); 432da347917Sbeck return file; 433da347917Sbeck } 434bbdd77aaSbeck LCRYPTO_ALIAS(CONF_get1_default_config_file); 435da347917Sbeck 436da347917Sbeck /* This function takes a list separated by 'sep' and calls the 437da347917Sbeck * callback function giving the start and length of each member 438da347917Sbeck * optionally stripping leading and trailing whitespace. This can 439da347917Sbeck * be used to parse comma separated lists for example. 440da347917Sbeck */ 441da347917Sbeck 44244486fcbSjsing int 44344486fcbSjsing CONF_parse_list(const char *list_, int sep, int nospc, 444da347917Sbeck int (*list_cb)(const char *elem, int len, void *usr), void *arg) 445da347917Sbeck { 446da347917Sbeck int ret; 447da347917Sbeck const char *lstart, *tmpend, *p; 448da347917Sbeck 44944486fcbSjsing if (list_ == NULL) { 4505067ae9fSbeck CONFerror(CONF_R_LIST_CANNOT_BE_NULL); 4510a5d6edeSdjm return 0; 4520a5d6edeSdjm } 4530a5d6edeSdjm 4540a5d6edeSdjm lstart = list_; 45544486fcbSjsing for (;;) { 45644486fcbSjsing if (nospc) { 45750c17820Sdjm while (*lstart && isspace((unsigned char)*lstart)) 458da347917Sbeck lstart++; 459da347917Sbeck } 460da347917Sbeck p = strchr(lstart, sep); 461da347917Sbeck if (p == lstart || !*lstart) 462da347917Sbeck ret = list_cb(NULL, 0, arg); 46344486fcbSjsing else { 464da347917Sbeck if (p) 465da347917Sbeck tmpend = p - 1; 466da347917Sbeck else 467da347917Sbeck tmpend = lstart + strlen(lstart) - 1; 46844486fcbSjsing if (nospc) { 469da347917Sbeck while (isspace((unsigned char)*tmpend)) 470da347917Sbeck tmpend--; 471da347917Sbeck } 472da347917Sbeck ret = list_cb(lstart, tmpend - lstart + 1, arg); 473da347917Sbeck } 474da347917Sbeck if (ret <= 0) 475da347917Sbeck return ret; 476da347917Sbeck if (p == NULL) 477da347917Sbeck return 1; 478da347917Sbeck lstart = p + 1; 479da347917Sbeck } 480da347917Sbeck } 481