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