xref: /openssl/crypto/conf/conf_mod.c (revision 97bfbb98)
1 /*
2  * Copyright 2002-2024 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 /* We need to use some engine deprecated APIs */
11 #define OPENSSL_SUPPRESS_DEPRECATED
12 
13 #include "internal/cryptlib.h"
14 #include "internal/rcu.h"
15 #include <stdio.h>
16 #include <ctype.h>
17 #include <openssl/crypto.h>
18 #include "internal/conf.h"
19 #include <openssl/conf_api.h>
20 #include "internal/dso.h"
21 #include "internal/thread_once.h"
22 #include <openssl/x509.h>
23 #include <openssl/trace.h>
24 #include <openssl/engine.h>
25 #include "conf_local.h"
26 
27 DEFINE_STACK_OF(CONF_MODULE)
28 DEFINE_STACK_OF(CONF_IMODULE)
29 
30 #define DSO_mod_init_name "OPENSSL_init"
31 #define DSO_mod_finish_name "OPENSSL_finish"
32 
33 /*
34  * This structure contains a data about supported modules. entries in this
35  * table correspond to either dynamic or static modules.
36  */
37 
38 struct conf_module_st {
39     /* DSO of this module or NULL if static */
40     DSO *dso;
41     /* Name of the module */
42     char *name;
43     /* Init function */
44     conf_init_func *init;
45     /* Finish function */
46     conf_finish_func *finish;
47     /* Number of successfully initialized modules */
48     int links;
49     void *usr_data;
50 };
51 
52 /*
53  * This structure contains information about modules that have been
54  * successfully initialized. There may be more than one entry for a given
55  * module.
56  */
57 
58 struct conf_imodule_st {
59     CONF_MODULE *pmod;
60     char *name;
61     char *value;
62     unsigned long flags;
63     void *usr_data;
64 };
65 
66 static CRYPTO_ONCE init_module_list_lock = CRYPTO_ONCE_STATIC_INIT;
67 static CRYPTO_RCU_LOCK *module_list_lock = NULL;
68 static STACK_OF(CONF_MODULE) *supported_modules = NULL; /* protected by lock */
69 static STACK_OF(CONF_IMODULE) *initialized_modules = NULL; /* protected by lock */
70 
71 static CRYPTO_ONCE load_builtin_modules = CRYPTO_ONCE_STATIC_INIT;
72 
73 static void module_free(CONF_MODULE *md);
74 static void module_finish(CONF_IMODULE *imod);
75 static int module_run(const CONF *cnf, const char *name, const char *value,
76                       unsigned long flags);
77 static CONF_MODULE *module_add(DSO *dso, const char *name,
78                                conf_init_func *ifunc,
79                                conf_finish_func *ffunc);
80 static CONF_MODULE *module_find(const char *name);
81 static int module_init(CONF_MODULE *pmod, const char *name, const char *value,
82                        const CONF *cnf);
83 static CONF_MODULE *module_load_dso(const CONF *cnf, const char *name,
84                                     const char *value);
85 
86 static int conf_modules_finish_int(void);
87 
module_lists_free(void)88 static void module_lists_free(void)
89 {
90     ossl_rcu_lock_free(module_list_lock);
91     module_list_lock = NULL;
92 
93     sk_CONF_MODULE_free(supported_modules);
94     supported_modules = NULL;
95 
96     sk_CONF_IMODULE_free(initialized_modules);
97     initialized_modules = NULL;
98 }
99 
DEFINE_RUN_ONCE_STATIC(do_init_module_list_lock)100 DEFINE_RUN_ONCE_STATIC(do_init_module_list_lock)
101 {
102     module_list_lock = ossl_rcu_lock_new(1, NULL);
103     if (module_list_lock == NULL) {
104         ERR_raise(ERR_LIB_CONF, ERR_R_CRYPTO_LIB);
105         return 0;
106     }
107 
108     return 1;
109 }
110 
conf_diagnostics(const CONF * cnf)111 static int conf_diagnostics(const CONF *cnf)
112 {
113     int status;
114     long result = 0;
115 
116     ERR_set_mark();
117     status = NCONF_get_number_e(cnf, NULL, "config_diagnostics", &result);
118     ERR_pop_to_mark();
119     if (status > 0) {
120         OSSL_LIB_CTX_set_conf_diagnostics(cnf->libctx, result > 0);
121         return result > 0;
122     }
123     return OSSL_LIB_CTX_get_conf_diagnostics(cnf->libctx);
124 }
125 
126 /* Main function: load modules from a CONF structure */
127 
CONF_modules_load(const CONF * cnf,const char * appname,unsigned long flags)128 int CONF_modules_load(const CONF *cnf, const char *appname,
129                       unsigned long flags)
130 {
131     STACK_OF(CONF_VALUE) *values;
132     CONF_VALUE *vl;
133     char *vsection = NULL;
134     int ret, i;
135 
136     if (!cnf)
137         return 1;
138 
139     if (conf_diagnostics(cnf))
140         flags &= ~(CONF_MFLAGS_IGNORE_ERRORS
141                    | CONF_MFLAGS_IGNORE_RETURN_CODES
142                    | CONF_MFLAGS_SILENT
143                    | CONF_MFLAGS_IGNORE_MISSING_FILE);
144 
145     ERR_set_mark();
146     if (appname)
147         vsection = NCONF_get_string(cnf, NULL, appname);
148 
149     if (!appname || (!vsection && (flags & CONF_MFLAGS_DEFAULT_SECTION)))
150         vsection = NCONF_get_string(cnf, NULL, "openssl_conf");
151 
152     if (!vsection) {
153         ERR_pop_to_mark();
154         return 1;
155     }
156 
157     OSSL_TRACE1(CONF, "Configuration in section %s\n", vsection);
158     values = NCONF_get_section(cnf, vsection);
159 
160     if (values == NULL) {
161         if (!(flags & CONF_MFLAGS_SILENT)) {
162             ERR_clear_last_mark();
163             ERR_raise_data(ERR_LIB_CONF,
164                            CONF_R_OPENSSL_CONF_REFERENCES_MISSING_SECTION,
165                            "openssl_conf=%s", vsection);
166         } else {
167             ERR_pop_to_mark();
168         }
169         return 0;
170     }
171     ERR_pop_to_mark();
172 
173     for (i = 0; i < sk_CONF_VALUE_num(values); i++) {
174         vl = sk_CONF_VALUE_value(values, i);
175         ERR_set_mark();
176         ret = module_run(cnf, vl->name, vl->value, flags);
177         OSSL_TRACE3(CONF, "Running module %s (%s) returned %d\n",
178                     vl->name, vl->value, ret);
179         if (ret <= 0)
180             if (!(flags & CONF_MFLAGS_IGNORE_ERRORS)) {
181                 ERR_clear_last_mark();
182                 return ret;
183             }
184         ERR_pop_to_mark();
185     }
186 
187     return 1;
188 
189 }
190 
CONF_modules_load_file_ex(OSSL_LIB_CTX * libctx,const char * filename,const char * appname,unsigned long flags)191 int CONF_modules_load_file_ex(OSSL_LIB_CTX *libctx, const char *filename,
192                               const char *appname, unsigned long flags)
193 {
194     char *file = NULL;
195     CONF *conf = NULL;
196     int ret = 0, diagnostics = OSSL_LIB_CTX_get_conf_diagnostics(libctx);
197 
198     ERR_set_mark();
199 
200     if (filename == NULL) {
201         file = CONF_get1_default_config_file();
202         if (file == NULL)
203             goto err;
204         if (*file == '\0') {
205             /* Do not try to load an empty file name but do not error out */
206             ret = 1;
207             goto err;
208         }
209     } else {
210         file = (char *)filename;
211     }
212 
213     conf = NCONF_new_ex(libctx, NULL);
214     if (conf == NULL)
215         goto err;
216 
217     if (NCONF_load(conf, file, NULL) <= 0) {
218         if ((flags & CONF_MFLAGS_IGNORE_MISSING_FILE) &&
219             (ERR_GET_REASON(ERR_peek_last_error()) == CONF_R_NO_SUCH_FILE)) {
220             ret = 1;
221         }
222         goto err;
223     }
224 
225     ret = CONF_modules_load(conf, appname, flags);
226     /* CONF_modules_load() might change the diagnostics setting, reread it. */
227     diagnostics = OSSL_LIB_CTX_get_conf_diagnostics(libctx);
228 
229  err:
230     if (filename == NULL)
231         OPENSSL_free(file);
232     NCONF_free(conf);
233 
234     if ((flags & CONF_MFLAGS_IGNORE_RETURN_CODES) != 0 && !diagnostics)
235         ret = 1;
236 
237     if (ret > 0)
238         ERR_pop_to_mark();
239     else
240         ERR_clear_last_mark();
241 
242     return ret;
243 }
244 
CONF_modules_load_file(const char * filename,const char * appname,unsigned long flags)245 int CONF_modules_load_file(const char *filename,
246                            const char *appname, unsigned long flags)
247 {
248     return CONF_modules_load_file_ex(NULL, filename, appname, flags);
249 }
250 
DEFINE_RUN_ONCE_STATIC(do_load_builtin_modules)251 DEFINE_RUN_ONCE_STATIC(do_load_builtin_modules)
252 {
253     OPENSSL_load_builtin_modules();
254 #ifndef OPENSSL_NO_ENGINE
255     /* Need to load ENGINEs */
256     ENGINE_load_builtin_engines();
257 #endif
258     return 1;
259 }
260 
module_run(const CONF * cnf,const char * name,const char * value,unsigned long flags)261 static int module_run(const CONF *cnf, const char *name, const char *value,
262                       unsigned long flags)
263 {
264     CONF_MODULE *md;
265     int ret;
266 
267     if (!RUN_ONCE(&load_builtin_modules, do_load_builtin_modules))
268         return -1;
269 
270     md = module_find(name);
271 
272     /* Module not found: try to load DSO */
273     if (!md && !(flags & CONF_MFLAGS_NO_DSO))
274         md = module_load_dso(cnf, name, value);
275 
276     if (!md) {
277         if (!(flags & CONF_MFLAGS_SILENT)) {
278             ERR_raise_data(ERR_LIB_CONF, CONF_R_UNKNOWN_MODULE_NAME,
279                            "module=%s", name);
280         }
281         return -1;
282     }
283 
284     ret = module_init(md, name, value, cnf);
285 
286     if (ret <= 0) {
287         if (!(flags & CONF_MFLAGS_SILENT))
288             ERR_raise_data(ERR_LIB_CONF, CONF_R_MODULE_INITIALIZATION_ERROR,
289                            "module=%s, value=%s retcode=%-8d",
290                            name, value, ret);
291     }
292 
293     return ret;
294 }
295 
296 /* Load a module from a DSO */
module_load_dso(const CONF * cnf,const char * name,const char * value)297 static CONF_MODULE *module_load_dso(const CONF *cnf,
298                                     const char *name, const char *value)
299 {
300     DSO *dso = NULL;
301     conf_init_func *ifunc;
302     conf_finish_func *ffunc;
303     const char *path = NULL;
304     int errcode = 0;
305     CONF_MODULE *md;
306 
307     /* Look for alternative path in module section */
308     path = _CONF_get_string(cnf, value, "path");
309     if (path == NULL) {
310         path = name;
311     }
312     dso = DSO_load(NULL, path, NULL, 0);
313     if (dso == NULL) {
314         errcode = CONF_R_ERROR_LOADING_DSO;
315         goto err;
316     }
317     ifunc = (conf_init_func *)DSO_bind_func(dso, DSO_mod_init_name);
318     if (ifunc == NULL) {
319         errcode = CONF_R_MISSING_INIT_FUNCTION;
320         goto err;
321     }
322     ffunc = (conf_finish_func *)DSO_bind_func(dso, DSO_mod_finish_name);
323     /* All OK, add module */
324     md = module_add(dso, name, ifunc, ffunc);
325 
326     if (md == NULL)
327         goto err;
328 
329     return md;
330 
331  err:
332     DSO_free(dso);
333     ERR_raise_data(ERR_LIB_CONF, errcode, "module=%s, path=%s", name, path);
334     return NULL;
335 }
336 
337 /* add module to list */
module_add(DSO * dso,const char * name,conf_init_func * ifunc,conf_finish_func * ffunc)338 static CONF_MODULE *module_add(DSO *dso, const char *name,
339                                conf_init_func *ifunc, conf_finish_func *ffunc)
340 {
341     CONF_MODULE *tmod = NULL;
342     STACK_OF(CONF_MODULE) *old_modules;
343     STACK_OF(CONF_MODULE) *new_modules;
344 
345     if (!RUN_ONCE(&init_module_list_lock, do_init_module_list_lock))
346         return NULL;
347 
348     ossl_rcu_write_lock(module_list_lock);
349 
350     old_modules = ossl_rcu_deref(&supported_modules);
351 
352     if (old_modules == NULL)
353         new_modules = sk_CONF_MODULE_new_null();
354     else
355         new_modules = sk_CONF_MODULE_dup(old_modules);
356 
357     if (new_modules == NULL)
358         goto err;
359 
360     if ((tmod = OPENSSL_zalloc(sizeof(*tmod))) == NULL)
361         goto err;
362 
363     tmod->dso = dso;
364     tmod->name = OPENSSL_strdup(name);
365     tmod->init = ifunc;
366     tmod->finish = ffunc;
367     if (tmod->name == NULL)
368         goto err;
369 
370     if (!sk_CONF_MODULE_push(new_modules, tmod))
371         goto err;
372 
373     ossl_rcu_assign_ptr(&supported_modules, &new_modules);
374     ossl_rcu_write_unlock(module_list_lock);
375     ossl_synchronize_rcu(module_list_lock);
376 
377     sk_CONF_MODULE_free(old_modules);
378     return tmod;
379 
380  err:
381     ossl_rcu_write_unlock(module_list_lock);
382     if (tmod != NULL) {
383         OPENSSL_free(tmod->name);
384         OPENSSL_free(tmod);
385     }
386     sk_CONF_MODULE_free(new_modules);
387     return NULL;
388 }
389 
390 /*
391  * Find a module from the list. We allow module names of the form
392  * modname.XXXX to just search for modname to allow the same module to be
393  * initialized more than once.
394  */
395 
module_find(const char * name)396 static CONF_MODULE *module_find(const char *name)
397 {
398     CONF_MODULE *tmod;
399     int i, nchar;
400     char *p;
401     STACK_OF(CONF_MODULE) *mods;
402 
403     p = strrchr(name, '.');
404 
405     if (p)
406         nchar = p - name;
407     else
408         nchar = strlen(name);
409 
410     if (!RUN_ONCE(&init_module_list_lock, do_init_module_list_lock))
411         return NULL;
412 
413     ossl_rcu_read_lock(module_list_lock);
414     mods = ossl_rcu_deref(&supported_modules);
415 
416     for (i = 0; i < sk_CONF_MODULE_num(mods); i++) {
417         tmod = sk_CONF_MODULE_value(mods, i);
418         if (strncmp(tmod->name, name, nchar) == 0) {
419             ossl_rcu_read_unlock(module_list_lock);
420             return tmod;
421         }
422     }
423 
424     ossl_rcu_read_unlock(module_list_lock);
425     return NULL;
426 }
427 
428 /* initialize a module */
module_init(CONF_MODULE * pmod,const char * name,const char * value,const CONF * cnf)429 static int module_init(CONF_MODULE *pmod, const char *name, const char *value,
430                        const CONF *cnf)
431 {
432     int ret = 1;
433     int init_called = 0;
434     CONF_IMODULE *imod = NULL;
435     STACK_OF(CONF_IMODULE) *old_modules;
436     STACK_OF(CONF_IMODULE) *new_modules;
437 
438     /* Otherwise add initialized module to list */
439     imod = OPENSSL_malloc(sizeof(*imod));
440     if (imod == NULL)
441         goto err;
442 
443     imod->pmod = pmod;
444     imod->name = OPENSSL_strdup(name);
445     imod->value = OPENSSL_strdup(value);
446     imod->usr_data = NULL;
447 
448     if (!imod->name || !imod->value)
449         goto memerr;
450 
451     /* Try to initialize module */
452     if (pmod->init) {
453         ret = pmod->init(imod, cnf);
454         init_called = 1;
455         /* Error occurred, exit */
456         if (ret <= 0)
457             goto err;
458     }
459 
460     if (!RUN_ONCE(&init_module_list_lock, do_init_module_list_lock))
461         goto err;
462 
463     ossl_rcu_write_lock(module_list_lock);
464 
465     old_modules = ossl_rcu_deref(&initialized_modules);
466 
467     if (old_modules == NULL)
468         new_modules = sk_CONF_IMODULE_new_null();
469     else
470         new_modules = sk_CONF_IMODULE_dup(old_modules);
471 
472     if (new_modules == NULL) {
473         ossl_rcu_write_unlock(module_list_lock);
474         ERR_raise(ERR_LIB_CONF, ERR_R_CRYPTO_LIB);
475         goto err;
476     }
477 
478     if (!sk_CONF_IMODULE_push(new_modules, imod)) {
479         ossl_rcu_write_unlock(module_list_lock);
480         sk_CONF_IMODULE_free(new_modules);
481         ERR_raise(ERR_LIB_CONF, ERR_R_CRYPTO_LIB);
482         goto err;
483     }
484 
485     pmod->links++;
486 
487     ossl_rcu_assign_ptr(&initialized_modules, &new_modules);
488     ossl_rcu_write_unlock(module_list_lock);
489     ossl_synchronize_rcu(module_list_lock);
490     sk_CONF_IMODULE_free(old_modules);
491     return ret;
492 
493  err:
494 
495     /* We've started the module so we'd better finish it */
496     if (pmod->finish && init_called)
497         pmod->finish(imod);
498 
499  memerr:
500     if (imod) {
501         OPENSSL_free(imod->name);
502         OPENSSL_free(imod->value);
503         OPENSSL_free(imod);
504     }
505 
506     return -1;
507 
508 }
509 
510 /*
511  * Unload any dynamic modules that have a link count of zero: i.e. have no
512  * active initialized modules. If 'all' is set then all modules are unloaded
513  * including static ones.
514  */
515 
CONF_modules_unload(int all)516 void CONF_modules_unload(int all)
517 {
518     int i;
519     CONF_MODULE *md;
520     STACK_OF(CONF_MODULE) *old_modules;
521     STACK_OF(CONF_MODULE) *new_modules;
522     STACK_OF(CONF_MODULE) *to_delete;
523 
524     if (!conf_modules_finish_int()) /* also inits module list lock */
525         return;
526 
527     ossl_rcu_write_lock(module_list_lock);
528 
529     old_modules = ossl_rcu_deref(&supported_modules);
530     new_modules = sk_CONF_MODULE_dup(old_modules);
531 
532     if (new_modules == NULL) {
533         ossl_rcu_write_unlock(module_list_lock);
534         return;
535     }
536 
537     to_delete = sk_CONF_MODULE_new_null();
538 
539     /* unload modules in reverse order */
540     for (i = sk_CONF_MODULE_num(new_modules) - 1; i >= 0; i--) {
541         md = sk_CONF_MODULE_value(new_modules, i);
542         /* If static or in use and 'all' not set ignore it */
543         if (((md->links > 0) || !md->dso) && !all)
544             continue;
545         /* Since we're working in reverse this is OK */
546         (void)sk_CONF_MODULE_delete(new_modules, i);
547         sk_CONF_MODULE_push(to_delete, md);
548     }
549 
550     if (sk_CONF_MODULE_num(new_modules) == 0) {
551         sk_CONF_MODULE_free(new_modules);
552         new_modules = NULL;
553     }
554 
555     ossl_rcu_assign_ptr(&supported_modules, &new_modules);
556     ossl_rcu_write_unlock(module_list_lock);
557     ossl_synchronize_rcu(module_list_lock);
558     sk_CONF_MODULE_free(old_modules);
559     sk_CONF_MODULE_pop_free(to_delete, module_free);
560 
561 }
562 
563 /* unload a single module */
module_free(CONF_MODULE * md)564 static void module_free(CONF_MODULE *md)
565 {
566     DSO_free(md->dso);
567     OPENSSL_free(md->name);
568     OPENSSL_free(md);
569 }
570 
571 /* finish and free up all modules instances */
572 
conf_modules_finish_int(void)573 static int conf_modules_finish_int(void)
574 {
575     CONF_IMODULE *imod;
576     STACK_OF(CONF_IMODULE) *old_modules;
577     STACK_OF(CONF_IMODULE) *new_modules = NULL;
578 
579     if (!RUN_ONCE(&init_module_list_lock, do_init_module_list_lock))
580         return 0;
581 
582     /* If module_list_lock is NULL here it means we were already unloaded */
583     if (module_list_lock == NULL)
584         return 0;
585 
586     ossl_rcu_write_lock(module_list_lock);
587     old_modules = ossl_rcu_deref(&initialized_modules);
588     ossl_rcu_assign_ptr(&initialized_modules, &new_modules);
589     ossl_rcu_write_unlock(module_list_lock);
590     ossl_synchronize_rcu(module_list_lock);
591 
592     while (sk_CONF_IMODULE_num(old_modules) > 0) {
593         imod = sk_CONF_IMODULE_pop(old_modules);
594         module_finish(imod);
595     }
596     sk_CONF_IMODULE_free(old_modules);
597 
598     return 1;
599 }
600 
CONF_modules_finish(void)601 void CONF_modules_finish(void)
602 {
603     conf_modules_finish_int();
604 }
605 
606 /* finish a module instance */
607 
module_finish(CONF_IMODULE * imod)608 static void module_finish(CONF_IMODULE *imod)
609 {
610     if (!imod)
611         return;
612     if (imod->pmod->finish)
613         imod->pmod->finish(imod);
614     imod->pmod->links--;
615     OPENSSL_free(imod->name);
616     OPENSSL_free(imod->value);
617     OPENSSL_free(imod);
618 }
619 
620 /* Add a static module to OpenSSL */
621 
CONF_module_add(const char * name,conf_init_func * ifunc,conf_finish_func * ffunc)622 int CONF_module_add(const char *name, conf_init_func *ifunc,
623                     conf_finish_func *ffunc)
624 {
625     if (module_add(NULL, name, ifunc, ffunc))
626         return 1;
627     else
628         return 0;
629 }
630 
ossl_config_modules_free(void)631 void ossl_config_modules_free(void)
632 {
633     CONF_modules_unload(1); /* calls CONF_modules_finish */
634     module_lists_free();
635 }
636 
637 /* Utility functions */
638 
CONF_imodule_get_name(const CONF_IMODULE * md)639 const char *CONF_imodule_get_name(const CONF_IMODULE *md)
640 {
641     return md->name;
642 }
643 
CONF_imodule_get_value(const CONF_IMODULE * md)644 const char *CONF_imodule_get_value(const CONF_IMODULE *md)
645 {
646     return md->value;
647 }
648 
CONF_imodule_get_usr_data(const CONF_IMODULE * md)649 void *CONF_imodule_get_usr_data(const CONF_IMODULE *md)
650 {
651     return md->usr_data;
652 }
653 
CONF_imodule_set_usr_data(CONF_IMODULE * md,void * usr_data)654 void CONF_imodule_set_usr_data(CONF_IMODULE *md, void *usr_data)
655 {
656     md->usr_data = usr_data;
657 }
658 
CONF_imodule_get_module(const CONF_IMODULE * md)659 CONF_MODULE *CONF_imodule_get_module(const CONF_IMODULE *md)
660 {
661     return md->pmod;
662 }
663 
CONF_imodule_get_flags(const CONF_IMODULE * md)664 unsigned long CONF_imodule_get_flags(const CONF_IMODULE *md)
665 {
666     return md->flags;
667 }
668 
CONF_imodule_set_flags(CONF_IMODULE * md,unsigned long flags)669 void CONF_imodule_set_flags(CONF_IMODULE *md, unsigned long flags)
670 {
671     md->flags = flags;
672 }
673 
CONF_module_get_usr_data(CONF_MODULE * pmod)674 void *CONF_module_get_usr_data(CONF_MODULE *pmod)
675 {
676     return pmod->usr_data;
677 }
678 
CONF_module_set_usr_data(CONF_MODULE * pmod,void * usr_data)679 void CONF_module_set_usr_data(CONF_MODULE *pmod, void *usr_data)
680 {
681     pmod->usr_data = usr_data;
682 }
683 
684 /* Return default config file name */
CONF_get1_default_config_file(void)685 char *CONF_get1_default_config_file(void)
686 {
687     const char *t;
688     char *file, *sep = "";
689     size_t size;
690 
691     if ((file = ossl_safe_getenv("OPENSSL_CONF")) != NULL)
692         return OPENSSL_strdup(file);
693 
694     t = X509_get_default_cert_area();
695     /*
696      * On windows systems with -DOSSL_WINCTX set, if the needed registry
697      * keys are not yet set, openssl applets will return, due to an inability
698      * to locate various directories, like the default cert area.  In that
699      * event, clone an empty string here, so that commands like openssl version
700      * continue to operate properly without needing to set OPENSSL_CONF.
701      * Applets like cms will fail gracefully later when they try to parse an
702      * empty config file
703      */
704     if (t == NULL)
705         return OPENSSL_strdup("");
706 
707 #ifndef OPENSSL_SYS_VMS
708     sep = "/";
709 #endif
710     size = strlen(t) + strlen(sep) + strlen(OPENSSL_CONF) + 1;
711     file = OPENSSL_malloc(size);
712 
713     if (file == NULL)
714         return NULL;
715     BIO_snprintf(file, size, "%s%s%s", t, sep, OPENSSL_CONF);
716 
717     return file;
718 }
719 
720 /*
721  * This function takes a list separated by 'sep' and calls the callback
722  * function giving the start and length of each member optionally stripping
723  * leading and trailing whitespace. This can be used to parse comma separated
724  * lists for example.
725  */
726 
CONF_parse_list(const char * list_,int sep,int nospc,int (* list_cb)(const char * elem,int len,void * usr),void * arg)727 int CONF_parse_list(const char *list_, int sep, int nospc,
728                     int (*list_cb) (const char *elem, int len, void *usr),
729                     void *arg)
730 {
731     int ret;
732     const char *lstart, *tmpend, *p;
733 
734     if (list_ == NULL) {
735         ERR_raise(ERR_LIB_CONF, CONF_R_LIST_CANNOT_BE_NULL);
736         return 0;
737     }
738 
739     lstart = list_;
740     for (;;) {
741         if (nospc) {
742             while (*lstart && isspace((unsigned char)*lstart))
743                 lstart++;
744         }
745         p = strchr(lstart, sep);
746         if (p == lstart || *lstart == '\0')
747             ret = list_cb(NULL, 0, arg);
748         else {
749             if (p)
750                 tmpend = p - 1;
751             else
752                 tmpend = lstart + strlen(lstart) - 1;
753             if (nospc) {
754                 while (isspace((unsigned char)*tmpend))
755                     tmpend--;
756             }
757             ret = list_cb(lstart, tmpend - lstart + 1, arg);
758         }
759         if (ret <= 0)
760             return ret;
761         if (p == NULL)
762             return 1;
763         lstart = p + 1;
764     }
765 }
766