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