conf_def.c revision 291721
1/* crypto/conf/conf.c */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved.
4 *
5 * This package is an SSL implementation written
6 * by Eric Young (eay@cryptsoft.com).
7 * The implementation was written so as to conform with Netscapes SSL.
8 *
9 * This library is free for commercial and non-commercial use as long as
10 * the following conditions are aheared to.  The following conditions
11 * apply to all code found in this distribution, be it the RC4, RSA,
12 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13 * included with this distribution is covered by the same copyright terms
14 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15 *
16 * Copyright remains Eric Young's, and as such any Copyright notices in
17 * the code are not to be removed.
18 * If this package is used in a product, Eric Young should be given attribution
19 * as the author of the parts of the library used.
20 * This can be in the form of a textual message at program startup or
21 * in documentation (online or textual) provided with the package.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the copyright
27 *    notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 *    notice, this list of conditions and the following disclaimer in the
30 *    documentation and/or other materials provided with the distribution.
31 * 3. All advertising materials mentioning features or use of this software
32 *    must display the following acknowledgement:
33 *    "This product includes cryptographic software written by
34 *     Eric Young (eay@cryptsoft.com)"
35 *    The word 'cryptographic' can be left out if the rouines from the library
36 *    being used are not cryptographic related :-).
37 * 4. If you include any Windows specific code (or a derivative thereof) from
38 *    the apps directory (application code) you must include an acknowledgement:
39 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40 *
41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 * SUCH DAMAGE.
52 *
53 * The licence and distribution terms for any publically available version or
54 * derivative of this code cannot be changed.  i.e. this code cannot simply be
55 * copied and put under another distribution licence
56 * [including the GNU Public Licence.]
57 */
58
59/* Part of the code in here was originally in conf.c, which is now removed */
60
61#include <stdio.h>
62#include <string.h>
63#include "cryptlib.h"
64#include <openssl/stack.h>
65#include <openssl/lhash.h>
66#include <openssl/conf.h>
67#include <openssl/conf_api.h>
68#include "conf_def.h"
69#include <openssl/buffer.h>
70#include <openssl/err.h>
71
72static char *eat_ws(CONF *conf, char *p);
73static char *eat_alpha_numeric(CONF *conf, char *p);
74static void clear_comments(CONF *conf, char *p);
75static int str_copy(CONF *conf, char *section, char **to, char *from);
76static char *scan_quote(CONF *conf, char *p);
77static char *scan_dquote(CONF *conf, char *p);
78#define scan_esc(conf,p)        (((IS_EOF((conf),(p)[1]))?((p)+1):((p)+2)))
79
80static CONF *def_create(CONF_METHOD *meth);
81static int def_init_default(CONF *conf);
82static int def_init_WIN32(CONF *conf);
83static int def_destroy(CONF *conf);
84static int def_destroy_data(CONF *conf);
85static int def_load(CONF *conf, const char *name, long *eline);
86static int def_load_bio(CONF *conf, BIO *bp, long *eline);
87static int def_dump(const CONF *conf, BIO *bp);
88static int def_is_number(const CONF *conf, char c);
89static int def_to_int(const CONF *conf, char c);
90
91const char CONF_def_version[] = "CONF_def" OPENSSL_VERSION_PTEXT;
92
93static CONF_METHOD default_method = {
94    "OpenSSL default",
95    def_create,
96    def_init_default,
97    def_destroy,
98    def_destroy_data,
99    def_load_bio,
100    def_dump,
101    def_is_number,
102    def_to_int,
103    def_load
104};
105
106static CONF_METHOD WIN32_method = {
107    "WIN32",
108    def_create,
109    def_init_WIN32,
110    def_destroy,
111    def_destroy_data,
112    def_load_bio,
113    def_dump,
114    def_is_number,
115    def_to_int,
116    def_load
117};
118
119CONF_METHOD *NCONF_default()
120{
121    return &default_method;
122}
123
124CONF_METHOD *NCONF_WIN32()
125{
126    return &WIN32_method;
127}
128
129static CONF *def_create(CONF_METHOD *meth)
130{
131    CONF *ret;
132
133    ret = OPENSSL_malloc(sizeof(CONF) + sizeof(unsigned short *));
134    if (ret)
135        if (meth->init(ret) == 0) {
136            OPENSSL_free(ret);
137            ret = NULL;
138        }
139    return ret;
140}
141
142static int def_init_default(CONF *conf)
143{
144    if (conf == NULL)
145        return 0;
146
147    conf->meth = &default_method;
148    conf->meth_data = CONF_type_default;
149    conf->data = NULL;
150
151    return 1;
152}
153
154static int def_init_WIN32(CONF *conf)
155{
156    if (conf == NULL)
157        return 0;
158
159    conf->meth = &WIN32_method;
160    conf->meth_data = (void *)CONF_type_win32;
161    conf->data = NULL;
162
163    return 1;
164}
165
166static int def_destroy(CONF *conf)
167{
168    if (def_destroy_data(conf)) {
169        OPENSSL_free(conf);
170        return 1;
171    }
172    return 0;
173}
174
175static int def_destroy_data(CONF *conf)
176{
177    if (conf == NULL)
178        return 0;
179    _CONF_free_data(conf);
180    return 1;
181}
182
183static int def_load(CONF *conf, const char *name, long *line)
184{
185    int ret;
186    BIO *in = NULL;
187
188#ifdef OPENSSL_SYS_VMS
189    in = BIO_new_file(name, "r");
190#else
191    in = BIO_new_file(name, "rb");
192#endif
193    if (in == NULL) {
194        if (ERR_GET_REASON(ERR_peek_last_error()) == BIO_R_NO_SUCH_FILE)
195            CONFerr(CONF_F_DEF_LOAD, CONF_R_NO_SUCH_FILE);
196        else
197            CONFerr(CONF_F_DEF_LOAD, ERR_R_SYS_LIB);
198        return 0;
199    }
200
201    ret = def_load_bio(conf, in, line);
202    BIO_free(in);
203
204    return ret;
205}
206
207static int def_load_bio(CONF *conf, BIO *in, long *line)
208{
209/* The macro BUFSIZE conflicts with a system macro in VxWorks */
210#define CONFBUFSIZE     512
211    int bufnum = 0, i, ii;
212    BUF_MEM *buff = NULL;
213    char *s, *p, *end;
214    int again;
215    long eline = 0;
216    char btmp[DECIMAL_SIZE(eline) + 1];
217    CONF_VALUE *v = NULL, *tv;
218    CONF_VALUE *sv = NULL;
219    char *section = NULL, *buf;
220    char *start, *psection, *pname;
221    void *h = (void *)(conf->data);
222
223    if ((buff = BUF_MEM_new()) == NULL) {
224        CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_BUF_LIB);
225        goto err;
226    }
227
228    section = BUF_strdup("default");
229    if (section == NULL) {
230        CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE);
231        goto err;
232    }
233
234    if (_CONF_new_data(conf) == 0) {
235        CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE);
236        goto err;
237    }
238
239    sv = _CONF_new_section(conf, section);
240    if (sv == NULL) {
241        CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
242        goto err;
243    }
244
245    bufnum = 0;
246    again = 0;
247    for (;;) {
248        if (!BUF_MEM_grow(buff, bufnum + CONFBUFSIZE)) {
249            CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_BUF_LIB);
250            goto err;
251        }
252        p = &(buff->data[bufnum]);
253        *p = '\0';
254        BIO_gets(in, p, CONFBUFSIZE - 1);
255        p[CONFBUFSIZE - 1] = '\0';
256        ii = i = strlen(p);
257        if (i == 0 && !again)
258            break;
259        again = 0;
260        while (i > 0) {
261            if ((p[i - 1] != '\r') && (p[i - 1] != '\n'))
262                break;
263            else
264                i--;
265        }
266        /*
267         * we removed some trailing stuff so there is a new line on the end.
268         */
269        if (ii && i == ii)
270            again = 1;          /* long line */
271        else {
272            p[i] = '\0';
273            eline++;            /* another input line */
274        }
275
276        /* we now have a line with trailing \r\n removed */
277
278        /* i is the number of bytes */
279        bufnum += i;
280
281        v = NULL;
282        /* check for line continuation */
283        if (bufnum >= 1) {
284            /*
285             * If we have bytes and the last char '\\' and second last char
286             * is not '\\'
287             */
288            p = &(buff->data[bufnum - 1]);
289            if (IS_ESC(conf, p[0]) && ((bufnum <= 1) || !IS_ESC(conf, p[-1]))) {
290                bufnum--;
291                again = 1;
292            }
293        }
294        if (again)
295            continue;
296        bufnum = 0;
297        buf = buff->data;
298
299        clear_comments(conf, buf);
300        s = eat_ws(conf, buf);
301        if (IS_EOF(conf, *s))
302            continue;           /* blank line */
303        if (*s == '[') {
304            char *ss;
305
306            s++;
307            start = eat_ws(conf, s);
308            ss = start;
309 again:
310            end = eat_alpha_numeric(conf, ss);
311            p = eat_ws(conf, end);
312            if (*p != ']') {
313                if (*p != '\0' && ss != p) {
314                    ss = p;
315                    goto again;
316                }
317                CONFerr(CONF_F_DEF_LOAD_BIO,
318                        CONF_R_MISSING_CLOSE_SQUARE_BRACKET);
319                goto err;
320            }
321            *end = '\0';
322            if (!str_copy(conf, NULL, &section, start))
323                goto err;
324            if ((sv = _CONF_get_section(conf, section)) == NULL)
325                sv = _CONF_new_section(conf, section);
326            if (sv == NULL) {
327                CONFerr(CONF_F_DEF_LOAD_BIO,
328                        CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
329                goto err;
330            }
331            continue;
332        } else {
333            pname = s;
334            psection = NULL;
335            end = eat_alpha_numeric(conf, s);
336            if ((end[0] == ':') && (end[1] == ':')) {
337                *end = '\0';
338                end += 2;
339                psection = pname;
340                pname = end;
341                end = eat_alpha_numeric(conf, end);
342            }
343            p = eat_ws(conf, end);
344            if (*p != '=') {
345                CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_MISSING_EQUAL_SIGN);
346                goto err;
347            }
348            *end = '\0';
349            p++;
350            start = eat_ws(conf, p);
351            while (!IS_EOF(conf, *p))
352                p++;
353            p--;
354            while ((p != start) && (IS_WS(conf, *p)))
355                p--;
356            p++;
357            *p = '\0';
358
359            if (!(v = (CONF_VALUE *)OPENSSL_malloc(sizeof(CONF_VALUE)))) {
360                CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE);
361                goto err;
362            }
363            if (psection == NULL)
364                psection = section;
365            v->name = (char *)OPENSSL_malloc(strlen(pname) + 1);
366            v->value = NULL;
367            if (v->name == NULL) {
368                CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE);
369                goto err;
370            }
371            BUF_strlcpy(v->name, pname, strlen(pname) + 1);
372            if (!str_copy(conf, psection, &(v->value), start))
373                goto err;
374
375            if (strcmp(psection, section) != 0) {
376                if ((tv = _CONF_get_section(conf, psection))
377                    == NULL)
378                    tv = _CONF_new_section(conf, psection);
379                if (tv == NULL) {
380                    CONFerr(CONF_F_DEF_LOAD_BIO,
381                            CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
382                    goto err;
383                }
384            } else
385                tv = sv;
386#if 1
387            if (_CONF_add_string(conf, tv, v) == 0) {
388                CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE);
389                goto err;
390            }
391#else
392            v->section = tv->section;
393            if (!sk_CONF_VALUE_push(ts, v)) {
394                CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE);
395                goto err;
396            }
397            vv = (CONF_VALUE *)lh_insert(conf->data, v);
398            if (vv != NULL) {
399                sk_CONF_VALUE_delete_ptr(ts, vv);
400                OPENSSL_free(vv->name);
401                OPENSSL_free(vv->value);
402                OPENSSL_free(vv);
403            }
404#endif
405            v = NULL;
406        }
407    }
408    if (buff != NULL)
409        BUF_MEM_free(buff);
410    if (section != NULL)
411        OPENSSL_free(section);
412    return (1);
413 err:
414    if (buff != NULL)
415        BUF_MEM_free(buff);
416    if (section != NULL)
417        OPENSSL_free(section);
418    if (line != NULL)
419        *line = eline;
420    BIO_snprintf(btmp, sizeof btmp, "%ld", eline);
421    ERR_add_error_data(2, "line ", btmp);
422    if ((h != conf->data) && (conf->data != NULL)) {
423        CONF_free(conf->data);
424        conf->data = NULL;
425    }
426    if (v != NULL) {
427        if (v->name != NULL)
428            OPENSSL_free(v->name);
429        if (v->value != NULL)
430            OPENSSL_free(v->value);
431        if (v != NULL)
432            OPENSSL_free(v);
433    }
434    return (0);
435}
436
437static void clear_comments(CONF *conf, char *p)
438{
439    for (;;) {
440        if (IS_FCOMMENT(conf, *p)) {
441            *p = '\0';
442            return;
443        }
444        if (!IS_WS(conf, *p)) {
445            break;
446        }
447        p++;
448    }
449
450    for (;;) {
451        if (IS_COMMENT(conf, *p)) {
452            *p = '\0';
453            return;
454        }
455        if (IS_DQUOTE(conf, *p)) {
456            p = scan_dquote(conf, p);
457            continue;
458        }
459        if (IS_QUOTE(conf, *p)) {
460            p = scan_quote(conf, p);
461            continue;
462        }
463        if (IS_ESC(conf, *p)) {
464            p = scan_esc(conf, p);
465            continue;
466        }
467        if (IS_EOF(conf, *p))
468            return;
469        else
470            p++;
471    }
472}
473
474static int str_copy(CONF *conf, char *section, char **pto, char *from)
475{
476    int q, r, rr = 0, to = 0, len = 0;
477    char *s, *e, *rp, *p, *rrp, *np, *cp, v;
478    BUF_MEM *buf;
479
480    if ((buf = BUF_MEM_new()) == NULL)
481        return (0);
482
483    len = strlen(from) + 1;
484    if (!BUF_MEM_grow(buf, len))
485        goto err;
486
487    for (;;) {
488        if (IS_QUOTE(conf, *from)) {
489            q = *from;
490            from++;
491            while (!IS_EOF(conf, *from) && (*from != q)) {
492                if (IS_ESC(conf, *from)) {
493                    from++;
494                    if (IS_EOF(conf, *from))
495                        break;
496                }
497                buf->data[to++] = *(from++);
498            }
499            if (*from == q)
500                from++;
501        } else if (IS_DQUOTE(conf, *from)) {
502            q = *from;
503            from++;
504            while (!IS_EOF(conf, *from)) {
505                if (*from == q) {
506                    if (*(from + 1) == q) {
507                        from++;
508                    } else {
509                        break;
510                    }
511                }
512                buf->data[to++] = *(from++);
513            }
514            if (*from == q)
515                from++;
516        } else if (IS_ESC(conf, *from)) {
517            from++;
518            v = *(from++);
519            if (IS_EOF(conf, v))
520                break;
521            else if (v == 'r')
522                v = '\r';
523            else if (v == 'n')
524                v = '\n';
525            else if (v == 'b')
526                v = '\b';
527            else if (v == 't')
528                v = '\t';
529            buf->data[to++] = v;
530        } else if (IS_EOF(conf, *from))
531            break;
532        else if (*from == '$') {
533            /* try to expand it */
534            rrp = NULL;
535            s = &(from[1]);
536            if (*s == '{')
537                q = '}';
538            else if (*s == '(')
539                q = ')';
540            else
541                q = 0;
542
543            if (q)
544                s++;
545            cp = section;
546            e = np = s;
547            while (IS_ALPHA_NUMERIC(conf, *e))
548                e++;
549            if ((e[0] == ':') && (e[1] == ':')) {
550                cp = np;
551                rrp = e;
552                rr = *e;
553                *rrp = '\0';
554                e += 2;
555                np = e;
556                while (IS_ALPHA_NUMERIC(conf, *e))
557                    e++;
558            }
559            r = *e;
560            *e = '\0';
561            rp = e;
562            if (q) {
563                if (r != q) {
564                    CONFerr(CONF_F_STR_COPY, CONF_R_NO_CLOSE_BRACE);
565                    goto err;
566                }
567                e++;
568            }
569            /*-
570             * So at this point we have
571             * np which is the start of the name string which is
572             *   '\0' terminated.
573             * cp which is the start of the section string which is
574             *   '\0' terminated.
575             * e is the 'next point after'.
576             * r and rr are the chars replaced by the '\0'
577             * rp and rrp is where 'r' and 'rr' came from.
578             */
579            p = _CONF_get_string(conf, cp, np);
580            if (rrp != NULL)
581                *rrp = rr;
582            *rp = r;
583            if (p == NULL) {
584                CONFerr(CONF_F_STR_COPY, CONF_R_VARIABLE_HAS_NO_VALUE);
585                goto err;
586            }
587            if (!BUF_MEM_grow_clean(buf,
588                        (strlen(p) + buf->length - (e - from)))) {
589                CONFerr(CONF_F_STR_COPY, ERR_R_MALLOC_FAILURE);
590                goto err;
591            }
592            while (*p)
593                buf->data[to++] = *(p++);
594
595            /*
596             * Since we change the pointer 'from', we also have to change the
597             * perceived length of the string it points at.  /RL
598             */
599            len -= e - from;
600            from = e;
601
602            /*
603             * In case there were no braces or parenthesis around the
604             * variable reference, we have to put back the character that was
605             * replaced with a '\0'.  /RL
606             */
607            *rp = r;
608        } else
609            buf->data[to++] = *(from++);
610    }
611    buf->data[to] = '\0';
612    if (*pto != NULL)
613        OPENSSL_free(*pto);
614    *pto = buf->data;
615    OPENSSL_free(buf);
616    return (1);
617 err:
618    if (buf != NULL)
619        BUF_MEM_free(buf);
620    return (0);
621}
622
623static char *eat_ws(CONF *conf, char *p)
624{
625    while (IS_WS(conf, *p) && (!IS_EOF(conf, *p)))
626        p++;
627    return (p);
628}
629
630static char *eat_alpha_numeric(CONF *conf, char *p)
631{
632    for (;;) {
633        if (IS_ESC(conf, *p)) {
634            p = scan_esc(conf, p);
635            continue;
636        }
637        if (!IS_ALPHA_NUMERIC_PUNCT(conf, *p))
638            return (p);
639        p++;
640    }
641}
642
643static char *scan_quote(CONF *conf, char *p)
644{
645    int q = *p;
646
647    p++;
648    while (!(IS_EOF(conf, *p)) && (*p != q)) {
649        if (IS_ESC(conf, *p)) {
650            p++;
651            if (IS_EOF(conf, *p))
652                return (p);
653        }
654        p++;
655    }
656    if (*p == q)
657        p++;
658    return (p);
659}
660
661static char *scan_dquote(CONF *conf, char *p)
662{
663    int q = *p;
664
665    p++;
666    while (!(IS_EOF(conf, *p))) {
667        if (*p == q) {
668            if (*(p + 1) == q) {
669                p++;
670            } else {
671                break;
672            }
673        }
674        p++;
675    }
676    if (*p == q)
677        p++;
678    return (p);
679}
680
681static void dump_value_doall_arg(CONF_VALUE *a, BIO *out)
682{
683    if (a->name)
684        BIO_printf(out, "[%s] %s=%s\n", a->section, a->name, a->value);
685    else
686        BIO_printf(out, "[[%s]]\n", a->section);
687}
688
689static IMPLEMENT_LHASH_DOALL_ARG_FN(dump_value, CONF_VALUE, BIO)
690
691static int def_dump(const CONF *conf, BIO *out)
692{
693    lh_CONF_VALUE_doall_arg(conf->data, LHASH_DOALL_ARG_FN(dump_value),
694                            BIO, out);
695    return 1;
696}
697
698static int def_is_number(const CONF *conf, char c)
699{
700    return IS_NUMBER(conf, c);
701}
702
703static int def_to_int(const CONF *conf, char c)
704{
705    return c - '0';
706}
707