1219820Sjeff/* conf_mod.c */ 2219820Sjeff/* 3219820Sjeff * Written by Stephen Henson (steve@openssl.org) for the OpenSSL project 4219820Sjeff * 2001. 5270710Shselasky */ 6328653Shselasky/* ==================================================================== 7219820Sjeff * Copyright (c) 2001 The OpenSSL Project. All rights reserved. 8219820Sjeff * 9219820Sjeff * Redistribution and use in source and binary forms, with or without 10219820Sjeff * modification, are permitted provided that the following conditions 11219820Sjeff * are met: 12219820Sjeff * 13219820Sjeff * 1. Redistributions of source code must retain the above copyright 14219820Sjeff * notice, this list of conditions and the following disclaimer. 15219820Sjeff * 16219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright 17219820Sjeff * notice, this list of conditions and the following disclaimer in 18219820Sjeff * the documentation and/or other materials provided with the 19219820Sjeff * distribution. 20219820Sjeff * 21219820Sjeff * 3. All advertising materials mentioning features or use of this 22219820Sjeff * software must display the following acknowledgment: 23219820Sjeff * "This product includes software developed by the OpenSSL Project 24219820Sjeff * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 25219820Sjeff * 26219820Sjeff * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 27219820Sjeff * endorse or promote products derived from this software without 28219820Sjeff * prior written permission. For written permission, please contact 29289644Shselasky * licensing@OpenSSL.org. 30289644Shselasky * 31219820Sjeff * 5. Products derived from this software may not be called "OpenSSL" 32328653Shselasky * nor may "OpenSSL" appear in their names without prior written 33328653Shselasky * permission of the OpenSSL Project. 34219820Sjeff * 35219820Sjeff * 6. Redistributions of any form whatsoever must retain the following 36300671Shselasky * acknowledgment: 37328653Shselasky * "This product includes software developed by the OpenSSL Project 38219820Sjeff * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 39219820Sjeff * 40328653Shselasky * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 41328653Shselasky * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42219820Sjeff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43219820Sjeff * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44219820Sjeff * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45328653Shselasky * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46289564Shselasky * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47328653Shselasky * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48328653Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49219820Sjeff * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50335425Shselasky * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51335425Shselasky * OF THE POSSIBILITY OF SUCH DAMAGE. 52335425Shselasky * ==================================================================== 53335425Shselasky * 54328653Shselasky * This product includes cryptographic software written by Eric Young 55328653Shselasky * (eay@cryptsoft.com). This product includes software written by Tim 56219820Sjeff * Hudson (tjh@cryptsoft.com). 57328653Shselasky * 58328653Shselasky */ 59219820Sjeff 60328653Shselasky#include <stdio.h> 61219820Sjeff#include <ctype.h> 62328653Shselasky#include <openssl/crypto.h> 63328653Shselasky#include "cryptlib.h" 64328653Shselasky#include <openssl/conf.h> 65328653Shselasky#include <openssl/dso.h> 66328653Shselasky#include <openssl/x509.h> 67328653Shselasky 68328653Shselasky#define DSO_mod_init_name "OPENSSL_init" 69328653Shselasky#define DSO_mod_finish_name "OPENSSL_finish" 70335424Shselasky 71335424Shselasky/* 72335424Shselasky * This structure contains a data about supported modules. entries in this 73335424Shselasky * table correspond to either dynamic or static modules. 74328653Shselasky */ 75219820Sjeff 76328653Shselaskystruct conf_module_st { 77328653Shselasky /* DSO of this module or NULL if static */ 78335424Shselasky DSO *dso; 79335424Shselasky /* Name of the module */ 80335424Shselasky char *name; 81335424Shselasky /* Init function */ 82328653Shselasky conf_init_func *init; 83328653Shselasky /* Finish function */ 84328653Shselasky conf_finish_func *finish; 85328653Shselasky /* Number of successfully initialized modules */ 86328653Shselasky int links; 87328653Shselasky void *usr_data; 88328653Shselasky}; 89330861Shselasky 90328653Shselasky/* 91330861Shselasky * This structure contains information about modules that have been 92328653Shselasky * successfully initialized. There may be more than one entry for a given 93328653Shselasky * module. 94330861Shselasky */ 95328653Shselasky 96328653Shselaskystruct conf_imodule_st { 97328653Shselasky CONF_MODULE *pmod; 98330861Shselasky char *name; 99330861Shselasky char *value; 100330861Shselasky unsigned long flags; 101328653Shselasky void *usr_data; 102328653Shselasky}; 103328653Shselasky 104328653Shselaskystatic STACK_OF(CONF_MODULE) *supported_modules = NULL; 105328653Shselaskystatic STACK_OF(CONF_IMODULE) *initialized_modules = NULL; 106328653Shselasky 107328653Shselaskystatic void module_free(CONF_MODULE *md); 108328653Shselaskystatic void module_finish(CONF_IMODULE *imod); 109328653Shselaskystatic int module_run(const CONF *cnf, char *name, char *value, 110328653Shselasky unsigned long flags); 111328653Shselaskystatic CONF_MODULE *module_add(DSO *dso, const char *name, 112328653Shselasky conf_init_func *ifunc, 113328653Shselasky conf_finish_func *ffunc); 114328653Shselaskystatic CONF_MODULE *module_find(char *name); 115328653Shselaskystatic int module_init(CONF_MODULE *pmod, char *name, char *value, 116328653Shselasky const CONF *cnf); 117219820Sjeffstatic CONF_MODULE *module_load_dso(const CONF *cnf, char *name, char *value, 118219820Sjeff unsigned long flags); 119335423Shselasky 120328653Shselasky/* Main function: load modules from a CONF structure */ 121328653Shselasky 122335423Shselaskyint CONF_modules_load(const CONF *cnf, const char *appname, 123335423Shselasky unsigned long flags) 124328653Shselasky{ 125328653Shselasky STACK_OF(CONF_VALUE) *values; 126328653Shselasky CONF_VALUE *vl; 127328653Shselasky char *vsection = NULL; 128328653Shselasky 129328653Shselasky int ret, i; 130328653Shselasky 131328653Shselasky if (!cnf) 132328653Shselasky return 1; 133328653Shselasky 134328653Shselasky if (appname) 135328653Shselasky vsection = NCONF_get_string(cnf, NULL, appname); 136328653Shselasky 137328653Shselasky if (!appname || (!vsection && (flags & CONF_MFLAGS_DEFAULT_SECTION))) 138328653Shselasky vsection = NCONF_get_string(cnf, NULL, "openssl_conf"); 139328653Shselasky 140328653Shselasky if (!vsection) { 141328653Shselasky ERR_clear_error(); 142328653Shselasky return 1; 143328653Shselasky } 144328653Shselasky 145328653Shselasky values = NCONF_get_section(cnf, vsection); 146328653Shselasky 147328653Shselasky if (!values) 148328653Shselasky return 0; 149328653Shselasky 150328653Shselasky for (i = 0; i < sk_CONF_VALUE_num(values); i++) { 151328653Shselasky vl = sk_CONF_VALUE_value(values, i); 152328653Shselasky ret = module_run(cnf, vl->name, vl->value, flags); 153328653Shselasky if (ret <= 0) 154328653Shselasky if (!(flags & CONF_MFLAGS_IGNORE_ERRORS)) 155328653Shselasky return ret; 156328653Shselasky } 157328653Shselasky 158328653Shselasky return 1; 159328653Shselasky 160328653Shselasky} 161328653Shselasky 162328653Shselaskyint CONF_modules_load_file(const char *filename, const char *appname, 163328653Shselasky unsigned long flags) 164328653Shselasky{ 165328653Shselasky char *file = NULL; 166328653Shselasky CONF *conf = NULL; 167328653Shselasky int ret = 0; 168328653Shselasky conf = NCONF_new(NULL); 169328653Shselasky if (!conf) 170328653Shselasky goto err; 171328653Shselasky 172328653Shselasky if (filename == NULL) { 173328653Shselasky file = CONF_get1_default_config_file(); 174219820Sjeff if (!file) 175219820Sjeff goto err; 176328653Shselasky } else 177328653Shselasky file = (char *)filename; 178328653Shselasky 179328653Shselasky if (NCONF_load(conf, file, NULL) <= 0) { 180328653Shselasky if ((flags & CONF_MFLAGS_IGNORE_MISSING_FILE) && 181328653Shselasky (ERR_GET_REASON(ERR_peek_last_error()) == CONF_R_NO_SUCH_FILE)) { 182328653Shselasky ERR_clear_error(); 183328653Shselasky ret = 1; 184328653Shselasky } 185328653Shselasky goto err; 186334760Shselasky } 187334760Shselasky 188334760Shselasky ret = CONF_modules_load(conf, appname, flags); 189334760Shselasky 190334760Shselasky err: 191328653Shselasky if (filename == NULL) 192328653Shselasky OPENSSL_free(file); 193328653Shselasky NCONF_free(conf); 194328653Shselasky 195328653Shselasky return ret; 196328653Shselasky} 197328653Shselasky 198328653Shselaskystatic int module_run(const CONF *cnf, char *name, char *value, 199328653Shselasky unsigned long flags) 200328653Shselasky{ 201328653Shselasky CONF_MODULE *md; 202328653Shselasky int ret; 203328653Shselasky 204328653Shselasky md = module_find(name); 205328653Shselasky 206297459Snp /* Module not found: try to load DSO */ 207328653Shselasky if (!md && !(flags & CONF_MFLAGS_NO_DSO)) 208328653Shselasky md = module_load_dso(cnf, name, value, flags); 209328653Shselasky 210328653Shselasky if (!md) { 211297459Snp if (!(flags & CONF_MFLAGS_SILENT)) { 212297459Snp CONFerr(CONF_F_MODULE_RUN, CONF_R_UNKNOWN_MODULE_NAME); 213297459Snp ERR_add_error_data(2, "module=", name); 214328653Shselasky } 215330862Shselasky return -1; 216328653Shselasky } 217328653Shselasky 218328653Shselasky ret = module_init(md, name, value, cnf); 219328653Shselasky 220328653Shselasky if (ret <= 0) { 221297459Snp if (!(flags & CONF_MFLAGS_SILENT)) { 222330862Shselasky char rcode[DECIMAL_SIZE(ret) + 1]; 223330862Shselasky CONFerr(CONF_F_MODULE_RUN, CONF_R_MODULE_INITIALIZATION_ERROR); 224330862Shselasky BIO_snprintf(rcode, sizeof rcode, "%-8d", ret); 225330862Shselasky ERR_add_error_data(6, "module=", name, ", value=", value, 226330862Shselasky ", retcode=", rcode); 227330862Shselasky } 228330862Shselasky } 229330862Shselasky 230328653Shselasky return ret; 231328653Shselasky} 232289564Shselasky 233328653Shselasky/* Load a module from a DSO */ 234289564Shselaskystatic CONF_MODULE *module_load_dso(const CONF *cnf, char *name, char *value, 235219820Sjeff unsigned long flags) 236328653Shselasky{ 237328653Shselasky DSO *dso = NULL; 238328653Shselasky conf_init_func *ifunc; 239289564Shselasky conf_finish_func *ffunc; 240328653Shselasky char *path = NULL; 241328653Shselasky int errcode = 0; 242328653Shselasky CONF_MODULE *md; 243328653Shselasky /* Look for alternative path in module section */ 244328653Shselasky path = NCONF_get_string(cnf, value, "path"); 245289564Shselasky if (!path) { 246328653Shselasky ERR_clear_error(); 247289564Shselasky path = name; 248328653Shselasky } 249289564Shselasky dso = DSO_load(NULL, path, NULL, 0); 250289564Shselasky if (!dso) { 251289564Shselasky errcode = CONF_R_ERROR_LOADING_DSO; 252328653Shselasky goto err; 253289564Shselasky } 254328653Shselasky ifunc = (conf_init_func *)DSO_bind_func(dso, DSO_mod_init_name); 255289564Shselasky if (!ifunc) { 256289564Shselasky errcode = CONF_R_MISSING_INIT_FUNCTION; 257328653Shselasky goto err; 258328653Shselasky } 259328653Shselasky ffunc = (conf_finish_func *)DSO_bind_func(dso, DSO_mod_finish_name); 260328653Shselasky /* All OK, add module */ 261328653Shselasky md = module_add(dso, name, ifunc, ffunc); 262328653Shselasky 263328653Shselasky if (!md) 264328653Shselasky goto err; 265328653Shselasky 266328653Shselasky return md; 267328653Shselasky 268328653Shselasky err: 269328653Shselasky if (dso) 270328653Shselasky DSO_free(dso); 271328653Shselasky CONFerr(CONF_F_MODULE_LOAD_DSO, errcode); 272328653Shselasky ERR_add_error_data(4, "module=", name, ", path=", path); 273328653Shselasky return NULL; 274328653Shselasky} 275328653Shselasky 276328653Shselasky/* add module to list */ 277328653Shselaskystatic CONF_MODULE *module_add(DSO *dso, const char *name, 278328653Shselasky conf_init_func *ifunc, conf_finish_func *ffunc) 279328653Shselasky{ 280328653Shselasky CONF_MODULE *tmod = NULL; 281328653Shselasky if (supported_modules == NULL) 282330847Shselasky supported_modules = sk_CONF_MODULE_new_null(); 283330847Shselasky if (supported_modules == NULL) 284328653Shselasky return NULL; 285328653Shselasky tmod = OPENSSL_malloc(sizeof(CONF_MODULE)); 286328653Shselasky if (tmod == NULL) 287328653Shselasky return NULL; 288328653Shselasky 289328653Shselasky tmod->dso = dso; 290328653Shselasky tmod->name = BUF_strdup(name); 291328653Shselasky tmod->init = ifunc; 292328653Shselasky tmod->finish = ffunc; 293328653Shselasky tmod->links = 0; 294328653Shselasky 295328653Shselasky if (!sk_CONF_MODULE_push(supported_modules, tmod)) { 296328653Shselasky OPENSSL_free(tmod); 297328653Shselasky return NULL; 298328653Shselasky } 299328653Shselasky 300328653Shselasky return tmod; 301328653Shselasky} 302 303/* 304 * Find a module from the list. We allow module names of the form 305 * modname.XXXX to just search for modname to allow the same module to be 306 * initialized more than once. 307 */ 308 309static CONF_MODULE *module_find(char *name) 310{ 311 CONF_MODULE *tmod; 312 int i, nchar; 313 char *p; 314 p = strrchr(name, '.'); 315 316 if (p) 317 nchar = p - name; 318 else 319 nchar = strlen(name); 320 321 for (i = 0; i < sk_CONF_MODULE_num(supported_modules); i++) { 322 tmod = sk_CONF_MODULE_value(supported_modules, i); 323 if (!strncmp(tmod->name, name, nchar)) 324 return tmod; 325 } 326 327 return NULL; 328 329} 330 331/* initialize a module */ 332static int module_init(CONF_MODULE *pmod, char *name, char *value, 333 const CONF *cnf) 334{ 335 int ret = 1; 336 int init_called = 0; 337 CONF_IMODULE *imod = NULL; 338 339 /* Otherwise add initialized module to list */ 340 imod = OPENSSL_malloc(sizeof(CONF_IMODULE)); 341 if (!imod) 342 goto err; 343 344 imod->pmod = pmod; 345 imod->name = BUF_strdup(name); 346 imod->value = BUF_strdup(value); 347 imod->usr_data = NULL; 348 349 if (!imod->name || !imod->value) 350 goto memerr; 351 352 /* Try to initialize module */ 353 if (pmod->init) { 354 ret = pmod->init(imod, cnf); 355 init_called = 1; 356 /* Error occurred, exit */ 357 if (ret <= 0) 358 goto err; 359 } 360 361 if (initialized_modules == NULL) { 362 initialized_modules = sk_CONF_IMODULE_new_null(); 363 if (!initialized_modules) { 364 CONFerr(CONF_F_MODULE_INIT, ERR_R_MALLOC_FAILURE); 365 goto err; 366 } 367 } 368 369 if (!sk_CONF_IMODULE_push(initialized_modules, imod)) { 370 CONFerr(CONF_F_MODULE_INIT, ERR_R_MALLOC_FAILURE); 371 goto err; 372 } 373 374 pmod->links++; 375 376 return ret; 377 378 err: 379 380 /* We've started the module so we'd better finish it */ 381 if (pmod->finish && init_called) 382 pmod->finish(imod); 383 384 memerr: 385 if (imod) { 386 if (imod->name) 387 OPENSSL_free(imod->name); 388 if (imod->value) 389 OPENSSL_free(imod->value); 390 OPENSSL_free(imod); 391 } 392 393 return -1; 394 395} 396 397/* 398 * Unload any dynamic modules that have a link count of zero: i.e. have no 399 * active initialized modules. If 'all' is set then all modules are unloaded 400 * including static ones. 401 */ 402 403void CONF_modules_unload(int all) 404{ 405 int i; 406 CONF_MODULE *md; 407 CONF_modules_finish(); 408 /* unload modules in reverse order */ 409 for (i = sk_CONF_MODULE_num(supported_modules) - 1; i >= 0; i--) { 410 md = sk_CONF_MODULE_value(supported_modules, i); 411 /* If static or in use and 'all' not set ignore it */ 412 if (((md->links > 0) || !md->dso) && !all) 413 continue; 414 /* Since we're working in reverse this is OK */ 415 (void)sk_CONF_MODULE_delete(supported_modules, i); 416 module_free(md); 417 } 418 if (sk_CONF_MODULE_num(supported_modules) == 0) { 419 sk_CONF_MODULE_free(supported_modules); 420 supported_modules = NULL; 421 } 422} 423 424/* unload a single module */ 425static void module_free(CONF_MODULE *md) 426{ 427 if (md->dso) 428 DSO_free(md->dso); 429 OPENSSL_free(md->name); 430 OPENSSL_free(md); 431} 432 433/* finish and free up all modules instances */ 434 435void CONF_modules_finish(void) 436{ 437 CONF_IMODULE *imod; 438 while (sk_CONF_IMODULE_num(initialized_modules) > 0) { 439 imod = sk_CONF_IMODULE_pop(initialized_modules); 440 module_finish(imod); 441 } 442 sk_CONF_IMODULE_free(initialized_modules); 443 initialized_modules = NULL; 444} 445 446/* finish a module instance */ 447 448static void module_finish(CONF_IMODULE *imod) 449{ 450 if (imod->pmod->finish) 451 imod->pmod->finish(imod); 452 imod->pmod->links--; 453 OPENSSL_free(imod->name); 454 OPENSSL_free(imod->value); 455 OPENSSL_free(imod); 456} 457 458/* Add a static module to OpenSSL */ 459 460int CONF_module_add(const char *name, conf_init_func *ifunc, 461 conf_finish_func *ffunc) 462{ 463 if (module_add(NULL, name, ifunc, ffunc)) 464 return 1; 465 else 466 return 0; 467} 468 469void CONF_modules_free(void) 470{ 471 CONF_modules_finish(); 472 CONF_modules_unload(1); 473} 474 475/* Utility functions */ 476 477const char *CONF_imodule_get_name(const CONF_IMODULE *md) 478{ 479 return md->name; 480} 481 482const char *CONF_imodule_get_value(const CONF_IMODULE *md) 483{ 484 return md->value; 485} 486 487void *CONF_imodule_get_usr_data(const CONF_IMODULE *md) 488{ 489 return md->usr_data; 490} 491 492void CONF_imodule_set_usr_data(CONF_IMODULE *md, void *usr_data) 493{ 494 md->usr_data = usr_data; 495} 496 497CONF_MODULE *CONF_imodule_get_module(const CONF_IMODULE *md) 498{ 499 return md->pmod; 500} 501 502unsigned long CONF_imodule_get_flags(const CONF_IMODULE *md) 503{ 504 return md->flags; 505} 506 507void CONF_imodule_set_flags(CONF_IMODULE *md, unsigned long flags) 508{ 509 md->flags = flags; 510} 511 512void *CONF_module_get_usr_data(CONF_MODULE *pmod) 513{ 514 return pmod->usr_data; 515} 516 517void CONF_module_set_usr_data(CONF_MODULE *pmod, void *usr_data) 518{ 519 pmod->usr_data = usr_data; 520} 521 522/* Return default config file name */ 523 524char *CONF_get1_default_config_file(void) 525{ 526 char *file; 527 int len; 528 529 file = getenv("OPENSSL_CONF"); 530 if (file) 531 return BUF_strdup(file); 532 533 len = strlen(X509_get_default_cert_area()); 534#ifndef OPENSSL_SYS_VMS 535 len++; 536#endif 537 len += strlen(OPENSSL_CONF); 538 539 file = OPENSSL_malloc(len + 1); 540 541 if (!file) 542 return NULL; 543 BUF_strlcpy(file, X509_get_default_cert_area(), len + 1); 544#ifndef OPENSSL_SYS_VMS 545 BUF_strlcat(file, "/", len + 1); 546#endif 547 BUF_strlcat(file, OPENSSL_CONF, len + 1); 548 549 return file; 550} 551 552/* 553 * This function takes a list separated by 'sep' and calls the callback 554 * function giving the start and length of each member optionally stripping 555 * leading and trailing whitespace. This can be used to parse comma separated 556 * lists for example. 557 */ 558 559int CONF_parse_list(const char *list_, int sep, int nospc, 560 int (*list_cb) (const char *elem, int len, void *usr), 561 void *arg) 562{ 563 int ret; 564 const char *lstart, *tmpend, *p; 565 566 if (list_ == NULL) { 567 CONFerr(CONF_F_CONF_PARSE_LIST, CONF_R_LIST_CANNOT_BE_NULL); 568 return 0; 569 } 570 571 lstart = list_; 572 for (;;) { 573 if (nospc) { 574 while (*lstart && isspace((unsigned char)*lstart)) 575 lstart++; 576 } 577 p = strchr(lstart, sep); 578 if (p == lstart || !*lstart) 579 ret = list_cb(NULL, 0, arg); 580 else { 581 if (p) 582 tmpend = p - 1; 583 else 584 tmpend = lstart + strlen(lstart) - 1; 585 if (nospc) { 586 while (isspace((unsigned char)*tmpend)) 587 tmpend--; 588 } 589 ret = list_cb(lstart, tmpend - lstart + 1, arg); 590 } 591 if (ret <= 0) 592 return ret; 593 if (p == NULL) 594 return 1; 595 lstart = p + 1; 596 } 597} 598