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