• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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 
str_copy(CONF * conf,char * section,char ** pto,char * from)186 static int str_copy(CONF *conf, char *section, char **pto, char *from) {
187   int q, to = 0, len = 0;
188   char v;
189   BUF_MEM *buf;
190 
191   buf = BUF_MEM_new();
192   if (buf == NULL) {
193     return 0;
194   }
195 
196   len = strlen(from) + 1;
197   if (!BUF_MEM_grow(buf, len)) {
198     goto err;
199   }
200 
201   for (;;) {
202     if (IS_QUOTE(conf, *from)) {
203       q = *from;
204       from++;
205       while (!IS_EOF(conf, *from) && (*from != q)) {
206         if (IS_ESC(conf, *from)) {
207           from++;
208           if (IS_EOF(conf, *from)) {
209             break;
210           }
211         }
212         buf->data[to++] = *(from++);
213       }
214       if (*from == q) {
215         from++;
216       }
217     } else if (IS_ESC(conf, *from)) {
218       from++;
219       v = *(from++);
220       if (IS_EOF(conf, v)) {
221         break;
222       } else if (v == 'r') {
223         v = '\r';
224       } else if (v == 'n') {
225         v = '\n';
226       } else if (v == 'b') {
227         v = '\b';
228       } else if (v == 't') {
229         v = '\t';
230       }
231       buf->data[to++] = v;
232     } else if (IS_EOF(conf, *from)) {
233       break;
234     } else if (*from == '$') {
235       // Historically, $foo would expand to a previously-parsed value. This
236       // feature has been removed as it was unused and is a DoS vector. If
237       // trying to embed '$' in a line, either escape it or wrap the value in
238       // quotes.
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_SECTION *get_section(const CONF *conf, const char *section) {
258   CONF_SECTION template;
259   OPENSSL_memset(&template, 0, sizeof(template));
260   template.name = (char *) section;
261   return lh_CONF_SECTION_retrieve(conf->sections, &template);
262 }
263 
STACK_OF(CONF_VALUE)264 const STACK_OF(CONF_VALUE) *NCONF_get_section(const CONF *conf,
265                                               const char *section) {
266   const CONF_SECTION *section_obj = get_section(conf, section);
267   if (section_obj == NULL) {
268     return NULL;
269   }
270   return section_obj->values;
271 }
272 
NCONF_get_string(const CONF * conf,const char * section,const char * name)273 const char *NCONF_get_string(const CONF *conf, const char *section,
274                              const char *name) {
275   CONF_VALUE template, *value;
276 
277   if (section == NULL) {
278     section = kDefaultSectionName;
279   }
280 
281   OPENSSL_memset(&template, 0, sizeof(template));
282   template.section = (char *)section;
283   template.name = (char *)name;
284   value = lh_CONF_VALUE_retrieve(conf->values, &template);
285   if (value == NULL) {
286     return NULL;
287   }
288   return value->value;
289 }
290 
add_string(const CONF * conf,CONF_SECTION * section,CONF_VALUE * value)291 static int add_string(const CONF *conf, CONF_SECTION *section,
292                       CONF_VALUE *value) {
293   value->section = OPENSSL_strdup(section->name);
294   if (value->section == NULL) {
295     return 0;
296   }
297 
298   if (!sk_CONF_VALUE_push(section->values, value)) {
299     return 0;
300   }
301 
302   CONF_VALUE *old_value;
303   if (!lh_CONF_VALUE_insert(conf->values, &old_value, value)) {
304     // Remove |value| from |section->values|, so we do not leave a dangling
305     // pointer.
306     sk_CONF_VALUE_pop(section->values);
307     return 0;
308   }
309   if (old_value != NULL) {
310     (void)sk_CONF_VALUE_delete_ptr(section->values, old_value);
311     value_free(old_value);
312   }
313 
314   return 1;
315 }
316 
eat_ws(CONF * conf,char * p)317 static char *eat_ws(CONF *conf, char *p) {
318   while (IS_WS(conf, *p) && !IS_EOF(conf, *p)) {
319     p++;
320   }
321   return p;
322 }
323 
324 #define scan_esc(conf, p) (((IS_EOF((conf), (p)[1])) ? ((p) + 1) : ((p) + 2)))
325 
eat_alpha_numeric(CONF * conf,char * p)326 static char *eat_alpha_numeric(CONF *conf, char *p) {
327   for (;;) {
328     if (IS_ESC(conf, *p)) {
329       p = scan_esc(conf, p);
330       continue;
331     }
332     if (!IS_ALPHA_NUMERIC_PUNCT(conf, *p)) {
333       return p;
334     }
335     p++;
336   }
337 }
338 
scan_quote(CONF * conf,char * p)339 static char *scan_quote(CONF *conf, char *p) {
340   int q = *p;
341 
342   p++;
343   while (!IS_EOF(conf, *p) && *p != q) {
344     if (IS_ESC(conf, *p)) {
345       p++;
346       if (IS_EOF(conf, *p)) {
347         return p;
348       }
349     }
350     p++;
351   }
352   if (*p == q) {
353     p++;
354   }
355   return p;
356 }
357 
clear_comments(CONF * conf,char * p)358 static void clear_comments(CONF *conf, char *p) {
359   for (;;) {
360     if (!IS_WS(conf, *p)) {
361       break;
362     }
363     p++;
364   }
365 
366   for (;;) {
367     if (IS_COMMENT(conf, *p)) {
368       *p = '\0';
369       return;
370     }
371     if (IS_QUOTE(conf, *p)) {
372       p = scan_quote(conf, p);
373       continue;
374     }
375     if (IS_ESC(conf, *p)) {
376       p = scan_esc(conf, p);
377       continue;
378     }
379     if (IS_EOF(conf, *p)) {
380       return;
381     } else {
382       p++;
383     }
384   }
385 }
386 
NCONF_load_bio(CONF * conf,BIO * in,long * out_error_line)387 int NCONF_load_bio(CONF *conf, BIO *in, long *out_error_line) {
388   static const size_t CONFBUFSIZE = 512;
389   int bufnum = 0, i, ii;
390   BUF_MEM *buff = NULL;
391   char *s, *p, *end;
392   int again;
393   long eline = 0;
394   char btmp[DECIMAL_SIZE(eline) + 1];
395   CONF_VALUE *v = NULL;
396   CONF_SECTION *sv = NULL;
397   char *section = NULL, *buf;
398   char *start, *psection, *pname;
399 
400   if ((buff = BUF_MEM_new()) == NULL) {
401     OPENSSL_PUT_ERROR(CONF, ERR_R_BUF_LIB);
402     goto err;
403   }
404 
405   section = OPENSSL_strdup(kDefaultSectionName);
406   if (section == NULL) {
407     goto err;
408   }
409 
410   sv = NCONF_new_section(conf, section);
411   if (sv == NULL) {
412     OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
413     goto err;
414   }
415 
416   bufnum = 0;
417   again = 0;
418   for (;;) {
419     if (!BUF_MEM_grow(buff, bufnum + CONFBUFSIZE)) {
420       OPENSSL_PUT_ERROR(CONF, ERR_R_BUF_LIB);
421       goto err;
422     }
423     p = &(buff->data[bufnum]);
424     *p = '\0';
425     BIO_gets(in, p, CONFBUFSIZE - 1);
426     p[CONFBUFSIZE - 1] = '\0';
427     ii = i = strlen(p);
428     if (i == 0 && !again) {
429       break;
430     }
431     again = 0;
432     while (i > 0) {
433       if ((p[i - 1] != '\r') && (p[i - 1] != '\n')) {
434         break;
435       } else {
436         i--;
437       }
438     }
439     // we removed some trailing stuff so there is a new
440     // line on the end.
441     if (ii && i == ii) {
442       again = 1;  // long line
443     } else {
444       p[i] = '\0';
445       eline++;  // another input line
446     }
447 
448     // we now have a line with trailing \r\n removed
449 
450     // i is the number of bytes
451     bufnum += i;
452 
453     v = NULL;
454     // check for line continuation
455     if (bufnum >= 1) {
456       // If we have bytes and the last char '\\' and
457       // second last char is not '\\'
458       p = &(buff->data[bufnum - 1]);
459       if (IS_ESC(conf, p[0]) && ((bufnum <= 1) || !IS_ESC(conf, p[-1]))) {
460         bufnum--;
461         again = 1;
462       }
463     }
464     if (again) {
465       continue;
466     }
467     bufnum = 0;
468     buf = buff->data;
469 
470     clear_comments(conf, buf);
471     s = eat_ws(conf, buf);
472     if (IS_EOF(conf, *s)) {
473       continue;  // blank line
474     }
475     if (*s == '[') {
476       char *ss;
477 
478       s++;
479       start = eat_ws(conf, s);
480       ss = start;
481     again:
482       end = eat_alpha_numeric(conf, ss);
483       p = eat_ws(conf, end);
484       if (*p != ']') {
485         if (*p != '\0' && ss != p) {
486           ss = p;
487           goto again;
488         }
489         OPENSSL_PUT_ERROR(CONF, CONF_R_MISSING_CLOSE_SQUARE_BRACKET);
490         goto err;
491       }
492       *end = '\0';
493       if (!str_copy(conf, NULL, &section, start)) {
494         goto err;
495       }
496       if ((sv = get_section(conf, section)) == NULL) {
497         sv = NCONF_new_section(conf, section);
498       }
499       if (sv == NULL) {
500         OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
501         goto err;
502       }
503       continue;
504     } else {
505       pname = s;
506       psection = NULL;
507       end = eat_alpha_numeric(conf, s);
508       if ((end[0] == ':') && (end[1] == ':')) {
509         *end = '\0';
510         end += 2;
511         psection = pname;
512         pname = end;
513         end = eat_alpha_numeric(conf, end);
514       }
515       p = eat_ws(conf, end);
516       if (*p != '=') {
517         OPENSSL_PUT_ERROR(CONF, CONF_R_MISSING_EQUAL_SIGN);
518         goto err;
519       }
520       *end = '\0';
521       p++;
522       start = eat_ws(conf, p);
523       while (!IS_EOF(conf, *p)) {
524         p++;
525       }
526       p--;
527       while ((p != start) && (IS_WS(conf, *p))) {
528         p--;
529       }
530       p++;
531       *p = '\0';
532 
533       if (!(v = CONF_VALUE_new())) {
534         goto err;
535       }
536       if (psection == NULL) {
537         psection = section;
538       }
539       v->name = OPENSSL_strdup(pname);
540       if (v->name == NULL) {
541         goto err;
542       }
543       if (!str_copy(conf, psection, &(v->value), start)) {
544         goto err;
545       }
546 
547       CONF_SECTION *tv;
548       if (strcmp(psection, section) != 0) {
549         if ((tv = get_section(conf, psection)) == NULL) {
550           tv = NCONF_new_section(conf, psection);
551         }
552         if (tv == NULL) {
553           OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
554           goto err;
555         }
556       } else {
557         tv = sv;
558       }
559       if (add_string(conf, tv, v) == 0) {
560         goto err;
561       }
562       v = NULL;
563     }
564   }
565   BUF_MEM_free(buff);
566   OPENSSL_free(section);
567   return 1;
568 
569 err:
570   BUF_MEM_free(buff);
571   OPENSSL_free(section);
572   if (out_error_line != NULL) {
573     *out_error_line = eline;
574   }
575   snprintf(btmp, sizeof btmp, "%ld", eline);
576   ERR_add_error_data(2, "line ", btmp);
577   value_free(v);
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