1 // Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <openssl/conf.h>
16
17 #include <assert.h>
18 #include <ctype.h>
19 #include <string.h>
20
21 #include <openssl/bio.h>
22 #include <openssl/buf.h>
23 #include <openssl/err.h>
24 #include <openssl/mem.h>
25
26 #include "../internal.h"
27 #include "internal.h"
28
29
30 struct conf_section_st {
31 char *name;
32 // values contains non-owning pointers to the values in the section.
33 STACK_OF(CONF_VALUE) *values;
34 };
35
36 static const char kDefaultSectionName[] = "default";
37
conf_section_hash(const CONF_SECTION * s)38 static uint32_t conf_section_hash(const CONF_SECTION *s) {
39 return OPENSSL_strhash(s->name);
40 }
41
conf_section_cmp(const CONF_SECTION * a,const CONF_SECTION * b)42 static int conf_section_cmp(const CONF_SECTION *a, const CONF_SECTION *b) {
43 return strcmp(a->name, b->name);
44 }
45
conf_value_hash(const CONF_VALUE * v)46 static uint32_t conf_value_hash(const CONF_VALUE *v) {
47 const uint32_t section_hash = OPENSSL_strhash(v->section);
48 const uint32_t name_hash = OPENSSL_strhash(v->name);
49 return (section_hash << 2) ^ name_hash;
50 }
51
conf_value_cmp(const CONF_VALUE * a,const CONF_VALUE * b)52 static int conf_value_cmp(const CONF_VALUE *a, const CONF_VALUE *b) {
53 int cmp = strcmp(a->section, b->section);
54 if (cmp != 0) {
55 return cmp;
56 }
57
58 return strcmp(a->name, b->name);
59 }
60
NCONF_new(void * method)61 CONF *NCONF_new(void *method) {
62 if (method != NULL) {
63 return NULL;
64 }
65
66 CONF *conf = reinterpret_cast<CONF *>(OPENSSL_malloc(sizeof(CONF)));
67 if (conf == NULL) {
68 return NULL;
69 }
70
71 conf->sections = lh_CONF_SECTION_new(conf_section_hash, conf_section_cmp);
72 conf->values = lh_CONF_VALUE_new(conf_value_hash, conf_value_cmp);
73 if (conf->sections == NULL || conf->values == NULL) {
74 NCONF_free(conf);
75 return NULL;
76 }
77
78 return conf;
79 }
80
CONF_VALUE_new(void)81 CONF_VALUE *CONF_VALUE_new(void) {
82 return reinterpret_cast<CONF_VALUE *>(OPENSSL_zalloc(sizeof(CONF_VALUE)));
83 }
84
value_free(CONF_VALUE * value)85 static void value_free(CONF_VALUE *value) {
86 if (value == NULL) {
87 return;
88 }
89 OPENSSL_free(value->section);
90 OPENSSL_free(value->name);
91 OPENSSL_free(value->value);
92 OPENSSL_free(value);
93 }
94
section_free(CONF_SECTION * section)95 static void section_free(CONF_SECTION *section) {
96 if (section == NULL) {
97 return;
98 }
99 OPENSSL_free(section->name);
100 sk_CONF_VALUE_free(section->values);
101 OPENSSL_free(section);
102 }
103
value_free_arg(CONF_VALUE * value,void * arg)104 static void value_free_arg(CONF_VALUE *value, void *arg) { value_free(value); }
105
section_free_arg(CONF_SECTION * section,void * arg)106 static void section_free_arg(CONF_SECTION *section, void *arg) {
107 section_free(section);
108 }
109
NCONF_free(CONF * conf)110 void NCONF_free(CONF *conf) {
111 if (conf == NULL) {
112 return;
113 }
114
115 lh_CONF_SECTION_doall_arg(conf->sections, section_free_arg, NULL);
116 lh_CONF_SECTION_free(conf->sections);
117 lh_CONF_VALUE_doall_arg(conf->values, value_free_arg, NULL);
118 lh_CONF_VALUE_free(conf->values);
119 OPENSSL_free(conf);
120 }
121
NCONF_new_section(const CONF * conf,const char * section)122 static CONF_SECTION *NCONF_new_section(const CONF *conf, const char *section) {
123 CONF_SECTION *s =
124 reinterpret_cast<CONF_SECTION *>(OPENSSL_malloc(sizeof(CONF_SECTION)));
125 if (!s) {
126 return NULL;
127 }
128 s->name = OPENSSL_strdup(section);
129 s->values = sk_CONF_VALUE_new_null();
130 if (s->name == NULL || s->values == NULL) {
131 goto err;
132 }
133
134 CONF_SECTION *old_section;
135 if (!lh_CONF_SECTION_insert(conf->sections, &old_section, s)) {
136 goto err;
137 }
138 section_free(old_section);
139 return s;
140
141 err:
142 section_free(s);
143 return NULL;
144 }
145
is_comment(char c)146 static int is_comment(char c) { return c == '#'; }
147
is_quote(char c)148 static int is_quote(char c) { return c == '"' || c == '\'' || c == '`'; }
149
is_esc(char c)150 static int is_esc(char c) { return c == '\\'; }
151
is_conf_ws(char c)152 static int is_conf_ws(char c) {
153 // This differs from |OPENSSL_isspace| in that CONF does not accept '\v' and
154 // '\f' as whitespace.
155 return c == ' ' || c == '\t' || c == '\r' || c == '\n';
156 }
157
is_name_char(char c)158 static int is_name_char(char c) {
159 // Alphanumeric characters, and a handful of symbols, may appear in value and
160 // section names without escaping.
161 return OPENSSL_isalnum(c) || c == '_' || c == '!' || c == '.' || c == '%' ||
162 c == '&' || c == '*' || c == '+' || c == ',' || c == '/' || c == ';' ||
163 c == '?' || c == '@' || c == '^' || c == '~' || c == '|' || c == '-';
164 }
165
str_copy(CONF * conf,char * section,char ** pto,char * from)166 static int str_copy(CONF *conf, char *section, char **pto, char *from) {
167 int q, to = 0, len = 0;
168 char v;
169 BUF_MEM *buf;
170
171 buf = BUF_MEM_new();
172 if (buf == NULL) {
173 return 0;
174 }
175
176 len = strlen(from) + 1;
177 if (!BUF_MEM_grow(buf, len)) {
178 goto err;
179 }
180
181 for (;;) {
182 if (is_quote(*from)) {
183 q = *from;
184 from++;
185 while (*from != '\0' && *from != q) {
186 if (is_esc(*from)) {
187 from++;
188 if (*from == '\0') {
189 break;
190 }
191 }
192 buf->data[to++] = *(from++);
193 }
194 if (*from == q) {
195 from++;
196 }
197 } else if (is_esc(*from)) {
198 from++;
199 v = *(from++);
200 if (v == '\0') {
201 break;
202 } else if (v == 'r') {
203 v = '\r';
204 } else if (v == 'n') {
205 v = '\n';
206 } else if (v == 'b') {
207 v = '\b';
208 } else if (v == 't') {
209 v = '\t';
210 }
211 buf->data[to++] = v;
212 } else if (*from == '\0') {
213 break;
214 } else if (*from == '$') {
215 // Historically, $foo would expand to a previously-parsed value. This
216 // feature has been removed as it was unused and is a DoS vector. If
217 // trying to embed '$' in a line, either escape it or wrap the value in
218 // quotes.
219 OPENSSL_PUT_ERROR(CONF, CONF_R_VARIABLE_EXPANSION_NOT_SUPPORTED);
220 goto err;
221 } else {
222 buf->data[to++] = *(from++);
223 }
224 }
225
226 buf->data[to] = '\0';
227 OPENSSL_free(*pto);
228 *pto = buf->data;
229 OPENSSL_free(buf);
230 return 1;
231
232 err:
233 BUF_MEM_free(buf);
234 return 0;
235 }
236
get_section(const CONF * conf,const char * section)237 static CONF_SECTION *get_section(const CONF *conf, const char *section) {
238 CONF_SECTION templ;
239 OPENSSL_memset(&templ, 0, sizeof(templ));
240 templ.name = (char *)section;
241 return lh_CONF_SECTION_retrieve(conf->sections, &templ);
242 }
243
STACK_OF(CONF_VALUE)244 const STACK_OF(CONF_VALUE) *NCONF_get_section(const CONF *conf,
245 const char *section) {
246 const CONF_SECTION *section_obj = get_section(conf, section);
247 if (section_obj == NULL) {
248 return NULL;
249 }
250 return section_obj->values;
251 }
252
NCONF_get_string(const CONF * conf,const char * section,const char * name)253 const char *NCONF_get_string(const CONF *conf, const char *section,
254 const char *name) {
255 CONF_VALUE templ, *value;
256
257 if (section == NULL) {
258 section = kDefaultSectionName;
259 }
260
261 OPENSSL_memset(&templ, 0, sizeof(templ));
262 templ.section = (char *)section;
263 templ.name = (char *)name;
264 value = lh_CONF_VALUE_retrieve(conf->values, &templ);
265 if (value == NULL) {
266 return NULL;
267 }
268 return value->value;
269 }
270
add_string(const CONF * conf,CONF_SECTION * section,CONF_VALUE * value)271 static int add_string(const CONF *conf, CONF_SECTION *section,
272 CONF_VALUE *value) {
273 value->section = OPENSSL_strdup(section->name);
274 if (value->section == NULL) {
275 return 0;
276 }
277
278 if (!sk_CONF_VALUE_push(section->values, value)) {
279 return 0;
280 }
281
282 CONF_VALUE *old_value;
283 if (!lh_CONF_VALUE_insert(conf->values, &old_value, value)) {
284 // Remove |value| from |section->values|, so we do not leave a dangling
285 // pointer.
286 sk_CONF_VALUE_pop(section->values);
287 return 0;
288 }
289 if (old_value != NULL) {
290 (void)sk_CONF_VALUE_delete_ptr(section->values, old_value);
291 value_free(old_value);
292 }
293
294 return 1;
295 }
296
eat_ws(char * p)297 static char *eat_ws(char *p) {
298 while (*p != '\0' && is_conf_ws(*p)) {
299 p++;
300 }
301 return p;
302 }
303
scan_esc(char * p)304 static char *scan_esc(char *p) {
305 assert(p[0] == '\\');
306 return p[1] == '\0' ? p + 1 : p + 2;
307 }
308
eat_name(char * p)309 static char *eat_name(char *p) {
310 for (;;) {
311 if (is_esc(*p)) {
312 p = scan_esc(p);
313 continue;
314 }
315 if (!is_name_char(*p)) {
316 return p;
317 }
318 p++;
319 }
320 }
321
scan_quote(char * p)322 static char *scan_quote(char *p) {
323 int q = *p;
324
325 p++;
326 while (*p != '\0' && *p != q) {
327 if (is_esc(*p)) {
328 p++;
329 if (*p == '\0') {
330 return p;
331 }
332 }
333 p++;
334 }
335 if (*p == q) {
336 p++;
337 }
338 return p;
339 }
340
clear_comments(char * p)341 static void clear_comments(char *p) {
342 for (;;) {
343 if (!is_conf_ws(*p)) {
344 break;
345 }
346 p++;
347 }
348
349 for (;;) {
350 if (is_comment(*p)) {
351 *p = '\0';
352 return;
353 }
354 if (is_quote(*p)) {
355 p = scan_quote(p);
356 continue;
357 }
358 if (is_esc(*p)) {
359 p = scan_esc(p);
360 continue;
361 }
362 if (*p == '\0') {
363 return;
364 } else {
365 p++;
366 }
367 }
368 }
369
NCONF_load_bio(CONF * conf,BIO * in,long * out_error_line)370 int NCONF_load_bio(CONF *conf, BIO *in, long *out_error_line) {
371 static const size_t CONFBUFSIZE = 512;
372 int bufnum = 0, i, ii;
373 BUF_MEM *buff = NULL;
374 char *s, *p, *end;
375 int again;
376 long eline = 0;
377 CONF_VALUE *v = NULL;
378 CONF_SECTION *sv = NULL;
379 char *section = NULL, *buf;
380 char *start, *psection, *pname;
381
382 if ((buff = BUF_MEM_new()) == NULL) {
383 OPENSSL_PUT_ERROR(CONF, ERR_R_BUF_LIB);
384 goto err;
385 }
386
387 section = OPENSSL_strdup(kDefaultSectionName);
388 if (section == NULL) {
389 goto err;
390 }
391
392 sv = NCONF_new_section(conf, section);
393 if (sv == NULL) {
394 OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
395 goto err;
396 }
397
398 bufnum = 0;
399 again = 0;
400 for (;;) {
401 if (!BUF_MEM_grow(buff, bufnum + CONFBUFSIZE)) {
402 OPENSSL_PUT_ERROR(CONF, ERR_R_BUF_LIB);
403 goto err;
404 }
405 p = &(buff->data[bufnum]);
406 *p = '\0';
407 BIO_gets(in, p, CONFBUFSIZE - 1);
408 p[CONFBUFSIZE - 1] = '\0';
409 ii = i = strlen(p);
410 if (i == 0 && !again) {
411 break;
412 }
413 again = 0;
414 while (i > 0) {
415 if ((p[i - 1] != '\r') && (p[i - 1] != '\n')) {
416 break;
417 } else {
418 i--;
419 }
420 }
421 // we removed some trailing stuff so there is a new
422 // line on the end.
423 if (ii && i == ii) {
424 again = 1; // long line
425 } else {
426 p[i] = '\0';
427 eline++; // another input line
428 }
429
430 // we now have a line with trailing \r\n removed
431
432 // i is the number of bytes
433 bufnum += i;
434
435 v = NULL;
436 // check for line continuation
437 if (bufnum >= 1) {
438 // If we have bytes and the last char '\\' and
439 // second last char is not '\\'
440 p = &(buff->data[bufnum - 1]);
441 if (is_esc(p[0]) && ((bufnum <= 1) || !is_esc(p[-1]))) {
442 bufnum--;
443 again = 1;
444 }
445 }
446 if (again) {
447 continue;
448 }
449 bufnum = 0;
450 buf = buff->data;
451
452 clear_comments(buf);
453 s = eat_ws(buf);
454 if (*s == '\0') {
455 continue; // blank line
456 }
457 if (*s == '[') {
458 char *ss;
459
460 s++;
461 start = eat_ws(s);
462 ss = start;
463 again:
464 end = eat_name(ss);
465 p = eat_ws(end);
466 if (*p != ']') {
467 if (*p != '\0' && ss != p) {
468 ss = p;
469 goto again;
470 }
471 OPENSSL_PUT_ERROR(CONF, CONF_R_MISSING_CLOSE_SQUARE_BRACKET);
472 goto err;
473 }
474 *end = '\0';
475 if (!str_copy(conf, NULL, §ion, start)) {
476 goto err;
477 }
478 if ((sv = get_section(conf, section)) == NULL) {
479 sv = NCONF_new_section(conf, section);
480 }
481 if (sv == NULL) {
482 OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
483 goto err;
484 }
485 continue;
486 } else {
487 pname = s;
488 psection = NULL;
489 end = eat_name(s);
490 if ((end[0] == ':') && (end[1] == ':')) {
491 *end = '\0';
492 end += 2;
493 psection = pname;
494 pname = end;
495 end = eat_name(end);
496 }
497 p = eat_ws(end);
498 if (*p != '=') {
499 OPENSSL_PUT_ERROR(CONF, CONF_R_MISSING_EQUAL_SIGN);
500 goto err;
501 }
502 *end = '\0';
503 p++;
504 start = eat_ws(p);
505 while (*p != '\0') {
506 p++;
507 }
508 p--;
509 while (p != start && is_conf_ws(*p)) {
510 p--;
511 }
512 p++;
513 *p = '\0';
514
515 if (!(v = CONF_VALUE_new())) {
516 goto err;
517 }
518 if (psection == NULL) {
519 psection = section;
520 }
521 v->name = OPENSSL_strdup(pname);
522 if (v->name == NULL) {
523 goto err;
524 }
525 if (!str_copy(conf, psection, &(v->value), start)) {
526 goto err;
527 }
528
529 CONF_SECTION *tv;
530 if (strcmp(psection, section) != 0) {
531 if ((tv = get_section(conf, psection)) == NULL) {
532 tv = NCONF_new_section(conf, psection);
533 }
534 if (tv == NULL) {
535 OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
536 goto err;
537 }
538 } else {
539 tv = sv;
540 }
541 if (add_string(conf, tv, v) == 0) {
542 goto err;
543 }
544 v = NULL;
545 }
546 }
547 BUF_MEM_free(buff);
548 OPENSSL_free(section);
549 return 1;
550
551 err:
552 BUF_MEM_free(buff);
553 OPENSSL_free(section);
554 if (out_error_line != NULL) {
555 *out_error_line = eline;
556 }
557 ERR_add_error_dataf("line %ld", eline);
558 value_free(v);
559 return 0;
560 }
561
NCONF_load(CONF * conf,const char * filename,long * out_error_line)562 int NCONF_load(CONF *conf, const char *filename, long *out_error_line) {
563 BIO *in = BIO_new_file(filename, "rb");
564 int ret;
565
566 if (in == NULL) {
567 OPENSSL_PUT_ERROR(CONF, ERR_R_SYS_LIB);
568 return 0;
569 }
570
571 ret = NCONF_load_bio(conf, in, out_error_line);
572 BIO_free(in);
573
574 return ret;
575 }
576
CONF_parse_list(const char * list,char sep,int remove_whitespace,int (* list_cb)(const char * elem,size_t len,void * usr),void * arg)577 int CONF_parse_list(const char *list, char sep, int remove_whitespace,
578 int (*list_cb)(const char *elem, size_t len, void *usr),
579 void *arg) {
580 int ret;
581 const char *lstart, *tmpend, *p;
582
583 if (list == NULL) {
584 OPENSSL_PUT_ERROR(CONF, CONF_R_LIST_CANNOT_BE_NULL);
585 return 0;
586 }
587
588 lstart = list;
589 for (;;) {
590 if (remove_whitespace) {
591 while (*lstart && OPENSSL_isspace((unsigned char)*lstart)) {
592 lstart++;
593 }
594 }
595 p = strchr(lstart, sep);
596 if (p == lstart || !*lstart) {
597 ret = list_cb(NULL, 0, arg);
598 } else {
599 if (p) {
600 tmpend = p - 1;
601 } else {
602 tmpend = lstart + strlen(lstart) - 1;
603 }
604 if (remove_whitespace) {
605 while (OPENSSL_isspace((unsigned char)*tmpend)) {
606 tmpend--;
607 }
608 }
609 ret = list_cb(lstart, tmpend - lstart + 1, arg);
610 }
611 if (ret <= 0) {
612 return ret;
613 }
614 if (p == NULL) {
615 return 1;
616 }
617 lstart = p + 1;
618 }
619 }
620
CONF_modules_load_file(const char * filename,const char * appname,unsigned long flags)621 int CONF_modules_load_file(const char *filename, const char *appname,
622 unsigned long flags) {
623 return 1;
624 }
625
CONF_modules_unload(int all)626 void CONF_modules_unload(int all) {}
627
CONF_modules_free(void)628 void CONF_modules_free(void) {}
629
OPENSSL_config(const char * config_name)630 void OPENSSL_config(const char *config_name) {}
631
OPENSSL_no_config(void)632 void OPENSSL_no_config(void) {}
633