1/* crypto/conf/conf.c */ 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay@cryptsoft.com). 7 * The implementation was written so as to conform with Netscapes SSL. 8 * 9 * This library is free for commercial and non-commercial use as long as 10 * the following conditions are aheared to. The following conditions 11 * apply to all code found in this distribution, be it the RC4, RSA, 12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 * included with this distribution is covered by the same copyright terms 14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15 * 16 * Copyright remains Eric Young's, and as such any Copyright notices in 17 * the code are not to be removed. 18 * If this package is used in a product, Eric Young should be given attribution 19 * as the author of the parts of the library used. 20 * This can be in the form of a textual message at program startup or 21 * in documentation (online or textual) provided with the package. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * "This product includes cryptographic software written by 34 * Eric Young (eay@cryptsoft.com)" 35 * The word 'cryptographic' can be left out if the rouines from the library 36 * being used are not cryptographic related :-). 37 * 4. If you include any Windows specific code (or a derivative thereof) from 38 * the apps directory (application code) you must include an acknowledgement: 39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * The licence and distribution terms for any publically available version or 54 * derivative of this code cannot be changed. i.e. this code cannot simply be 55 * copied and put under another distribution licence 56 * [including the GNU Public Licence.] 57 */ 58 59/* Part of the code in here was originally in conf.c, which is now removed */ 60 61#include <stdio.h> 62#include <string.h> 63#include "cryptlib.h" 64#include <openssl/stack.h> 65#include <openssl/lhash.h> 66#include <openssl/conf.h> 67#include <openssl/conf_api.h> 68#include "conf_def.h" 69#include <openssl/buffer.h> 70#include <openssl/err.h> 71 72/* 73 * The maximum length we can grow a value to after variable expansion. 64k 74 * should be more than enough for all reasonable uses. 75 */ 76#define MAX_CONF_VALUE_LENGTH 65536 77 78static char *eat_ws(CONF *conf, char *p); 79static char *eat_alpha_numeric(CONF *conf, char *p); 80static void clear_comments(CONF *conf, char *p); 81static int str_copy(CONF *conf, char *section, char **to, char *from); 82static char *scan_quote(CONF *conf, char *p); 83static char *scan_dquote(CONF *conf, char *p); 84#define scan_esc(conf,p) (((IS_EOF((conf),(p)[1]))?((p)+1):((p)+2))) 85 86static CONF *def_create(CONF_METHOD *meth); 87static int def_init_default(CONF *conf); 88static int def_init_WIN32(CONF *conf); 89static int def_destroy(CONF *conf); 90static int def_destroy_data(CONF *conf); 91static int def_load(CONF *conf, const char *name, long *eline); 92static int def_load_bio(CONF *conf, BIO *bp, long *eline); 93static int def_dump(const CONF *conf, BIO *bp); 94static int def_is_number(const CONF *conf, char c); 95static int def_to_int(const CONF *conf, char c); 96 97const char CONF_def_version[] = "CONF_def" OPENSSL_VERSION_PTEXT; 98 99static CONF_METHOD default_method = { 100 "OpenSSL default", 101 def_create, 102 def_init_default, 103 def_destroy, 104 def_destroy_data, 105 def_load_bio, 106 def_dump, 107 def_is_number, 108 def_to_int, 109 def_load 110}; 111 112static CONF_METHOD WIN32_method = { 113 "WIN32", 114 def_create, 115 def_init_WIN32, 116 def_destroy, 117 def_destroy_data, 118 def_load_bio, 119 def_dump, 120 def_is_number, 121 def_to_int, 122 def_load 123}; 124 125CONF_METHOD *NCONF_default() 126{ 127 return &default_method; 128} 129 130CONF_METHOD *NCONF_WIN32() 131{ 132 return &WIN32_method; 133} 134 135static CONF *def_create(CONF_METHOD *meth) 136{ 137 CONF *ret; 138 139 ret = OPENSSL_malloc(sizeof(CONF) + sizeof(unsigned short *)); 140 if (ret) 141 if (meth->init(ret) == 0) { 142 OPENSSL_free(ret); 143 ret = NULL; 144 } 145 return ret; 146} 147 148static int def_init_default(CONF *conf) 149{ 150 if (conf == NULL) 151 return 0; 152 153 conf->meth = &default_method; 154 conf->meth_data = CONF_type_default; 155 conf->data = NULL; 156 157 return 1; 158} 159 160static int def_init_WIN32(CONF *conf) 161{ 162 if (conf == NULL) 163 return 0; 164 165 conf->meth = &WIN32_method; 166 conf->meth_data = (void *)CONF_type_win32; 167 conf->data = NULL; 168 169 return 1; 170} 171 172static int def_destroy(CONF *conf) 173{ 174 if (def_destroy_data(conf)) { 175 OPENSSL_free(conf); 176 return 1; 177 } 178 return 0; 179} 180 181static int def_destroy_data(CONF *conf) 182{ 183 if (conf == NULL) 184 return 0; 185 _CONF_free_data(conf); 186 return 1; 187} 188 189static int def_load(CONF *conf, const char *name, long *line) 190{ 191 int ret; 192 BIO *in = NULL; 193 194#ifdef OPENSSL_SYS_VMS 195 in = BIO_new_file(name, "r"); 196#else 197 in = BIO_new_file(name, "rb"); 198#endif 199 if (in == NULL) { 200 if (ERR_GET_REASON(ERR_peek_last_error()) == BIO_R_NO_SUCH_FILE) 201 CONFerr(CONF_F_DEF_LOAD, CONF_R_NO_SUCH_FILE); 202 else 203 CONFerr(CONF_F_DEF_LOAD, ERR_R_SYS_LIB); 204 return 0; 205 } 206 207 ret = def_load_bio(conf, in, line); 208 BIO_free(in); 209 210 return ret; 211} 212 213static int def_load_bio(CONF *conf, BIO *in, long *line) 214{ 215/* The macro BUFSIZE conflicts with a system macro in VxWorks */ 216#define CONFBUFSIZE 512 217 int bufnum = 0, i, ii; 218 BUF_MEM *buff = NULL; 219 char *s, *p, *end; 220 int again; 221 long eline = 0; 222 char btmp[DECIMAL_SIZE(eline) + 1]; 223 CONF_VALUE *v = NULL, *tv; 224 CONF_VALUE *sv = NULL; 225 char *section = NULL, *buf; 226 char *start, *psection, *pname; 227 void *h = (void *)(conf->data); 228 229 if ((buff = BUF_MEM_new()) == NULL) { 230 CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_BUF_LIB); 231 goto err; 232 } 233 234 section = BUF_strdup("default"); 235 if (section == NULL) { 236 CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); 237 goto err; 238 } 239 240 if (_CONF_new_data(conf) == 0) { 241 CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); 242 goto err; 243 } 244 245 sv = _CONF_new_section(conf, section); 246 if (sv == NULL) { 247 CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_UNABLE_TO_CREATE_NEW_SECTION); 248 goto err; 249 } 250 251 bufnum = 0; 252 again = 0; 253 for (;;) { 254 if (!BUF_MEM_grow(buff, bufnum + CONFBUFSIZE)) { 255 CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_BUF_LIB); 256 goto err; 257 } 258 p = &(buff->data[bufnum]); 259 *p = '\0'; 260 BIO_gets(in, p, CONFBUFSIZE - 1); 261 p[CONFBUFSIZE - 1] = '\0'; 262 ii = i = strlen(p); 263 if (i == 0 && !again) 264 break; 265 again = 0; 266 while (i > 0) { 267 if ((p[i - 1] != '\r') && (p[i - 1] != '\n')) 268 break; 269 else 270 i--; 271 } 272 /* 273 * we removed some trailing stuff so there is a new line on the end. 274 */ 275 if (ii && i == ii) 276 again = 1; /* long line */ 277 else { 278 p[i] = '\0'; 279 eline++; /* another input line */ 280 } 281 282 /* we now have a line with trailing \r\n removed */ 283 284 /* i is the number of bytes */ 285 bufnum += i; 286 287 v = NULL; 288 /* check for line continuation */ 289 if (bufnum >= 1) { 290 /* 291 * If we have bytes and the last char '\\' and second last char 292 * is not '\\' 293 */ 294 p = &(buff->data[bufnum - 1]); 295 if (IS_ESC(conf, p[0]) && ((bufnum <= 1) || !IS_ESC(conf, p[-1]))) { 296 bufnum--; 297 again = 1; 298 } 299 } 300 if (again) 301 continue; 302 bufnum = 0; 303 buf = buff->data; 304 305 clear_comments(conf, buf); 306 s = eat_ws(conf, buf); 307 if (IS_EOF(conf, *s)) 308 continue; /* blank line */ 309 if (*s == '[') { 310 char *ss; 311 312 s++; 313 start = eat_ws(conf, s); 314 ss = start; 315 again: 316 end = eat_alpha_numeric(conf, ss); 317 p = eat_ws(conf, end); 318 if (*p != ']') { 319 if (*p != '\0' && ss != p) { 320 ss = p; 321 goto again; 322 } 323 CONFerr(CONF_F_DEF_LOAD_BIO, 324 CONF_R_MISSING_CLOSE_SQUARE_BRACKET); 325 goto err; 326 } 327 *end = '\0'; 328 if (!str_copy(conf, NULL, §ion, start)) 329 goto err; 330 if ((sv = _CONF_get_section(conf, section)) == NULL) 331 sv = _CONF_new_section(conf, section); 332 if (sv == NULL) { 333 CONFerr(CONF_F_DEF_LOAD_BIO, 334 CONF_R_UNABLE_TO_CREATE_NEW_SECTION); 335 goto err; 336 } 337 continue; 338 } else { 339 pname = s; 340 psection = NULL; 341 end = eat_alpha_numeric(conf, s); 342 if ((end[0] == ':') && (end[1] == ':')) { 343 *end = '\0'; 344 end += 2; 345 psection = pname; 346 pname = end; 347 end = eat_alpha_numeric(conf, end); 348 } 349 p = eat_ws(conf, end); 350 if (*p != '=') { 351 CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_MISSING_EQUAL_SIGN); 352 goto err; 353 } 354 *end = '\0'; 355 p++; 356 start = eat_ws(conf, p); 357 while (!IS_EOF(conf, *p)) 358 p++; 359 p--; 360 while ((p != start) && (IS_WS(conf, *p))) 361 p--; 362 p++; 363 *p = '\0'; 364 365 if (!(v = (CONF_VALUE *)OPENSSL_malloc(sizeof(CONF_VALUE)))) { 366 CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); 367 goto err; 368 } 369 if (psection == NULL) 370 psection = section; 371 v->name = (char *)OPENSSL_malloc(strlen(pname) + 1); 372 v->value = NULL; 373 if (v->name == NULL) { 374 CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); 375 goto err; 376 } 377 BUF_strlcpy(v->name, pname, strlen(pname) + 1); 378 if (!str_copy(conf, psection, &(v->value), start)) 379 goto err; 380 381 if (strcmp(psection, section) != 0) { 382 if ((tv = _CONF_get_section(conf, psection)) 383 == NULL) 384 tv = _CONF_new_section(conf, psection); 385 if (tv == NULL) { 386 CONFerr(CONF_F_DEF_LOAD_BIO, 387 CONF_R_UNABLE_TO_CREATE_NEW_SECTION); 388 goto err; 389 } 390 } else 391 tv = sv; 392#if 1 393 if (_CONF_add_string(conf, tv, v) == 0) { 394 CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); 395 goto err; 396 } 397#else 398 v->section = tv->section; 399 if (!sk_CONF_VALUE_push(ts, v)) { 400 CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); 401 goto err; 402 } 403 vv = (CONF_VALUE *)lh_insert(conf->data, v); 404 if (vv != NULL) { 405 sk_CONF_VALUE_delete_ptr(ts, vv); 406 OPENSSL_free(vv->name); 407 OPENSSL_free(vv->value); 408 OPENSSL_free(vv); 409 } 410#endif 411 v = NULL; 412 } 413 } 414 if (buff != NULL) 415 BUF_MEM_free(buff); 416 if (section != NULL) 417 OPENSSL_free(section); 418 return (1); 419 err: 420 if (buff != NULL) 421 BUF_MEM_free(buff); 422 if (section != NULL) 423 OPENSSL_free(section); 424 if (line != NULL) 425 *line = eline; 426 BIO_snprintf(btmp, sizeof(btmp), "%ld", eline); 427 ERR_add_error_data(2, "line ", btmp); 428 if ((h != conf->data) && (conf->data != NULL)) { 429 CONF_free(conf->data); 430 conf->data = NULL; 431 } 432 if (v != NULL) { 433 if (v->name != NULL) 434 OPENSSL_free(v->name); 435 if (v->value != NULL) 436 OPENSSL_free(v->value); 437 if (v != NULL) 438 OPENSSL_free(v); 439 } 440 return (0); 441} 442 443static void clear_comments(CONF *conf, char *p) 444{ 445 for (;;) { 446 if (IS_FCOMMENT(conf, *p)) { 447 *p = '\0'; 448 return; 449 } 450 if (!IS_WS(conf, *p)) { 451 break; 452 } 453 p++; 454 } 455 456 for (;;) { 457 if (IS_COMMENT(conf, *p)) { 458 *p = '\0'; 459 return; 460 } 461 if (IS_DQUOTE(conf, *p)) { 462 p = scan_dquote(conf, p); 463 continue; 464 } 465 if (IS_QUOTE(conf, *p)) { 466 p = scan_quote(conf, p); 467 continue; 468 } 469 if (IS_ESC(conf, *p)) { 470 p = scan_esc(conf, p); 471 continue; 472 } 473 if (IS_EOF(conf, *p)) 474 return; 475 else 476 p++; 477 } 478} 479 480static int str_copy(CONF *conf, char *section, char **pto, char *from) 481{ 482 int q, r, rr = 0, to = 0, len = 0; 483 char *s, *e, *rp, *p, *rrp, *np, *cp, v; 484 BUF_MEM *buf; 485 486 if ((buf = BUF_MEM_new()) == NULL) 487 return (0); 488 489 len = strlen(from) + 1; 490 if (!BUF_MEM_grow(buf, len)) 491 goto err; 492 493 for (;;) { 494 if (IS_QUOTE(conf, *from)) { 495 q = *from; 496 from++; 497 while (!IS_EOF(conf, *from) && (*from != q)) { 498 if (IS_ESC(conf, *from)) { 499 from++; 500 if (IS_EOF(conf, *from)) 501 break; 502 } 503 buf->data[to++] = *(from++); 504 } 505 if (*from == q) 506 from++; 507 } else if (IS_DQUOTE(conf, *from)) { 508 q = *from; 509 from++; 510 while (!IS_EOF(conf, *from)) { 511 if (*from == q) { 512 if (*(from + 1) == q) { 513 from++; 514 } else { 515 break; 516 } 517 } 518 buf->data[to++] = *(from++); 519 } 520 if (*from == q) 521 from++; 522 } else if (IS_ESC(conf, *from)) { 523 from++; 524 v = *(from++); 525 if (IS_EOF(conf, v)) 526 break; 527 else if (v == 'r') 528 v = '\r'; 529 else if (v == 'n') 530 v = '\n'; 531 else if (v == 'b') 532 v = '\b'; 533 else if (v == 't') 534 v = '\t'; 535 buf->data[to++] = v; 536 } else if (IS_EOF(conf, *from)) 537 break; 538 else if (*from == '$') { 539 size_t newsize; 540 541 /* try to expand it */ 542 rrp = NULL; 543 s = &(from[1]); 544 if (*s == '{') 545 q = '}'; 546 else if (*s == '(') 547 q = ')'; 548 else 549 q = 0; 550 551 if (q) 552 s++; 553 cp = section; 554 e = np = s; 555 while (IS_ALPHA_NUMERIC(conf, *e)) 556 e++; 557 if ((e[0] == ':') && (e[1] == ':')) { 558 cp = np; 559 rrp = e; 560 rr = *e; 561 *rrp = '\0'; 562 e += 2; 563 np = e; 564 while (IS_ALPHA_NUMERIC(conf, *e)) 565 e++; 566 } 567 r = *e; 568 *e = '\0'; 569 rp = e; 570 if (q) { 571 if (r != q) { 572 CONFerr(CONF_F_STR_COPY, CONF_R_NO_CLOSE_BRACE); 573 goto err; 574 } 575 e++; 576 } 577 /*- 578 * So at this point we have 579 * np which is the start of the name string which is 580 * '\0' terminated. 581 * cp which is the start of the section string which is 582 * '\0' terminated. 583 * e is the 'next point after'. 584 * r and rr are the chars replaced by the '\0' 585 * rp and rrp is where 'r' and 'rr' came from. 586 */ 587 p = _CONF_get_string(conf, cp, np); 588 if (rrp != NULL) 589 *rrp = rr; 590 *rp = r; 591 if (p == NULL) { 592 CONFerr(CONF_F_STR_COPY, CONF_R_VARIABLE_HAS_NO_VALUE); 593 goto err; 594 } 595 newsize = strlen(p) + buf->length - (e - from); 596 if (newsize > MAX_CONF_VALUE_LENGTH) { 597 CONFerr(CONF_F_STR_COPY, CONF_R_VARIABLE_EXPANSION_TOO_LONG); 598 goto err; 599 } 600 if (!BUF_MEM_grow_clean(buf, newsize)) { 601 CONFerr(CONF_F_STR_COPY, ERR_R_MALLOC_FAILURE); 602 goto err; 603 } 604 while (*p) 605 buf->data[to++] = *(p++); 606 607 /* 608 * Since we change the pointer 'from', we also have to change the 609 * perceived length of the string it points at. /RL 610 */ 611 len -= e - from; 612 from = e; 613 614 /* 615 * In case there were no braces or parenthesis around the 616 * variable reference, we have to put back the character that was 617 * replaced with a '\0'. /RL 618 */ 619 *rp = r; 620 } else 621 buf->data[to++] = *(from++); 622 } 623 buf->data[to] = '\0'; 624 if (*pto != NULL) 625 OPENSSL_free(*pto); 626 *pto = buf->data; 627 OPENSSL_free(buf); 628 return (1); 629 err: 630 if (buf != NULL) 631 BUF_MEM_free(buf); 632 return (0); 633} 634 635static char *eat_ws(CONF *conf, char *p) 636{ 637 while (IS_WS(conf, *p) && (!IS_EOF(conf, *p))) 638 p++; 639 return (p); 640} 641 642static char *eat_alpha_numeric(CONF *conf, char *p) 643{ 644 for (;;) { 645 if (IS_ESC(conf, *p)) { 646 p = scan_esc(conf, p); 647 continue; 648 } 649 if (!IS_ALPHA_NUMERIC_PUNCT(conf, *p)) 650 return (p); 651 p++; 652 } 653} 654 655static char *scan_quote(CONF *conf, char *p) 656{ 657 int q = *p; 658 659 p++; 660 while (!(IS_EOF(conf, *p)) && (*p != q)) { 661 if (IS_ESC(conf, *p)) { 662 p++; 663 if (IS_EOF(conf, *p)) 664 return (p); 665 } 666 p++; 667 } 668 if (*p == q) 669 p++; 670 return (p); 671} 672 673static char *scan_dquote(CONF *conf, char *p) 674{ 675 int q = *p; 676 677 p++; 678 while (!(IS_EOF(conf, *p))) { 679 if (*p == q) { 680 if (*(p + 1) == q) { 681 p++; 682 } else { 683 break; 684 } 685 } 686 p++; 687 } 688 if (*p == q) 689 p++; 690 return (p); 691} 692 693static void dump_value_doall_arg(CONF_VALUE *a, BIO *out) 694{ 695 if (a->name) 696 BIO_printf(out, "[%s] %s=%s\n", a->section, a->name, a->value); 697 else 698 BIO_printf(out, "[[%s]]\n", a->section); 699} 700 701static IMPLEMENT_LHASH_DOALL_ARG_FN(dump_value, CONF_VALUE, BIO) 702 703static int def_dump(const CONF *conf, BIO *out) 704{ 705 lh_CONF_VALUE_doall_arg(conf->data, LHASH_DOALL_ARG_FN(dump_value), 706 BIO, out); 707 return 1; 708} 709 710static int def_is_number(const CONF *conf, char c) 711{ 712 return IS_NUMBER(conf, c); 713} 714 715static int def_to_int(const CONF *conf, char c) 716{ 717 return c - '0'; 718} 719