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