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