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