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