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