Home | History | Annotate | Download | only in conf
      1 /* Copyright (C) 1995-1998 Eric Young (eay (at) cryptsoft.com)
      2  * All rights reserved.
      3  *
      4  * This package is an SSL implementation written
      5  * by Eric Young (eay (at) 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 (at) 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 (at) 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 (at) 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/mem.h>
     66 
     67 #include "conf_def.h"
     68 #include "internal.h"
     69 #include "../internal.h"
     70 
     71 
     72 // The maximum length we can grow a value to after variable expansion. 64k
     73 // should be more than enough for all reasonable uses.
     74 #define MAX_CONF_VALUE_LENGTH 65536
     75 
     76 static uint32_t conf_value_hash(const CONF_VALUE *v) {
     77   return (lh_strhash(v->section) << 2) ^ lh_strhash(v->name);
     78 }
     79 
     80 static int conf_value_cmp(const CONF_VALUE *a, const CONF_VALUE *b) {
     81   int i;
     82 
     83   if (a->section != b->section) {
     84     i = strcmp(a->section, b->section);
     85     if (i) {
     86       return i;
     87     }
     88   }
     89 
     90   if (a->name != NULL && b->name != NULL) {
     91     return strcmp(a->name, b->name);
     92   } else if (a->name == b->name) {
     93     return 0;
     94   } else {
     95     return (a->name == NULL) ? -1 : 1;
     96   }
     97 }
     98 
     99 CONF *NCONF_new(void *method) {
    100   CONF *conf;
    101 
    102   if (method != NULL) {
    103     return NULL;
    104   }
    105 
    106   conf = OPENSSL_malloc(sizeof(CONF));
    107   if (conf == NULL) {
    108     return NULL;
    109   }
    110 
    111   conf->data = lh_CONF_VALUE_new(conf_value_hash, conf_value_cmp);
    112   if (conf->data == NULL) {
    113     OPENSSL_free(conf);
    114     return NULL;
    115   }
    116 
    117   return conf;
    118 }
    119 
    120 CONF_VALUE *CONF_VALUE_new(void) {
    121   CONF_VALUE *v = OPENSSL_malloc(sizeof(CONF_VALUE));
    122   if (!v) {
    123     OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE);
    124     return NULL;
    125   }
    126   OPENSSL_memset(v, 0, sizeof(CONF_VALUE));
    127   return v;
    128 }
    129 
    130 static void value_free_contents(CONF_VALUE *value) {
    131   if (value->section) {
    132     OPENSSL_free(value->section);
    133   }
    134   if (value->name) {
    135     OPENSSL_free(value->name);
    136     if (value->value) {
    137       OPENSSL_free(value->value);
    138     }
    139   } else {
    140     if (value->value) {
    141       sk_CONF_VALUE_free((STACK_OF(CONF_VALUE)*)value->value);
    142     }
    143   }
    144 }
    145 
    146 static void value_free(CONF_VALUE *value) {
    147   value_free_contents(value);
    148   OPENSSL_free(value);
    149 }
    150 
    151 void NCONF_free(CONF *conf) {
    152   if (conf == NULL || conf->data == NULL) {
    153     return;
    154   }
    155 
    156   lh_CONF_VALUE_doall(conf->data, value_free);
    157   lh_CONF_VALUE_free(conf->data);
    158   OPENSSL_free(conf);
    159 }
    160 
    161 static CONF_VALUE *NCONF_new_section(const CONF *conf, const char *section) {
    162   STACK_OF(CONF_VALUE) *sk = NULL;
    163   int ok = 0;
    164   CONF_VALUE *v = NULL, *old_value;
    165 
    166   sk = sk_CONF_VALUE_new_null();
    167   v = CONF_VALUE_new();
    168   if (sk == NULL || v == NULL) {
    169     goto err;
    170   }
    171   v->section = OPENSSL_strdup(section);
    172   if (v->section == NULL) {
    173     goto err;
    174   }
    175 
    176   v->name = NULL;
    177   v->value = (char *)sk;
    178 
    179   if (!lh_CONF_VALUE_insert(conf->data, &old_value, v)) {
    180     goto err;
    181   }
    182   if (old_value) {
    183     value_free(old_value);
    184   }
    185   ok = 1;
    186 
    187 err:
    188   if (!ok) {
    189     if (sk != NULL) {
    190       sk_CONF_VALUE_free(sk);
    191     }
    192     if (v != NULL) {
    193       OPENSSL_free(v);
    194     }
    195     v = NULL;
    196   }
    197   return v;
    198 }
    199 
    200 static int str_copy(CONF *conf, char *section, char **pto, char *from) {
    201   int q, r, rr = 0, to = 0, len = 0;
    202   char *s, *e, *rp, *rrp, *np, *cp, v;
    203   const char *p;
    204   BUF_MEM *buf;
    205 
    206   buf = BUF_MEM_new();
    207   if (buf == NULL) {
    208     return 0;
    209   }
    210 
    211   len = strlen(from) + 1;
    212   if (!BUF_MEM_grow(buf, len)) {
    213     goto err;
    214   }
    215 
    216   for (;;) {
    217     if (IS_QUOTE(conf, *from)) {
    218       q = *from;
    219       from++;
    220       while (!IS_EOF(conf, *from) && (*from != q)) {
    221         if (IS_ESC(conf, *from)) {
    222           from++;
    223           if (IS_EOF(conf, *from)) {
    224             break;
    225           }
    226         }
    227         buf->data[to++] = *(from++);
    228       }
    229       if (*from == q) {
    230         from++;
    231       }
    232     } else if (IS_DQUOTE(conf, *from)) {
    233       q = *from;
    234       from++;
    235       while (!IS_EOF(conf, *from)) {
    236         if (*from == q) {
    237           if (*(from + 1) == q) {
    238             from++;
    239           } else {
    240             break;
    241           }
    242         }
    243         buf->data[to++] = *(from++);
    244       }
    245       if (*from == q) {
    246         from++;
    247       }
    248     } else if (IS_ESC(conf, *from)) {
    249       from++;
    250       v = *(from++);
    251       if (IS_EOF(conf, v)) {
    252         break;
    253       } else if (v == 'r') {
    254         v = '\r';
    255       } else if (v == 'n') {
    256         v = '\n';
    257       } else if (v == 'b') {
    258         v = '\b';
    259       } else if (v == 't') {
    260         v = '\t';
    261       }
    262       buf->data[to++] = v;
    263     } else if (IS_EOF(conf, *from)) {
    264       break;
    265     } else if (*from == '$') {
    266       // try to expand it
    267       rrp = NULL;
    268       s = &(from[1]);
    269       if (*s == '{') {
    270         q = '}';
    271       } else if (*s == '(') {
    272         q = ')';
    273       } else {
    274         q = 0;
    275       }
    276 
    277       if (q) {
    278         s++;
    279       }
    280       cp = section;
    281       e = np = s;
    282       while (IS_ALPHA_NUMERIC(conf, *e)) {
    283         e++;
    284       }
    285       if (e[0] == ':' && e[1] == ':') {
    286         cp = np;
    287         rrp = e;
    288         rr = *e;
    289         *rrp = '\0';
    290         e += 2;
    291         np = e;
    292         while (IS_ALPHA_NUMERIC(conf, *e)) {
    293           e++;
    294         }
    295       }
    296       r = *e;
    297       *e = '\0';
    298       rp = e;
    299       if (q) {
    300         if (r != q) {
    301           OPENSSL_PUT_ERROR(CONF, CONF_R_NO_CLOSE_BRACE);
    302           goto err;
    303         }
    304         e++;
    305       }
    306       // So at this point we have
    307       // np which is the start of the name string which is
    308       //   '\0' terminated.
    309       // cp which is the start of the section string which is
    310       //   '\0' terminated.
    311       // e is the 'next point after'.
    312       // r and rr are the chars replaced by the '\0'
    313       // rp and rrp is where 'r' and 'rr' came from.
    314       p = NCONF_get_string(conf, cp, np);
    315       if (rrp != NULL) {
    316         *rrp = rr;
    317       }
    318       *rp = r;
    319       if (p == NULL) {
    320         OPENSSL_PUT_ERROR(CONF, CONF_R_VARIABLE_HAS_NO_VALUE);
    321         goto err;
    322       }
    323       size_t newsize = strlen(p) + buf->length - (e - from);
    324       if (newsize > MAX_CONF_VALUE_LENGTH) {
    325         OPENSSL_PUT_ERROR(CONF, CONF_R_VARIABLE_EXPANSION_TOO_LONG);
    326         goto err;
    327       }
    328       if (!BUF_MEM_grow_clean(buf, newsize)) {
    329         OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE);
    330         goto err;
    331       }
    332       while (*p) {
    333         buf->data[to++] = *(p++);
    334       }
    335 
    336       /* Since we change the pointer 'from', we also have
    337          to change the perceived length of the string it
    338          points at.  /RL */
    339       len -= e - from;
    340       from = e;
    341 
    342       /* In case there were no braces or parenthesis around
    343          the variable reference, we have to put back the
    344          character that was replaced with a '\0'.  /RL */
    345       *rp = r;
    346     } else {
    347       buf->data[to++] = *(from++);
    348     }
    349   }
    350 
    351   buf->data[to] = '\0';
    352   if (*pto != NULL) {
    353     OPENSSL_free(*pto);
    354   }
    355   *pto = buf->data;
    356   OPENSSL_free(buf);
    357   return 1;
    358 
    359 err:
    360   if (buf != NULL) {
    361     BUF_MEM_free(buf);
    362   }
    363   return 0;
    364 }
    365 
    366 static CONF_VALUE *get_section(const CONF *conf, const char *section) {
    367   CONF_VALUE template;
    368 
    369   OPENSSL_memset(&template, 0, sizeof(template));
    370   template.section = (char *) section;
    371   return lh_CONF_VALUE_retrieve(conf->data, &template);
    372 }
    373 
    374 STACK_OF(CONF_VALUE) *NCONF_get_section(const CONF *conf, const char *section) {
    375   CONF_VALUE *section_value = get_section(conf, section);
    376   if (section_value == NULL) {
    377     return NULL;
    378   }
    379   return (STACK_OF(CONF_VALUE)*) section_value->value;
    380 }
    381 
    382 const char *NCONF_get_string(const CONF *conf, const char *section,
    383                              const char *name) {
    384   CONF_VALUE template, *value;
    385 
    386   OPENSSL_memset(&template, 0, sizeof(template));
    387   template.section = (char *) section;
    388   template.name = (char *) name;
    389   value = lh_CONF_VALUE_retrieve(conf->data, &template);
    390   if (value == NULL) {
    391     return NULL;
    392   }
    393   return value->value;
    394 }
    395 
    396 static int add_string(const CONF *conf, CONF_VALUE *section,
    397                       CONF_VALUE *value) {
    398   STACK_OF(CONF_VALUE) *section_stack = (STACK_OF(CONF_VALUE)*) section->value;
    399   CONF_VALUE *old_value;
    400 
    401   value->section = OPENSSL_strdup(section->section);
    402   if (!sk_CONF_VALUE_push(section_stack, value)) {
    403     return 0;
    404   }
    405 
    406   if (!lh_CONF_VALUE_insert(conf->data, &old_value, value)) {
    407     return 0;
    408   }
    409   if (old_value != NULL) {
    410     (void)sk_CONF_VALUE_delete_ptr(section_stack, old_value);
    411     value_free(old_value);
    412   }
    413 
    414   return 1;
    415 }
    416 
    417 static char *eat_ws(CONF *conf, char *p) {
    418   while (IS_WS(conf, *p) && !IS_EOF(conf, *p)) {
    419     p++;
    420   }
    421   return p;
    422 }
    423 
    424 #define scan_esc(conf, p) (((IS_EOF((conf), (p)[1])) ? ((p) + 1) : ((p) + 2)))
    425 
    426 static char *eat_alpha_numeric(CONF *conf, char *p) {
    427   for (;;) {
    428     if (IS_ESC(conf, *p)) {
    429       p = scan_esc(conf, p);
    430       continue;
    431     }
    432     if (!IS_ALPHA_NUMERIC_PUNCT(conf, *p)) {
    433       return p;
    434     }
    435     p++;
    436   }
    437 }
    438 
    439 static char *scan_quote(CONF *conf, char *p) {
    440   int q = *p;
    441 
    442   p++;
    443   while (!IS_EOF(conf, *p) && *p != q) {
    444     if (IS_ESC(conf, *p)) {
    445       p++;
    446       if (IS_EOF(conf, *p)) {
    447         return p;
    448       }
    449     }
    450     p++;
    451   }
    452   if (*p == q) {
    453     p++;
    454   }
    455   return p;
    456 }
    457 
    458 
    459 static char *scan_dquote(CONF *conf, char *p) {
    460   int q = *p;
    461 
    462   p++;
    463   while (!(IS_EOF(conf, *p))) {
    464     if (*p == q) {
    465       if (*(p + 1) == q) {
    466         p++;
    467       } else {
    468         break;
    469       }
    470     }
    471     p++;
    472   }
    473   if (*p == q) {
    474     p++;
    475   }
    476   return p;
    477 }
    478 
    479 static void clear_comments(CONF *conf, char *p) {
    480   for (;;) {
    481     if (IS_FCOMMENT(conf, *p)) {
    482       *p = '\0';
    483       return;
    484     }
    485     if (!IS_WS(conf, *p)) {
    486       break;
    487     }
    488     p++;
    489   }
    490 
    491   for (;;) {
    492     if (IS_COMMENT(conf, *p)) {
    493       *p = '\0';
    494       return;
    495     }
    496     if (IS_DQUOTE(conf, *p)) {
    497       p = scan_dquote(conf, p);
    498       continue;
    499     }
    500     if (IS_QUOTE(conf, *p)) {
    501       p = scan_quote(conf, p);
    502       continue;
    503     }
    504     if (IS_ESC(conf, *p)) {
    505       p = scan_esc(conf, p);
    506       continue;
    507     }
    508     if (IS_EOF(conf, *p)) {
    509       return;
    510     } else {
    511       p++;
    512     }
    513   }
    514 }
    515 
    516 static int def_load_bio(CONF *conf, BIO *in, long *out_error_line) {
    517   static const size_t CONFBUFSIZE = 512;
    518   int bufnum = 0, i, ii;
    519   BUF_MEM *buff = NULL;
    520   char *s, *p, *end;
    521   int again;
    522   long eline = 0;
    523   char btmp[DECIMAL_SIZE(eline) + 1];
    524   CONF_VALUE *v = NULL, *tv;
    525   CONF_VALUE *sv = NULL;
    526   char *section = NULL, *buf;
    527   char *start, *psection, *pname;
    528 
    529   if ((buff = BUF_MEM_new()) == NULL) {
    530     OPENSSL_PUT_ERROR(CONF, ERR_R_BUF_LIB);
    531     goto err;
    532   }
    533 
    534   section = OPENSSL_strdup("default");
    535   if (section == NULL) {
    536     OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE);
    537     goto err;
    538   }
    539 
    540   sv = NCONF_new_section(conf, section);
    541   if (sv == NULL) {
    542     OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
    543     goto err;
    544   }
    545 
    546   bufnum = 0;
    547   again = 0;
    548   for (;;) {
    549     if (!BUF_MEM_grow(buff, bufnum + CONFBUFSIZE)) {
    550       OPENSSL_PUT_ERROR(CONF, ERR_R_BUF_LIB);
    551       goto err;
    552     }
    553     p = &(buff->data[bufnum]);
    554     *p = '\0';
    555     BIO_gets(in, p, CONFBUFSIZE - 1);
    556     p[CONFBUFSIZE - 1] = '\0';
    557     ii = i = strlen(p);
    558     if (i == 0 && !again) {
    559       break;
    560     }
    561     again = 0;
    562     while (i > 0) {
    563       if ((p[i - 1] != '\r') && (p[i - 1] != '\n')) {
    564         break;
    565       } else {
    566         i--;
    567       }
    568     }
    569     // we removed some trailing stuff so there is a new
    570     // line on the end.
    571     if (ii && i == ii) {
    572       again = 1;  // long line
    573     } else {
    574       p[i] = '\0';
    575       eline++;  // another input line
    576     }
    577 
    578     // we now have a line with trailing \r\n removed
    579 
    580     // i is the number of bytes
    581     bufnum += i;
    582 
    583     v = NULL;
    584     // check for line continuation
    585     if (bufnum >= 1) {
    586       // If we have bytes and the last char '\\' and
    587       // second last char is not '\\'
    588       p = &(buff->data[bufnum - 1]);
    589       if (IS_ESC(conf, p[0]) && ((bufnum <= 1) || !IS_ESC(conf, p[-1]))) {
    590         bufnum--;
    591         again = 1;
    592       }
    593     }
    594     if (again) {
    595       continue;
    596     }
    597     bufnum = 0;
    598     buf = buff->data;
    599 
    600     clear_comments(conf, buf);
    601     s = eat_ws(conf, buf);
    602     if (IS_EOF(conf, *s)) {
    603       continue;  // blank line
    604     }
    605     if (*s == '[') {
    606       char *ss;
    607 
    608       s++;
    609       start = eat_ws(conf, s);
    610       ss = start;
    611     again:
    612       end = eat_alpha_numeric(conf, ss);
    613       p = eat_ws(conf, end);
    614       if (*p != ']') {
    615         if (*p != '\0' && ss != p) {
    616           ss = p;
    617           goto again;
    618         }
    619         OPENSSL_PUT_ERROR(CONF, CONF_R_MISSING_CLOSE_SQUARE_BRACKET);
    620         goto err;
    621       }
    622       *end = '\0';
    623       if (!str_copy(conf, NULL, &section, start)) {
    624         goto err;
    625       }
    626       if ((sv = get_section(conf, section)) == NULL) {
    627         sv = NCONF_new_section(conf, section);
    628       }
    629       if (sv == NULL) {
    630         OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
    631         goto err;
    632       }
    633       continue;
    634     } else {
    635       pname = s;
    636       psection = NULL;
    637       end = eat_alpha_numeric(conf, s);
    638       if ((end[0] == ':') && (end[1] == ':')) {
    639         *end = '\0';
    640         end += 2;
    641         psection = pname;
    642         pname = end;
    643         end = eat_alpha_numeric(conf, end);
    644       }
    645       p = eat_ws(conf, end);
    646       if (*p != '=') {
    647         OPENSSL_PUT_ERROR(CONF, CONF_R_MISSING_EQUAL_SIGN);
    648         goto err;
    649       }
    650       *end = '\0';
    651       p++;
    652       start = eat_ws(conf, p);
    653       while (!IS_EOF(conf, *p)) {
    654         p++;
    655       }
    656       p--;
    657       while ((p != start) && (IS_WS(conf, *p))) {
    658         p--;
    659       }
    660       p++;
    661       *p = '\0';
    662 
    663       if (!(v = CONF_VALUE_new())) {
    664         goto err;
    665       }
    666       if (psection == NULL) {
    667         psection = section;
    668       }
    669       v->name = OPENSSL_strdup(pname);
    670       if (v->name == NULL) {
    671         OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE);
    672         goto err;
    673       }
    674       if (!str_copy(conf, psection, &(v->value), start)) {
    675         goto err;
    676       }
    677 
    678       if (strcmp(psection, section) != 0) {
    679         if ((tv = get_section(conf, psection)) == NULL) {
    680           tv = NCONF_new_section(conf, psection);
    681         }
    682         if (tv == NULL) {
    683           OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
    684           goto err;
    685         }
    686       } else {
    687         tv = sv;
    688       }
    689       if (add_string(conf, tv, v) == 0) {
    690         OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE);
    691         goto err;
    692       }
    693       v = NULL;
    694     }
    695   }
    696   if (buff != NULL) {
    697     BUF_MEM_free(buff);
    698   }
    699   if (section != NULL) {
    700     OPENSSL_free(section);
    701   }
    702   return 1;
    703 
    704 err:
    705   if (buff != NULL) {
    706     BUF_MEM_free(buff);
    707   }
    708   if (section != NULL) {
    709     OPENSSL_free(section);
    710   }
    711   if (out_error_line != NULL) {
    712     *out_error_line = eline;
    713   }
    714   BIO_snprintf(btmp, sizeof btmp, "%ld", eline);
    715   ERR_add_error_data(2, "line ", btmp);
    716 
    717   if (v != NULL) {
    718     if (v->name != NULL) {
    719       OPENSSL_free(v->name);
    720     }
    721     if (v->value != NULL) {
    722       OPENSSL_free(v->value);
    723     }
    724     if (v != NULL) {
    725       OPENSSL_free(v);
    726     }
    727   }
    728   return 0;
    729 }
    730 
    731 int NCONF_load(CONF *conf, const char *filename, long *out_error_line) {
    732   BIO *in = BIO_new_file(filename, "rb");
    733   int ret;
    734 
    735   if (in == NULL) {
    736     OPENSSL_PUT_ERROR(CONF, ERR_R_SYS_LIB);
    737     return 0;
    738   }
    739 
    740   ret = def_load_bio(conf, in, out_error_line);
    741   BIO_free(in);
    742 
    743   return ret;
    744 }
    745 
    746 int NCONF_load_bio(CONF *conf, BIO *bio, long *out_error_line) {
    747   return def_load_bio(conf, bio, out_error_line);
    748 }
    749 
    750 int CONF_parse_list(const char *list, char sep, int remove_whitespace,
    751                     int (*list_cb)(const char *elem, int len, void *usr),
    752                     void *arg) {
    753   int ret;
    754   const char *lstart, *tmpend, *p;
    755 
    756   if (list == NULL) {
    757     OPENSSL_PUT_ERROR(CONF, CONF_R_LIST_CANNOT_BE_NULL);
    758     return 0;
    759   }
    760 
    761   lstart = list;
    762   for (;;) {
    763     if (remove_whitespace) {
    764       while (*lstart && isspace((unsigned char)*lstart)) {
    765         lstart++;
    766       }
    767     }
    768     p = strchr(lstart, sep);
    769     if (p == lstart || !*lstart) {
    770       ret = list_cb(NULL, 0, arg);
    771     } else {
    772       if (p) {
    773         tmpend = p - 1;
    774       } else {
    775         tmpend = lstart + strlen(lstart) - 1;
    776       }
    777       if (remove_whitespace) {
    778         while (isspace((unsigned char)*tmpend)) {
    779           tmpend--;
    780         }
    781       }
    782       ret = list_cb(lstart, tmpend - lstart + 1, arg);
    783     }
    784     if (ret <= 0) {
    785       return ret;
    786     }
    787     if (p == NULL) {
    788       return 1;
    789     }
    790     lstart = p + 1;
    791   }
    792 }
    793 
    794 int CONF_modules_load_file(const char *filename, const char *appname,
    795                            unsigned long flags) {
    796   return 1;
    797 }
    798 
    799 void CONF_modules_free(void) {}
    800 
    801 void OPENSSL_config(const char *config_name) {}
    802 
    803 void OPENSSL_no_config(void) {}
    804