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, &section, 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