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 #include "internal.h" 69 #include "../internal.h" 70 71 72 // The maximum length we can grow a value to after variable expansion. 64k 73 // should be more than enough for all reasonable uses. 74 #define MAX_CONF_VALUE_LENGTH 65536 75 76 static uint32_t conf_value_hash(const CONF_VALUE *v) { 77 return (lh_strhash(v->section) << 2) ^ lh_strhash(v->name); 78 } 79 80 static int conf_value_cmp(const CONF_VALUE *a, const CONF_VALUE *b) { 81 int i; 82 83 if (a->section != b->section) { 84 i = strcmp(a->section, b->section); 85 if (i) { 86 return i; 87 } 88 } 89 90 if (a->name != NULL && b->name != NULL) { 91 return strcmp(a->name, b->name); 92 } else if (a->name == b->name) { 93 return 0; 94 } else { 95 return (a->name == NULL) ? -1 : 1; 96 } 97 } 98 99 CONF *NCONF_new(void *method) { 100 CONF *conf; 101 102 if (method != NULL) { 103 return NULL; 104 } 105 106 conf = OPENSSL_malloc(sizeof(CONF)); 107 if (conf == NULL) { 108 return NULL; 109 } 110 111 conf->data = lh_CONF_VALUE_new(conf_value_hash, conf_value_cmp); 112 if (conf->data == NULL) { 113 OPENSSL_free(conf); 114 return NULL; 115 } 116 117 return conf; 118 } 119 120 CONF_VALUE *CONF_VALUE_new(void) { 121 CONF_VALUE *v = OPENSSL_malloc(sizeof(CONF_VALUE)); 122 if (!v) { 123 OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE); 124 return NULL; 125 } 126 OPENSSL_memset(v, 0, sizeof(CONF_VALUE)); 127 return v; 128 } 129 130 static void value_free_contents(CONF_VALUE *value) { 131 if (value->section) { 132 OPENSSL_free(value->section); 133 } 134 if (value->name) { 135 OPENSSL_free(value->name); 136 if (value->value) { 137 OPENSSL_free(value->value); 138 } 139 } else { 140 if (value->value) { 141 sk_CONF_VALUE_free((STACK_OF(CONF_VALUE)*)value->value); 142 } 143 } 144 } 145 146 static void value_free(CONF_VALUE *value) { 147 value_free_contents(value); 148 OPENSSL_free(value); 149 } 150 151 void NCONF_free(CONF *conf) { 152 if (conf == NULL || conf->data == NULL) { 153 return; 154 } 155 156 lh_CONF_VALUE_doall(conf->data, value_free); 157 lh_CONF_VALUE_free(conf->data); 158 OPENSSL_free(conf); 159 } 160 161 static CONF_VALUE *NCONF_new_section(const CONF *conf, const char *section) { 162 STACK_OF(CONF_VALUE) *sk = NULL; 163 int ok = 0; 164 CONF_VALUE *v = NULL, *old_value; 165 166 sk = sk_CONF_VALUE_new_null(); 167 v = CONF_VALUE_new(); 168 if (sk == NULL || v == NULL) { 169 goto err; 170 } 171 v->section = OPENSSL_strdup(section); 172 if (v->section == NULL) { 173 goto err; 174 } 175 176 v->name = NULL; 177 v->value = (char *)sk; 178 179 if (!lh_CONF_VALUE_insert(conf->data, &old_value, v)) { 180 goto err; 181 } 182 if (old_value) { 183 value_free(old_value); 184 } 185 ok = 1; 186 187 err: 188 if (!ok) { 189 if (sk != NULL) { 190 sk_CONF_VALUE_free(sk); 191 } 192 if (v != NULL) { 193 OPENSSL_free(v); 194 } 195 v = NULL; 196 } 197 return v; 198 } 199 200 static int str_copy(CONF *conf, char *section, char **pto, char *from) { 201 int q, r, rr = 0, to = 0, len = 0; 202 char *s, *e, *rp, *rrp, *np, *cp, v; 203 const char *p; 204 BUF_MEM *buf; 205 206 buf = BUF_MEM_new(); 207 if (buf == NULL) { 208 return 0; 209 } 210 211 len = strlen(from) + 1; 212 if (!BUF_MEM_grow(buf, len)) { 213 goto err; 214 } 215 216 for (;;) { 217 if (IS_QUOTE(conf, *from)) { 218 q = *from; 219 from++; 220 while (!IS_EOF(conf, *from) && (*from != q)) { 221 if (IS_ESC(conf, *from)) { 222 from++; 223 if (IS_EOF(conf, *from)) { 224 break; 225 } 226 } 227 buf->data[to++] = *(from++); 228 } 229 if (*from == q) { 230 from++; 231 } 232 } else if (IS_DQUOTE(conf, *from)) { 233 q = *from; 234 from++; 235 while (!IS_EOF(conf, *from)) { 236 if (*from == q) { 237 if (*(from + 1) == q) { 238 from++; 239 } else { 240 break; 241 } 242 } 243 buf->data[to++] = *(from++); 244 } 245 if (*from == q) { 246 from++; 247 } 248 } else if (IS_ESC(conf, *from)) { 249 from++; 250 v = *(from++); 251 if (IS_EOF(conf, v)) { 252 break; 253 } else if (v == 'r') { 254 v = '\r'; 255 } else if (v == 'n') { 256 v = '\n'; 257 } else if (v == 'b') { 258 v = '\b'; 259 } else if (v == 't') { 260 v = '\t'; 261 } 262 buf->data[to++] = v; 263 } else if (IS_EOF(conf, *from)) { 264 break; 265 } else if (*from == '$') { 266 // try to expand it 267 rrp = NULL; 268 s = &(from[1]); 269 if (*s == '{') { 270 q = '}'; 271 } else if (*s == '(') { 272 q = ')'; 273 } else { 274 q = 0; 275 } 276 277 if (q) { 278 s++; 279 } 280 cp = section; 281 e = np = s; 282 while (IS_ALPHA_NUMERIC(conf, *e)) { 283 e++; 284 } 285 if (e[0] == ':' && e[1] == ':') { 286 cp = np; 287 rrp = e; 288 rr = *e; 289 *rrp = '\0'; 290 e += 2; 291 np = e; 292 while (IS_ALPHA_NUMERIC(conf, *e)) { 293 e++; 294 } 295 } 296 r = *e; 297 *e = '\0'; 298 rp = e; 299 if (q) { 300 if (r != q) { 301 OPENSSL_PUT_ERROR(CONF, CONF_R_NO_CLOSE_BRACE); 302 goto err; 303 } 304 e++; 305 } 306 // So at this point we have 307 // np which is the start of the name string which is 308 // '\0' terminated. 309 // cp which is the start of the section string which is 310 // '\0' terminated. 311 // e is the 'next point after'. 312 // r and rr are the chars replaced by the '\0' 313 // rp and rrp is where 'r' and 'rr' came from. 314 p = NCONF_get_string(conf, cp, np); 315 if (rrp != NULL) { 316 *rrp = rr; 317 } 318 *rp = r; 319 if (p == NULL) { 320 OPENSSL_PUT_ERROR(CONF, CONF_R_VARIABLE_HAS_NO_VALUE); 321 goto err; 322 } 323 size_t newsize = strlen(p) + buf->length - (e - from); 324 if (newsize > MAX_CONF_VALUE_LENGTH) { 325 OPENSSL_PUT_ERROR(CONF, CONF_R_VARIABLE_EXPANSION_TOO_LONG); 326 goto err; 327 } 328 if (!BUF_MEM_grow_clean(buf, newsize)) { 329 OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE); 330 goto err; 331 } 332 while (*p) { 333 buf->data[to++] = *(p++); 334 } 335 336 /* Since we change the pointer 'from', we also have 337 to change the perceived length of the string it 338 points at. /RL */ 339 len -= e - from; 340 from = e; 341 342 /* In case there were no braces or parenthesis around 343 the variable reference, we have to put back the 344 character that was replaced with a '\0'. /RL */ 345 *rp = r; 346 } else { 347 buf->data[to++] = *(from++); 348 } 349 } 350 351 buf->data[to] = '\0'; 352 if (*pto != NULL) { 353 OPENSSL_free(*pto); 354 } 355 *pto = buf->data; 356 OPENSSL_free(buf); 357 return 1; 358 359 err: 360 if (buf != NULL) { 361 BUF_MEM_free(buf); 362 } 363 return 0; 364 } 365 366 static CONF_VALUE *get_section(const CONF *conf, const char *section) { 367 CONF_VALUE template; 368 369 OPENSSL_memset(&template, 0, sizeof(template)); 370 template.section = (char *) section; 371 return lh_CONF_VALUE_retrieve(conf->data, &template); 372 } 373 374 STACK_OF(CONF_VALUE) *NCONF_get_section(const CONF *conf, const char *section) { 375 CONF_VALUE *section_value = get_section(conf, section); 376 if (section_value == NULL) { 377 return NULL; 378 } 379 return (STACK_OF(CONF_VALUE)*) section_value->value; 380 } 381 382 const char *NCONF_get_string(const CONF *conf, const char *section, 383 const char *name) { 384 CONF_VALUE template, *value; 385 386 OPENSSL_memset(&template, 0, sizeof(template)); 387 template.section = (char *) section; 388 template.name = (char *) name; 389 value = lh_CONF_VALUE_retrieve(conf->data, &template); 390 if (value == NULL) { 391 return NULL; 392 } 393 return value->value; 394 } 395 396 static int add_string(const CONF *conf, CONF_VALUE *section, 397 CONF_VALUE *value) { 398 STACK_OF(CONF_VALUE) *section_stack = (STACK_OF(CONF_VALUE)*) section->value; 399 CONF_VALUE *old_value; 400 401 value->section = OPENSSL_strdup(section->section); 402 if (!sk_CONF_VALUE_push(section_stack, value)) { 403 return 0; 404 } 405 406 if (!lh_CONF_VALUE_insert(conf->data, &old_value, value)) { 407 return 0; 408 } 409 if (old_value != NULL) { 410 (void)sk_CONF_VALUE_delete_ptr(section_stack, old_value); 411 value_free(old_value); 412 } 413 414 return 1; 415 } 416 417 static char *eat_ws(CONF *conf, char *p) { 418 while (IS_WS(conf, *p) && !IS_EOF(conf, *p)) { 419 p++; 420 } 421 return p; 422 } 423 424 #define scan_esc(conf, p) (((IS_EOF((conf), (p)[1])) ? ((p) + 1) : ((p) + 2))) 425 426 static char *eat_alpha_numeric(CONF *conf, char *p) { 427 for (;;) { 428 if (IS_ESC(conf, *p)) { 429 p = scan_esc(conf, p); 430 continue; 431 } 432 if (!IS_ALPHA_NUMERIC_PUNCT(conf, *p)) { 433 return p; 434 } 435 p++; 436 } 437 } 438 439 static char *scan_quote(CONF *conf, char *p) { 440 int q = *p; 441 442 p++; 443 while (!IS_EOF(conf, *p) && *p != q) { 444 if (IS_ESC(conf, *p)) { 445 p++; 446 if (IS_EOF(conf, *p)) { 447 return p; 448 } 449 } 450 p++; 451 } 452 if (*p == q) { 453 p++; 454 } 455 return p; 456 } 457 458 459 static char *scan_dquote(CONF *conf, char *p) { 460 int q = *p; 461 462 p++; 463 while (!(IS_EOF(conf, *p))) { 464 if (*p == q) { 465 if (*(p + 1) == q) { 466 p++; 467 } else { 468 break; 469 } 470 } 471 p++; 472 } 473 if (*p == q) { 474 p++; 475 } 476 return p; 477 } 478 479 static void clear_comments(CONF *conf, char *p) { 480 for (;;) { 481 if (IS_FCOMMENT(conf, *p)) { 482 *p = '\0'; 483 return; 484 } 485 if (!IS_WS(conf, *p)) { 486 break; 487 } 488 p++; 489 } 490 491 for (;;) { 492 if (IS_COMMENT(conf, *p)) { 493 *p = '\0'; 494 return; 495 } 496 if (IS_DQUOTE(conf, *p)) { 497 p = scan_dquote(conf, p); 498 continue; 499 } 500 if (IS_QUOTE(conf, *p)) { 501 p = scan_quote(conf, p); 502 continue; 503 } 504 if (IS_ESC(conf, *p)) { 505 p = scan_esc(conf, p); 506 continue; 507 } 508 if (IS_EOF(conf, *p)) { 509 return; 510 } else { 511 p++; 512 } 513 } 514 } 515 516 static int def_load_bio(CONF *conf, BIO *in, long *out_error_line) { 517 static const size_t CONFBUFSIZE = 512; 518 int bufnum = 0, i, ii; 519 BUF_MEM *buff = NULL; 520 char *s, *p, *end; 521 int again; 522 long eline = 0; 523 char btmp[DECIMAL_SIZE(eline) + 1]; 524 CONF_VALUE *v = NULL, *tv; 525 CONF_VALUE *sv = NULL; 526 char *section = NULL, *buf; 527 char *start, *psection, *pname; 528 529 if ((buff = BUF_MEM_new()) == NULL) { 530 OPENSSL_PUT_ERROR(CONF, ERR_R_BUF_LIB); 531 goto err; 532 } 533 534 section = OPENSSL_strdup("default"); 535 if (section == NULL) { 536 OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE); 537 goto err; 538 } 539 540 sv = NCONF_new_section(conf, section); 541 if (sv == NULL) { 542 OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION); 543 goto err; 544 } 545 546 bufnum = 0; 547 again = 0; 548 for (;;) { 549 if (!BUF_MEM_grow(buff, bufnum + CONFBUFSIZE)) { 550 OPENSSL_PUT_ERROR(CONF, ERR_R_BUF_LIB); 551 goto err; 552 } 553 p = &(buff->data[bufnum]); 554 *p = '\0'; 555 BIO_gets(in, p, CONFBUFSIZE - 1); 556 p[CONFBUFSIZE - 1] = '\0'; 557 ii = i = strlen(p); 558 if (i == 0 && !again) { 559 break; 560 } 561 again = 0; 562 while (i > 0) { 563 if ((p[i - 1] != '\r') && (p[i - 1] != '\n')) { 564 break; 565 } else { 566 i--; 567 } 568 } 569 // we removed some trailing stuff so there is a new 570 // line on the end. 571 if (ii && i == ii) { 572 again = 1; // long line 573 } else { 574 p[i] = '\0'; 575 eline++; // another input line 576 } 577 578 // we now have a line with trailing \r\n removed 579 580 // i is the number of bytes 581 bufnum += i; 582 583 v = NULL; 584 // check for line continuation 585 if (bufnum >= 1) { 586 // If we have bytes and the last char '\\' and 587 // second last char is not '\\' 588 p = &(buff->data[bufnum - 1]); 589 if (IS_ESC(conf, p[0]) && ((bufnum <= 1) || !IS_ESC(conf, p[-1]))) { 590 bufnum--; 591 again = 1; 592 } 593 } 594 if (again) { 595 continue; 596 } 597 bufnum = 0; 598 buf = buff->data; 599 600 clear_comments(conf, buf); 601 s = eat_ws(conf, buf); 602 if (IS_EOF(conf, *s)) { 603 continue; // blank line 604 } 605 if (*s == '[') { 606 char *ss; 607 608 s++; 609 start = eat_ws(conf, s); 610 ss = start; 611 again: 612 end = eat_alpha_numeric(conf, ss); 613 p = eat_ws(conf, end); 614 if (*p != ']') { 615 if (*p != '\0' && ss != p) { 616 ss = p; 617 goto again; 618 } 619 OPENSSL_PUT_ERROR(CONF, CONF_R_MISSING_CLOSE_SQUARE_BRACKET); 620 goto err; 621 } 622 *end = '\0'; 623 if (!str_copy(conf, NULL, §ion, start)) { 624 goto err; 625 } 626 if ((sv = get_section(conf, section)) == NULL) { 627 sv = NCONF_new_section(conf, section); 628 } 629 if (sv == NULL) { 630 OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION); 631 goto err; 632 } 633 continue; 634 } else { 635 pname = s; 636 psection = NULL; 637 end = eat_alpha_numeric(conf, s); 638 if ((end[0] == ':') && (end[1] == ':')) { 639 *end = '\0'; 640 end += 2; 641 psection = pname; 642 pname = end; 643 end = eat_alpha_numeric(conf, end); 644 } 645 p = eat_ws(conf, end); 646 if (*p != '=') { 647 OPENSSL_PUT_ERROR(CONF, CONF_R_MISSING_EQUAL_SIGN); 648 goto err; 649 } 650 *end = '\0'; 651 p++; 652 start = eat_ws(conf, p); 653 while (!IS_EOF(conf, *p)) { 654 p++; 655 } 656 p--; 657 while ((p != start) && (IS_WS(conf, *p))) { 658 p--; 659 } 660 p++; 661 *p = '\0'; 662 663 if (!(v = CONF_VALUE_new())) { 664 goto err; 665 } 666 if (psection == NULL) { 667 psection = section; 668 } 669 v->name = OPENSSL_strdup(pname); 670 if (v->name == NULL) { 671 OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE); 672 goto err; 673 } 674 if (!str_copy(conf, psection, &(v->value), start)) { 675 goto err; 676 } 677 678 if (strcmp(psection, section) != 0) { 679 if ((tv = get_section(conf, psection)) == NULL) { 680 tv = NCONF_new_section(conf, psection); 681 } 682 if (tv == NULL) { 683 OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION); 684 goto err; 685 } 686 } else { 687 tv = sv; 688 } 689 if (add_string(conf, tv, v) == 0) { 690 OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE); 691 goto err; 692 } 693 v = NULL; 694 } 695 } 696 if (buff != NULL) { 697 BUF_MEM_free(buff); 698 } 699 if (section != NULL) { 700 OPENSSL_free(section); 701 } 702 return 1; 703 704 err: 705 if (buff != NULL) { 706 BUF_MEM_free(buff); 707 } 708 if (section != NULL) { 709 OPENSSL_free(section); 710 } 711 if (out_error_line != NULL) { 712 *out_error_line = eline; 713 } 714 BIO_snprintf(btmp, sizeof btmp, "%ld", eline); 715 ERR_add_error_data(2, "line ", btmp); 716 717 if (v != NULL) { 718 if (v->name != NULL) { 719 OPENSSL_free(v->name); 720 } 721 if (v->value != NULL) { 722 OPENSSL_free(v->value); 723 } 724 if (v != NULL) { 725 OPENSSL_free(v); 726 } 727 } 728 return 0; 729 } 730 731 int NCONF_load(CONF *conf, const char *filename, long *out_error_line) { 732 BIO *in = BIO_new_file(filename, "rb"); 733 int ret; 734 735 if (in == NULL) { 736 OPENSSL_PUT_ERROR(CONF, ERR_R_SYS_LIB); 737 return 0; 738 } 739 740 ret = def_load_bio(conf, in, out_error_line); 741 BIO_free(in); 742 743 return ret; 744 } 745 746 int NCONF_load_bio(CONF *conf, BIO *bio, long *out_error_line) { 747 return def_load_bio(conf, bio, out_error_line); 748 } 749 750 int CONF_parse_list(const char *list, char sep, int remove_whitespace, 751 int (*list_cb)(const char *elem, int len, void *usr), 752 void *arg) { 753 int ret; 754 const char *lstart, *tmpend, *p; 755 756 if (list == NULL) { 757 OPENSSL_PUT_ERROR(CONF, CONF_R_LIST_CANNOT_BE_NULL); 758 return 0; 759 } 760 761 lstart = list; 762 for (;;) { 763 if (remove_whitespace) { 764 while (*lstart && isspace((unsigned char)*lstart)) { 765 lstart++; 766 } 767 } 768 p = strchr(lstart, sep); 769 if (p == lstart || !*lstart) { 770 ret = list_cb(NULL, 0, arg); 771 } else { 772 if (p) { 773 tmpend = p - 1; 774 } else { 775 tmpend = lstart + strlen(lstart) - 1; 776 } 777 if (remove_whitespace) { 778 while (isspace((unsigned char)*tmpend)) { 779 tmpend--; 780 } 781 } 782 ret = list_cb(lstart, tmpend - lstart + 1, arg); 783 } 784 if (ret <= 0) { 785 return ret; 786 } 787 if (p == NULL) { 788 return 1; 789 } 790 lstart = p + 1; 791 } 792 } 793 794 int CONF_modules_load_file(const char *filename, const char *appname, 795 unsigned long flags) { 796 return 1; 797 } 798 799 void CONF_modules_free(void) {} 800 801 void OPENSSL_config(const char *config_name) {} 802 803 void OPENSSL_no_config(void) {} 804