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