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