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