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