4803300b011a9f81792f19a0a27fbb61787f1b10
[freeradius.git] / src / main / conffile.c
1 /*
2  * conffile.c   Read the radiusd.conf file.
3  *
4  *              Yep I should learn to use lex & yacc, or at least
5  *              write a decent parser. I know how to do that, really :)
6  *              miquels@cistron.nl
7  *
8  * Version:     $Id$
9  *
10  */
11
12 #include "autoconf.h"
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <string.h>
18 #include <errno.h>
19
20 #include "radiusd.h"
21 #include "conffile.h"
22 #include "token.h"
23 #include "modules.h"
24
25 static const char rcsid[] =
26 "$Id$";
27
28 #define xalloc malloc
29 #define xstrdup strdup
30
31 CONF_SECTION    *config = NULL;
32
33 extern RADCLIENT *clients;
34 extern REALM     *realms;
35
36 static int generate_realms(const char *filename);
37 static int generate_clients(const char *filename);
38
39 #ifndef RADIUS_CONFIG
40 #define RADIUS_CONFIG "radiusd.conf"
41 #endif
42
43 /*
44  *      Create a new CONF_PAIR
45  */
46 CONF_PAIR *cf_pair_alloc(const char *attr, const char *value, int operator)
47 {
48         CONF_PAIR       *cp;
49
50         cp = (CONF_PAIR *)xalloc(sizeof(CONF_PAIR));
51         memset(cp, 0, sizeof(CONF_PAIR));
52         cp->attr = xstrdup(attr);
53         cp->value = xstrdup(value);
54         cp->operator = operator;
55
56         return cp;
57 }
58
59 /*
60  *      Add a pair to a configuration section.
61  */
62 void cf_pair_add(CONF_SECTION *cs, CONF_PAIR *cp_new)
63 {
64         CONF_PAIR *cp;
65         
66         for (cp = cs->cps; cp && cp->next; cp = cp->next)
67                 ;
68
69         if (cp == NULL)
70                 cs->cps = cp_new;
71         else
72                 cp->next = cp_new;
73 }
74
75 /*
76  *      Free a CONF_PAIR
77  */
78 void cf_pair_free(CONF_PAIR *cp)
79 {
80         if (cp == NULL) return;
81
82         if (cp->attr)  free(cp->attr);
83         if (cp->value) free(cp->value);
84         free(cp);
85 }
86
87 /*
88  *      Allocate a CONF_SECTION
89  */
90 CONF_SECTION *cf_section_alloc(const char *name1, const char *name2)
91 {
92         CONF_SECTION    *cs;
93
94         if (name1 == NULL || !name1[0]) name1 = "main";
95
96         cs = (CONF_SECTION *)xalloc(sizeof(CONF_SECTION));
97         memset(cs, 0, sizeof(CONF_SECTION));
98         cs->name1 = xstrdup(name1);
99         cs->name2 = (name2 && *name2) ? xstrdup(name2) : NULL;
100
101         return cs;
102 }
103
104 /*
105  *      Free a CONF_SECTION
106  */
107 void cf_section_free(CONF_SECTION *cs)
108 {
109         CONF_PAIR       *cp, *next;
110         CONF_SECTION *sub, *next_sub;
111
112         if (cs == NULL) return;
113
114         for (cp = cs->cps; cp; cp = next) {
115                 next = cp->next;
116                 cf_pair_free(cp);
117         }
118
119         /*
120          * Clear out any possible subsections as well
121          */
122         for (sub = cs->sub; sub; sub = next_sub) {
123                 next_sub = sub->next;
124                 cf_section_free(sub);
125         }
126
127         if (cs->name1) free(cs->name1);
128         if (cs->name2) free(cs->name2);
129
130         /*
131          * And free the section
132          */
133         free(cs);
134 }
135
136 /*
137  *      Parse a configuration section into user-supplied variables.
138  */
139 int cf_section_parse(CONF_SECTION *cs, const CONF_PARSER *variables)
140 {
141         int             i;
142         char            **q;
143         CONF_PAIR       *cp;
144         uint32_t        ipaddr;
145         char            buffer[1024];
146         const char      *value;
147
148         /*
149          *      Handle the user-supplied variables.
150          */
151         for (i = 0; variables[i].name != NULL; i++) {
152                 value = variables[i].dflt;
153
154                 cp = cf_pair_find(cs, variables[i].name);
155                 if (cp) {
156                         value = cp->value;
157                 }
158                 
159                 switch (variables[i].type)
160                 {
161                 case PW_TYPE_BOOLEAN:
162                         /*
163                          *      Allow yes/no and on/off
164                          */
165                         if ((strcasecmp(value, "yes") == 0) ||
166                             (strcasecmp(value, "on") == 0)) {
167                                 *(int *)variables[i].data = 1;
168                         } else if ((strcasecmp(value, "no") == 0) ||
169                                    (strcasecmp(value, "off") == 0)) {
170                                 *(int *)variables[i].data = 0;
171                         } else {
172                                 *(int *)variables[i].data = 0;
173                                 log(L_ERR, "Bad value \"%s\" for boolean variable %s", value, variables[i].name);
174                                 return -1;
175                         }
176                         DEBUG2("Config: %s.%s = %s",
177                                cs->name1,
178                                variables[i].name,
179                                value);
180                         break;
181
182                 case PW_TYPE_INTEGER:
183                         *(int *)variables[i].data = strtol(value, 0, 0);
184                         DEBUG2("Config: %s.%s = %d",
185                                cs->name1,
186                                variables[i].name,
187                                *(int *)variables[i].data);
188                         break;
189                         
190                 case PW_TYPE_STRING_PTR:
191                         q = (char **) variables[i].data;
192                         if (*q != NULL) {
193                                 free(*q);
194                         }
195                         DEBUG2("Config: %s.%s = \"%s\"",
196                                cs->name1,
197                                variables[i].name,
198                                value ? value : "(null)");
199                         *q = value ? strdup(value) : NULL;
200                         break;
201
202                 case PW_TYPE_IPADDR:
203                         /*
204                          *      Allow '*' as any address
205                          */
206                         if (strcmp(value, "*") == 0) {
207                                 *(uint32_t *) variables[i].data = 0;
208                                 break;
209                         }
210                         ipaddr = ip_getaddr(value);
211                         if (ipaddr == 0) {
212                                 log(L_ERR, "Can't find IP address for host %s", value);
213                                 return -1;
214                         }
215                         DEBUG2("Config: %s.%s = %s IP address [%s]",
216                                cs->name1,
217                                variables[i].name,
218                                value, ip_ntoa(buffer, ipaddr));
219                         *(uint32_t *) variables[i].data = ipaddr;
220                         break;
221                         
222                 default:
223                         log(L_ERR, "type %d not supported yet", variables[i].type);
224                         return -1;
225                         break;
226                 } /* switch over variable type */
227         } /* for all variables in the configuration section */
228         
229         return 0;
230 }
231
232
233 /*
234  *      Read a part of the config file.
235  */
236 static CONF_SECTION *cf_section_read(const char *cf, int *lineno, FILE *fp,
237                                      const char *name1, const char *name2)
238 {
239         CONF_SECTION    *cs, *csp, *css;
240         CONF_PAIR       *cpn;
241         char            *ptr, *p, *q;
242         char            buf[8192];
243         char            buf1[1024];
244         char            buf2[1024];
245         char            buf3[1024];
246         int             t1, t2, t3;
247         
248         /*
249          *      Ensure that the user can't add CONF_SECTIONs
250          *      with 'internal' names;
251          */
252         if ((name1 != NULL) && (name1[0] == '_')) {
253                 log(L_ERR, "%s[%d]: Illegal configuration section name",
254                     cf, *lineno);
255                 return NULL;
256         }
257
258         /*
259          *      Allow for $INCLUDE files???
260          *
261          *      This sure looks wrong. But it looked wrong before I touched
262          *      the file, so don't blame me. Please, just pass the config
263          *      file through cpp or m4 and cut out the bloat. --Pac.
264          */
265         if (name1 && strcasecmp(name1, "$INCLUDE") == 0) {
266           return conf_read(name2);
267         }
268
269         /*
270          *      Allocate new section.
271          */
272         cs = cf_section_alloc(name1, name2);
273         cs->lineno = *lineno;
274
275         /*
276          *      Read.
277          */
278         while (fgets(buf, sizeof(buf), fp) != NULL) {
279                 (*lineno)++;
280                 ptr = buf;
281
282                 if (*ptr == '#')
283                         continue;
284
285                 /*
286                  *      No '=': must be a section or sub-section.
287                  */
288                 if (strchr(ptr, '=') == NULL) {
289                         t1 = gettoken(&ptr, buf1, sizeof(buf1));
290                         t2 = gettoken(&ptr, buf2, sizeof(buf2));
291                         t3 = gettoken(&ptr, buf3, sizeof(buf3));
292                 } else {
293                         t1 = gettoken(&ptr, buf1, sizeof(buf1));
294                         t2 = gettoken(&ptr, buf2, sizeof(buf2));
295                         t3 = getword(&ptr, buf3, sizeof(buf3));
296                 }
297
298                 if (buf1[0] == 0 || buf1[0] == '#')
299                         continue;
300
301                 /*
302                  *      See if it's the end of a section.
303                  */
304                 if (t1 == T_RCBRACE) {
305                         if (name1 == NULL || buf2[0]) {
306                                 log(L_ERR, "%s[%d]: Unexpected end of section",
307                                         cf, *lineno);
308                                 cf_section_free(cs);
309                                 return NULL;
310                         }
311                         return cs;
312                 }
313
314                 /*
315                  * Perhaps a subsection.
316                  */
317
318                 if (t2 == T_LCBRACE || t3 == T_LCBRACE) {
319                         css = cf_section_read(cf, lineno, fp, buf1,
320                                                 t2==T_LCBRACE ? NULL : buf2);
321                         if (css == NULL) {
322                                 cf_section_free(cs);
323                                 return NULL;
324                         }
325                         for (csp = cs->sub; csp && csp->next; csp = csp->next)
326                                 ;
327                         if (csp == NULL)
328                                 cs->sub = css;
329                         else
330                                 csp->next = css;
331
332                         continue;               
333                 }
334
335                 /*
336                  *      Must be a normal attr = value line.
337                  */
338                 if (buf1[0] != 0 && buf2[0] == 0 && buf3[0] == 0) {
339                         t2 = T_OP_EQ;
340                 } else if (buf1[0] == 0 || buf2[0] == 0 || buf3[0] == 0 ||
341                           (t2 < T_EQSTART || t2 > T_EQEND)) {
342                         log(L_ERR, "%s[%d]: Line is not in 'attribute = value' format",
343                                 cf, *lineno);
344                         cf_section_free(cs);
345                         return NULL;
346                 }
347
348                 /*
349                  *      Ensure that the user can't add CONF_PAIRs
350                  *      with 'internal' names;
351                  */
352                 if (buf1[0] == '_') {
353                         log(L_ERR, "%s[%d]: Illegal configuration pair name \"%s\"",
354                                 cf, *lineno, buf1);
355                         cf_section_free(cs);
356                         return NULL;
357                 }
358                 
359                 /*
360                  *      Handle variable substitution via ${foo}
361                  */
362                 p = buf;
363                 ptr = buf3;
364                 while (*ptr >= ' ') {
365                         /*
366                          *      Ignore anything other than "${"
367                          */
368                         if ((*ptr != '$') ||
369                             (ptr[1] != '{')) {
370                                 *(p++) = *(ptr++);
371                                 continue;
372                         }
373
374                         /*
375                          *      Look for trailing '}', and silently
376                          *      ignore anything that doesn't match.
377                          */
378                         q = strchr(ptr, '}');
379                         if (q == NULL) {
380                                 *(p++) = *(ptr++);
381                                 continue;
382                         }
383                         
384                         memcpy(buf2, ptr + 2, q - ptr - 2);
385                         buf2[q - ptr - 2] = '\0';
386                         cpn = cf_pair_find(cs, buf2);
387                         if (!cpn) {
388                                 log(L_ERR, "%s[%d]: Unknown variable \"%s\"",
389                                     cf, *lineno, buf2);
390                                 cf_section_free(cs);
391                                 return NULL;
392                         }
393                         strcpy(p, cpn->value);
394                         p += strlen(p);
395                         ptr = q + 1;
396                 }
397                 *p = '\0';
398
399                 /*
400                  *      Add this CONF_PAIR to our CONF_SECTION
401                  */
402                 cpn = cf_pair_alloc(buf1, buf, t2);
403                 cpn->lineno = *lineno;
404                 cf_pair_add(cs, cpn);
405         }
406
407         /*
408          *      See if EOF was unexpected ..
409          */
410         if (name1 != NULL) {
411                 log(L_ERR, "%s[%d]: unexpected end of file", cf, *lineno);
412                 cf_section_free(cs);
413                 return NULL;
414         }
415
416         return cs;
417 }
418
419 /*
420  *      Read the config file.
421  */
422 CONF_SECTION *conf_read(const char *conffile)
423 {
424         FILE            *fp;
425         int             lineno = 0;
426         CONF_SECTION    *cs;
427         
428         if ((fp = fopen(conffile, "r")) == NULL) {
429                 log(L_ERR, "cannot open %s: %s",
430                         conffile, strerror(errno));
431                 return NULL;
432         }
433
434         cs = cf_section_read(conffile, &lineno, fp, NULL, NULL);
435         fclose(fp);
436
437         return cs;
438 }
439
440 /* JLN
441  * Read the configuration and library
442  * This uses the new kind of configuration file as defined by
443  * Miquel at http://www.miquels.cistron.nl/radius/
444  */
445
446 int read_radius_conf_file(void)
447 {
448         char buffer[256];
449         CONF_SECTION *cs;
450
451         /* Lets go for the new configuration files */
452
453         sprintf(buffer, "%.200s/%.50s", radius_dir, RADIUS_CONFIG);
454         if ((cs = conf_read(buffer)) == NULL) {
455                 return -1;
456         }
457
458         /*
459          *      Free the old configuration data, and replace it
460          *      with the new one.
461          */
462         cf_section_free(config);
463         config = cs;
464         
465
466
467         /*
468          * Fail if we can't generate list of clients
469          */
470
471         if (generate_clients(buffer) < 0) {
472                 return -1;
473         }
474
475         /*
476          * If there isn't any realms it isn't fatal..
477          */
478         if (generate_realms(buffer) < 0) {
479                 return -1;
480         }
481
482         return 0;       
483 }
484
485 /* JLN
486  * Create the linked list of realms from the new configuration type
487  * This way we don't have to change to much in the other source-files
488  */
489
490 static int generate_realms(const char *filename)
491 {
492         CONF_SECTION    *cs;
493         REALM           *c;
494         char            *s, *authhost, *accthost;
495
496         for (cs = config->sub; cs; cs = cs->next) {
497                 if (strcmp(cs->name1, "realm") == 0) {
498                         if (!cs->name2) {
499                                 log(L_CONS|L_ERR, "%s[%d]: Missing realm name", filename, cs->lineno);
500                                 return -1;
501                         }
502                         /*
503                          * We've found a realm, allocate space for it
504                          */
505                         if ((c = malloc(sizeof(REALM))) == NULL) {
506                                 log(L_CONS|L_ERR, "Out of memory");
507                                 return -1;
508                         }
509                         memset(c, 0, sizeof(REALM));
510                         /*
511                          * An authhost must exist in the configuration
512                          */
513                         if ((authhost = cf_section_value_find(cs, "authhost")) == NULL) {
514                                 log(L_CONS|L_ERR, 
515                                     "%s[%d]: No authhost entry in realm", 
516                                     filename, cs->lineno);
517                                 return -1;
518                         }
519                         if ((s = strchr(authhost, ':')) != NULL) {
520                                 *s++ = 0;
521                                 c->auth_port = atoi(s);
522                         } else {
523                                 c->auth_port = auth_port;
524                         }
525                         accthost = cf_section_value_find(cs, "accthost");
526                         if ((s =strchr(accthost, ':')) != NULL) {
527                                 *s++ = 0;
528                                 c->acct_port = atoi(s); 
529                         } else {
530                                 c->acct_port = acct_port;
531                         }
532                         if (strcmp(authhost, "LOCAL") != 0)
533                                 c->ipaddr = ip_getaddr(authhost);
534
535                         /* 
536                          * Double check length, just to be sure!
537                          */
538                         if (strlen(authhost) >= sizeof(c->server)) {
539                                 log(L_ERR, "%s[%d]: Server name of length %d is greater that allowed: %d",
540                                     filename, cs->lineno,
541                                     strlen(authhost), sizeof(c->server) - 1);
542                                 return -1;
543                         }
544                         if (strlen(cs->name2) >= sizeof(c->realm)) {
545                                 log(L_ERR, "%s[%d]: Realm name of length %d is greater than allowed %d",
546                                     filename, cs->lineno,
547                                     strlen(cs->name2), sizeof(c->server) - 1);
548                                 return -1;
549                         }
550                         
551                         strcpy(c->realm, cs->name2);
552                         strcpy(c->server, authhost);    
553
554                         s = cf_section_value_find(cs, "secret");
555                         if (s == NULL) {
556                                 log(L_ERR, "%s[%d]: No shared secret supplied for realm",
557                                     filename, cs->lineno);
558                                 return -1;
559                         }
560
561                         if (strlen(s) >= sizeof(c->secret)) {
562                           log(L_ERR, "%s[%d]: Secret of length %d is greater than the allowed maximum of %d.",
563                               filename, cs->lineno,
564                               strlen(s), sizeof(c->secret) - 1);
565                           return -1;
566                         }
567                         strNcpy(c->secret, s, sizeof(c->secret));
568
569                         c->striprealm = 1;
570                         
571                         if ((cf_section_value_find(cs, "nostrip")) != NULL)
572                                 c->striprealm = 0;
573                         if ((cf_section_value_find(cs, "noacct")) != NULL)
574                                 c->acct_port = 0;
575                         if ((cf_section_value_find(cs, "trusted")) != NULL)
576                                 c->trusted = 1;
577
578                         c->next = realms;
579                         realms = c;
580
581                 }
582         }
583
584         return 0;
585 }
586
587 /* JLN
588  * Create the linked list of realms from the new configuration type
589  * This way we don't have to change to much in the other source-files
590  */
591
592 static int generate_clients(const char *filename)
593 {
594         CONF_SECTION    *cs;
595         RADCLIENT       *c;
596         char            *hostnm, *secret, *shortnm;
597
598         for (cs = config->sub; cs; cs = cs->next) {
599                 if (strcmp(cs->name1, "client") == 0) {
600                         if (!cs->name2) {
601                                 log(L_CONS|L_ERR, "%s[%d]: Missing client name", filename, cs->lineno);
602                                 return -1;
603                         }
604                         /*
605                          * Check the lengths, we don't want any core dumps
606                          */
607                         hostnm = cs->name2;
608                         secret = cf_section_value_find(cs, "secret");
609                         shortnm = cf_section_value_find(cs, "shortname");
610
611                         if (strlen(secret) >= sizeof(c->secret)) {
612                                 log(L_ERR, "%s[%d]: Secret of length %d is greater than the allowed maximum of %d.",
613                                     filename, cs->lineno,
614                                     strlen(secret), sizeof(c->secret) - 1);
615                                 return -1;
616                         }
617                         if (strlen(shortnm) > sizeof(c->shortname)) {
618                                 log(L_ERR, "%s[%d]: NAS short name of length %d is greater than the allowed maximum of %d.",
619                                     filename, cs->lineno,
620                                     strlen(shortnm), sizeof(c->shortname) - 1);
621                                 return -1;
622                         }
623                         /*
624                          * The size is fine.. Let's create the buffer
625                          */
626                         if ((c = malloc(sizeof(RADCLIENT))) == NULL) {
627                                 log(L_CONS|L_ERR, "Out of memory");
628                                 return -1;
629                         }
630
631                         c->ipaddr = ip_getaddr(hostnm);
632                         strcpy(c->secret, secret);
633                         strcpy(c->shortname, shortnm);
634                         ip_hostname(c->longname, sizeof(c->longname),
635                                     c->ipaddr);
636
637                         c->next = clients;
638                         clients = c;
639                 }
640         }
641
642         return 0;
643 }
644
645 /* 
646  * Return a CONF_PAIR within a CONF_SECTION.
647  */
648
649 CONF_PAIR *cf_pair_find(CONF_SECTION *section, const char *name)
650 {
651         CONF_PAIR       *cp;
652
653         if (section == NULL) {
654           section = config;
655         }
656
657         for (cp = section->cps; cp; cp = cp->next)
658                 if (strcmp(cp->attr, name) == 0)
659                         break;
660
661         return cp;
662 }
663
664 /*
665  * Return the value of a CONF_PAIR
666  */
667
668 char *cf_pair_value(CONF_PAIR *pair)
669 {
670         return (pair ? pair->value : NULL);
671 }
672
673
674 /* 
675  * Find a value in a CONF_SECTION
676  */
677 char *cf_section_value_find(CONF_SECTION *section, const char *attr)
678 {
679         CONF_PAIR       *cp;
680
681         cp = cf_pair_find(section, attr);
682
683         return (cp ? cp->value : NULL);
684 }
685
686 /*
687  * Return the next pair after a CONF_PAIR
688  * with a certain name (char *attr)
689  */
690
691 CONF_PAIR *cf_pair_find_next(CONF_SECTION *section, CONF_PAIR *pair, const char *attr)
692 {
693         CONF_PAIR       *cp;
694
695         /*
696          * If pair is NULL this must be a first time run
697          * Find the pair with correct name
698          */
699
700         if (pair == NULL){
701                 cp = cf_pair_find(section, attr);
702         } else {
703                 cp = pair->next;
704         }
705
706         for (; cp; cp = cp->next)
707                 if (strcmp(cp->attr, attr) == 0)
708                         break;
709
710         return cp;
711 }
712
713 /*
714  * Find a CONF_SECTION, or return the root if name is NULL
715  */
716
717 CONF_SECTION *cf_section_find(const char *name)
718 {
719         if (name)
720                 return cf_section_sub_find(config, name);
721         else
722                 return config;
723 }
724
725 /*
726  * Find a sub-section in a section
727  */
728
729 CONF_SECTION *cf_section_sub_find(CONF_SECTION *section, const char *name)
730 {
731
732         CONF_SECTION *cs;
733         for (cs = section->sub; cs; cs = cs->next)
734                 if (strcmp(cs->name1, name) == 0)
735                         break;
736         
737         return cs;
738
739 }
740
741 /*
742  * Return the next subsection after a CONF_SECTION
743  * with a certain name1 (char *name1)
744  */
745
746 CONF_SECTION *cf_subsection_find_next(CONF_SECTION *section,
747                                       CONF_SECTION *subsection,
748                                       const char *name1)
749 {
750         CONF_SECTION    *cp;
751
752         /*
753          * If subsection is NULL this must be a first time run
754          * Find the subsection with correct name
755          */
756
757         if (subsection == NULL){
758                 cp = section->sub;
759         } else {
760                 cp = subsection->next;
761         }
762
763         for (; cp; cp = cp->next)
764                 if (strcmp(cp->name1, name1) == 0)
765                         break;
766
767         return cp;
768 }
769
770 /*
771  * Find the configuration section for a module
772  */
773
774 CONF_SECTION *cf_module_config_find(const char *modulename)
775 {
776         CONF_SECTION *cs;
777
778         for (cs = config->sub; cs; cs = cs->next)
779                 if ((strcmp(cs->name1, "module") == 0)
780                         && (strcmp(cs->name2, modulename) == 0))
781                         break;
782
783         return cs;
784 }
785
786 /* 
787  * JMG dump_config tries to dump the config structure in a readable format
788  * 
789 */
790
791 static int dump_config_section(CONF_SECTION *cs, int indent)
792 {
793         CONF_SECTION    *scs;
794
795         CONF_PAIR       *cp;
796
797         /* The DEBUG macro doesn't let me
798          *   for(i=0;i<indent;++i) debugputchar('\t');
799          * so I had to get creative. --Pac. */
800
801         for (cp = cs->cps; cp; cp = cp->next) 
802                 DEBUG("%.*s%s = %s",
803                         indent, "\t\t\t\t\t\t\t\t\t\t\t", cp->attr, cp->value);
804
805         for (scs = cs->sub; scs; scs = scs->next) {
806                 DEBUG("%.*s%s %s%s{",
807                         indent, "\t\t\t\t\t\t\t\t\t\t\t",
808                         scs->name1,
809                         scs->name2 ? scs->name2 : "",
810                         scs->name2 ?  " " : "");
811                 dump_config_section(scs, indent+1);
812                 DEBUG("%.*s}",
813                         indent, "\t\t\t\t\t\t\t\t\t\t\t");
814         }
815
816         return 0;
817 }
818
819 int dump_config(void)
820 {
821         return dump_config_section(config, 0);
822 }