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