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