xref: /openbsd/lib/libcrypto/conf/conf_def.c (revision 140d1653)
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, &section, 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