Added a second mode of operation to cf_section_parse, where it takes a base
[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  *   This program is free software; you can redistribute it and/or modify
11  *   it under the terms of the GNU General Public License as published by
12  *   the Free Software Foundation; either version 2 of the License, or
13  *   (at your option) any later version.
14  *
15  *   This program is distributed in the hope that it will be useful,
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *   GNU General Public License for more details.
19  *
20  *   You should have received a copy of the GNU General Public License
21  *   along with this program; if not, write to the Free Software
22  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  *
24  * Copyright 2000  The FreeRADIUS server project
25  * Copyright 2000  Miquel van Smoorenburg <miquels@cistron.nl>
26  * Copyright 2000  Alan DeKok <aland@ox.org>
27  */
28
29 #include "autoconf.h"
30 #include "libradius.h"
31
32 #include <stdlib.h>
33 #include <string.h>
34 #include <assert.h>
35
36 #if HAVE_NETINET_IN_H
37 #       include <netinet/in.h>
38 #endif
39
40 #include "radiusd.h"
41 #include "conffile.h"
42 #include "token.h"
43 #include "modules.h"
44
45 static const char rcsid[] =
46 "$Id$";
47
48 #define xstrdup strdup
49
50 typedef enum conf_type {
51         CONF_ITEM_PAIR,
52         CONF_ITEM_SECTION
53 } CONF_ITEM_TYPE;
54
55 struct conf_item {
56         struct conf_item        *next;
57         struct conf_part        *parent;
58         int                     lineno;
59         CONF_ITEM_TYPE          type;
60 };
61 struct conf_pair {
62         CONF_ITEM       item;
63         char            *attr;
64         char            *value;
65         int             operator;
66 };
67 struct conf_part {
68         CONF_ITEM               item;
69         char                    *name1;
70         char                    *name2;
71         struct conf_item        *children;
72 };
73
74 CONF_SECTION    *config = NULL;
75
76 /*
77  *      Yucky hacks.
78  */
79 extern RADCLIENT *clients;
80 extern REALM     *realms;
81 extern int read_realms_file(const char *file);
82
83 static int generate_realms(const char *filename);
84 static int generate_clients(const char *filename);
85 static CONF_SECTION *conf_read(const char *fromfile, int fromline, const char *conffile);
86
87 #ifndef RADIUS_CONFIG
88 #define RADIUS_CONFIG "radiusd.conf"
89 #endif
90
91 /*
92  *      Isolate the scary casts in these tiny provably-safe functions
93  */
94 CONF_PAIR *cf_itemtopair(CONF_ITEM *ci)
95 {
96         if (ci == NULL)
97                 return NULL;
98         assert(ci->type == CONF_ITEM_PAIR);
99         return (CONF_PAIR *)ci;
100 }
101 CONF_SECTION *cf_itemtosection(CONF_ITEM *ci)
102 {
103         if (ci == NULL)
104                 return NULL;
105         assert(ci->type == CONF_ITEM_SECTION);
106         return (CONF_SECTION *)ci;
107 }
108 CONF_ITEM *cf_pairtoitem(CONF_PAIR *cp)
109 {
110         if (cp == NULL)
111                 return NULL;
112         return (CONF_ITEM *)cp;
113 }
114 CONF_ITEM *cf_sectiontoitem(CONF_SECTION *cs)
115 {
116         if (cs == NULL)
117                 return NULL;
118         return (CONF_ITEM *)cs;
119 }
120
121 /*
122  *      Create a new CONF_PAIR
123  */
124 static CONF_PAIR *cf_pair_alloc(const char *attr, const char *value,
125                 int operator, CONF_SECTION *parent)
126 {
127         CONF_PAIR       *cp;
128
129         cp = (CONF_PAIR *)rad_malloc(sizeof(CONF_PAIR));
130         memset(cp, 0, sizeof(CONF_PAIR));
131         cp->item.type = CONF_ITEM_PAIR;
132         cp->item.parent = parent;
133         cp->attr = xstrdup(attr);
134         cp->value = xstrdup(value);
135         cp->operator = operator;
136
137         return cp;
138 }
139
140 /*
141  *      Free a CONF_PAIR
142  */
143 void cf_pair_free(CONF_PAIR **cp)
144 {
145         if (!cp || !*cp) return;
146
147         if ((*cp)->attr)
148                 free((*cp)->attr);
149         if ((*cp)->value)
150                 free((*cp)->value);
151
152 #ifndef NDEBUG
153         memset(*cp, 0, sizeof(*cp));
154 #endif
155         free(*cp);
156
157         *cp = NULL;
158 }
159
160 /*
161  *      Allocate a CONF_SECTION
162  */
163 static CONF_SECTION *cf_section_alloc(const char *name1, const char *name2,
164                 CONF_SECTION *parent)
165 {
166         CONF_SECTION    *cs;
167
168         if (name1 == NULL || !name1[0]) 
169                 name1 = "main";
170
171         cs = (CONF_SECTION *)rad_malloc(sizeof(CONF_SECTION));
172         memset(cs, 0, sizeof(CONF_SECTION));
173         cs->item.type = CONF_ITEM_SECTION;
174         cs->item.parent = parent;
175         cs->name1 = xstrdup(name1);
176         cs->name2 = (name2 && *name2) ? xstrdup(name2) : NULL;
177
178         return cs;
179 }
180
181 /*
182  *      Free a CONF_SECTION
183  */
184 void cf_section_free(CONF_SECTION **cs)
185 {
186         CONF_ITEM       *ci, *next;
187
188         if (!cs || !*cs) return;
189
190         for (ci = (*cs)->children; ci; ci = next) {
191                 next = ci->next;
192                 if (ci->type==CONF_ITEM_PAIR) {
193                         CONF_PAIR *pair = cf_itemtopair(ci);
194                         cf_pair_free(&pair);
195                 } else {
196                         CONF_SECTION *section = cf_itemtosection(ci);
197                         cf_section_free(&section);
198                 }
199         }
200
201         if ((*cs)->name1) free((*cs)->name1);
202         if ((*cs)->name2) free((*cs)->name2);
203
204         /*
205          * And free the section
206          */
207 #ifndef NDEBUG
208         memset(*cs, 0, sizeof(*cs));
209 #endif
210         free(*cs);
211
212         *cs = NULL;
213 }
214
215 /*
216  *      Add an item to a configuration section.
217  */
218 static void cf_item_add(CONF_SECTION *cs, CONF_ITEM *ci_new)
219 {
220         CONF_ITEM *ci;
221         
222         for (ci = cs->children; ci && ci->next; ci = ci->next)
223                 ;
224
225         if (ci == NULL)
226                 cs->children = ci_new;
227         else
228                 ci->next = ci_new;
229 }
230
231 /*
232  *      Expand the variables in an input string.
233  */
234 static const char *cf_expand_variables(const char *cf, int *lineno,
235                                         CONF_SECTION *cs,
236                                         char *output, const char *input)
237 {
238         char            *p;
239         const char      *end, *ptr;
240         char            name[1024];
241         CONF_PAIR       *cpn;
242         CONF_SECTION    *outercs;
243
244         p = output;
245         ptr = input;
246         while (*ptr >= ' ') {
247                 /*
248                  *      Ignore anything other than "${"
249                  */
250                 if ((*ptr != '$') || (ptr[1] != '{')) {
251                         *(p++) = *(ptr++);
252                         continue;
253                 }
254                 
255                 /*
256                  *      Look for trailing '}', and log a
257                  *      warning for anything that doesn't match,
258                  *      and exit with a fatal error.
259                  */
260                 end = strchr(ptr, '}');
261                 if (end == NULL) {
262                         *(p++) = *(ptr++);
263                         radlog(L_INFO, "%s[%d]: Variable expansion missing }",
264                                         cf, *lineno);
265                         return NULL;
266                 }
267                 
268                 ptr += 2;
269
270                 memcpy(name, ptr, end - ptr);
271                 name[end - ptr] = '\0';
272
273                 cpn = cf_pair_find(cs, name);
274                 
275                 /*
276                  *      Also look recursively up the section tree,
277                  *      so things like ${confdir} can be defined
278                  *      there and used inside the module config
279                  *      sections.
280                  */
281                 for (outercs=cs->item.parent; 
282                                 (cpn == NULL) && (outercs != NULL);
283                                 outercs=outercs->item.parent) {
284                         cpn = cf_pair_find(outercs, name);
285                 }
286                 if (!cpn) {
287                         radlog(L_ERR, "%s[%d]: Unknown variable \"%s\"",
288                                         cf, *lineno, name);
289                         return NULL;
290                 }
291                 
292                 /*
293                  *  Substitute the value of the variable.
294                  */
295                 strcpy(p, cpn->value);
296                 p += strlen(p);
297                 ptr = end + 1;
298         } /* loop over all of the input string. */
299
300         *p = '\0';
301
302         return output;
303 }
304
305 /*
306  *      Parse a configuration section into user-supplied variables.
307  */
308 int cf_section_parse(CONF_SECTION *cs, void *base, const CONF_PARSER *variables)
309 {
310         int             i;
311         int             rcode;
312         char            **q;
313         CONF_PAIR       *cp;
314         CONF_SECTION    *subsection;
315         uint32_t        ipaddr;
316         char            buffer[1024];
317         const char      *value;
318         void            *data;
319
320         /*
321          *      Handle the user-supplied variables.
322          */
323         for (i = 0; variables[i].name != NULL; i++) {
324                 value = variables[i].dflt;
325                 if (base) {
326                         data = ((char *)base) + variables[i].offset;
327                 } else {
328                         data = variables[i].data;
329                 }
330
331                 cp = cf_pair_find(cs, variables[i].name);
332                 if (cp) {
333                         value = cp->value;
334                 }
335                 
336                 switch (variables[i].type)
337                 {
338                 case PW_TYPE_SUBSECTION:
339                         subsection = cf_section_sub_find(cs,variables[i].name);
340
341                         /*
342                          *      If the configuration section is NOT there,
343                          *      then ignore it.
344                          *
345                          *      FIXME! This is probably wrong... we should
346                          *      probably set the items to their default values.
347                          */
348                         if (!subsection) {
349                                 break;
350                         }
351
352                         rcode = cf_section_parse(subsection, base,
353                                                  (CONF_PARSER *) data);
354                         if (rcode < 0) {
355                                 return -1;
356                         }
357                         break;
358
359                 case PW_TYPE_BOOLEAN:
360                         /*
361                          *      Allow yes/no and on/off
362                          */
363                         if ((strcasecmp(value, "yes") == 0) ||
364                                         (strcasecmp(value, "on") == 0)) {
365                                 *(int *)data = 1;
366                         } else if ((strcasecmp(value, "no") == 0) ||
367                                                 (strcasecmp(value, "off") == 0)) {
368                                 *(int *)data = 0;
369                         } else {
370                                 *(int *)data = 0;
371                                 radlog(L_ERR, "Bad value \"%s\" for boolean variable %s", value, variables[i].name);
372                                 return -1;
373                         }
374                         DEBUG2(" %s: %s = %s",
375                                 cs->name1,
376                                 variables[i].name,
377                                 value);
378                         break;
379
380                 case PW_TYPE_INTEGER:
381                         *(int *)data = strtol(value, 0, 0);
382                         DEBUG2(" %s: %s = %d",
383                                 cs->name1,
384                                 variables[i].name,
385                                 *(int *)data);
386                         break;
387                         
388                 case PW_TYPE_STRING_PTR:
389                         q = (char **) data;
390                         if (base == NULL && *q != NULL) {
391                                 free(*q);
392                         }
393
394                         /*
395                          *      Expand variables while parsing,
396                          *      but ONLY expand ones which haven't already
397                          *      been expanded.
398                          */
399                         if (value && (value == variables[i].dflt)) {
400                                 value = cf_expand_variables(NULL, 0, cs, buffer,value);
401                                 if (!value) {
402                                         return -1;
403                                 }
404                         }
405
406                         DEBUG2(" %s: %s = \"%s\"",
407                                 cs->name1,
408                                 variables[i].name,
409                                 value ? value : "(null)");
410                         *q = value ? strdup(value) : NULL;
411                         break;
412
413                 case PW_TYPE_IPADDR:
414                         /*
415                          *      Allow '*' as any address
416                          */
417                         if (strcmp(value, "*") == 0) {
418                                 *(uint32_t *) data = 0;
419                                 break;
420                         }
421                         ipaddr = ip_getaddr(value);
422                         if (ipaddr == 0) {
423                                 radlog(L_ERR, "Can't find IP address for host %s", value);
424                                 return -1;
425                         }
426                         DEBUG2(" %s: %s = %s IP address [%s]",
427                                 cs->name1,
428                                 variables[i].name,
429                                 value, ip_ntoa(buffer, ipaddr));
430                         *(uint32_t *) data = ipaddr;
431                         break;
432                         
433                 default:
434                         radlog(L_ERR, "type %d not supported yet", variables[i].type);
435                         return -1;
436                         break;
437                 } /* switch over variable type */
438         } /* for all variables in the configuration section */
439         
440         return 0;
441 }
442
443 /*
444  *      Read a part of the config file.
445  */
446 static CONF_SECTION *cf_section_read(const char *cf, int *lineno, FILE *fp,
447                                         const char *name1, const char *name2,
448                                         CONF_SECTION *parent)
449 {
450         CONF_SECTION    *cs, *css;
451         CONF_PAIR       *cpn;
452         char            *ptr;
453         const char      *value;
454         char            buf[8192];
455         char            buf1[1024];
456         char            buf2[1024];
457         char            buf3[1024];
458         int             t1, t2, t3;
459         
460         /*
461          *      Ensure that the user can't add CONF_SECTIONs
462          *      with 'internal' names;
463          */
464         if ((name1 != NULL) && (name1[0] == '_')) {
465                 radlog(L_ERR, "%s[%d]: Illegal configuration section name",
466                         cf, *lineno);
467                 return NULL;
468         }
469
470         /*
471          *      Allocate new section.
472          */
473         cs = cf_section_alloc(name1, name2, parent);
474         cs->item.lineno = *lineno;
475
476         /*
477          *      Read.
478          */
479         while (fgets(buf, sizeof(buf), fp) != NULL) {
480                 (*lineno)++;
481                 ptr = buf;
482
483                 t1 = gettoken(&ptr, buf1, sizeof(buf1));
484
485                 /*
486                  *      Skip comments and blank lines immediately.
487                  */
488                 if ((*buf1 == '#') || (*buf1 == '\0')) {
489                         continue;
490                 }
491
492                 /*
493                  *      Allow for $INCLUDE files
494                  *
495                  *      Currently this allows for includes only at the top 
496                  *      level of config.  IE you cannot have an $INCLUDE nested
497                  *      inside section.  -cparker
498                  */
499                 if ((strcasecmp(buf1, "$INCLUDE") == 0) &&
500                         (name1 == NULL) && (name2 == NULL)) {
501
502                         CONF_SECTION      *is;
503
504                         t2 = getword(&ptr, buf2, sizeof(buf2));
505
506                         value = cf_expand_variables(cf, lineno, cs, buf, buf2);
507                         if (!value) {
508                                 cf_section_free(&cs);
509                                 return NULL;
510                         }
511
512                         DEBUG2( "Config:   including file: %s", value );
513
514                         if ((is = conf_read(cf, *lineno, value)) == NULL) {
515                                 cf_section_free(&cs);
516                                 return NULL;
517                         }
518
519                         /*
520                          *      Add the included conf to our CONF_SECTION
521                          */
522                         if (is != NULL) {
523                                 if (is->children != NULL) {
524                                         CONF_ITEM *ci;
525                          
526                                         /*
527                                          *      Re-write the parent of the
528                                          *      moved children to be the
529                                          *      upper-layer section.
530                                          */
531                                         for (ci = is->children; ci; ci = ci->next) {
532                                                 ci->parent = cs;
533                                         }
534
535                                         /*
536                                          *      If there are children, then
537                                          *      move them up a layer.
538                                          */
539                                         if (is->children) {
540                                                 cf_item_add(cs, is->children);
541                                         }
542                                         is->children = NULL;
543                                 }
544                                 /*
545                                  *      Always free the section for the
546                                  *      $INCLUDEd file.
547                                  */
548                                 cf_section_free(&is);
549                         }
550
551                         continue;
552                 }
553
554                 /*
555                  *      No '=': must be a section or sub-section.
556                  */
557                 if (strchr(ptr, '=') == NULL) {
558                         t2 = gettoken(&ptr, buf2, sizeof(buf2));
559                         t3 = gettoken(&ptr, buf3, sizeof(buf3));
560                 } else {
561                         t2 = gettoken(&ptr, buf2, sizeof(buf2));
562                         t3 = getword(&ptr, buf3, sizeof(buf3));
563                 }
564
565                 /*
566                  *      See if it's the end of a section.
567                  */
568                 if (t1 == T_RCBRACE) {
569                         if (name1 == NULL || buf2[0]) {
570                                 radlog(L_ERR, "%s[%d]: Unexpected end of section",
571                                                 cf, *lineno);
572                                 cf_section_free(&cs);
573                                 return NULL;
574                         }
575                         return cs;
576                 }
577
578                 /*
579                  * Perhaps a subsection.
580                  */
581                 if (t2 == T_LCBRACE || t3 == T_LCBRACE) {
582                         css = cf_section_read(cf, lineno, fp, buf1,
583                                         t2==T_LCBRACE ? NULL : buf2, cs);
584                         if (css == NULL) {
585                                 cf_section_free(&cs);
586                                 return NULL;
587                         }
588                         cf_item_add(cs, cf_sectiontoitem(css));
589
590                         continue;               
591                 }
592
593                 /*
594                  *      Ignore semi-colons.
595                  */
596                 if (*buf2 == ';') *buf2 = '\0';
597
598                 /*
599                  *      Must be a normal attr = value line.
600                  */
601                 if (buf1[0] != 0 && buf2[0] == 0 && buf3[0] == 0) {
602                         t2 = T_OP_EQ;
603                 } else if (buf1[0] == 0 || buf2[0] == 0 || buf3[0] == 0 ||
604                                 (t2 < T_EQSTART || t2 > T_EQEND)) {
605                         radlog(L_ERR, "%s[%d]: Line is not in 'attribute = value' format",
606                                 cf, *lineno);
607                         cf_section_free(&cs);
608                         return NULL;
609                 }
610
611                 /*
612                  *      Ensure that the user can't add CONF_PAIRs
613                  *      with 'internal' names;
614                  */
615                 if (buf1[0] == '_') {
616                         radlog(L_ERR, "%s[%d]: Illegal configuration pair name \"%s\"",
617                                 cf, *lineno, buf1);
618                         cf_section_free(&cs);
619                         return NULL;
620                 }
621                 
622                 /*
623                  *      Handle variable substitution via ${foo}
624                  */
625                 value = cf_expand_variables(cf, lineno, cs, buf, buf3);
626                 if (!value) {
627                         cf_section_free(&cs);
628                         return NULL;
629                 }
630
631
632                 /*
633                  *      Add this CONF_PAIR to our CONF_SECTION
634                  */
635                 cpn = cf_pair_alloc(buf1, value, t2, parent);
636                 cpn->item.lineno = *lineno;
637                 cf_item_add(cs, cf_pairtoitem(cpn));
638         }
639
640         /*
641          *      See if EOF was unexpected ..
642          */
643         if (name1 != NULL) {
644                 radlog(L_ERR, "%s[%d]: Unexpected end of file", cf, *lineno);
645                 cf_section_free(&cs);
646                 return NULL;
647         }
648
649         return cs;
650 }
651
652 /*
653  *      Read the config file.
654  */
655 static CONF_SECTION *conf_read(const char *fromfile, int fromline, const char *conffile)
656 {
657         FILE            *fp;
658         int             lineno = 0;
659         CONF_SECTION    *cs;
660         
661         if ((fp = fopen(conffile, "r")) == NULL) {
662                 if (fromfile) {
663                         radlog(L_ERR|L_CONS, "%s[%d]: Unable to open file \"%s\": %s",
664                                 fromfile, fromline, conffile, strerror(errno));
665                 } else {
666                         radlog(L_ERR|L_CONS, "Unable to open file \"%s\": %s",
667                                 conffile, strerror(errno));
668                 }
669                 return NULL;
670         }
671
672         cs = cf_section_read(conffile, &lineno, fp, NULL, NULL, NULL);
673         fclose(fp);
674
675         return cs;
676 }
677
678 /*
679  *      These are not used anywhere else..
680  */
681 static const char *localstatedir = NULL;
682 static const char *prefix = NULL;
683
684 static CONF_PARSER directory_config[] = {
685   /*
686    *    FIXME: 'prefix' is the ONLY one which should be configured
687    *    at compile time.  Hard-coding it here is bad.  It will be cleaned
688    *    up once we clean up the hard-coded defines for the locations of
689    *    the various files.
690    */
691   {  "prefix",            PW_TYPE_STRING_PTR, 0, &prefix,            "/usr/local"},
692   { "localstatedir",      PW_TYPE_STRING_PTR, 0, &localstatedir,     "${prefix}/var"}, 
693   { "logdir",             PW_TYPE_STRING_PTR, 0, &radlog_dir,        "${localstatedir}/log"},
694   { "libdir",             PW_TYPE_STRING_PTR, 0, &radlib_dir,        "${prefix}/lib"},
695   { "radacctdir",         PW_TYPE_STRING_PTR, 0, &radacct_dir,       "${logdir}/radacct" },
696   { "hostname_lookups",   PW_TYPE_BOOLEAN,    0, &librad_dodns,      "no" },
697
698   /*
699    *    We don't allow re-defining this, as doing so will cause
700    *    all sorts of confusion.
701    */
702 #if 0
703   { "confdir",            PW_TYPE_STRING_PTR, 0, &radius_dir,        RADIUS_DIR },
704 #endif
705   { NULL, -1, 0, NULL, NULL }
706 };
707
708
709 /* JLN
710  * Read the configuration and library
711  * This uses the new kind of configuration file as defined by
712  * Miquel at http://www.miquels.cistron.nl/radius/
713  */
714
715 int read_radius_conf_file(void)
716 {
717         char buffer[256];
718         CONF_SECTION *cs;
719
720         /* Lets go look for the new configuration files */
721         sprintf(buffer, "%.200s/%.50s", radius_dir, RADIUS_CONFIG);
722         if ((cs = conf_read(NULL, 0, buffer)) == NULL) {
723                 return -1;
724         }
725
726         /*
727          *      Free the old configuration data, and replace it
728          *      with the new one.
729          */
730         cf_section_free(&config);
731         config = cs;
732         
733         /*
734          *      And parse the directory configuration values.
735          */
736         cs = cf_section_find(NULL);
737         if (!cs)
738                 return -1;
739
740         /*
741          *      This allows us to figure out where, relative to
742          *      radiusd.conf, the other configuration files exist.
743          */
744         cf_section_parse(cs, NULL, directory_config);
745
746         /* Initialize the dictionary */
747         DEBUG2("read_config_files:  reading dictionary");
748         if (dict_init(radius_dir, RADIUS_DICTIONARY) != 0) {
749                 radlog(L_ERR|L_CONS, "Errors reading dictionary: %s",
750                         librad_errstr);
751                 return -1;
752         }
753
754         /* old-style clients file */
755         sprintf(buffer, "%.200s/%.50s", radius_dir, RADIUS_CLIENTS);
756         DEBUG2("read_config_files:  reading clients");
757         if (read_clients_file(buffer) < 0) {
758                 radlog(L_ERR|L_CONS, "Errors reading clients");
759                 return -1;
760         }
761
762         /*
763          *      Add to that, the *new* list of clients.
764          */
765         sprintf(buffer, "%.200s/%.50s", radius_dir, RADIUS_CONFIG);
766         if (generate_clients(buffer) < 0) {
767                 return -1;
768         }
769
770         /* old-style realms file */
771         sprintf(buffer, "%.200s/%.50s", radius_dir, RADIUS_REALMS);
772         DEBUG2("read_config_files:  reading realms");
773         if (read_realms_file(buffer) < 0) {
774                 radlog(L_ERR|L_CONS, "Errors reading realms");
775                 return -1;
776         }
777
778         /*
779          *      If there isn't any realms it isn't fatal..
780          */
781         sprintf(buffer, "%.200s/%.50s", radius_dir, RADIUS_CONFIG);
782         if (generate_realms(buffer) < 0) {
783                 return -1;
784         }
785
786         /* old-style naslist file */
787         sprintf(buffer, "%.200s/%.50s", radius_dir, RADIUS_NASLIST);
788         DEBUG2("read_config_files:  reading naslist");
789         if (read_naslist_file(buffer) < 0) {
790                 radlog(L_ERR|L_CONS, "Errors reading naslist");
791                 return -1;
792         }
793
794         return 0;       
795 }
796
797 /* JLN
798  * Create the linked list of realms from the new configuration type
799  * This way we don't have to change to much in the other source-files
800  */
801
802 static int generate_realms(const char *filename)
803 {
804         CONF_SECTION    *cs;
805         REALM           *c;
806         char            *s, *authhost, *accthost;
807
808         for (cs = cf_subsection_find_next(config, NULL, "realm"); cs != NULL;
809                         cs = cf_subsection_find_next(config, cs, "realm")) {
810                 if (!cs->name2) {
811                         radlog(L_CONS|L_ERR, "%s[%d]: Missing realm name", filename, cs->item.lineno);
812                         return -1;
813                 }
814                 /*
815                  * We've found a realm, allocate space for it
816                  */
817                 c = rad_malloc(sizeof(REALM));
818                 memset(c, 0, sizeof(REALM));
819                 /*
820                  * An authhost must exist in the configuration
821                  */
822                 if ((authhost = cf_section_value_find(cs, "authhost")) == NULL) {
823                         radlog(L_CONS|L_ERR, 
824                                 "%s[%d]: No authhost entry in realm", 
825                                 filename, cs->item.lineno);
826                         return -1;
827                 }
828                 if ((s = strchr(authhost, ':')) != NULL) {
829                         *s++ = 0;
830                         c->auth_port = atoi(s);
831                 } else {
832                         c->auth_port = auth_port;
833                 }
834                 accthost = cf_section_value_find(cs, "accthost");
835                 if ((s =strchr(accthost, ':')) != NULL) {
836                         *s++ = 0;
837                         c->acct_port = atoi(s); 
838                 } else {
839                         c->acct_port = acct_port;
840                 }
841                 if (strcmp(authhost, "LOCAL") != 0)
842                         c->ipaddr = ip_getaddr(authhost);
843
844                 /* 
845                  * Double check length, just to be sure!
846                  */
847                 if (strlen(authhost) >= sizeof(c->server)) {
848                         radlog(L_ERR, "%s[%d]: Server name of length %d is greater that allowed: %d",
849                                         filename, cs->item.lineno,
850                                         strlen(authhost), sizeof(c->server) - 1);
851                         return -1;
852                 }
853                 if (strlen(cs->name2) >= sizeof(c->realm)) {
854                         radlog(L_ERR, "%s[%d]: Realm name of length %d is greater than allowed %d",
855                                         filename, cs->item.lineno,
856                                         strlen(cs->name2), sizeof(c->server) - 1);
857                         return -1;
858                 }
859                 
860                 strcpy(c->realm, cs->name2);
861                 strcpy(c->server, authhost);    
862
863                 s = cf_section_value_find(cs, "secret");
864                 if (s == NULL) {
865                         radlog(L_ERR, "%s[%d]: No shared secret supplied for realm",
866                                         filename, cs->item.lineno);
867                         return -1;
868                 }
869
870                 if (strlen(s) >= sizeof(c->secret)) {
871                         radlog(L_ERR, "%s[%d]: Secret of length %d is greater than the allowed maximum of %d.",
872                                         filename, cs->item.lineno,
873                                         strlen(s), sizeof(c->secret) - 1);
874                         return -1;
875                 }
876                 strNcpy((char *)c->secret, s, sizeof(c->secret));
877
878                 c->striprealm = 1;
879                 
880                 if ((cf_section_value_find(cs, "nostrip")) != NULL)
881                         c->striprealm = 0;
882                 if ((cf_section_value_find(cs, "noacct")) != NULL)
883                         c->acct_port = 0;
884                 if ((cf_section_value_find(cs, "trusted")) != NULL)
885                         c->trusted = 1;
886                 if ((cf_section_value_find(cs, "notrealm")) != NULL)
887                         c->notrealm = 1;
888                 if ((cf_section_value_find(cs, "notsuffix")) != NULL)
889                         c->notrealm = 1;
890
891
892                 c->next = realms;
893                 realms = c;
894
895         }
896
897         return 0;
898 }
899
900 /* JLN
901  * Create the linked list of realms from the new configuration type
902  * This way we don't have to change to much in the other source-files
903  */
904 static int generate_clients(const char *filename)
905 {
906         CONF_SECTION    *cs;
907         RADCLIENT       *c;
908         char            *hostnm, *secret, *shortnm, *netmask;
909
910         for (cs = cf_subsection_find_next(config, NULL, "client"); cs != NULL; 
911                         cs = cf_subsection_find_next(config, cs, "client")) {
912                 if (!cs->name2) {
913                         radlog(L_CONS|L_ERR, "%s[%d]: Missing client name", filename, cs->item.lineno);
914                         return -1;
915                 }
916                 /*
917                  * Check the lengths, we don't want any core dumps
918                  */
919                 hostnm = cs->name2;
920                 secret = cf_section_value_find(cs, "secret");
921                 shortnm = cf_section_value_find(cs, "shortname");
922                 netmask = strchr(hostnm, '/');
923
924                 if (strlen(secret) >= sizeof(c->secret)) {
925                         radlog(L_ERR, "%s[%d]: Secret of length %d is greater than the allowed maximum of %d.",
926                                 filename, cs->item.lineno,
927                                 strlen(secret), sizeof(c->secret) - 1);
928                         return -1;
929                 }
930                 if (strlen(shortnm) > sizeof(c->shortname)) {
931                         radlog(L_ERR, "%s[%d]: Client short name of length %d is greater than the allowed maximum of %d.",
932                                         filename, cs->item.lineno,
933                                         strlen(shortnm), sizeof(c->shortname) - 1);
934                         return -1;
935                 }
936                 /*
937                  * The size is fine.. Let's create the buffer
938                  */
939                 c = rad_malloc(sizeof(RADCLIENT));
940
941                 /*
942                  *      Look for netmasks.
943                  */
944                 c->netmask = ~0;
945                 if (netmask) {
946                         int i, mask_length;
947
948                         mask_length = atoi(netmask + 1);
949                         if ((mask_length <= 0) || (mask_length > 32)) {
950                                 radlog(L_ERR, "%s[%d]: Invalid value '%s' for IP network mask.",
951                                                 filename, cs->item.lineno, netmask + 1);
952                                 return -1;
953                         }
954                         
955                         c->netmask = (1 << 31);
956                         for (i = 1; i < mask_length; i++) {
957                                 c->netmask |= (c->netmask >> 1);
958                         }
959
960                         *netmask = '\0';
961                         c->netmask = htonl(c->netmask);
962                 }
963
964                 c->ipaddr = ip_getaddr(hostnm);
965                 if (c->ipaddr == INADDR_NONE) {
966                         radlog(L_CONS|L_ERR, "%s[%d]: Failed to look up hostname %s",
967                                         filename, cs->item.lineno, hostnm);
968                         return -1;
969                 }
970
971                 /*
972                  *      Update the client name again...
973                  */
974                 if (netmask) {
975                         *netmask = '/';
976                         c->ipaddr &= c->netmask;
977                         strcpy(c->longname, hostnm);
978                 } else {
979                         ip_hostname(c->longname, sizeof(c->longname),
980                                         c->ipaddr);
981                 }
982
983                 strcpy((char *)c->secret, secret);
984                 strcpy(c->shortname, shortnm);
985
986                 c->next = clients;
987                 clients = c;
988         }
989
990         return 0;
991 }
992
993 /* 
994  * Return a CONF_PAIR within a CONF_SECTION.
995  */
996
997 CONF_PAIR *cf_pair_find(CONF_SECTION *section, const char *name)
998 {
999         CONF_ITEM       *ci;
1000
1001         if (section == NULL) {
1002           section = config;
1003         }
1004
1005         for (ci = section->children; ci; ci = ci->next) {
1006                 if (ci->type != CONF_ITEM_PAIR)
1007                         continue;
1008                 if (name == NULL || strcmp(cf_itemtopair(ci)->attr, name) == 0)
1009                         break;
1010         }
1011
1012         return cf_itemtopair(ci);
1013 }
1014
1015 /*
1016  * Return the attr of a CONF_PAIR
1017  */
1018
1019 char *cf_pair_attr(CONF_PAIR *pair)
1020 {
1021         return (pair ? pair->attr : NULL);
1022 }
1023
1024 /*
1025  * Return the value of a CONF_PAIR
1026  */
1027
1028 char *cf_pair_value(CONF_PAIR *pair)
1029 {
1030         return (pair ? pair->value : NULL);
1031 }
1032
1033 /*
1034  * Return the first label of a CONF_SECTION
1035  */
1036
1037 char *cf_section_name1(CONF_SECTION *section)
1038 {
1039         return (section ? section->name1 : NULL);
1040 }
1041
1042 /*
1043  * Return the second label of a CONF_SECTION
1044  */
1045
1046 char *cf_section_name2(CONF_SECTION *section)
1047 {
1048         return (section ? section->name2 : NULL);
1049 }
1050
1051 /* 
1052  * Find a value in a CONF_SECTION
1053  */
1054 char *cf_section_value_find(CONF_SECTION *section, const char *attr)
1055 {
1056         CONF_PAIR       *cp;
1057
1058         cp = cf_pair_find(section, attr);
1059
1060         return (cp ? cp->value : NULL);
1061 }
1062
1063 /*
1064  * Return the next pair after a CONF_PAIR
1065  * with a certain name (char *attr) If the requested
1066  * attr is NULL, any attr matches.
1067  */
1068
1069 CONF_PAIR *cf_pair_find_next(CONF_SECTION *section, CONF_PAIR *pair, const char *attr)
1070 {
1071         CONF_ITEM       *ci;
1072
1073         /*
1074          * If pair is NULL this must be a first time run
1075          * Find the pair with correct name
1076          */
1077
1078         if (pair == NULL){
1079                 return cf_pair_find(section, attr);
1080         }
1081
1082         ci = cf_pairtoitem(pair)->next;
1083
1084         for (; ci; ci = ci->next) {
1085                 if (ci->type != CONF_ITEM_PAIR)
1086                         continue;
1087                 if (attr == NULL || strcmp(cf_itemtopair(ci)->attr, attr) == 0)
1088                         break;
1089         }
1090
1091         return cf_itemtopair(ci);
1092 }
1093
1094 /*
1095  * Find a CONF_SECTION, or return the root if name is NULL
1096  */
1097
1098 CONF_SECTION *cf_section_find(const char *name)
1099 {
1100         if (name)
1101                 return cf_section_sub_find(config, name);
1102         else
1103                 return config;
1104 }
1105
1106 /*
1107  * Find a sub-section in a section
1108  */
1109
1110 CONF_SECTION *cf_section_sub_find(CONF_SECTION *section, const char *name)
1111 {
1112         CONF_ITEM *ci;
1113
1114         for (ci = section->children; ci; ci = ci->next) {
1115                 if (ci->type != CONF_ITEM_SECTION)
1116                         continue;
1117                 if (strcmp(cf_itemtosection(ci)->name1, name) == 0)
1118                         break;
1119         }
1120
1121         return cf_itemtosection(ci);
1122
1123 }
1124
1125 /*
1126  * Return the next subsection after a CONF_SECTION
1127  * with a certain name1 (char *name1). If the requested
1128  * name1 is NULL, any name1 matches.
1129  */
1130
1131 CONF_SECTION *cf_subsection_find_next(CONF_SECTION *section,
1132                 CONF_SECTION *subsection,
1133                 const char *name1)
1134 {
1135         CONF_ITEM       *ci;
1136
1137         /*
1138          * If subsection is NULL this must be a first time run
1139          * Find the subsection with correct name
1140          */
1141
1142         if (subsection == NULL){
1143                 ci = section->children;
1144         } else {
1145                 ci = cf_sectiontoitem(subsection)->next;
1146         }
1147
1148         for (; ci; ci = ci->next) {
1149                 if (ci->type != CONF_ITEM_SECTION)
1150                         continue;
1151                 if ((name1 == NULL) || 
1152                                 (strcmp(cf_itemtosection(ci)->name1, name1) == 0))
1153                         break;
1154         }
1155
1156         return cf_itemtosection(ci);
1157 }
1158
1159 /*
1160  * Return the next item after a CONF_ITEM.
1161  */
1162
1163 CONF_ITEM *cf_item_find_next(CONF_SECTION *section, CONF_ITEM *item)
1164 {
1165         /*
1166          * If item is NULL this must be a first time run
1167          * Return the first item
1168          */
1169
1170         if (item == NULL) {
1171                 return section->children;
1172         } else {
1173                 return item->next;
1174         }
1175 }
1176
1177 int cf_section_lineno(CONF_SECTION *section)
1178 {
1179         return cf_sectiontoitem(section)->lineno;
1180 }
1181
1182 int cf_pair_lineno(CONF_PAIR *pair)
1183 {
1184         return cf_pairtoitem(pair)->lineno;
1185 }
1186
1187 int cf_item_is_section(CONF_ITEM *item)
1188 {
1189         return item->type == CONF_ITEM_SECTION;
1190 }
1191
1192
1193 /* 
1194  * JMG dump_config tries to dump the config structure in a readable format
1195  * 
1196 */
1197
1198 static int dump_config_section(CONF_SECTION *cs, int indent)
1199 {
1200         CONF_SECTION    *scs;
1201         CONF_PAIR       *cp;
1202         CONF_ITEM       *ci;
1203
1204         /* The DEBUG macro doesn't let me
1205          *   for(i=0;i<indent;++i) debugputchar('\t');
1206          * so I had to get creative. --Pac. */
1207
1208         for (ci = cs->children; ci; ci = ci->next) {
1209                 if (ci->type == CONF_ITEM_PAIR) {
1210                         cp=cf_itemtopair(ci);
1211                         DEBUG("%.*s%s = %s",
1212                                 indent, "\t\t\t\t\t\t\t\t\t\t\t",
1213                                 cp->attr, cp->value);
1214                 } else {
1215                         scs=cf_itemtosection(ci);
1216                         DEBUG("%.*s%s %s%s{",
1217                                 indent, "\t\t\t\t\t\t\t\t\t\t\t",
1218                                 scs->name1,
1219                                 scs->name2 ? scs->name2 : "",
1220                                 scs->name2 ?  " " : "");
1221                         dump_config_section(scs, indent+1);
1222                         DEBUG("%.*s}",
1223                                 indent, "\t\t\t\t\t\t\t\t\t\t\t");
1224                 }
1225         }
1226
1227         return 0;
1228 }
1229
1230 int dump_config(void)
1231 {
1232         return dump_config_section(config, 0);
1233 }