Coverage Report

Created: 2022-11-30 06:20

/src/openssl/crypto/conf/conf_mod.c
Line
Count
Source (jump to first uncovered line)
1
/* conf_mod.c */
2
/*
3
 * Written by Stephen Henson (steve@openssl.org) for the OpenSSL project
4
 * 2001.
5
 */
6
/* ====================================================================
7
 * Copyright (c) 2001 The OpenSSL Project.  All rights reserved.
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 *
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 *
16
 * 2. Redistributions in binary form must reproduce the above copyright
17
 *    notice, this list of conditions and the following disclaimer in
18
 *    the documentation and/or other materials provided with the
19
 *    distribution.
20
 *
21
 * 3. All advertising materials mentioning features or use of this
22
 *    software must display the following acknowledgment:
23
 *    "This product includes software developed by the OpenSSL Project
24
 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25
 *
26
 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27
 *    endorse or promote products derived from this software without
28
 *    prior written permission. For written permission, please contact
29
 *    licensing@OpenSSL.org.
30
 *
31
 * 5. Products derived from this software may not be called "OpenSSL"
32
 *    nor may "OpenSSL" appear in their names without prior written
33
 *    permission of the OpenSSL Project.
34
 *
35
 * 6. Redistributions of any form whatsoever must retain the following
36
 *    acknowledgment:
37
 *    "This product includes software developed by the OpenSSL Project
38
 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39
 *
40
 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51
 * OF THE POSSIBILITY OF SUCH DAMAGE.
52
 * ====================================================================
53
 *
54
 * This product includes cryptographic software written by Eric Young
55
 * (eay@cryptsoft.com).  This product includes software written by Tim
56
 * Hudson (tjh@cryptsoft.com).
57
 *
58
 */
59
60
#include <stdio.h>
61
#include <ctype.h>
62
#include <openssl/crypto.h>
63
#include "cryptlib.h"
64
#include <openssl/conf.h>
65
#include <openssl/dso.h>
66
#include <openssl/x509.h>
67
68
0
#define DSO_mod_init_name "OPENSSL_init"
69
0
#define DSO_mod_finish_name "OPENSSL_finish"
70
71
/*
72
 * This structure contains a data about supported modules. entries in this
73
 * table correspond to either dynamic or static modules.
74
 */
75
76
struct conf_module_st {
77
    /* DSO of this module or NULL if static */
78
    DSO *dso;
79
    /* Name of the module */
80
    char *name;
81
    /* Init function */
82
    conf_init_func *init;
83
    /* Finish function */
84
    conf_finish_func *finish;
85
    /* Number of successfully initialized modules */
86
    int links;
87
    void *usr_data;
88
};
89
90
/*
91
 * This structure contains information about modules that have been
92
 * successfully initialized. There may be more than one entry for a given
93
 * module.
94
 */
95
96
struct conf_imodule_st {
97
    CONF_MODULE *pmod;
98
    char *name;
99
    char *value;
100
    unsigned long flags;
101
    void *usr_data;
102
};
103
104
static STACK_OF(CONF_MODULE) *supported_modules = NULL;
105
static STACK_OF(CONF_IMODULE) *initialized_modules = NULL;
106
107
static void module_free(CONF_MODULE *md);
108
static void module_finish(CONF_IMODULE *imod);
109
static int module_run(const CONF *cnf, char *name, char *value,
110
                      unsigned long flags);
111
static CONF_MODULE *module_add(DSO *dso, const char *name,
112
                               conf_init_func *ifunc,
113
                               conf_finish_func *ffunc);
114
static CONF_MODULE *module_find(char *name);
115
static int module_init(CONF_MODULE *pmod, char *name, char *value,
116
                       const CONF *cnf);
117
static CONF_MODULE *module_load_dso(const CONF *cnf, char *name, char *value,
118
                                    unsigned long flags);
119
120
/* Main function: load modules from a CONF structure */
121
122
int CONF_modules_load(const CONF *cnf, const char *appname,
123
                      unsigned long flags)
124
0
{
125
0
    STACK_OF(CONF_VALUE) *values;
126
0
    CONF_VALUE *vl;
127
0
    char *vsection = NULL;
128
129
0
    int ret, i;
130
131
0
    if (!cnf)
132
0
        return 1;
133
134
0
    if (appname)
135
0
        vsection = NCONF_get_string(cnf, NULL, appname);
136
137
0
    if (!appname || (!vsection && (flags & CONF_MFLAGS_DEFAULT_SECTION)))
138
0
        vsection = NCONF_get_string(cnf, NULL, "openssl_conf");
139
140
0
    if (!vsection) {
141
0
        ERR_clear_error();
142
0
        return 1;
143
0
    }
144
145
0
    values = NCONF_get_section(cnf, vsection);
146
147
0
    if (!values)
148
0
        return 0;
149
150
0
    for (i = 0; i < sk_CONF_VALUE_num(values); i++) {
151
0
        vl = sk_CONF_VALUE_value(values, i);
152
0
        ret = module_run(cnf, vl->name, vl->value, flags);
153
0
        if (ret <= 0)
154
0
            if (!(flags & CONF_MFLAGS_IGNORE_ERRORS))
155
0
                return ret;
156
0
    }
157
158
0
    return 1;
159
160
0
}
161
162
int CONF_modules_load_file(const char *filename, const char *appname,
163
                           unsigned long flags)
164
19
{
165
19
    char *file = NULL;
166
19
    CONF *conf = NULL;
167
19
    int ret = 0;
168
19
    conf = NCONF_new(NULL);
169
19
    if (!conf)
170
0
        goto err;
171
172
19
    if (filename == NULL) {
173
19
        file = CONF_get1_default_config_file();
174
19
        if (!file)
175
0
            goto err;
176
19
    } else
177
0
        file = (char *)filename;
178
179
19
    if (NCONF_load(conf, file, NULL) <= 0) {
180
19
        if ((flags & CONF_MFLAGS_IGNORE_MISSING_FILE) &&
181
19
            (ERR_GET_REASON(ERR_peek_last_error()) == CONF_R_NO_SUCH_FILE)) {
182
19
            ERR_clear_error();
183
19
            ret = 1;
184
19
        }
185
19
        goto err;
186
19
    }
187
188
0
    ret = CONF_modules_load(conf, appname, flags);
189
190
19
 err:
191
19
    if (filename == NULL)
192
19
        OPENSSL_free(file);
193
19
    NCONF_free(conf);
194
195
19
    return ret;
196
0
}
197
198
static int module_run(const CONF *cnf, char *name, char *value,
199
                      unsigned long flags)
200
0
{
201
0
    CONF_MODULE *md;
202
0
    int ret;
203
204
0
    md = module_find(name);
205
206
    /* Module not found: try to load DSO */
207
0
    if (!md && !(flags & CONF_MFLAGS_NO_DSO))
208
0
        md = module_load_dso(cnf, name, value, flags);
209
210
0
    if (!md) {
211
0
        if (!(flags & CONF_MFLAGS_SILENT)) {
212
0
            CONFerr(CONF_F_MODULE_RUN, CONF_R_UNKNOWN_MODULE_NAME);
213
0
            ERR_add_error_data(2, "module=", name);
214
0
        }
215
0
        return -1;
216
0
    }
217
218
0
    ret = module_init(md, name, value, cnf);
219
220
0
    if (ret <= 0) {
221
0
        if (!(flags & CONF_MFLAGS_SILENT)) {
222
0
            char rcode[DECIMAL_SIZE(ret) + 1];
223
0
            CONFerr(CONF_F_MODULE_RUN, CONF_R_MODULE_INITIALIZATION_ERROR);
224
0
            BIO_snprintf(rcode, sizeof rcode, "%-8d", ret);
225
0
            ERR_add_error_data(6, "module=", name, ", value=", value,
226
0
                               ", retcode=", rcode);
227
0
        }
228
0
    }
229
230
0
    return ret;
231
0
}
232
233
/* Load a module from a DSO */
234
static CONF_MODULE *module_load_dso(const CONF *cnf, char *name, char *value,
235
                                    unsigned long flags)
236
0
{
237
0
    DSO *dso = NULL;
238
0
    conf_init_func *ifunc;
239
0
    conf_finish_func *ffunc;
240
0
    char *path = NULL;
241
0
    int errcode = 0;
242
0
    CONF_MODULE *md;
243
    /* Look for alternative path in module section */
244
0
    path = NCONF_get_string(cnf, value, "path");
245
0
    if (!path) {
246
0
        ERR_clear_error();
247
0
        path = name;
248
0
    }
249
0
    dso = DSO_load(NULL, path, NULL, 0);
250
0
    if (!dso) {
251
0
        errcode = CONF_R_ERROR_LOADING_DSO;
252
0
        goto err;
253
0
    }
254
0
    ifunc = (conf_init_func *)DSO_bind_func(dso, DSO_mod_init_name);
255
0
    if (!ifunc) {
256
0
        errcode = CONF_R_MISSING_INIT_FUNCTION;
257
0
        goto err;
258
0
    }
259
0
    ffunc = (conf_finish_func *)DSO_bind_func(dso, DSO_mod_finish_name);
260
    /* All OK, add module */
261
0
    md = module_add(dso, name, ifunc, ffunc);
262
263
0
    if (!md)
264
0
        goto err;
265
266
0
    return md;
267
268
0
 err:
269
0
    if (dso)
270
0
        DSO_free(dso);
271
0
    CONFerr(CONF_F_MODULE_LOAD_DSO, errcode);
272
0
    ERR_add_error_data(4, "module=", name, ", path=", path);
273
0
    return NULL;
274
0
}
275
276
/* add module to list */
277
static CONF_MODULE *module_add(DSO *dso, const char *name,
278
                               conf_init_func *ifunc, conf_finish_func *ffunc)
279
57
{
280
57
    CONF_MODULE *tmod = NULL;
281
57
    if (supported_modules == NULL)
282
19
        supported_modules = sk_CONF_MODULE_new_null();
283
57
    if (supported_modules == NULL)
284
0
        return NULL;
285
57
    tmod = OPENSSL_malloc(sizeof(CONF_MODULE));
286
57
    if (tmod == NULL)
287
0
        return NULL;
288
289
57
    tmod->dso = dso;
290
57
    tmod->name = BUF_strdup(name);
291
57
    if (tmod->name == NULL) {
292
0
        OPENSSL_free(tmod);
293
0
        return NULL;
294
0
    }
295
57
    tmod->init = ifunc;
296
57
    tmod->finish = ffunc;
297
57
    tmod->links = 0;
298
299
57
    if (!sk_CONF_MODULE_push(supported_modules, tmod)) {
300
0
        OPENSSL_free(tmod);
301
0
        return NULL;
302
0
    }
303
304
57
    return tmod;
305
57
}
306
307
/*
308
 * Find a module from the list. We allow module names of the form
309
 * modname.XXXX to just search for modname to allow the same module to be
310
 * initialized more than once.
311
 */
312
313
static CONF_MODULE *module_find(char *name)
314
0
{
315
0
    CONF_MODULE *tmod;
316
0
    int i, nchar;
317
0
    char *p;
318
0
    p = strrchr(name, '.');
319
320
0
    if (p)
321
0
        nchar = p - name;
322
0
    else
323
0
        nchar = strlen(name);
324
325
0
    for (i = 0; i < sk_CONF_MODULE_num(supported_modules); i++) {
326
0
        tmod = sk_CONF_MODULE_value(supported_modules, i);
327
0
        if (!strncmp(tmod->name, name, nchar))
328
0
            return tmod;
329
0
    }
330
331
0
    return NULL;
332
333
0
}
334
335
/* initialize a module */
336
static int module_init(CONF_MODULE *pmod, char *name, char *value,
337
                       const CONF *cnf)
338
0
{
339
0
    int ret = 1;
340
0
    int init_called = 0;
341
0
    CONF_IMODULE *imod = NULL;
342
343
    /* Otherwise add initialized module to list */
344
0
    imod = OPENSSL_malloc(sizeof(CONF_IMODULE));
345
0
    if (!imod)
346
0
        goto err;
347
348
0
    imod->pmod = pmod;
349
0
    imod->name = BUF_strdup(name);
350
0
    imod->value = BUF_strdup(value);
351
0
    imod->usr_data = NULL;
352
353
0
    if (!imod->name || !imod->value)
354
0
        goto memerr;
355
356
    /* Try to initialize module */
357
0
    if (pmod->init) {
358
0
        ret = pmod->init(imod, cnf);
359
0
        init_called = 1;
360
        /* Error occurred, exit */
361
0
        if (ret <= 0)
362
0
            goto err;
363
0
    }
364
365
0
    if (initialized_modules == NULL) {
366
0
        initialized_modules = sk_CONF_IMODULE_new_null();
367
0
        if (!initialized_modules) {
368
0
            CONFerr(CONF_F_MODULE_INIT, ERR_R_MALLOC_FAILURE);
369
0
            goto err;
370
0
        }
371
0
    }
372
373
0
    if (!sk_CONF_IMODULE_push(initialized_modules, imod)) {
374
0
        CONFerr(CONF_F_MODULE_INIT, ERR_R_MALLOC_FAILURE);
375
0
        goto err;
376
0
    }
377
378
0
    pmod->links++;
379
380
0
    return ret;
381
382
0
 err:
383
384
    /* We've started the module so we'd better finish it */
385
0
    if (pmod->finish && init_called)
386
0
        pmod->finish(imod);
387
388
0
 memerr:
389
0
    if (imod) {
390
0
        if (imod->name)
391
0
            OPENSSL_free(imod->name);
392
0
        if (imod->value)
393
0
            OPENSSL_free(imod->value);
394
0
        OPENSSL_free(imod);
395
0
    }
396
397
0
    return -1;
398
399
0
}
400
401
/*
402
 * Unload any dynamic modules that have a link count of zero: i.e. have no
403
 * active initialized modules. If 'all' is set then all modules are unloaded
404
 * including static ones.
405
 */
406
407
void CONF_modules_unload(int all)
408
0
{
409
0
    int i;
410
0
    CONF_MODULE *md;
411
0
    CONF_modules_finish();
412
    /* unload modules in reverse order */
413
0
    for (i = sk_CONF_MODULE_num(supported_modules) - 1; i >= 0; i--) {
414
0
        md = sk_CONF_MODULE_value(supported_modules, i);
415
        /* If static or in use and 'all' not set ignore it */
416
0
        if (((md->links > 0) || !md->dso) && !all)
417
0
            continue;
418
        /* Since we're working in reverse this is OK */
419
0
        (void)sk_CONF_MODULE_delete(supported_modules, i);
420
0
        module_free(md);
421
0
    }
422
0
    if (sk_CONF_MODULE_num(supported_modules) == 0) {
423
0
        sk_CONF_MODULE_free(supported_modules);
424
0
        supported_modules = NULL;
425
0
    }
426
0
}
427
428
/* unload a single module */
429
static void module_free(CONF_MODULE *md)
430
0
{
431
0
    if (md->dso)
432
0
        DSO_free(md->dso);
433
0
    OPENSSL_free(md->name);
434
0
    OPENSSL_free(md);
435
0
}
436
437
/* finish and free up all modules instances */
438
439
void CONF_modules_finish(void)
440
0
{
441
0
    CONF_IMODULE *imod;
442
0
    while (sk_CONF_IMODULE_num(initialized_modules) > 0) {
443
0
        imod = sk_CONF_IMODULE_pop(initialized_modules);
444
0
        module_finish(imod);
445
0
    }
446
0
    sk_CONF_IMODULE_free(initialized_modules);
447
0
    initialized_modules = NULL;
448
0
}
449
450
/* finish a module instance */
451
452
static void module_finish(CONF_IMODULE *imod)
453
0
{
454
0
    if (imod->pmod->finish)
455
0
        imod->pmod->finish(imod);
456
0
    imod->pmod->links--;
457
0
    OPENSSL_free(imod->name);
458
0
    OPENSSL_free(imod->value);
459
0
    OPENSSL_free(imod);
460
0
}
461
462
/* Add a static module to OpenSSL */
463
464
int CONF_module_add(const char *name, conf_init_func *ifunc,
465
                    conf_finish_func *ffunc)
466
57
{
467
57
    if (module_add(NULL, name, ifunc, ffunc))
468
57
        return 1;
469
0
    else
470
0
        return 0;
471
57
}
472
473
void CONF_modules_free(void)
474
0
{
475
0
    CONF_modules_finish();
476
0
    CONF_modules_unload(1);
477
0
}
478
479
/* Utility functions */
480
481
const char *CONF_imodule_get_name(const CONF_IMODULE *md)
482
0
{
483
0
    return md->name;
484
0
}
485
486
const char *CONF_imodule_get_value(const CONF_IMODULE *md)
487
0
{
488
0
    return md->value;
489
0
}
490
491
void *CONF_imodule_get_usr_data(const CONF_IMODULE *md)
492
0
{
493
0
    return md->usr_data;
494
0
}
495
496
void CONF_imodule_set_usr_data(CONF_IMODULE *md, void *usr_data)
497
0
{
498
0
    md->usr_data = usr_data;
499
0
}
500
501
CONF_MODULE *CONF_imodule_get_module(const CONF_IMODULE *md)
502
0
{
503
0
    return md->pmod;
504
0
}
505
506
unsigned long CONF_imodule_get_flags(const CONF_IMODULE *md)
507
0
{
508
0
    return md->flags;
509
0
}
510
511
void CONF_imodule_set_flags(CONF_IMODULE *md, unsigned long flags)
512
0
{
513
0
    md->flags = flags;
514
0
}
515
516
void *CONF_module_get_usr_data(CONF_MODULE *pmod)
517
0
{
518
0
    return pmod->usr_data;
519
0
}
520
521
void CONF_module_set_usr_data(CONF_MODULE *pmod, void *usr_data)
522
0
{
523
0
    pmod->usr_data = usr_data;
524
0
}
525
526
/* Return default config file name */
527
528
char *CONF_get1_default_config_file(void)
529
19
{
530
19
    char *file;
531
19
    int len;
532
533
19
    file = getenv("OPENSSL_CONF");
534
19
    if (file)
535
0
        return BUF_strdup(file);
536
537
19
    len = strlen(X509_get_default_cert_area());
538
19
#ifndef OPENSSL_SYS_VMS
539
19
    len++;
540
19
#endif
541
19
    len += strlen(OPENSSL_CONF);
542
543
19
    file = OPENSSL_malloc(len + 1);
544
545
19
    if (!file)
546
0
        return NULL;
547
19
    BUF_strlcpy(file, X509_get_default_cert_area(), len + 1);
548
19
#ifndef OPENSSL_SYS_VMS
549
19
    BUF_strlcat(file, "/", len + 1);
550
19
#endif
551
19
    BUF_strlcat(file, OPENSSL_CONF, len + 1);
552
553
19
    return file;
554
19
}
555
556
/*
557
 * This function takes a list separated by 'sep' and calls the callback
558
 * function giving the start and length of each member optionally stripping
559
 * leading and trailing whitespace. This can be used to parse comma separated
560
 * lists for example.
561
 */
562
563
int CONF_parse_list(const char *list_, int sep, int nospc,
564
                    int (*list_cb) (const char *elem, int len, void *usr),
565
                    void *arg)
566
0
{
567
0
    int ret;
568
0
    const char *lstart, *tmpend, *p;
569
570
0
    if (list_ == NULL) {
571
0
        CONFerr(CONF_F_CONF_PARSE_LIST, CONF_R_LIST_CANNOT_BE_NULL);
572
0
        return 0;
573
0
    }
574
575
0
    lstart = list_;
576
0
    for (;;) {
577
0
        if (nospc) {
578
0
            while (*lstart && isspace((unsigned char)*lstart))
579
0
                lstart++;
580
0
        }
581
0
        p = strchr(lstart, sep);
582
0
        if (p == lstart || !*lstart)
583
0
            ret = list_cb(NULL, 0, arg);
584
0
        else {
585
0
            if (p)
586
0
                tmpend = p - 1;
587
0
            else
588
0
                tmpend = lstart + strlen(lstart) - 1;
589
0
            if (nospc) {
590
0
                while (isspace((unsigned char)*tmpend))
591
0
                    tmpend--;
592
0
            }
593
0
            ret = list_cb(lstart, tmpend - lstart + 1, arg);
594
0
        }
595
0
        if (ret <= 0)
596
0
            return ret;
597
0
        if (p == NULL)
598
0
            return 1;
599
0
        lstart = p + 1;
600
0
    }
601
0
}