]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/conf/conf.c
New functions CONF_load_bio() and CONF_load_fp() to load a configuration
[thirdparty/openssl.git] / crypto / conf / conf.c
CommitLineData
d02b48c6 1/* crypto/conf/conf.c */
58964a49 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
d02b48c6
RE
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#include <stdio.h>
60#include <errno.h>
61#include "cryptlib.h"
ec577822
BM
62#include <openssl/stack.h>
63#include <openssl/lhash.h>
64#include <openssl/conf.h>
65#include <openssl/buffer.h>
66#include <openssl/err.h>
d02b48c6
RE
67
68#include "conf_lcl.h"
69
d02b48c6
RE
70static void value_free_hash(CONF_VALUE *a, LHASH *conf);
71static void value_free_stack(CONF_VALUE *a,LHASH *conf);
72static unsigned long hash(CONF_VALUE *v);
73static int cmp(CONF_VALUE *a,CONF_VALUE *b);
74static char *eat_ws(char *p);
75static char *eat_alpha_numeric(char *p);
76static void clear_comments(char *p);
77static int str_copy(LHASH *conf,char *section,char **to, char *from);
78static char *scan_quote(char *p);
79static CONF_VALUE *new_section(LHASH *conf,char *section);
80static CONF_VALUE *get_section(LHASH *conf,char *section);
dfeab068 81#define scan_esc(p) ((((p)[1] == '\0')?(p++):(p+=2)),p)
d02b48c6 82
e778802f 83const char *CONF_version="CONF" OPENSSL_VERSION_PTEXT;
d02b48c6 84
8623f693
DSH
85
86LHASH *CONF_load(LHASH *h, const char *file, long *line)
d02b48c6 87 {
8623f693 88 LHASH *ltmp;
d02b48c6 89 FILE *in=NULL;
8623f693
DSH
90
91#ifdef VMS
92 in=fopen(file,"r");
93#else
94 in=fopen(file,"rb");
95#endif
96 if (in == NULL)
97 {
98 SYSerr(SYS_F_FOPEN,get_last_sys_error());
99 ERR_set_error_data(BUF_strdup(file),
100 ERR_TXT_MALLOCED|ERR_TXT_STRING);
101 CONFerr(CONF_F_CONF_LOAD,ERR_R_SYS_LIB);
102 return NULL;
103 }
104
105 ltmp = CONF_load_fp(h, in, line);
106 fclose(in);
107
108 return ltmp;
109}
110
111LHASH *CONF_load_fp(LHASH *h, FILE *in, long *line)
112{
113 BIO *btmp;
114 LHASH *ltmp;
115 if(!(btmp = BIO_new_fp(in, BIO_NOCLOSE))) {
116 CONFerr(CONF_F_CONF_LOAD_FP,ERR_R_BUF_LIB);
117 return NULL;
118 }
119 ltmp = CONF_load_bio(h, btmp, line);
120 BIO_free(btmp);
121 return ltmp;
122}
123
124LHASH *CONF_load_bio(LHASH *h, BIO *in, long *line)
125 {
126 LHASH *ret=NULL;
d02b48c6 127#define BUFSIZE 512
dfeab068 128 char btmp[16];
d02b48c6
RE
129 int bufnum=0,i,ii;
130 BUF_MEM *buff=NULL;
131 char *s,*p,*end;
dfeab068
RE
132 int again,n;
133 long eline=0;
d02b48c6
RE
134 CONF_VALUE *v=NULL,*vv,*tv;
135 CONF_VALUE *sv=NULL;
136 char *section=NULL,*buf;
137 STACK *section_sk=NULL,*ts;
138 char *start,*psection,*pname;
139
140 if ((buff=BUF_MEM_new()) == NULL)
141 {
8623f693 142 CONFerr(CONF_F_CONF_LOAD_BIO,ERR_R_BUF_LIB);
d02b48c6
RE
143 goto err;
144 }
145
146 section=(char *)Malloc(10);
147 if (section == NULL)
148 {
8623f693 149 CONFerr(CONF_F_CONF_LOAD_BIO,ERR_R_MALLOC_FAILURE);
d02b48c6
RE
150 goto err;
151 }
152 strcpy(section,"default");
153
154 if (h == NULL)
155 {
156 if ((ret=lh_new(hash,cmp)) == NULL)
157 {
8623f693 158 CONFerr(CONF_F_CONF_LOAD_BIO,ERR_R_MALLOC_FAILURE);
d02b48c6
RE
159 goto err;
160 }
161 }
162 else
163 ret=h;
164
165 sv=new_section(ret,section);
166 if (sv == NULL)
167 {
8623f693
DSH
168 CONFerr(CONF_F_CONF_LOAD_BIO,
169 CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
d02b48c6
RE
170 goto err;
171 }
172 section_sk=(STACK *)sv->value;
173
174 bufnum=0;
175 for (;;)
176 {
177 again=0;
178 if (!BUF_MEM_grow(buff,bufnum+BUFSIZE))
179 {
8623f693 180 CONFerr(CONF_F_CONF_LOAD_BIO,ERR_R_BUF_LIB);
d02b48c6
RE
181 goto err;
182 }
183 p= &(buff->data[bufnum]);
184 *p='\0';
8623f693 185 BIO_gets(in, p, BUFSIZE-1);
d02b48c6
RE
186 p[BUFSIZE-1]='\0';
187 ii=i=strlen(p);
188 if (i == 0) break;
189 while (i > 0)
190 {
191 if ((p[i-1] != '\r') && (p[i-1] != '\n'))
192 break;
193 else
194 i--;
195 }
196 /* we removed some trailing stuff so there is a new
197 * line on the end. */
198 if (i == ii)
199 again=1; /* long line */
200 else
201 {
202 p[i]='\0';
203 eline++; /* another input line */
204 }
205
206 /* we now have a line with trailing \r\n removed */
207
208 /* i is the number of bytes */
209 bufnum+=i;
210
211 v=NULL;
212 /* check for line continuation */
213 if (bufnum >= 1)
214 {
215 /* If we have bytes and the last char '\\' and
216 * second last char is not '\\' */
217 p= &(buff->data[bufnum-1]);
218 if ( IS_ESC(p[0]) &&
219 ((bufnum <= 1) || !IS_ESC(p[-1])))
220 {
221 bufnum--;
222 again=1;
223 }
224 }
225 if (again) continue;
226 bufnum=0;
227 buf=buff->data;
228
229 clear_comments(buf);
230 n=strlen(buf);
231 s=eat_ws(buf);
232 if (IS_EOF(*s)) continue; /* blank line */
233 if (*s == '[')
234 {
dfeab068
RE
235 char *ss;
236
d02b48c6
RE
237 s++;
238 start=eat_ws(s);
dfeab068
RE
239 ss=start;
240again:
241 end=eat_alpha_numeric(ss);
d02b48c6
RE
242 p=eat_ws(end);
243 if (*p != ']')
244 {
dfeab068
RE
245 if (*p != '\0')
246 {
247 ss=p;
248 goto again;
249 }
8623f693
DSH
250 CONFerr(CONF_F_CONF_LOAD_BIO,
251 CONF_R_MISSING_CLOSE_SQUARE_BRACKET);
d02b48c6
RE
252 goto err;
253 }
254 *end='\0';
255 if (!str_copy(ret,NULL,&section,start)) goto err;
256 if ((sv=get_section(ret,section)) == NULL)
257 sv=new_section(ret,section);
258 if (sv == NULL)
259 {
8623f693
DSH
260 CONFerr(CONF_F_CONF_LOAD_BIO,
261 CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
d02b48c6
RE
262 goto err;
263 }
264 section_sk=(STACK *)sv->value;
265 continue;
266 }
267 else
268 {
269 pname=s;
270 psection=NULL;
271 end=eat_alpha_numeric(s);
272 if ((end[0] == ':') && (end[1] == ':'))
273 {
274 *end='\0';
275 end+=2;
276 psection=pname;
277 pname=end;
278 end=eat_alpha_numeric(end);
279 }
280 p=eat_ws(end);
281 if (*p != '=')
282 {
8623f693
DSH
283 CONFerr(CONF_F_CONF_LOAD_BIO,
284 CONF_R_MISSING_EQUAL_SIGN);
d02b48c6
RE
285 goto err;
286 }
287 *end='\0';
288 p++;
289 start=eat_ws(p);
290 while (!IS_EOF(*p))
291 p++;
292 p--;
293 while ((p != start) && (IS_WS(*p)))
294 p--;
295 p++;
296 *p='\0';
297
298 if ((v=(CONF_VALUE *)Malloc(sizeof(CONF_VALUE))) == NULL)
299 {
8623f693
DSH
300 CONFerr(CONF_F_CONF_LOAD_BIO,
301 ERR_R_MALLOC_FAILURE);
d02b48c6
RE
302 goto err;
303 }
304 if (psection == NULL) psection=section;
305 v->name=(char *)Malloc(strlen(pname)+1);
306 v->value=NULL;
307 if (v->name == NULL)
308 {
8623f693
DSH
309 CONFerr(CONF_F_CONF_LOAD_BIO,
310 ERR_R_MALLOC_FAILURE);
d02b48c6
RE
311 goto err;
312 }
313 strcpy(v->name,pname);
314 if (!str_copy(ret,psection,&(v->value),start)) goto err;
315
316 if (strcmp(psection,section) != 0)
317 {
318 if ((tv=get_section(ret,psection))
319 == NULL)
320 tv=new_section(ret,psection);
321 if (tv == NULL)
322 {
8623f693
DSH
323 CONFerr(CONF_F_CONF_LOAD_BIO,
324 CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
d02b48c6
RE
325 goto err;
326 }
327 ts=(STACK *)tv->value;
328 }
329 else
330 {
331 tv=sv;
332 ts=section_sk;
333 }
334 v->section=tv->section;
335 if (!sk_push(ts,(char *)v))
336 {
8623f693
DSH
337 CONFerr(CONF_F_CONF_LOAD_BIO,
338 ERR_R_MALLOC_FAILURE);
d02b48c6
RE
339 goto err;
340 }
341 vv=(CONF_VALUE *)lh_insert(ret,(char *)v);
342 if (vv != NULL)
343 {
344 sk_delete_ptr(ts,(char *)vv);
345 Free(vv->name);
346 Free(vv->value);
347 Free(vv);
348 }
349 v=NULL;
350 }
351 }
352 if (buff != NULL) BUF_MEM_free(buff);
353 if (section != NULL) Free(section);
d02b48c6
RE
354 return(ret);
355err:
356 if (buff != NULL) BUF_MEM_free(buff);
357 if (section != NULL) Free(section);
358 if (line != NULL) *line=eline;
dfeab068
RE
359 sprintf(btmp,"%ld",eline);
360 ERR_add_error_data(2,"line ",btmp);
d02b48c6
RE
361 if ((h != ret) && (ret != NULL)) CONF_free(ret);
362 if (v != NULL)
363 {
364 if (v->name != NULL) Free(v->name);
365 if (v->value != NULL) Free(v->value);
366 if (v != NULL) Free(v);
367 }
368 return(NULL);
369 }
8623f693 370
6b691a5c 371char *CONF_get_string(LHASH *conf, char *section, char *name)
d02b48c6
RE
372 {
373 CONF_VALUE *v,vv;
374 char *p;
375
376 if (name == NULL) return(NULL);
377 if (conf != NULL)
378 {
379 if (section != NULL)
380 {
381 vv.name=name;
382 vv.section=section;
383 v=(CONF_VALUE *)lh_retrieve(conf,(char *)&vv);
384 if (v != NULL) return(v->value);
385 if (strcmp(section,"ENV") == 0)
386 {
387 p=Getenv(name);
388 if (p != NULL) return(p);
389 }
390 }
f3c75106 391 vv.section="default";
d02b48c6
RE
392 vv.name=name;
393 v=(CONF_VALUE *)lh_retrieve(conf,(char *)&vv);
394 if (v != NULL)
395 return(v->value);
396 else
397 return(NULL);
398 }
399 else
400 return(Getenv(name));
401 }
402
6b691a5c 403static CONF_VALUE *get_section(LHASH *conf, char *section)
d02b48c6
RE
404 {
405 CONF_VALUE *v,vv;
406
407 if ((conf == NULL) || (section == NULL)) return(NULL);
408 vv.name=NULL;
409 vv.section=section;
410 v=(CONF_VALUE *)lh_retrieve(conf,(char *)&vv);
411 return(v);
412 }
413
6b691a5c 414STACK *CONF_get_section(LHASH *conf, char *section)
d02b48c6
RE
415 {
416 CONF_VALUE *v;
417
418 v=get_section(conf,section);
419 if (v != NULL)
420 return((STACK *)v->value);
421 else
422 return(NULL);
423 }
424
6b691a5c 425long CONF_get_number(LHASH *conf, char *section, char *name)
d02b48c6
RE
426 {
427 char *str;
428 long ret=0;
429
430 str=CONF_get_string(conf,section,name);
431 if (str == NULL) return(0);
432 for (;;)
433 {
434 if (IS_NUMER(*str))
435 ret=ret*10+(*str -'0');
436 else
437 return(ret);
438 str++;
439 }
440 }
441
6b691a5c 442void CONF_free(LHASH *conf)
d02b48c6
RE
443 {
444 if (conf == NULL) return;
445
446 conf->down_load=0; /* evil thing to make sure the 'Free()'
447 * works as expected */
448 lh_doall_arg(conf,(void (*)())value_free_hash,(char *)conf);
449
450 /* We now have only 'section' entries in the hash table.
451 * Due to problems with */
452
453 lh_doall_arg(conf,(void (*)())value_free_stack,(char *)conf);
454 lh_free(conf);
455 }
456
6b691a5c 457static void value_free_hash(CONF_VALUE *a, LHASH *conf)
d02b48c6
RE
458 {
459 if (a->name != NULL)
460 {
461 a=(CONF_VALUE *)lh_delete(conf,(char *)a);
462 }
463 }
464
6b691a5c 465static void value_free_stack(CONF_VALUE *a, LHASH *conf)
d02b48c6
RE
466 {
467 CONF_VALUE *vv;
468 STACK *sk;
469 int i;
470
471 if (a->name != NULL) return;
472
473 sk=(STACK *)a->value;
474 for (i=sk_num(sk)-1; i>=0; i--)
475 {
476 vv=(CONF_VALUE *)sk_value(sk,i);
477 Free(vv->value);
478 Free(vv->name);
479 Free(vv);
480 }
481 if (sk != NULL) sk_free(sk);
482 Free(a->section);
483 Free(a);
484 }
485
6b691a5c 486static void clear_comments(char *p)
d02b48c6
RE
487 {
488 char *to;
489
490 to=p;
491 for (;;)
492 {
493 if (IS_COMMENT(*p))
494 {
495 *p='\0';
496 return;
497 }
498 if (IS_QUOTE(*p))
499 {
500 p=scan_quote(p);
501 continue;
502 }
503 if (IS_ESC(*p))
504 {
505 p=scan_esc(p);
506 continue;
507 }
508 if (IS_EOF(*p))
509 return;
510 else
511 p++;
512 }
513 }
514
6b691a5c 515static int str_copy(LHASH *conf, char *section, char **pto, char *from)
d02b48c6
RE
516 {
517 int q,r,rr=0,to=0,len=0;
518 char *s,*e,*rp,*p,*rrp,*np,*cp,v;
519 BUF_MEM *buf;
520
521 if ((buf=BUF_MEM_new()) == NULL) return(0);
522
523 len=strlen(from)+1;
524 if (!BUF_MEM_grow(buf,len)) goto err;
525
526 for (;;)
527 {
528 if (IS_QUOTE(*from))
529 {
530 q= *from;
531 from++;
532 while ((*from != '\0') && (*from != q))
533 {
534 if (*from == '\\')
535 {
536 from++;
537 if (*from == '\0') break;
538 }
539 buf->data[to++]= *(from++);
540 }
541 }
542 else if (*from == '\\')
543 {
544 from++;
545 v= *(from++);
546 if (v == '\0') break;
547 else if (v == 'r') v='\r';
548 else if (v == 'n') v='\n';
549 else if (v == 'b') v='\b';
550 else if (v == 't') v='\t';
551 buf->data[to++]= v;
552 }
553 else if (*from == '\0')
554 break;
555 else if (*from == '$')
556 {
557 /* try to expand it */
558 rrp=NULL;
559 s= &(from[1]);
560 if (*s == '{')
561 q='}';
562 else if (*s == '(')
563 q=')';
564 else q=0;
565
566 if (q) s++;
567 cp=section;
568 e=np=s;
569 while (IS_ALPHA_NUMERIC(*e))
570 e++;
571 if ((e[0] == ':') && (e[1] == ':'))
572 {
573 cp=np;
574 rrp=e;
575 rr= *e;
576 *rrp='\0';
577 e+=2;
578 np=e;
579 while (IS_ALPHA_NUMERIC(*e))
580 e++;
581 }
582 r= *e;
583 *e='\0';
584 rp=e;
585 if (q)
586 {
587 if (r != q)
588 {
589 CONFerr(CONF_F_STR_COPY,CONF_R_NO_CLOSE_BRACE);
590 goto err;
591 }
592 e++;
593 }
594 /* So at this point we have
595 * ns which is the start of the name string which is
596 * '\0' terminated.
597 * cs which is the start of the section string which is
598 * '\0' terminated.
599 * e is the 'next point after'.
600 * r and s are the chars replaced by the '\0'
601 * rp and sp is where 'r' and 's' came from.
602 */
603 p=CONF_get_string(conf,cp,np);
604 if (rrp != NULL) *rrp=rr;
605 *rp=r;
606 if (p == NULL)
607 {
608 CONFerr(CONF_F_STR_COPY,CONF_R_VARIABLE_HAS_NO_VALUE);
609 goto err;
610 }
611 BUF_MEM_grow(buf,(strlen(p)+len-(e-from)));
612 while (*p)
613 buf->data[to++]= *(p++);
614 from=e;
615 }
616 else
617 buf->data[to++]= *(from++);
618 }
619 buf->data[to]='\0';
620 if (*pto != NULL) Free(*pto);
621 *pto=buf->data;
622 Free(buf);
623 return(1);
624err:
625 if (buf != NULL) BUF_MEM_free(buf);
626 return(0);
627 }
628
6b691a5c 629static char *eat_ws(char *p)
d02b48c6
RE
630 {
631 while (IS_WS(*p) && (!IS_EOF(*p)))
632 p++;
633 return(p);
634 }
635
6b691a5c 636static char *eat_alpha_numeric(char *p)
d02b48c6
RE
637 {
638 for (;;)
639 {
640 if (IS_ESC(*p))
641 {
642 p=scan_esc(p);
643 continue;
644 }
645 if (!IS_ALPHA_NUMERIC_PUNCT(*p))
646 return(p);
647 p++;
648 }
649 }
650
6b691a5c 651static unsigned long hash(CONF_VALUE *v)
d02b48c6
RE
652 {
653 return((lh_strhash(v->section)<<2)^lh_strhash(v->name));
654 }
655
6b691a5c 656static int cmp(CONF_VALUE *a, CONF_VALUE *b)
d02b48c6
RE
657 {
658 int i;
659
660 if (a->section != b->section)
661 {
662 i=strcmp(a->section,b->section);
663 if (i) return(i);
664 }
665
666 if ((a->name != NULL) && (b->name != NULL))
667 {
668 i=strcmp(a->name,b->name);
669 return(i);
670 }
671 else if (a->name == b->name)
672 return(0);
673 else
674 return((a->name == NULL)?-1:1);
675 }
676
6b691a5c 677static char *scan_quote(char *p)
d02b48c6
RE
678 {
679 int q= *p;
680
681 p++;
682 while (!(IS_EOF(*p)) && (*p != q))
683 {
684 if (IS_ESC(*p))
685 {
686 p++;
687 if (IS_EOF(*p)) return(p);
688 }
689 p++;
690 }
691 if (*p == q) p++;
692 return(p);
693 }
694
6b691a5c 695static CONF_VALUE *new_section(LHASH *conf, char *section)
d02b48c6
RE
696 {
697 STACK *sk=NULL;
698 int ok=0,i;
699 CONF_VALUE *v=NULL,*vv;
700
701 if ((sk=sk_new_null()) == NULL)
702 goto err;
703 if ((v=(CONF_VALUE *)Malloc(sizeof(CONF_VALUE))) == NULL)
704 goto err;
705 i=strlen(section)+1;
706 if ((v->section=(char *)Malloc(i)) == NULL)
707 goto err;
708
709 memcpy(v->section,section,i);
710 v->name=NULL;
711 v->value=(char *)sk;
712
713 vv=(CONF_VALUE *)lh_insert(conf,(char *)v);
d02b48c6
RE
714 if (vv != NULL)
715 {
58964a49 716#if !defined(NO_STDIO) && !defined(WIN16)
d02b48c6 717 fprintf(stderr,"internal fault\n");
58964a49 718#endif
d02b48c6
RE
719 abort();
720 }
d02b48c6
RE
721 ok=1;
722err:
723 if (!ok)
724 {
725 if (sk != NULL) sk_free(sk);
726 if (v != NULL) Free(v);
727 v=NULL;
728 }
729 return(v);
730 }