1 /* $OpenBSD: conf_def.c,v 1.44 2024/08/31 09:46:17 tb Exp $ */
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
64 #include <openssl/buffer.h>
65 #include <openssl/conf.h>
66 #include <openssl/err.h>
67 #include <openssl/lhash.h>
68 #include <openssl/stack.h>
69
70 #include "conf_def.h"
71 #include "conf_local.h"
72
73 #define MAX_CONF_VALUE_LENGTH 65536
74
75 static char *eat_ws(CONF *conf, char *p);
76 static char *eat_alpha_numeric(CONF *conf, char *p);
77 static void clear_comments(CONF *conf, char *p);
78 static int str_copy(CONF *conf, char *section, char **to, char *from);
79 static char *scan_quote(CONF *conf, char *p);
80 static char *scan_dquote(CONF *conf, char *p);
81 #define scan_esc(conf,p) (((IS_EOF((conf),(p)[1]))?((p)+1):((p)+2)))
82
83 static CONF *
def_create(const CONF_METHOD * meth)84 def_create(const CONF_METHOD *meth)
85 {
86 CONF *ret;
87
88 ret = calloc(1, sizeof(CONF) + sizeof(unsigned short *));
89 if (ret)
90 if (meth->init(ret) == 0) {
91 free(ret);
92 ret = NULL;
93 }
94 return ret;
95 }
96
97 static int
def_init_default(CONF * conf)98 def_init_default(CONF *conf)
99 {
100 if (conf == NULL)
101 return 0;
102
103 conf->meth = NCONF_default();
104 conf->data = NULL;
105
106 return 1;
107 }
108
109 static int
def_destroy_data(CONF * conf)110 def_destroy_data(CONF *conf)
111 {
112 if (conf == NULL)
113 return 0;
114 _CONF_free_data(conf);
115 return 1;
116 }
117
118 static int
def_destroy(CONF * conf)119 def_destroy(CONF *conf)
120 {
121 if (def_destroy_data(conf)) {
122 free(conf);
123 return 1;
124 }
125 return 0;
126 }
127
128 static int
def_load_bio(CONF * conf,BIO * in,long * line)129 def_load_bio(CONF *conf, BIO *in, long *line)
130 {
131 /* The macro BUFSIZE conflicts with a system macro in VxWorks */
132 #define CONFBUFSIZE 512
133 int bufnum = 0, i, ii;
134 BUF_MEM *buff = NULL;
135 char *s, *p, *end;
136 int again;
137 long eline = 0;
138 CONF_VALUE *v = NULL, *tv;
139 CONF_VALUE *sv = NULL;
140 char *section = NULL, *buf;
141 char *start, *psection, *pname;
142 void *h = (void *)(conf->data);
143
144 if ((buff = BUF_MEM_new()) == NULL) {
145 CONFerror(ERR_R_BUF_LIB);
146 goto err;
147 }
148
149 section = strdup("default");
150 if (section == NULL) {
151 CONFerror(ERR_R_MALLOC_FAILURE);
152 goto err;
153 }
154
155 if (_CONF_new_data(conf) == 0) {
156 CONFerror(ERR_R_MALLOC_FAILURE);
157 goto err;
158 }
159
160 sv = _CONF_new_section(conf, section);
161 if (sv == NULL) {
162 CONFerror(CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
163 goto err;
164 }
165
166 bufnum = 0;
167 again = 0;
168 for (;;) {
169 if (!BUF_MEM_grow(buff, bufnum + CONFBUFSIZE)) {
170 CONFerror(ERR_R_BUF_LIB);
171 goto err;
172 }
173 p = &(buff->data[bufnum]);
174 *p = '\0';
175 BIO_gets(in, p, CONFBUFSIZE - 1);
176 p[CONFBUFSIZE - 1] = '\0';
177 ii = i = strlen(p);
178 if (i == 0 && !again)
179 break;
180 again = 0;
181 while (i > 0) {
182 if ((p[i - 1] != '\r') && (p[i - 1] != '\n'))
183 break;
184 else
185 i--;
186 }
187 /* we removed some trailing stuff so there is a new
188 * line on the end. */
189 if (ii && i == ii)
190 again = 1; /* long line */
191 else {
192 p[i] = '\0';
193 eline++; /* another input line */
194 }
195
196 /* we now have a line with trailing \r\n removed */
197
198 /* i is the number of bytes */
199 bufnum += i;
200
201 v = NULL;
202 /* check for line continuation */
203 if (bufnum >= 1) {
204 /* If we have bytes and the last char '\\' and
205 * second last char is not '\\' */
206 p = &(buff->data[bufnum - 1]);
207 if (IS_ESC(conf, p[0]) &&
208 ((bufnum <= 1) || !IS_ESC(conf, p[-1]))) {
209 bufnum--;
210 again = 1;
211 }
212 }
213 if (again)
214 continue;
215 bufnum = 0;
216 buf = buff->data;
217
218 clear_comments(conf, buf);
219 s = eat_ws(conf, buf);
220 if (IS_EOF(conf, *s))
221 continue; /* blank line */
222 if (*s == '[') {
223 char *ss;
224
225 s++;
226 start = eat_ws(conf, s);
227 ss = start;
228 again:
229 end = eat_alpha_numeric(conf, ss);
230 p = eat_ws(conf, end);
231 if (*p != ']') {
232 if (*p != '\0' && ss != p) {
233 ss = p;
234 goto again;
235 }
236 CONFerror(CONF_R_MISSING_CLOSE_SQUARE_BRACKET);
237 goto err;
238 }
239 *end = '\0';
240 if (!str_copy(conf, NULL, §ion, start))
241 goto err;
242 if ((sv = _CONF_get_section(conf, section)) == NULL)
243 sv = _CONF_new_section(conf, section);
244 if (sv == NULL) {
245 CONFerror(CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
246 goto err;
247 }
248 continue;
249 } else {
250 pname = s;
251 psection = NULL;
252 end = eat_alpha_numeric(conf, s);
253 if ((end[0] == ':') && (end[1] == ':')) {
254 *end = '\0';
255 end += 2;
256 psection = pname;
257 pname = end;
258 end = eat_alpha_numeric(conf, end);
259 }
260 p = eat_ws(conf, end);
261 if (*p != '=') {
262 CONFerror(CONF_R_MISSING_EQUAL_SIGN);
263 goto err;
264 }
265 *end = '\0';
266 p++;
267 start = eat_ws(conf, p);
268 while (!IS_EOF(conf, *p))
269 p++;
270 p--;
271 while ((p != start) && (IS_WS(conf, *p)))
272 p--;
273 p++;
274 *p = '\0';
275
276 if (!(v = malloc(sizeof(CONF_VALUE)))) {
277 CONFerror(ERR_R_MALLOC_FAILURE);
278 goto err;
279 }
280 if (psection == NULL)
281 psection = section;
282 v->name = strdup(pname);
283 v->value = NULL;
284 if (v->name == NULL) {
285 CONFerror(ERR_R_MALLOC_FAILURE);
286 goto err;
287 }
288 if (!str_copy(conf, psection, &(v->value), start))
289 goto err;
290
291 if (strcmp(psection, section) != 0) {
292 if ((tv = _CONF_get_section(conf, psection))
293 == NULL)
294 tv = _CONF_new_section(conf, psection);
295 if (tv == NULL) {
296 CONFerror(CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
297 goto err;
298 }
299 } else
300 tv = sv;
301
302 if (_CONF_add_string(conf, tv, v) == 0) {
303 CONFerror(ERR_R_MALLOC_FAILURE);
304 goto err;
305 }
306 v = NULL;
307 }
308 }
309 if (buff != NULL)
310 BUF_MEM_free(buff);
311 free(section);
312 return (1);
313
314 err:
315 if (buff != NULL)
316 BUF_MEM_free(buff);
317 free(section);
318 if (line != NULL)
319 *line = eline;
320 ERR_asprintf_error_data("line %ld", eline);
321 if ((h != conf->data) && (conf->data != NULL)) {
322 CONF ctmp;
323
324 CONF_set_nconf(&ctmp, conf->data);
325 ctmp.meth->destroy_data(&ctmp);
326 conf->data = NULL;
327 }
328 if (v != NULL) {
329 free(v->name);
330 free(v->value);
331 free(v);
332 }
333 return (0);
334 }
335
336 static int
def_load(CONF * conf,const char * name,long * line)337 def_load(CONF *conf, const char *name, long *line)
338 {
339 int ret;
340 BIO *in = NULL;
341
342 in = BIO_new_file(name, "rb");
343 if (in == NULL) {
344 if (ERR_GET_REASON(ERR_peek_last_error()) == BIO_R_NO_SUCH_FILE)
345 CONFerror(CONF_R_NO_SUCH_FILE);
346 else
347 CONFerror(ERR_R_SYS_LIB);
348 return 0;
349 }
350
351 ret = def_load_bio(conf, in, line);
352 BIO_free(in);
353
354 return ret;
355 }
356
357 static void
clear_comments(CONF * conf,char * p)358 clear_comments(CONF *conf, char *p)
359 {
360 for (;;) {
361 if (IS_FCOMMENT(conf, *p)) {
362 *p = '\0';
363 return;
364 }
365 if (!IS_WS(conf, *p)) {
366 break;
367 }
368 p++;
369 }
370
371 for (;;) {
372 if (IS_COMMENT(conf, *p)) {
373 *p = '\0';
374 return;
375 }
376 if (IS_DQUOTE(conf, *p)) {
377 p = scan_dquote(conf, p);
378 continue;
379 }
380 if (IS_QUOTE(conf, *p)) {
381 p = scan_quote(conf, p);
382 continue;
383 }
384 if (IS_ESC(conf, *p)) {
385 p = scan_esc(conf, p);
386 continue;
387 }
388 if (IS_EOF(conf, *p))
389 return;
390 else
391 p++;
392 }
393 }
394
395 static int
str_copy(CONF * conf,char * section,char ** pto,char * from)396 str_copy(CONF *conf, char *section, char **pto, char *from)
397 {
398 int q, r,rr = 0, to = 0, len = 0;
399 char *s, *e, *rp, *p, *rrp, *np, *cp, v;
400 size_t newsize;
401 BUF_MEM *buf;
402
403 if ((buf = BUF_MEM_new()) == NULL)
404 return (0);
405
406 len = strlen(from) + 1;
407 if (!BUF_MEM_grow(buf, len))
408 goto err;
409
410 for (;;) {
411 if (IS_QUOTE(conf, *from)) {
412 q = *from;
413 from++;
414 while (!IS_EOF(conf, *from) && (*from != q)) {
415 if (IS_ESC(conf, *from)) {
416 from++;
417 if (IS_EOF(conf, *from))
418 break;
419 }
420 buf->data[to++] = *(from++);
421 }
422 if (*from == q)
423 from++;
424 } else if (IS_DQUOTE(conf, *from)) {
425 q = *from;
426 from++;
427 while (!IS_EOF(conf, *from)) {
428 if (*from == q) {
429 if (*(from + 1) == q) {
430 from++;
431 } else {
432 break;
433 }
434 }
435 buf->data[to++] = *(from++);
436 }
437 if (*from == q)
438 from++;
439 } else if (IS_ESC(conf, *from)) {
440 from++;
441 v = *(from++);
442 if (IS_EOF(conf, v))
443 break;
444 else if (v == 'r')
445 v = '\r';
446 else if (v == 'n')
447 v = '\n';
448 else if (v == 'b')
449 v = '\b';
450 else if (v == 't')
451 v = '\t';
452 buf->data[to++] = v;
453 } else if (IS_EOF(conf, *from))
454 break;
455 else if (*from == '$') {
456 /* try to expand it */
457 rrp = NULL;
458 s = &(from[1]);
459 if (*s == '{')
460 q = '}';
461 else if (*s == '(')
462 q = ')';
463 else
464 q = 0;
465
466 if (q)
467 s++;
468 cp = section;
469 e = np = s;
470 while (IS_ALPHA_NUMERIC(conf, *e))
471 e++;
472 if ((e[0] == ':') && (e[1] == ':')) {
473 cp = np;
474 rrp = e;
475 rr = *e;
476 *rrp = '\0';
477 e += 2;
478 np = e;
479 while (IS_ALPHA_NUMERIC(conf, *e))
480 e++;
481 }
482 r = *e;
483 *e = '\0';
484 rp = e;
485 if (q) {
486 if (r != q) {
487 CONFerror(CONF_R_NO_CLOSE_BRACE);
488 goto err;
489 }
490 e++;
491 }
492 /* So at this point we have
493 * np which is the start of the name string which is
494 * '\0' terminated.
495 * cp which is the start of the section string which is
496 * '\0' terminated.
497 * e is the 'next point after'.
498 * r and rr are the chars replaced by the '\0'
499 * rp and rrp is where 'r' and 'rr' came from.
500 */
501 p = _CONF_get_string(conf, cp, np);
502 if (rrp != NULL)
503 *rrp = rr;
504 *rp = r;
505 if (p == NULL) {
506 CONFerror(CONF_R_VARIABLE_HAS_NO_VALUE);
507 goto err;
508 }
509 newsize = strlen(p) + buf->length - (e - from);
510 if (newsize > MAX_CONF_VALUE_LENGTH) {
511 CONFerror(CONF_R_VARIABLE_EXPANSION_TOO_LONG);
512 goto err;
513 }
514 if (!BUF_MEM_grow_clean(buf, newsize)) {
515 CONFerror(CONF_R_MODULE_INITIALIZATION_ERROR);
516 goto err;
517 }
518 while (*p)
519 buf->data[to++] = *(p++);
520
521 /* Since we change the pointer 'from', we also have
522 to change the perceived length of the string it
523 points at. /RL */
524 len -= e - from;
525 from = e;
526
527 /* In case there were no braces or parenthesis around
528 the variable reference, we have to put back the
529 character that was replaced with a '\0'. /RL */
530 *rp = r;
531 } else
532 buf->data[to++] = *(from++);
533 }
534 buf->data[to]='\0';
535 free(*pto);
536 *pto = buf->data;
537 free(buf);
538 return (1);
539
540 err:
541 if (buf != NULL)
542 BUF_MEM_free(buf);
543 return (0);
544 }
545
546 static char *
eat_ws(CONF * conf,char * p)547 eat_ws(CONF *conf, char *p)
548 {
549 while (IS_WS(conf, *p) && (!IS_EOF(conf, *p)))
550 p++;
551 return (p);
552 }
553
554 static char *
eat_alpha_numeric(CONF * conf,char * p)555 eat_alpha_numeric(CONF *conf, char *p)
556 {
557 for (;;) {
558 if (IS_ESC(conf, *p)) {
559 p = scan_esc(conf, p);
560 continue;
561 }
562 if (!IS_ALPHA_NUMERIC_PUNCT(conf, *p))
563 return (p);
564 p++;
565 }
566 }
567
568 static char *
scan_quote(CONF * conf,char * p)569 scan_quote(CONF *conf, char *p)
570 {
571 int q = *p;
572
573 p++;
574 while (!(IS_EOF(conf, *p)) && (*p != q)) {
575 if (IS_ESC(conf, *p)) {
576 p++;
577 if (IS_EOF(conf, *p))
578 return (p);
579 }
580 p++;
581 }
582 if (*p == q)
583 p++;
584 return (p);
585 }
586
587
588 static char *
scan_dquote(CONF * conf,char * p)589 scan_dquote(CONF *conf, char *p)
590 {
591 int q = *p;
592
593 p++;
594 while (!(IS_EOF(conf, *p))) {
595 if (*p == q) {
596 if (*(p + 1) == q) {
597 p++;
598 } else {
599 break;
600 }
601 }
602 p++;
603 }
604 if (*p == q)
605 p++;
606 return (p);
607 }
608
609 static void
dump_value_doall_arg(CONF_VALUE * a,BIO * out)610 dump_value_doall_arg(CONF_VALUE *a, BIO *out)
611 {
612 if (a->name)
613 BIO_printf(out, "[%s] %s=%s\n", a->section, a->name, a->value);
614 else
615 BIO_printf(out, "[[%s]]\n", a->section);
616 }
617
IMPLEMENT_LHASH_DOALL_ARG_FN(dump_value,CONF_VALUE,BIO)618 static IMPLEMENT_LHASH_DOALL_ARG_FN(dump_value, CONF_VALUE, BIO)
619
620 static int
621 def_dump(const CONF *conf, BIO *out)
622 {
623 lh_CONF_VALUE_doall_arg(conf->data, LHASH_DOALL_ARG_FN(dump_value),
624 BIO, out);
625 return 1;
626 }
627
628 static int
def_is_number(const CONF * conf,char c)629 def_is_number(const CONF *conf, char c)
630 {
631 return IS_NUMBER(conf, c);
632 }
633
634 static int
def_to_int(const CONF * conf,char c)635 def_to_int(const CONF *conf, char c)
636 {
637 return c - '0';
638 }
639
640 static const CONF_METHOD default_method = {
641 .name = "OpenSSL default",
642 .create = def_create,
643 .init = def_init_default,
644 .destroy = def_destroy,
645 .destroy_data = def_destroy_data,
646 .load_bio = def_load_bio,
647 .dump = def_dump,
648 .is_number = def_is_number,
649 .to_int = def_to_int,
650 .load = def_load,
651 };
652
653 const CONF_METHOD *
NCONF_default(void)654 NCONF_default(void)
655 {
656 return &default_method;
657 }
658