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
73 static const char kDefaultSectionName[] = "default";
74
conf_value_hash(const CONF_VALUE * v)75 static uint32_t conf_value_hash(const CONF_VALUE *v) {
76 const uint32_t section_hash = v->section ? OPENSSL_strhash(v->section) : 0;
77 const uint32_t name_hash = v->name ? OPENSSL_strhash(v->name) : 0;
78 return (section_hash << 2) ^ name_hash;
79 }
80
conf_value_cmp(const CONF_VALUE * a,const CONF_VALUE * b)81 static int conf_value_cmp(const CONF_VALUE *a, const CONF_VALUE *b) {
82 int i;
83
84 if (a->section != b->section) {
85 i = strcmp(a->section, b->section);
86 if (i) {
87 return i;
88 }
89 }
90
91 if (a->name != NULL && b->name != NULL) {
92 return strcmp(a->name, b->name);
93 } else if (a->name == b->name) {
94 return 0;
95 } else {
96 return (a->name == NULL) ? -1 : 1;
97 }
98 }
99
NCONF_new(void * method)100 CONF *NCONF_new(void *method) {
101 CONF *conf;
102
103 if (method != NULL) {
104 return NULL;
105 }
106
107 conf = OPENSSL_malloc(sizeof(CONF));
108 if (conf == NULL) {
109 return NULL;
110 }
111
112 conf->data = lh_CONF_VALUE_new(conf_value_hash, conf_value_cmp);
113 if (conf->data == NULL) {
114 OPENSSL_free(conf);
115 return NULL;
116 }
117
118 return conf;
119 }
120
CONF_VALUE_new(void)121 CONF_VALUE *CONF_VALUE_new(void) { return OPENSSL_zalloc(sizeof(CONF_VALUE)); }
122
value_free_contents(CONF_VALUE * value)123 static void value_free_contents(CONF_VALUE *value) {
124 OPENSSL_free(value->section);
125 if (value->name) {
126 OPENSSL_free(value->name);
127 OPENSSL_free(value->value);
128 } else {
129 // TODO(davidben): When |value->name| is NULL, |CONF_VALUE| is actually an
130 // entirely different structure. This is fragile and confusing. Make a
131 // proper |CONF_SECTION| type that doesn't require this.
132 sk_CONF_VALUE_free((STACK_OF(CONF_VALUE) *)value->value);
133 }
134 }
135
value_free(CONF_VALUE * value)136 static void value_free(CONF_VALUE *value) {
137 if (value != NULL) {
138 value_free_contents(value);
139 OPENSSL_free(value);
140 }
141 }
142
value_free_arg(CONF_VALUE * value,void * arg)143 static void value_free_arg(CONF_VALUE *value, void *arg) { value_free(value); }
144
NCONF_free(CONF * conf)145 void NCONF_free(CONF *conf) {
146 if (conf == NULL || conf->data == NULL) {
147 return;
148 }
149
150 lh_CONF_VALUE_doall_arg(conf->data, value_free_arg, NULL);
151 lh_CONF_VALUE_free(conf->data);
152 OPENSSL_free(conf);
153 }
154
NCONF_new_section(const CONF * conf,const char * section)155 static CONF_VALUE *NCONF_new_section(const CONF *conf, const char *section) {
156 STACK_OF(CONF_VALUE) *sk = NULL;
157 int ok = 0;
158 CONF_VALUE *v = NULL, *old_value;
159
160 sk = sk_CONF_VALUE_new_null();
161 v = CONF_VALUE_new();
162 if (sk == NULL || v == NULL) {
163 goto err;
164 }
165 v->section = OPENSSL_strdup(section);
166 if (v->section == NULL) {
167 goto err;
168 }
169
170 v->name = NULL;
171 v->value = (char *)sk;
172
173 if (!lh_CONF_VALUE_insert(conf->data, &old_value, v)) {
174 goto err;
175 }
176 value_free(old_value);
177 ok = 1;
178
179 err:
180 if (!ok) {
181 sk_CONF_VALUE_free(sk);
182 OPENSSL_free(v);
183 v = NULL;
184 }
185 return v;
186 }
187
str_copy(CONF * conf,char * section,char ** pto,char * from)188 static int str_copy(CONF *conf, char *section, char **pto, char *from) {
189 int q, to = 0, len = 0;
190 char v;
191 BUF_MEM *buf;
192
193 buf = BUF_MEM_new();
194 if (buf == NULL) {
195 return 0;
196 }
197
198 len = strlen(from) + 1;
199 if (!BUF_MEM_grow(buf, len)) {
200 goto err;
201 }
202
203 for (;;) {
204 if (IS_QUOTE(conf, *from)) {
205 q = *from;
206 from++;
207 while (!IS_EOF(conf, *from) && (*from != q)) {
208 if (IS_ESC(conf, *from)) {
209 from++;
210 if (IS_EOF(conf, *from)) {
211 break;
212 }
213 }
214 buf->data[to++] = *(from++);
215 }
216 if (*from == q) {
217 from++;
218 }
219 } else if (IS_ESC(conf, *from)) {
220 from++;
221 v = *(from++);
222 if (IS_EOF(conf, v)) {
223 break;
224 } else if (v == 'r') {
225 v = '\r';
226 } else if (v == 'n') {
227 v = '\n';
228 } else if (v == 'b') {
229 v = '\b';
230 } else if (v == 't') {
231 v = '\t';
232 }
233 buf->data[to++] = v;
234 } else if (IS_EOF(conf, *from)) {
235 break;
236 } else if (*from == '$') {
237 // Historically, $foo would expand to a previously-parsed value. This
238 // feature has been removed as it was unused and is a DoS vector.
239 OPENSSL_PUT_ERROR(CONF, CONF_R_VARIABLE_EXPANSION_NOT_SUPPORTED);
240 goto err;
241 } else {
242 buf->data[to++] = *(from++);
243 }
244 }
245
246 buf->data[to] = '\0';
247 OPENSSL_free(*pto);
248 *pto = buf->data;
249 OPENSSL_free(buf);
250 return 1;
251
252 err:
253 BUF_MEM_free(buf);
254 return 0;
255 }
256
get_section(const CONF * conf,const char * section)257 static CONF_VALUE *get_section(const CONF *conf, const char *section) {
258 CONF_VALUE template;
259
260 OPENSSL_memset(&template, 0, sizeof(template));
261 template.section = (char *) section;
262 return lh_CONF_VALUE_retrieve(conf->data, &template);
263 }
264
STACK_OF(CONF_VALUE)265 const STACK_OF(CONF_VALUE) *NCONF_get_section(const CONF *conf,
266 const char *section) {
267 const CONF_VALUE *section_value = get_section(conf, section);
268 if (section_value == NULL) {
269 return NULL;
270 }
271 return (STACK_OF(CONF_VALUE)*) section_value->value;
272 }
273
NCONF_get_string(const CONF * conf,const char * section,const char * name)274 const char *NCONF_get_string(const CONF *conf, const char *section,
275 const char *name) {
276 CONF_VALUE template, *value;
277
278 if (section == NULL) {
279 section = kDefaultSectionName;
280 }
281
282 OPENSSL_memset(&template, 0, sizeof(template));
283 template.section = (char *) section;
284 template.name = (char *) name;
285 value = lh_CONF_VALUE_retrieve(conf->data, &template);
286 if (value == NULL) {
287 return NULL;
288 }
289 return value->value;
290 }
291
add_string(const CONF * conf,CONF_VALUE * section,CONF_VALUE * value)292 static int add_string(const CONF *conf, CONF_VALUE *section,
293 CONF_VALUE *value) {
294 STACK_OF(CONF_VALUE) *section_stack = (STACK_OF(CONF_VALUE)*) section->value;
295 CONF_VALUE *old_value;
296
297 value->section = OPENSSL_strdup(section->section);
298 if (!sk_CONF_VALUE_push(section_stack, value)) {
299 return 0;
300 }
301
302 if (!lh_CONF_VALUE_insert(conf->data, &old_value, value)) {
303 return 0;
304 }
305 if (old_value != NULL) {
306 (void)sk_CONF_VALUE_delete_ptr(section_stack, old_value);
307 value_free(old_value);
308 }
309
310 return 1;
311 }
312
eat_ws(CONF * conf,char * p)313 static char *eat_ws(CONF *conf, char *p) {
314 while (IS_WS(conf, *p) && !IS_EOF(conf, *p)) {
315 p++;
316 }
317 return p;
318 }
319
320 #define scan_esc(conf, p) (((IS_EOF((conf), (p)[1])) ? ((p) + 1) : ((p) + 2)))
321
eat_alpha_numeric(CONF * conf,char * p)322 static char *eat_alpha_numeric(CONF *conf, char *p) {
323 for (;;) {
324 if (IS_ESC(conf, *p)) {
325 p = scan_esc(conf, p);
326 continue;
327 }
328 if (!IS_ALPHA_NUMERIC_PUNCT(conf, *p)) {
329 return p;
330 }
331 p++;
332 }
333 }
334
scan_quote(CONF * conf,char * p)335 static char *scan_quote(CONF *conf, char *p) {
336 int q = *p;
337
338 p++;
339 while (!IS_EOF(conf, *p) && *p != q) {
340 if (IS_ESC(conf, *p)) {
341 p++;
342 if (IS_EOF(conf, *p)) {
343 return p;
344 }
345 }
346 p++;
347 }
348 if (*p == q) {
349 p++;
350 }
351 return p;
352 }
353
clear_comments(CONF * conf,char * p)354 static void clear_comments(CONF *conf, char *p) {
355 for (;;) {
356 if (!IS_WS(conf, *p)) {
357 break;
358 }
359 p++;
360 }
361
362 for (;;) {
363 if (IS_COMMENT(conf, *p)) {
364 *p = '\0';
365 return;
366 }
367 if (IS_QUOTE(conf, *p)) {
368 p = scan_quote(conf, p);
369 continue;
370 }
371 if (IS_ESC(conf, *p)) {
372 p = scan_esc(conf, p);
373 continue;
374 }
375 if (IS_EOF(conf, *p)) {
376 return;
377 } else {
378 p++;
379 }
380 }
381 }
382
NCONF_load_bio(CONF * conf,BIO * in,long * out_error_line)383 int NCONF_load_bio(CONF *conf, BIO *in, long *out_error_line) {
384 static const size_t CONFBUFSIZE = 512;
385 int bufnum = 0, i, ii;
386 BUF_MEM *buff = NULL;
387 char *s, *p, *end;
388 int again;
389 long eline = 0;
390 char btmp[DECIMAL_SIZE(eline) + 1];
391 CONF_VALUE *v = NULL, *tv;
392 CONF_VALUE *sv = NULL;
393 char *section = NULL, *buf;
394 char *start, *psection, *pname;
395
396 if ((buff = BUF_MEM_new()) == NULL) {
397 OPENSSL_PUT_ERROR(CONF, ERR_R_BUF_LIB);
398 goto err;
399 }
400
401 section = OPENSSL_strdup(kDefaultSectionName);
402 if (section == NULL) {
403 goto err;
404 }
405
406 sv = NCONF_new_section(conf, section);
407 if (sv == NULL) {
408 OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
409 goto err;
410 }
411
412 bufnum = 0;
413 again = 0;
414 for (;;) {
415 if (!BUF_MEM_grow(buff, bufnum + CONFBUFSIZE)) {
416 OPENSSL_PUT_ERROR(CONF, ERR_R_BUF_LIB);
417 goto err;
418 }
419 p = &(buff->data[bufnum]);
420 *p = '\0';
421 BIO_gets(in, p, CONFBUFSIZE - 1);
422 p[CONFBUFSIZE - 1] = '\0';
423 ii = i = strlen(p);
424 if (i == 0 && !again) {
425 break;
426 }
427 again = 0;
428 while (i > 0) {
429 if ((p[i - 1] != '\r') && (p[i - 1] != '\n')) {
430 break;
431 } else {
432 i--;
433 }
434 }
435 // we removed some trailing stuff so there is a new
436 // line on the end.
437 if (ii && i == ii) {
438 again = 1; // long line
439 } else {
440 p[i] = '\0';
441 eline++; // another input line
442 }
443
444 // we now have a line with trailing \r\n removed
445
446 // i is the number of bytes
447 bufnum += i;
448
449 v = NULL;
450 // check for line continuation
451 if (bufnum >= 1) {
452 // If we have bytes and the last char '\\' and
453 // second last char is not '\\'
454 p = &(buff->data[bufnum - 1]);
455 if (IS_ESC(conf, p[0]) && ((bufnum <= 1) || !IS_ESC(conf, p[-1]))) {
456 bufnum--;
457 again = 1;
458 }
459 }
460 if (again) {
461 continue;
462 }
463 bufnum = 0;
464 buf = buff->data;
465
466 clear_comments(conf, buf);
467 s = eat_ws(conf, buf);
468 if (IS_EOF(conf, *s)) {
469 continue; // blank line
470 }
471 if (*s == '[') {
472 char *ss;
473
474 s++;
475 start = eat_ws(conf, s);
476 ss = start;
477 again:
478 end = eat_alpha_numeric(conf, ss);
479 p = eat_ws(conf, end);
480 if (*p != ']') {
481 if (*p != '\0' && ss != p) {
482 ss = p;
483 goto again;
484 }
485 OPENSSL_PUT_ERROR(CONF, CONF_R_MISSING_CLOSE_SQUARE_BRACKET);
486 goto err;
487 }
488 *end = '\0';
489 if (!str_copy(conf, NULL, §ion, start)) {
490 goto err;
491 }
492 if ((sv = get_section(conf, section)) == NULL) {
493 sv = NCONF_new_section(conf, section);
494 }
495 if (sv == NULL) {
496 OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
497 goto err;
498 }
499 continue;
500 } else {
501 pname = s;
502 psection = NULL;
503 end = eat_alpha_numeric(conf, s);
504 if ((end[0] == ':') && (end[1] == ':')) {
505 *end = '\0';
506 end += 2;
507 psection = pname;
508 pname = end;
509 end = eat_alpha_numeric(conf, end);
510 }
511 p = eat_ws(conf, end);
512 if (*p != '=') {
513 OPENSSL_PUT_ERROR(CONF, CONF_R_MISSING_EQUAL_SIGN);
514 goto err;
515 }
516 *end = '\0';
517 p++;
518 start = eat_ws(conf, p);
519 while (!IS_EOF(conf, *p)) {
520 p++;
521 }
522 p--;
523 while ((p != start) && (IS_WS(conf, *p))) {
524 p--;
525 }
526 p++;
527 *p = '\0';
528
529 if (!(v = CONF_VALUE_new())) {
530 goto err;
531 }
532 if (psection == NULL) {
533 psection = section;
534 }
535 v->name = OPENSSL_strdup(pname);
536 if (v->name == NULL) {
537 goto err;
538 }
539 if (!str_copy(conf, psection, &(v->value), start)) {
540 goto err;
541 }
542
543 if (strcmp(psection, section) != 0) {
544 if ((tv = get_section(conf, psection)) == NULL) {
545 tv = NCONF_new_section(conf, psection);
546 }
547 if (tv == NULL) {
548 OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
549 goto err;
550 }
551 } else {
552 tv = sv;
553 }
554 if (add_string(conf, tv, v) == 0) {
555 goto err;
556 }
557 v = NULL;
558 }
559 }
560 BUF_MEM_free(buff);
561 OPENSSL_free(section);
562 return 1;
563
564 err:
565 BUF_MEM_free(buff);
566 OPENSSL_free(section);
567 if (out_error_line != NULL) {
568 *out_error_line = eline;
569 }
570 snprintf(btmp, sizeof btmp, "%ld", eline);
571 ERR_add_error_data(2, "line ", btmp);
572
573 if (v != NULL) {
574 OPENSSL_free(v->name);
575 OPENSSL_free(v->value);
576 OPENSSL_free(v);
577 }
578 return 0;
579 }
580
NCONF_load(CONF * conf,const char * filename,long * out_error_line)581 int NCONF_load(CONF *conf, const char *filename, long *out_error_line) {
582 BIO *in = BIO_new_file(filename, "rb");
583 int ret;
584
585 if (in == NULL) {
586 OPENSSL_PUT_ERROR(CONF, ERR_R_SYS_LIB);
587 return 0;
588 }
589
590 ret = NCONF_load_bio(conf, in, out_error_line);
591 BIO_free(in);
592
593 return ret;
594 }
595
CONF_parse_list(const char * list,char sep,int remove_whitespace,int (* list_cb)(const char * elem,size_t len,void * usr),void * arg)596 int CONF_parse_list(const char *list, char sep, int remove_whitespace,
597 int (*list_cb)(const char *elem, size_t len, void *usr),
598 void *arg) {
599 int ret;
600 const char *lstart, *tmpend, *p;
601
602 if (list == NULL) {
603 OPENSSL_PUT_ERROR(CONF, CONF_R_LIST_CANNOT_BE_NULL);
604 return 0;
605 }
606
607 lstart = list;
608 for (;;) {
609 if (remove_whitespace) {
610 while (*lstart && OPENSSL_isspace((unsigned char)*lstart)) {
611 lstart++;
612 }
613 }
614 p = strchr(lstart, sep);
615 if (p == lstart || !*lstart) {
616 ret = list_cb(NULL, 0, arg);
617 } else {
618 if (p) {
619 tmpend = p - 1;
620 } else {
621 tmpend = lstart + strlen(lstart) - 1;
622 }
623 if (remove_whitespace) {
624 while (OPENSSL_isspace((unsigned char)*tmpend)) {
625 tmpend--;
626 }
627 }
628 ret = list_cb(lstart, tmpend - lstart + 1, arg);
629 }
630 if (ret <= 0) {
631 return ret;
632 }
633 if (p == NULL) {
634 return 1;
635 }
636 lstart = p + 1;
637 }
638 }
639
CONF_modules_load_file(const char * filename,const char * appname,unsigned long flags)640 int CONF_modules_load_file(const char *filename, const char *appname,
641 unsigned long flags) {
642 return 1;
643 }
644
CONF_modules_free(void)645 void CONF_modules_free(void) {}
646
OPENSSL_config(const char * config_name)647 void OPENSSL_config(const char *config_name) {}
648
OPENSSL_no_config(void)649 void OPENSSL_no_config(void) {}
650