Allow `/path/to/program args`, too. This replaces much
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  *
24  * Copyright 2000,2006  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 <freeradius-devel/ident.h>
30 RCSID("$Id$")
31
32 #include <freeradius-devel/radiusd.h>
33 #include <freeradius-devel/rad_assert.h>
34
35 #ifdef HAVE_DIRENT_H
36 #include <dirent.h>
37 #endif
38
39 #ifdef HAVE_SYS_STAT_H
40 #include <sys/stat.h>
41 #endif
42
43 #include <ctype.h>
44
45 typedef enum conf_type {
46         CONF_ITEM_INVALID = 0,
47         CONF_ITEM_PAIR,
48         CONF_ITEM_SECTION,
49         CONF_ITEM_DATA
50 } CONF_ITEM_TYPE;
51
52 struct conf_item {
53         struct conf_item *next;
54         struct conf_part *parent;
55         int lineno;
56         const char *filename;
57         CONF_ITEM_TYPE type;
58 };
59 struct conf_pair {
60         CONF_ITEM item;
61         const char *attr;
62         const char *value;
63         FR_TOKEN operator;
64         FR_TOKEN value_type;
65 };
66 struct conf_part {
67         CONF_ITEM item;
68         const char *name1;
69         const char *name2;
70         struct conf_item *children;
71         struct conf_item *tail; /* for speed */
72         CONF_SECTION    *template;
73         rbtree_t        *pair_tree; /* and a partridge.. */
74         rbtree_t        *section_tree; /* no jokes here */
75         rbtree_t        *name2_tree; /* for sections of the same name2 */
76         rbtree_t        *data_tree;
77         void            *base;
78         int depth;
79         const CONF_PARSER *variables;
80 };
81
82
83 /*
84  *      Internal data that is associated with a configuration section,
85  *      so that we don't have to track it separately.
86  */
87 struct conf_data {
88         CONF_ITEM  item;
89         const char *name;
90         int        flag;
91         void       *data;       /* user data */
92         void       (*free)(void *); /* free user data function */
93 };
94
95
96 static int cf_data_add_internal(CONF_SECTION *cs, const char *name,
97                                 void *data, void (*data_free)(void *),
98                                 int flag);
99 static void *cf_data_find_internal(CONF_SECTION *cs, const char *name,
100                                    int flag);
101
102 int cf_log_config = 1;
103 int cf_log_modules = 1;
104
105 /*
106  *      Isolate the scary casts in these tiny provably-safe functions
107  */
108 CONF_PAIR *cf_itemtopair(CONF_ITEM *ci)
109 {
110         if (ci == NULL)
111                 return NULL;
112         rad_assert(ci->type == CONF_ITEM_PAIR);
113         return (CONF_PAIR *)ci;
114 }
115 CONF_SECTION *cf_itemtosection(CONF_ITEM *ci)
116 {
117         if (ci == NULL)
118                 return NULL;
119         rad_assert(ci->type == CONF_ITEM_SECTION);
120         return (CONF_SECTION *)ci;
121 }
122 CONF_ITEM *cf_pairtoitem(CONF_PAIR *cp)
123 {
124         if (cp == NULL)
125                 return NULL;
126         return (CONF_ITEM *)cp;
127 }
128 CONF_ITEM *cf_sectiontoitem(CONF_SECTION *cs)
129 {
130         if (cs == NULL)
131                 return NULL;
132         return (CONF_ITEM *)cs;
133 }
134
135 static CONF_DATA *cf_itemtodata(CONF_ITEM *ci)
136 {
137         if (ci == NULL)
138                 return NULL;
139         rad_assert(ci->type == CONF_ITEM_DATA);
140         return (CONF_DATA *)ci;
141 }
142 static CONF_ITEM *cf_datatoitem(CONF_DATA *cd)
143 {
144         if (cd == NULL)
145                 return NULL;
146         return (CONF_ITEM *)cd;
147 }
148
149 /*
150  *      Create a new CONF_PAIR
151  */
152 static CONF_PAIR *cf_pair_alloc(const char *attr, const char *value,
153                                 FR_TOKEN operator, FR_TOKEN value_type,
154                                 CONF_SECTION *parent)
155 {
156         char *p;
157         size_t attr_len, value_len = 0;
158         CONF_PAIR *cp;
159
160         if (!attr) return NULL;
161         attr_len = strlen(attr) + 1;
162         if (value) value_len = strlen(value) + 1;
163
164         p = rad_malloc(sizeof(*cp) + attr_len + value_len);
165
166         cp = (CONF_PAIR *) p;
167         memset(cp, 0, sizeof(*cp));
168         cp->item.type = CONF_ITEM_PAIR;
169         cp->item.parent = parent;
170
171         p += sizeof(*cp);
172         memcpy(p, attr, attr_len);
173         cp->attr = p;
174
175         if (value) {
176                 p += attr_len;
177                 memcpy(p, value, value_len);
178                 cp->value = p;
179         }
180         cp->value_type = value_type;
181         cp->operator = operator;
182
183         return cp;
184 }
185
186 /*
187  *      Free a CONF_PAIR
188  */
189 void cf_pair_free(CONF_PAIR **cp)
190 {
191         if (!cp || !*cp) return;
192
193         /*
194          *      attr && value are allocated contiguous with cp.
195          */
196
197 #ifndef NDEBUG
198         memset(*cp, 0, sizeof(*cp));
199 #endif
200         free(*cp);
201
202         *cp = NULL;
203 }
204
205
206 static void cf_data_free(CONF_DATA **cd)
207 {
208         if (!cd || !*cd) return;
209
210         /* name is allocated contiguous with cd */
211         if (!(*cd)->free) {
212                 free((*cd)->data);
213         } else {
214                 ((*cd)->free)((*cd)->data);
215         }
216 #ifndef NDEBUG
217         memset(*cd, 0, sizeof(*cd));
218 #endif
219         free(*cd);
220         *cd = NULL;
221 }
222
223 /*
224  *      rbtree callback function
225  */
226 static int pair_cmp(const void *a, const void *b)
227 {
228         const CONF_PAIR *one = a;
229         const CONF_PAIR *two = b;
230
231         return strcmp(one->attr, two->attr);
232 }
233
234
235 /*
236  *      rbtree callback function
237  */
238 static int section_cmp(const void *a, const void *b)
239 {
240         const CONF_SECTION *one = a;
241         const CONF_SECTION *two = b;
242
243         return strcmp(one->name1, two->name1);
244 }
245
246
247 /*
248  *      rbtree callback function
249  */
250 static int name2_cmp(const void *a, const void *b)
251 {
252         const CONF_SECTION *one = a;
253         const CONF_SECTION *two = b;
254
255         rad_assert(strcmp(one->name1, two->name1) == 0);
256
257         if (!one->name2 && !two->name2) return 0;
258         if (!one->name2) return -1;
259         if (!two->name2) return +1;
260
261         return strcmp(one->name2, two->name2);
262 }
263
264
265 /*
266  *      rbtree callback function
267  */
268 static int data_cmp(const void *a, const void *b)
269 {
270         int rcode;
271
272         const CONF_DATA *one = a;
273         const CONF_DATA *two = b;
274
275         rcode = one->flag - two->flag;
276         if (rcode != 0) return rcode;
277
278         return strcmp(one->name, two->name);
279 }
280
281
282 /*
283  *      Free strings we've parsed into data structures.
284  */
285 void cf_section_parse_free(CONF_SECTION *cs, void *base)
286 {
287         int i;
288         const CONF_PARSER *variables = cs->variables;
289
290         /*
291          *      Don't automatically free the strings if we're being
292          *      called from a module.  This is also for clients.c,
293          *      where client_free() expects to be able to free the
294          *      client structure.  If we moved everything to key off
295          *      of the config files, we might solve some problems...
296          */
297         if (!variables) return;
298
299         /*
300          *      Free up dynamically allocated string pointers.
301          */
302         for (i = 0; variables[i].name != NULL; i++) {
303                 char **p;
304
305                 if ((variables[i].type != PW_TYPE_STRING_PTR) &&
306                     (variables[i].type != PW_TYPE_FILENAME)) {
307                         continue;
308                 }
309
310                 /*
311                  *      No base struct offset, data must be the pointer.
312                  *      If data doesn't exist, ignore the entry, there
313                  *      must be something wrong.
314                  */
315                 if (!base) {
316                         if (!variables[i].data) {
317                                 continue;
318                         }
319
320                         p = (char **) variables[i].data;;
321
322                 } else if (variables[i].data) {
323                         p = (char **) variables[i].data;;
324
325                 } else {
326                         p = (char **) (((char *)base) + variables[i].offset);
327                 }
328
329                 free(*p);
330                 *p = NULL;
331         }
332 }
333
334
335 /*
336  *      Free a CONF_SECTION
337  */
338 void cf_section_free(CONF_SECTION **cs)
339 {
340         CONF_ITEM       *ci, *next;
341
342         if (!cs || !*cs) return;
343
344         cf_section_parse_free(*cs, (*cs)->base);
345
346         for (ci = (*cs)->children; ci; ci = next) {
347                 next = ci->next;
348
349                 switch (ci->type) {
350                 case CONF_ITEM_PAIR: {
351                                 CONF_PAIR *pair = cf_itemtopair(ci);
352                                 cf_pair_free(&pair);
353                         }
354                         break;
355
356                 case CONF_ITEM_SECTION: {
357                                 CONF_SECTION *section = cf_itemtosection(ci);
358                                 cf_section_free(&section);
359                         }
360                         break;
361
362                 case CONF_ITEM_DATA: {
363                                 CONF_DATA *data = cf_itemtodata(ci);
364                                 cf_data_free(&data);
365                         }
366                         break;
367
368                 default:        /* should really be an error. */
369                         break;
370                 }
371         }
372
373         /*
374          *      Name1 and name2 are allocated contiguous with
375          *      cs.
376          */
377         if ((*cs)->pair_tree)
378                 rbtree_free((*cs)->pair_tree);
379         if ((*cs)->section_tree)
380                 rbtree_free((*cs)->section_tree);
381         if ((*cs)->name2_tree)
382                 rbtree_free((*cs)->name2_tree);
383         if ((*cs)->data_tree)
384                 rbtree_free((*cs)->data_tree);
385
386         /*
387          * And free the section
388          */
389 #ifndef NDEBUG
390         memset(*cs, 0, sizeof(*cs));
391 #endif
392         free(*cs);
393
394         *cs = NULL;
395 }
396
397
398 /*
399  *      Allocate a CONF_SECTION
400  */
401 static CONF_SECTION *cf_section_alloc(const char *name1, const char *name2,
402                                       CONF_SECTION *parent)
403 {
404         size_t name1_len, name2_len = 0;
405         char *p;
406         CONF_SECTION    *cs;
407
408         if (!name1) return NULL;
409
410         name1_len = strlen(name1) + 1;
411         if (name2) name2_len = strlen(name2) + 1;
412
413         p = rad_malloc(sizeof(*cs) + name1_len + name2_len);
414
415         cs = (CONF_SECTION *) p;
416         memset(cs, 0, sizeof(*cs));
417         cs->item.type = CONF_ITEM_SECTION;
418         cs->item.parent = parent;
419
420         p += sizeof(*cs);
421         memcpy(p, name1, name1_len);
422         cs->name1 = p;
423
424         if (name2 && *name2) {
425                 p += name1_len;
426                 memcpy(p, name2, name2_len);
427                 cs->name2 = p;
428         }
429
430         cs->pair_tree = rbtree_create(pair_cmp, NULL, 0);
431         if (!cs->pair_tree) {
432                 cf_section_free(&cs);
433                 return NULL;
434         }
435
436         /*
437          *      Don't create a data tree, it may not be needed.
438          */
439
440         /*
441          *      Don't create the section tree here, it may not
442          *      be needed.
443          */
444
445         if (parent) cs->depth = parent->depth + 1;
446
447         return cs;
448 }
449
450
451 /*
452  *      Add an item to a configuration section.
453  */
454 static void cf_item_add(CONF_SECTION *cs, CONF_ITEM *ci)
455 {
456         if (!cs->children) {
457                 rad_assert(cs->tail == NULL);
458                 cs->children = ci;
459         } else {
460                 rad_assert(cs->tail != NULL);
461                 cs->tail->next = ci;
462         }
463
464         /*
465          *      Update the trees (and tail) for each item added.
466          */
467         for (/* nothing */; ci != NULL; ci = ci->next) {
468                 cs->tail = ci;
469
470                 /*
471                  *      For fast lookups, pair's and sections get
472                  *      added to rbtree's.
473                  */
474                 switch (ci->type) {
475                         case CONF_ITEM_PAIR:
476                                 rbtree_insert(cs->pair_tree, ci);
477                                 break;
478
479                         case CONF_ITEM_SECTION: {
480                                 CONF_SECTION *cs_new = cf_itemtosection(ci);
481
482                                 if (!cs->section_tree) {
483                                         cs->section_tree = rbtree_create(section_cmp, NULL, 0);
484                                         /* ignore any errors */
485                                 }
486
487                                 if (cs->section_tree) {
488                                         rbtree_insert(cs->section_tree, cs_new);                                }
489
490                                 /*
491                                  *      Two names: find the named instance.
492                                  */
493                                 {
494                                         CONF_SECTION *old_cs;
495
496                                         /*
497                                          *      Find the FIRST
498                                          *      CONF_SECTION having
499                                          *      the given name1, and
500                                          *      create a new tree
501                                          *      under it.
502                                          */
503                                         old_cs = rbtree_finddata(cs->section_tree, cs_new);
504                                         if (!old_cs) return; /* this is a bad error! */
505
506                                         if (!old_cs->name2_tree) {
507                                                 old_cs->name2_tree = rbtree_create(name2_cmp,
508                                                                                    NULL, 0);
509                                         }
510                                         if (old_cs->name2_tree) {
511                                                 rbtree_insert(old_cs->name2_tree, cs_new);
512                                         }
513                                 } /* had a name2 */
514                                 break;
515                         } /* was a section */
516
517                         case CONF_ITEM_DATA:
518                                 if (!cs->data_tree) {
519                                         cs->data_tree = rbtree_create(data_cmp, NULL, 0);
520                                 }
521                                 if (cs->data_tree) {
522                                         rbtree_insert(cs->data_tree, ci);
523                                 }
524                                 break;
525
526                         default: /* FIXME: assert & error! */
527                                 break;
528
529                 } /* switch over conf types */
530         } /* loop over ci */
531 }
532
533
534 CONF_ITEM *cf_reference_item(const CONF_SECTION *parentcs,
535                              CONF_SECTION *outercs,
536                              const char *ptr)
537 {
538         CONF_PAIR *cp;
539         CONF_SECTION *next;
540         const CONF_SECTION *cs = outercs;
541         char name[8192];
542         char *p;
543
544         strlcpy(name, ptr, sizeof(name));
545         p = name;
546
547         /*
548          *      ".foo" means "foo from the current section"
549          */
550         if (*p == '.') {
551                 p++;
552                 
553                 /*
554                  *      ..foo means "foo from the section
555                  *      enclosing this section" (etc.)
556                  */
557                 while (*p == '.') {
558                         if (cs->item.parent)
559                                 cs = cs->item.parent;
560                         p++;
561                 }
562
563                 /*
564                  *      "foo.bar.baz" means "from the root"
565                  */
566         } else if (strchr(p, '.') != NULL) {
567                 cs = parentcs;
568         }
569
570         while (*p) {
571                 char *q, *r;
572
573                 r = strchr(p, '[');
574                 q = strchr(p, '.');
575                 if (!r && !q) break;
576
577                 if (r && q > r) q = NULL;
578                 if (q && q < r) r = NULL;
579
580                 /*
581                  *      Split off name2.
582                  */
583                 if (r) {
584                         q = strchr(r + 1, ']');
585                         if (!q) return NULL; /* parse error */
586
587                         /*
588                          *      Points to foo[bar]xx: parse error,
589                          *      it should be foo[bar] or foo[bar].baz
590                          */
591                         if (q[1] && q[1] != '.') goto no_such_item;
592
593                         *r = '\0';
594                         *q = '\0';
595                         next = cf_section_sub_find_name2(cs, p, r + 1);
596                         *r = '[';
597                         *q = ']';
598
599                         /*
600                          *      Points to a named instance of a section.
601                          */
602                         if (!q[1]) {
603                                 if (!next) goto no_such_item;
604                                 return cf_sectiontoitem(next);
605                         }
606
607                         q++;    /* ensure we skip the ']' and '.' */
608
609                 } else {
610                         *q = '\0';
611                         next = cf_section_sub_find(cs, p);
612                         *q = '.';
613                 }
614
615                 if (!next) break; /* it MAY be a pair in this section! */
616
617                 cs = next;
618                 p = q + 1;
619         }
620
621         if (!*p) goto no_such_item;
622
623  retry:
624         /*
625          *      Find it in the current referenced
626          *      section.
627          */
628         cp = cf_pair_find(cs, p);
629         if (cp) return cf_pairtoitem(cp);
630
631         next = cf_section_sub_find(cs, p);
632         if (next) return cf_sectiontoitem(next);
633         
634         /*
635          *      "foo" is "in the current section, OR in main".
636          */
637         if ((p == name) && (cs != parentcs)) {
638                 cs = parentcs;
639                 goto retry;
640         }
641
642 no_such_item:
643         DEBUG2("WARNING: No such configuration item %s", ptr);
644         return NULL;
645 }
646
647
648 CONF_SECTION *cf_top_section(CONF_SECTION *cs)
649 {
650         while (cs->item.parent != NULL) {
651                 cs = cs->item.parent;
652         }
653
654         return cs;
655 }
656
657
658 /*
659  *      Expand the variables in an input string.
660  */
661 static const char *cf_expand_variables(const char *cf, int *lineno,
662                                        CONF_SECTION *outercs,
663                                        char *output, const char *input)
664 {
665         char *p;
666         const char *end, *ptr;
667         const CONF_SECTION *parentcs;
668         char name[8192];
669
670         /*
671          *      Find the master parent conf section.
672          *      We can't use mainconfig.config, because we're in the
673          *      process of re-building it, and it isn't set up yet...
674          */
675         parentcs = cf_top_section(outercs);
676
677         p = output;
678         ptr = input;
679         while (*ptr) {
680                 /*
681                  *      Ignore anything other than "${"
682                  */
683                 if ((*ptr == '$') && (ptr[1] == '{')) {
684                         CONF_ITEM *ci;
685                         CONF_PAIR *cp;
686
687                         /*
688                          *      FIXME: Add support for ${foo:-bar},
689                          *      like in xlat.c
690                          */
691
692                         /*
693                          *      Look for trailing '}', and log a
694                          *      warning for anything that doesn't match,
695                          *      and exit with a fatal error.
696                          */
697                         end = strchr(ptr, '}');
698                         if (end == NULL) {
699                                 *p = '\0';
700                                 radlog(L_INFO, "%s[%d]: Variable expansion missing }",
701                                        cf, *lineno);
702                                 return NULL;
703                         }
704
705                         ptr += 2;
706
707                         /*
708                          *      Can't really happen because input lines are
709                          *      capped at 8k, which is sizeof(name)
710                          */
711                         if ((size_t) (end - ptr) >= sizeof(name)) {
712                                 radlog(L_ERR, "%s[%d]: Reference string is too large",
713                                        cf, *lineno);
714                                 return NULL;
715                         }
716
717                         memcpy(name, ptr, end - ptr);
718                         name[end - ptr] = '\0';
719
720                         ci = cf_reference_item(parentcs, outercs, name);
721                         if (!ci || (ci->type != CONF_ITEM_PAIR)) {
722                                 radlog(L_ERR, "%s[%d]: Reference \"%s\" not found",
723                                        cf, *lineno, input);
724                                 return NULL;
725                         }
726
727                         /*
728                          *  Substitute the value of the variable.
729                          */
730                         cp = cf_itemtopair(ci);
731                         strcpy(p, cp->value);
732                         p += strlen(p);
733                         ptr = end + 1;
734
735                 } else if (memcmp(ptr, "$ENV{", 5) == 0) {
736                         char *env;
737
738                         ptr += 5;
739
740                         /*
741                          *      Look for trailing '}', and log a
742                          *      warning for anything that doesn't match,
743                          *      and exit with a fatal error.
744                          */
745                         end = strchr(ptr, '}');
746                         if (end == NULL) {
747                                 *p = '\0';
748                                 radlog(L_INFO, "%s[%d]: Environment variable expansion missing }",
749                                        cf, *lineno);
750                                 return NULL;
751                         }
752
753                         /*
754                          *      Can't really happen because input lines are
755                          *      capped at 8k, which is sizeof(name)
756                          */
757                         if ((size_t) (end - ptr) >= sizeof(name)) {
758                                 radlog(L_ERR, "%s[%d]: Environment variable name is too large",
759                                        cf, *lineno);
760                                 return NULL;
761                         }
762
763                         memcpy(name, ptr, end - ptr);
764                         name[end - ptr] = '\0';
765
766                         /*
767                          *      Get the environment variable.
768                          *      If none exists, then make it an empty string.
769                          */
770                         env = getenv(name);
771                         if (env == NULL) {
772                                 *name = '\0';
773                                 env = name;
774                         }
775
776                         strcpy(p, env);
777                         p += strlen(p);
778                         ptr = end + 1;
779
780                 } else {
781                         /*
782                          *      Copy it over verbatim.
783                          */
784                         *(p++) = *(ptr++);
785                 }
786         } /* loop over all of the input string. */
787
788         *p = '\0';
789
790         return output;
791 }
792
793
794 /*
795  *      Parses an item (not a CONF_ITEM) into the specified format,
796  *      with a default value.
797  *
798  *      Returns -1 on error, 0 for correctly parsed, and 1 if the
799  *      default value was used.  Note that the default value will be
800  *      used ONLY if the CONF_PAIR is NULL.
801  */
802 int cf_item_parse(CONF_SECTION *cs, const char *name,
803                   int type, void *data, const char *dflt)
804 {
805         int rcode = 0;
806         char **q;
807         const char *value;
808         fr_ipaddr_t ipaddr;
809         const CONF_PAIR *cp;
810         char ipbuf[128];
811
812         cp = cf_pair_find(cs, name);
813         if (cp) {
814                 value = cp->value;
815
816         } else if (!dflt) {
817                 return 1;       /* nothing to parse, return default value */
818
819         } else {
820                 rcode = 1;
821                 value = dflt;
822         }
823
824         if (!value) {
825                 return 0;
826         }
827
828         switch (type) {
829         case PW_TYPE_BOOLEAN:
830                 /*
831                  *      Allow yes/no and on/off
832                  */
833                 if ((strcasecmp(value, "yes") == 0) ||
834                     (strcasecmp(value, "on") == 0)) {
835                         *(int *)data = 1;
836                 } else if ((strcasecmp(value, "no") == 0) ||
837                            (strcasecmp(value, "off") == 0)) {
838                         *(int *)data = 0;
839                 } else {
840                         *(int *)data = 0;
841                         radlog(L_ERR, "Bad value \"%s\" for boolean variable %s", value, name);
842                         return -1;
843                 }
844                 cf_log_info(cs, "\t%s = %s", name, value);
845                 break;
846
847         case PW_TYPE_INTEGER:
848                 *(int *)data = strtol(value, 0, 0);
849                 cf_log_info(cs, "\t%s = %d", name, *(int *)data);
850                 break;
851
852         case PW_TYPE_STRING_PTR:
853                 q = (char **) data;
854                 if (*q != NULL) {
855                         free(*q);
856                 }
857
858                 /*
859                  *      Expand variables which haven't already been
860                  *      expanded automagically when the configuration
861                  *      file was read.
862                  */
863                 if (value == dflt) {
864                         char buffer[8192];
865
866                         int lineno = cs->item.lineno;
867
868                         /*
869                          *      FIXME: sizeof(buffer)?
870                          */
871                         value = cf_expand_variables("?",
872                                                     &lineno,
873                                                     cs, buffer, value);
874                         if (!value) return -1;
875                 }
876
877                 cf_log_info(cs, "\t%s = \"%s\"", name, value ? value : "(null)");
878                 *q = value ? strdup(value) : NULL;
879                 break;
880
881                 /*
882                  *      This is the same as PW_TYPE_STRING_PTR,
883                  *      except that we also "stat" the file, and
884                  *      cache the result.
885                  */
886         case PW_TYPE_FILENAME:
887                 q = (char **) data;
888                 if (*q != NULL) {
889                         free(*q);
890                 }
891
892                 /*
893                  *      Expand variables which haven't already been
894                  *      expanded automagically when the configuration
895                  *      file was read.
896                  */
897                 if (value == dflt) {
898                         char buffer[8192];
899
900                         int lineno = cs->item.lineno;
901
902                         /*
903                          *      FIXME: sizeof(buffer)?
904                          */
905                         value = cf_expand_variables("?",
906                                                     &lineno,
907                                                     cs, buffer, value);
908                         if (!value) return -1;
909                 }
910
911                 cf_log_info(cs, "\t%s = \"%s\"", name, value ? value : "(null)");
912                 *q = value ? strdup(value) : NULL;
913
914                 /*
915                  *      And now we "stat" the file.
916                  *
917                  *      FIXME: This appears to leak memory on exit,
918                  *      and we don't use this information.  So it's
919                  *      commented out for now.
920                  */
921                 if (0 && *q) {
922                         struct stat buf;
923
924                         if (stat(*q, &buf) == 0) {
925                                 time_t *mtime;
926
927                                 mtime = rad_malloc(sizeof(*mtime));
928                                 *mtime = buf.st_mtime;
929                                 /* FIXME: error? */
930                                 cf_data_add_internal(cs, *q, mtime, free,
931                                                      PW_TYPE_FILENAME);
932                         }
933                 }
934                 break;
935
936         case PW_TYPE_IPADDR:
937                 /*
938                  *      Allow '*' as any address
939                  */
940                 if (strcmp(value, "*") == 0) {
941                         *(uint32_t *) data = htonl(INADDR_ANY);
942                         cf_log_info(cs, "\t%s = *", name);
943                         break;
944                 }
945                 if (ip_hton(value, AF_INET, &ipaddr) < 0) {
946                         radlog(L_ERR, "Can't find IP address for host %s", value);
947                         return -1;
948                 }
949                 
950                 if (strspn(value, "0123456789.") == strlen(value)) {
951                         cf_log_info(cs, "\t%s = %s", name, value);
952                 } else {
953                         cf_log_info(cs, "\t%s = %s IP address [%s]", name, value,
954                                ip_ntoh(&ipaddr, ipbuf, sizeof(ipbuf)));
955                 }
956                 *(uint32_t *) data = ipaddr.ipaddr.ip4addr.s_addr;
957                 break;
958
959         case PW_TYPE_IPV6ADDR:
960                 if (ip_hton(value, AF_INET6, &ipaddr) < 0) {
961                         radlog(L_ERR, "Can't find IPv6 address for host %s", value);
962                         return -1;
963                 }
964                 cf_log_info(cs, "\t%s = %s IPv6 address [%s]", name, value,
965                                ip_ntoh(&ipaddr, ipbuf, sizeof(ipbuf)));
966                 memcpy(data, &ipaddr.ipaddr.ip6addr,
967                        sizeof(ipaddr.ipaddr.ip6addr));
968                 break;
969
970         default:
971                 radlog(L_ERR, "type %d not supported yet", type);
972                 return -1;
973                 break;
974         } /* switch over variable type */
975
976         return rcode;
977 }
978
979 static const char *parse_spaces = "                                                                                                                                                                                                                                                                ";
980
981 /*
982  *      Parse a configuration section into user-supplied variables.
983  */
984 int cf_section_parse(CONF_SECTION *cs, void *base,
985                      const CONF_PARSER *variables)
986 {
987         int i;
988         void *data;
989
990         cs->variables = variables; /* this doesn't hurt anything */
991
992         if (!cs->name2) {
993                 cf_log_info(cs, "%.*s%s {", cs->depth, parse_spaces,
994                        cs->name1);
995         } else {
996                 cf_log_info(cs, "%.*s%s %s {", cs->depth, parse_spaces,
997                        cs->name1, cs->name2);
998         }
999
1000         /*
1001          *      Handle the known configuration parameters.
1002          */
1003         for (i = 0; variables[i].name != NULL; i++) {
1004                 /*
1005                  *      Handle subsections specially
1006                  */
1007                 if (variables[i].type == PW_TYPE_SUBSECTION) {
1008                         CONF_SECTION *subcs;
1009                         subcs = cf_section_sub_find(cs, variables[i].name);
1010
1011                         /*
1012                          *      If the configuration section is NOT there,
1013                          *      then ignore it.
1014                          *
1015                          *      FIXME! This is probably wrong... we should
1016                          *      probably set the items to their default values.
1017                          */
1018                         if (!subcs) continue;
1019
1020                         if (!variables[i].dflt) {
1021                                 DEBUG2("Internal sanity check 1 failed in cf_section_parse");
1022                                 goto error;
1023                         }
1024
1025                         if (cf_section_parse(subcs, base,
1026                                              (const CONF_PARSER *) variables[i].dflt) < 0) {
1027                                 goto error;
1028                         }
1029                         continue;
1030                 } /* else it's a CONF_PAIR */
1031
1032                 if (variables[i].data) {
1033                         data = variables[i].data; /* prefer this. */
1034                 } else if (base) {
1035                         data = ((char *)base) + variables[i].offset;
1036                 } else {
1037                         DEBUG2("Internal sanity check 2 failed in cf_section_parse");
1038                         goto error;
1039                 }
1040
1041                 /*
1042                  *      Parse the pair we found, or a default value.
1043                  */
1044                 if (cf_item_parse(cs, variables[i].name, variables[i].type,
1045                                   data, variables[i].dflt) < 0) {
1046                         goto error;
1047                 }
1048         } /* for all variables in the configuration section */
1049
1050         cf_log_info(cs, "%.*s}", cs->depth, parse_spaces);
1051
1052         cs->base = base;
1053
1054         return 0;
1055
1056  error:
1057         cf_log_info(cs, "%.*s}", cs->depth, parse_spaces);
1058         cf_section_parse_free(cs, base);
1059         return -1;
1060 }
1061
1062
1063 /*
1064  *      Sanity check the "if" or "elsif", presuming that the first '('
1065  *      has already been eaten.
1066  *
1067  *      We're not really parsing it here, just checking if it's mostly
1068  *      well-formed.
1069  */
1070 static int condition_looks_ok(const char **ptr)
1071 {
1072         int num_braces = 1;
1073         int quote = 0;
1074         const char *p = *ptr;
1075
1076         while (*p) {
1077                 if (quote) {
1078                         if (*p == quote) {
1079                                 p++;
1080                                 quote = 0;
1081                                 continue;
1082                         }
1083
1084                         if (*p == '\\') {
1085                                 if (!p[1]) {
1086                                         return 0; /* no trailing slash */
1087                                 }
1088                                 p += 2;
1089                                 continue;
1090                         }
1091                         p++;
1092                         continue;
1093                 }
1094
1095                 switch (*p) {
1096                 case '\\':
1097                         if (!p[1]) {
1098                                 return 0; /* no trailing slash */
1099                         }
1100                         p += 2;
1101                         continue;
1102
1103                 case '(':
1104                         num_braces++;
1105                         p++;
1106                         continue;
1107
1108                 case ')':
1109                         if (num_braces == 1) {
1110                                 const char *q = p + 1;
1111
1112                                 /*
1113                                  *      Validate that there isn't much
1114                                  *      else after the closing brace.
1115                                  */
1116                                 while ((*q == ' ') || (*q == '\t')) q++;
1117
1118                                 /*
1119                                  *      Parse error.
1120                                  */
1121                                 if (*q != '{') {
1122                                         return 0;
1123                                 }
1124
1125                                 *ptr = p + 1; /* include the trailing ')' */
1126                                 return 1;
1127                         }
1128                         num_braces--;
1129                         p++;
1130                         continue;
1131
1132                 case '"':
1133                 case '\'':
1134                 case '/':
1135                 case '`':
1136                         quote = *p;
1137                         /* FALL-THROUGH */
1138
1139                 default:
1140                         p++;
1141                         break;
1142                 }
1143         }
1144
1145         return 0;
1146 }
1147
1148
1149 static const char *cf_local_file(CONF_SECTION *cs, const char *local,
1150                                  char *buffer, size_t bufsize)
1151 {
1152         size_t dirsize;
1153         const char *p;
1154         CONF_SECTION *parentcs = cf_top_section(cs);
1155
1156         p = strrchr(parentcs->item.filename, FR_DIR_SEP);
1157         if (!p) return local;
1158
1159         dirsize = (p - parentcs->item.filename) + 1;
1160
1161         if ((dirsize + strlen(local)) >= bufsize) {
1162                 return NULL;
1163         }
1164
1165         memcpy(buffer, parentcs->item.filename, dirsize);
1166         strlcpy(buffer + dirsize, local, bufsize - dirsize);
1167
1168         return buffer;
1169 }
1170
1171
1172 /*
1173  *      Read a part of the config file.
1174  */
1175 static int cf_section_read(const char *filename, int *lineno, FILE *fp,
1176                            CONF_SECTION *current)
1177
1178 {
1179         CONF_SECTION *this, *css;
1180         CONF_PAIR *cpn;
1181         const char *ptr;
1182         const char *value;
1183         char buf[8192];
1184         char buf1[8192];
1185         char buf2[8192];
1186         char buf3[8192];
1187         int t1, t2, t3;
1188         char *cbuf = buf;
1189         size_t len;
1190
1191         this = current;         /* add items here */
1192
1193         /*
1194          *      Read, checking for line continuations ('\\' at EOL)
1195          */
1196         for (;;) {
1197                 int eof;
1198
1199                 /*
1200                  *      Get data, and remember if we are at EOF.
1201                  */
1202                 eof = (fgets(cbuf, sizeof(buf) - (cbuf - buf), fp) == NULL);
1203                 (*lineno)++;
1204
1205                 /*
1206                  *      We read the entire 8k worth of data: complain.
1207                  *      Note that we don't care if the last character
1208                  *      is \n: it's still forbidden.  This means that
1209                  *      the maximum allowed length of text is 8k-1, which
1210                  *      should be plenty.
1211                  */
1212                 len = strlen(cbuf);
1213                 if ((cbuf + len + 1) >= (buf + sizeof(buf))) {
1214                         radlog(L_ERR, "%s[%d]: Line too long",
1215                                filename, *lineno);
1216                         return -1;
1217                 }
1218
1219                 /*
1220                  *      Not doing continuations: check for edge
1221                  *      conditions.
1222                  */
1223                 if (cbuf == buf) {
1224                         if (eof) break;
1225                         
1226                         ptr = buf;
1227                         while (*ptr && isspace((int) *ptr)) ptr++;
1228
1229                         if (!*ptr || (*ptr == '#')) continue;
1230
1231                 } else if (eof || (len == 0)) {
1232                         radlog(L_ERR, "%s[%d]: Continuation at EOF is illegal",
1233                                filename, *lineno);
1234                         return -1;
1235                 }
1236
1237                 /*
1238                  *      See if there's a continuation.
1239                  */
1240                 while ((len > 0) &&
1241                        ((cbuf[len - 1] == '\n') || (cbuf[len - 1] == '\r'))) {
1242                         len--;
1243                         cbuf[len] = '\0';
1244                 }
1245
1246                 if ((len > 0) && (cbuf[len - 1] == '\\')) {
1247                         cbuf[len - 1] = '\0';
1248                         cbuf += len - 1;
1249                         continue;
1250                 }
1251
1252                 ptr = cbuf = buf;
1253
1254                 /*
1255                  *      The parser is getting to be evil.
1256                  */
1257                 while ((*ptr == ' ') || (*ptr == '\t')) ptr++;
1258
1259                 if (((ptr[0] == '%') && (ptr[1] == '{')) ||
1260                     (ptr[0] == '`')) {
1261                         int hack;
1262
1263                         if (ptr[0] == '%') {
1264                                 hack = rad_copy_variable(buf1, ptr);
1265                         } else {
1266                                 hack = rad_copy_string(buf1, ptr);
1267                         }
1268                         if (hack < 0) {
1269                                 radlog(L_ERR, "%s[%d]: Invalid expansion: %s",
1270                                        filename, *lineno, ptr);
1271                                 return -1;
1272                         }
1273
1274                         t1 = T_BARE_WORD;
1275                         ptr += hack;
1276
1277                         t2 = gettoken(&ptr, buf2, sizeof(buf2));
1278                         switch (t2) {
1279                         case T_EOL:
1280                         case T_HASH:
1281                                 goto do_bare_word;
1282                                 
1283                         default:
1284                                 radlog(L_ERR, "%s[%d]: Invalid expansion: %s",
1285                                        filename, *lineno, ptr);
1286                                 return -1;
1287                         }
1288                 } else {
1289                         t1 = gettoken(&ptr, buf1, sizeof(buf1));
1290                 }
1291
1292                 /*
1293                  *      The caller eats "name1 name2 {", and calls us
1294                  *      for the data inside of the section.  So if we
1295                  *      receive a closing brace, then it must mean the
1296                  *      end of the section.
1297                  */
1298                if (t1 == T_RCBRACE) {
1299                        if (this == current) {
1300                                radlog(L_ERR, "%s[%d]: Too many closing braces",
1301                                       filename, *lineno);
1302                                return -1;
1303
1304                        }
1305                        this = this->item.parent;
1306                        continue;
1307                 }
1308
1309                 /*
1310                  *      Allow for $INCLUDE files
1311                  *
1312                  *      This *SHOULD* work for any level include.
1313                  *      I really really really hate this file.  -cparker
1314                  */
1315                if ((strcasecmp(buf1, "$INCLUDE") == 0) ||
1316                    (strcasecmp(buf1, "$-INCLUDE") == 0)) {
1317                        int relative = 1;
1318
1319                         t2 = getword(&ptr, buf2, sizeof(buf2));
1320
1321                         if (buf2[0] == '$') relative = 0;
1322
1323                         value = cf_expand_variables(filename, lineno, this, buf, buf2);
1324                         if (!value) return -1;
1325
1326                         if (!FR_DIR_IS_RELATIVE(value)) relative = 0;
1327
1328                         if (relative) {
1329                                 value = cf_local_file(current, value, buf3,
1330                                                       sizeof(buf3));
1331                                 if (!value) {
1332                                         radlog(L_ERR, "%s[%d]: Directories too deep.",
1333                                                filename, *lineno);
1334                                         return -1;
1335                                 }
1336                         }
1337
1338
1339 #ifdef HAVE_DIRENT_H
1340                         /*
1341                          *      $INCLUDE foo/
1342                          *
1343                          *      Include ALL non-"dot" files in the directory.
1344                          *      careful!
1345                          */
1346                         if (value[strlen(value) - 1] == '/') {
1347                                 DIR             *dir;
1348                                 struct dirent   *dp;
1349                                 struct stat stat_buf;
1350
1351                                 DEBUG2("including files in directory %s", value );
1352                                 dir = opendir(value);
1353                                 if (!dir) {
1354                                         radlog(L_ERR, "%s[%d]: Error reading directory %s: %s",
1355                                                filename, *lineno, value,
1356                                                strerror(errno));
1357                                         return -1;
1358                                 }
1359
1360                                 /*
1361                                  *      Read the directory, ignoring "." files.
1362                                  */
1363                                 while ((dp = readdir(dir)) != NULL) {
1364                                         const char *p;
1365
1366                                         if (dp->d_name[0] == '.') continue;
1367
1368                                         /*
1369                                          *      Check for valid characters
1370                                          */
1371                                         for (p = dp->d_name; *p != '\0'; p++) {
1372                                                 if (isalpha((int)*p) ||
1373                                                     isdigit((int)*p) ||
1374                                                     (*p == '-') ||
1375                                                     (*p == '_') ||
1376                                                     (*p == '.')) continue;
1377                                                 break;
1378                                         }
1379                                         if (*p != '\0') continue;
1380
1381                                         snprintf(buf2, sizeof(buf2), "%s%s",
1382                                                  value, dp->d_name);
1383                                         if ((stat(buf2, &stat_buf) != 0) ||
1384                                             S_ISDIR(stat_buf.st_mode)) continue;
1385                                         /*
1386                                          *      Read the file into the current
1387                                          *      configuration sectoin.
1388                                          */
1389                                         if (cf_file_include(buf2, this) < 0) {
1390                                                 closedir(dir);
1391                                                 return -1;
1392                                         }
1393                                 }
1394                                 closedir(dir);
1395                         }  else
1396 #endif
1397                         { /* it was a normal file */
1398                                 if (buf1[1] == '-') {
1399                                         struct stat statbuf;
1400
1401                                         if (stat(value, &statbuf) < 0) {
1402                                                 DEBUG("WARNING: Not including file %s: %s", value, strerror(errno));
1403                                                 continue;
1404                                         }
1405                                 }
1406
1407                                 if (cf_file_include(value, this) < 0) {
1408                                         return -1;
1409                                 }
1410                         }
1411                         continue;
1412                 } /* we were in an include */
1413
1414                if (strcasecmp(buf1, "$template") == 0) {
1415                        CONF_ITEM *ci;
1416                        CONF_SECTION *parentcs;
1417                        t2 = getword(&ptr, buf2, sizeof(buf2));
1418
1419                        parentcs = cf_top_section(current);
1420
1421                        ci = cf_reference_item(parentcs, this, buf2);
1422                        if (!ci || (ci->type != CONF_ITEM_SECTION)) {
1423                                 radlog(L_ERR, "%s[%d]: Reference \"%s\" not found",
1424                                        filename, *lineno, buf2);
1425                                 return -1;
1426                        }
1427                        
1428                        if (this->template) {
1429                                 radlog(L_ERR, "%s[%d]: Section already has a template",
1430                                        filename, *lineno);
1431                                 return -1;
1432                        }
1433
1434                        this->template = cf_itemtosection(ci);
1435                        continue;
1436                }
1437
1438                 /*
1439                  *      Ensure that the user can't add CONF_PAIRs
1440                  *      with 'internal' names;
1441                  */
1442                 if (buf1[0] == '_') {
1443                         radlog(L_ERR, "%s[%d]: Illegal configuration pair name \"%s\"",
1444                                         filename, *lineno, buf1);
1445                         return -1;
1446                 }
1447
1448                 /*
1449                  *      Grab the next token.
1450                  */
1451                 t2 = gettoken(&ptr, buf2, sizeof(buf2));
1452                 switch (t2) {
1453                 case T_EOL:
1454                 case T_HASH:
1455                 do_bare_word:
1456                         t2 = T_OP_EQ;
1457                         value = NULL;
1458                         goto do_set;
1459
1460                 case T_OP_ADD:
1461                 case T_OP_CMP_EQ:
1462                 case T_OP_SUB:
1463                 case T_OP_LE:
1464                 case T_OP_GE:
1465                         if (!this || (strcmp(this->name1, "update") != 0)) {
1466                                 radlog(L_ERR, "%s[%d]: Invalid operator in assignment",
1467                                        filename, *lineno);
1468                                 return -1;
1469                         }
1470
1471                 case T_OP_EQ:
1472                 case T_OP_SET:
1473                 do_set:
1474                         t3 = getstring(&ptr, buf3, sizeof(buf3));
1475
1476                         /*
1477                          *      Handle variable substitution via ${foo}
1478                          */
1479                         if ((t3 == T_BARE_WORD) ||
1480                             (t3 == T_DOUBLE_QUOTED_STRING)) {
1481                                 value = cf_expand_variables(filename, lineno, this,
1482                                                             buf, buf3);
1483                                 if (!value) return -1;
1484                         } else if ((t3 == T_EOL) ||
1485                                    (t3 == T_HASH)) {
1486                                 value = NULL;
1487                         } else {
1488                                 value = buf3;
1489                         }
1490                         
1491                         /*
1492                          *      Add this CONF_PAIR to our CONF_SECTION
1493                          */
1494                         cpn = cf_pair_alloc(buf1, value, t2, t3, this);
1495                         cpn->item.filename = filename;
1496                         cpn->item.lineno = *lineno;
1497                         cf_item_add(this, cf_pairtoitem(cpn));
1498                         continue;
1499
1500                         /*
1501                          *      This horrible code is here to support
1502                          *      if/then/else failover in the
1503                          *      authorize, etc. sections.  It makes no
1504                          *      sense anywhere else.
1505                          */
1506                 case T_LBRACE:
1507                         if ((strcmp(buf1, "if") == 0) ||
1508                             (strcmp(buf1, "elsif") == 0)) {
1509                                 const char *end = ptr;
1510                                 CONF_SECTION *server;
1511
1512                                 if (!condition_looks_ok(&end)) {
1513                                         radlog(L_ERR, "%s[%d]: Parse error in condition at: %s",
1514                                                filename, *lineno, ptr);
1515                                         return -1;
1516                                 }
1517
1518                                 if ((size_t) (end - ptr) >= (sizeof(buf2) - 1)) {
1519                                         radlog(L_ERR, "%s[%d]: Statement too complicated after \"%s\"",
1520                                                filename, *lineno, buf1);
1521                                         return -1;
1522                                 }
1523
1524                                 /*
1525                                  *      More sanity checking.  This is
1526                                  *      getting to be a horrible hack.
1527                                  */
1528                                 server = this;
1529                                 while (server) {
1530                                         if (strcmp(server->name1, "server") == 0) break;
1531                                         server = server->item.parent;
1532                                 }
1533                                 
1534                                 if (0 && !server) {
1535                                         radlog(L_ERR, "%s[%d]: Processing directives such as \"%s\" cannot be used here.",
1536                                                filename, *lineno, buf1);
1537                                         return -1;
1538                                 }
1539
1540                                 buf2[0] = '(';
1541                                 memcpy(buf2 + 1, ptr, end - ptr);
1542                                 buf2[end - ptr + 1] = '\0';
1543                                 ptr = end + 1;
1544                                 t2 = T_BARE_WORD;
1545                                 goto section_alloc;
1546
1547                         } else {
1548                                 radlog(L_ERR, "%s[%d]: Parse error after \"%s\"",
1549                                        filename, *lineno, buf1);
1550                                 return -1;
1551                         }
1552
1553                         /* FALL-THROUGH */
1554
1555                         /*
1556                          *      No '=', must be a section or sub-section.
1557                          */
1558                 case T_BARE_WORD:
1559                 case T_DOUBLE_QUOTED_STRING:
1560                 case T_SINGLE_QUOTED_STRING:
1561                         t3 = gettoken(&ptr, buf3, sizeof(buf3));
1562                         if (t3 != T_LCBRACE) {
1563                                 radlog(L_ERR, "%s[%d]: Expecting section start brace '{' after \"%s %s\"",
1564                                        filename, *lineno, buf1, buf2);
1565                                 return -1;
1566                         }
1567
1568                 case T_LCBRACE:
1569                 section_alloc:
1570                         css = cf_section_alloc(buf1,
1571                                                t2 == T_LCBRACE ? NULL : buf2,
1572                                                this);
1573                         if (!css) {
1574                                 radlog(L_ERR, "%s[%d]: Failed allocating memory for section",
1575                                                 filename, *lineno);
1576                                 return -1;
1577                         }
1578                         cf_item_add(this, cf_sectiontoitem(css));
1579                         css->item.filename = filename;
1580                         css->item.lineno = *lineno;
1581
1582                         /*
1583                          *      The current section is now the child section.
1584                          */
1585                         this = css;
1586                         continue;
1587
1588                 default:
1589                         radlog(L_ERR, "%s[%d]: Parse error after \"%s\"",
1590                                filename, *lineno, buf1);
1591                         return -1;
1592                 }
1593         }
1594
1595         /*
1596          *      See if EOF was unexpected ..
1597          */
1598         if (feof(fp) && (this != current)) {
1599                 radlog(L_ERR, "%s[%d]: EOF reached without closing brace for section %s starting at line %d",
1600                        filename, *lineno,
1601                        cf_section_name1(this), cf_section_lineno(this));
1602                 return -1;
1603         }
1604
1605         return 0;
1606 }
1607
1608 /*
1609  *      Include one config file in another.
1610  */
1611 int cf_file_include(const char *filename, CONF_SECTION *cs)
1612 {
1613         FILE            *fp;
1614         int             lineno = 0;
1615         struct stat     statbuf;
1616         time_t          *mtime;
1617         CONF_DATA       *cd;
1618
1619         DEBUG2( "including configuration file %s", filename);
1620
1621         if (stat(filename, &statbuf) == 0) {
1622 #ifdef S_IWOTH
1623                 if ((statbuf.st_mode & S_IWOTH) != 0) {
1624                         radlog(L_ERR|L_CONS, "Configuration file %s is globally writable.  Refusing to start due to insecure configuration.",
1625                                filename);
1626                         return -1;
1627                 }
1628 #endif
1629
1630 #ifdef S_IROTH
1631                 if (0 && (statbuf.st_mode & S_IROTH) != 0) {
1632                         radlog(L_ERR|L_CONS, "Configuration file %s is globally readable.  Refusing to start due to insecure configuration.",
1633                                filename);
1634                         return -1;
1635                 }
1636 #endif
1637         }
1638
1639         fp = fopen(filename, "r");
1640         if (!fp) {
1641                 radlog(L_ERR|L_CONS, "Unable to open file \"%s\": %s",
1642                        filename, strerror(errno));
1643                 return -1;
1644         }
1645
1646         /*
1647          *      Add the filename to the section
1648          */
1649         mtime = rad_malloc(sizeof(*mtime));
1650         *mtime = statbuf.st_mtime;
1651
1652         if (cf_data_add_internal(cs, filename, mtime, free,
1653                                  PW_TYPE_FILENAME) < 0) {
1654                 fclose(fp);
1655                 radlog(L_ERR|L_CONS, "Internal error open file \"%s\"",
1656                        filename);
1657                 return -1;
1658         }
1659
1660         cd = cf_data_find_internal(cs, filename, PW_TYPE_FILENAME);
1661         if (!cd) {
1662                 fclose(fp);
1663                 radlog(L_ERR|L_CONS, "Internal error open file \"%s\"",
1664                        filename);
1665                 return -1;
1666         }
1667
1668         if (!cs->item.filename) cs->item.filename = filename;
1669
1670         /*
1671          *      Read the section.  It's OK to have EOF without a
1672          *      matching close brace.
1673          */
1674         if (cf_section_read(cd->name, &lineno, fp, cs) < 0) {
1675                 fclose(fp);
1676                 return -1;
1677         }
1678
1679         fclose(fp);
1680         return 0;
1681 }
1682
1683 /*
1684  *      Bootstrap a config file.
1685  */
1686 CONF_SECTION *cf_file_read(const char *filename)
1687 {
1688         char *p;
1689         CONF_PAIR *cp;
1690         CONF_SECTION *cs;
1691
1692         cs = cf_section_alloc("main", NULL, NULL);
1693         if (!cs) return NULL;
1694
1695         cp = cf_pair_alloc("confdir", filename, T_OP_SET, T_BARE_WORD, cs);
1696         if (!cp) return NULL;
1697
1698         p = strrchr(cp->value, FR_DIR_SEP);
1699         if (p) *p = '\0';
1700
1701         cp->item.filename = "internal";
1702         cp->item.lineno = 0;
1703         cf_item_add(cs, cf_pairtoitem(cp));
1704
1705         if (cf_file_include(filename, cs) < 0) {
1706                 cf_section_free(&cs);
1707                 return NULL;
1708         }
1709
1710         return cs;
1711 }
1712
1713 /*
1714  * Return a CONF_PAIR within a CONF_SECTION.
1715  */
1716 CONF_PAIR *cf_pair_find(const CONF_SECTION *cs, const char *name)
1717 {
1718         CONF_ITEM       *ci;
1719         CONF_PAIR       *cp = NULL;
1720
1721         if (!cs) return NULL;
1722
1723         /*
1724          *      Find the name in the tree, for speed.
1725          */
1726         if (name) {
1727                 CONF_PAIR mycp;
1728
1729                 mycp.attr = name;
1730                 cp = rbtree_finddata(cs->pair_tree, &mycp);
1731         } else {
1732                 /*
1733                  *      Else find the first one that matches
1734                  */
1735                 for (ci = cs->children; ci; ci = ci->next) {
1736                         if (ci->type == CONF_ITEM_PAIR) {
1737                                 return cf_itemtopair(ci);
1738                         }
1739                 }
1740         }
1741
1742         if (cp || !cs->template) return cp;
1743
1744         return cf_pair_find(cs->template, name);
1745 }
1746
1747 /*
1748  * Return the attr of a CONF_PAIR
1749  */
1750
1751 const char *cf_pair_attr(CONF_PAIR *pair)
1752 {
1753         return (pair ? pair->attr : NULL);
1754 }
1755
1756 /*
1757  * Return the value of a CONF_PAIR
1758  */
1759
1760 const char *cf_pair_value(CONF_PAIR *pair)
1761 {
1762         return (pair ? pair->value : NULL);
1763 }
1764
1765 /*
1766  *      Copied here for error reporting.
1767  */
1768 extern void librad_log(const char *, ...);
1769
1770 /*
1771  * Turn a CONF_PAIR into a VALUE_PAIR
1772  * For now, ignore the "value_type" field...
1773  */
1774 VALUE_PAIR *cf_pairtovp(CONF_PAIR *pair)
1775 {
1776         VALUE_PAIR *vp;
1777
1778         if (!pair) {
1779                 librad_log("Internal error");
1780                 return NULL;
1781         }
1782
1783         if (!pair->value) {
1784                 librad_log("No value given for attribute %s", pair->attr);
1785                 return NULL;
1786         }
1787
1788         /*
1789          *      pairmake handles tags.  pairalloc() doesn't.
1790          */
1791         vp = pairmake(pair->attr, NULL, pair->operator);
1792         if (!vp) {
1793                 return NULL;
1794         }
1795
1796         if (pair->value_type == T_BARE_WORD) {
1797                 if ((vp->type == PW_TYPE_STRING) && 
1798                     (pair->value[0] == '0') && (pair->value[1] == 'x')) {
1799                         vp->type = PW_TYPE_OCTETS;
1800                 }
1801                 if (!pairparsevalue(vp, pair->value)) {
1802                         pairfree(&vp);
1803                         return NULL;
1804                 }
1805                 vp->flags.do_xlat = 0;
1806           
1807         } else if (pair->value_type == T_SINGLE_QUOTED_STRING) {
1808                 if (!pairparsevalue(vp, pair->value)) {
1809                         pairfree(&vp);
1810                         return NULL;
1811                 }
1812                 vp->flags.do_xlat = 0;
1813         } else {
1814                 vp->flags.do_xlat = 1;
1815         }
1816
1817         return vp;
1818 }
1819
1820 /*
1821  * Return the first label of a CONF_SECTION
1822  */
1823
1824 const char *cf_section_name1(const CONF_SECTION *cs)
1825 {
1826         return (cs ? cs->name1 : NULL);
1827 }
1828
1829 /*
1830  * Return the second label of a CONF_SECTION
1831  */
1832
1833 const char *cf_section_name2(const CONF_SECTION *cs)
1834 {
1835         return (cs ? cs->name2 : NULL);
1836 }
1837
1838 /*
1839  * Find a value in a CONF_SECTION
1840  */
1841 const char *cf_section_value_find(const CONF_SECTION *cs, const char *attr)
1842 {
1843         CONF_PAIR       *cp;
1844
1845         cp = cf_pair_find(cs, attr);
1846
1847         return (cp ? cp->value : NULL);
1848 }
1849
1850 /*
1851  * Return the next pair after a CONF_PAIR
1852  * with a certain name (char *attr) If the requested
1853  * attr is NULL, any attr matches.
1854  */
1855
1856 CONF_PAIR *cf_pair_find_next(const CONF_SECTION *cs,
1857                              CONF_PAIR *pair, const char *attr)
1858 {
1859         CONF_ITEM       *ci;
1860
1861         /*
1862          * If pair is NULL this must be a first time run
1863          * Find the pair with correct name
1864          */
1865
1866         if (pair == NULL){
1867                 return cf_pair_find(cs, attr);
1868         }
1869
1870         ci = cf_pairtoitem(pair)->next;
1871
1872         for (; ci; ci = ci->next) {
1873                 if (ci->type != CONF_ITEM_PAIR)
1874                         continue;
1875                 if (attr == NULL || strcmp(cf_itemtopair(ci)->attr, attr) == 0)
1876                         break;
1877         }
1878
1879         return cf_itemtopair(ci);
1880 }
1881
1882 /*
1883  * Find a CONF_SECTION, or return the root if name is NULL
1884  */
1885
1886 CONF_SECTION *cf_section_find(const char *name)
1887 {
1888         if (name)
1889                 return cf_section_sub_find(mainconfig.config, name);
1890         else
1891                 return mainconfig.config;
1892 }
1893
1894 /*
1895  * Find a sub-section in a section
1896  */
1897
1898 CONF_SECTION *cf_section_sub_find(const CONF_SECTION *cs, const char *name)
1899 {
1900         CONF_ITEM *ci;
1901
1902         /*
1903          *      Do the fast lookup if possible.
1904          */
1905         if (name && cs->section_tree) {
1906                 CONF_SECTION mycs;
1907
1908                 mycs.name1 = name;
1909                 mycs.name2 = NULL;
1910                 return rbtree_finddata(cs->section_tree, &mycs);
1911         }
1912
1913         for (ci = cs->children; ci; ci = ci->next) {
1914                 if (ci->type != CONF_ITEM_SECTION)
1915                         continue;
1916                 if (strcmp(cf_itemtosection(ci)->name1, name) == 0)
1917                         break;
1918         }
1919
1920         return cf_itemtosection(ci);
1921
1922 }
1923
1924
1925 /*
1926  *      Find a CONF_SECTION with both names.
1927  */
1928 CONF_SECTION *cf_section_sub_find_name2(const CONF_SECTION *cs,
1929                                         const char *name1, const char *name2)
1930 {
1931         CONF_ITEM    *ci;
1932
1933         if (!cs) cs = mainconfig.config;
1934
1935         if (name1 && (cs->section_tree)) {
1936                 CONF_SECTION mycs, *master_cs;
1937
1938                 mycs.name1 = name1;
1939                 mycs.name2 = name2;
1940
1941                 master_cs = rbtree_finddata(cs->section_tree, &mycs);
1942                 if (master_cs) {
1943                         return rbtree_finddata(master_cs->name2_tree, &mycs);
1944                 }
1945         }
1946
1947         /*
1948          *      Else do it the old-fashioned way.
1949          */
1950         for (ci = cs->children; ci; ci = ci->next) {
1951                 CONF_SECTION *subcs;
1952
1953                 if (ci->type != CONF_ITEM_SECTION)
1954                         continue;
1955
1956                 subcs = cf_itemtosection(ci);
1957                 if (!name1) {
1958                         if (!subcs->name2) {
1959                                 if (strcmp(subcs->name1, name2) == 0) break;
1960                         } else {
1961                                 if (strcmp(subcs->name2, name2) == 0) break;
1962                         }
1963                         continue; /* don't do the string comparisons below */
1964                 }
1965
1966                 if ((strcmp(subcs->name1, name1) == 0) &&
1967                     (subcs->name2 != NULL) &&
1968                     (strcmp(subcs->name2, name2) == 0))
1969                         break;
1970         }
1971
1972         return cf_itemtosection(ci);
1973 }
1974
1975 /*
1976  * Return the next subsection after a CONF_SECTION
1977  * with a certain name1 (char *name1). If the requested
1978  * name1 is NULL, any name1 matches.
1979  */
1980
1981 CONF_SECTION *cf_subsection_find_next(CONF_SECTION *section,
1982                                       CONF_SECTION *subsection,
1983                                       const char *name1)
1984 {
1985         CONF_ITEM       *ci;
1986
1987         /*
1988          * If subsection is NULL this must be a first time run
1989          * Find the subsection with correct name
1990          */
1991
1992         if (subsection == NULL){
1993                 ci = section->children;
1994         } else {
1995                 ci = cf_sectiontoitem(subsection)->next;
1996         }
1997
1998         for (; ci; ci = ci->next) {
1999                 if (ci->type != CONF_ITEM_SECTION)
2000                         continue;
2001                 if ((name1 == NULL) ||
2002                     (strcmp(cf_itemtosection(ci)->name1, name1) == 0))
2003                         break;
2004         }
2005
2006         return cf_itemtosection(ci);
2007 }
2008
2009
2010 /*
2011  * Return the next section after a CONF_SECTION
2012  * with a certain name1 (char *name1). If the requested
2013  * name1 is NULL, any name1 matches.
2014  */
2015
2016 CONF_SECTION *cf_section_find_next(CONF_SECTION *section,
2017                                    CONF_SECTION *subsection,
2018                                    const char *name1)
2019 {
2020         if (!section->item.parent) return NULL;
2021
2022         return cf_subsection_find_next(section->item.parent, subsection, name1);
2023 }
2024
2025 /*
2026  * Return the next item after a CONF_ITEM.
2027  */
2028
2029 CONF_ITEM *cf_item_find_next(CONF_SECTION *section, CONF_ITEM *item)
2030 {
2031         /*
2032          * If item is NULL this must be a first time run
2033          * Return the first item
2034          */
2035
2036         if (item == NULL) {
2037                 return section->children;
2038         } else {
2039                 return item->next;
2040         }
2041 }
2042
2043 int cf_section_lineno(CONF_SECTION *section)
2044 {
2045         return cf_sectiontoitem(section)->lineno;
2046 }
2047
2048 const char *cf_pair_filename(CONF_PAIR *pair)
2049 {
2050         return cf_pairtoitem(pair)->filename;
2051 }
2052
2053 const char *cf_section_filename(CONF_SECTION *section)
2054 {
2055         return cf_sectiontoitem(section)->filename;
2056 }
2057
2058 int cf_pair_lineno(CONF_PAIR *pair)
2059 {
2060         return cf_pairtoitem(pair)->lineno;
2061 }
2062
2063 int cf_item_is_section(CONF_ITEM *item)
2064 {
2065         return item->type == CONF_ITEM_SECTION;
2066 }
2067 int cf_item_is_pair(CONF_ITEM *item)
2068 {
2069         return item->type == CONF_ITEM_PAIR;
2070 }
2071
2072
2073 static CONF_DATA *cf_data_alloc(CONF_SECTION *parent, const char *name,
2074                                 void *data, void (*data_free)(void *))
2075 {
2076         char *p;
2077         size_t name_len;
2078         CONF_DATA *cd;
2079
2080         name_len = strlen(name) + 1;
2081
2082         p = rad_malloc(sizeof(*cd) + name_len);
2083         cd = (CONF_DATA *) p;
2084         memset(cd, 0, sizeof(*cd));
2085
2086         cd->item.type = CONF_ITEM_DATA;
2087         cd->item.parent = parent;
2088         cd->data = data;
2089         cd->free = data_free;
2090
2091         p += sizeof(*cd);
2092         memcpy(p, name, name_len);
2093         cd->name = p;
2094         return cd;
2095 }
2096
2097
2098 static void *cf_data_find_internal(CONF_SECTION *cs, const char *name,
2099                                    int flag)
2100 {
2101         if (!cs || !name) return NULL;
2102
2103         /*
2104          *      Find the name in the tree, for speed.
2105          */
2106         if (cs->data_tree) {
2107                 CONF_DATA mycd;
2108
2109                 mycd.name = name;
2110                 mycd.flag = flag;
2111                 return rbtree_finddata(cs->data_tree, &mycd);
2112         }
2113
2114         return NULL;
2115 }
2116
2117 /*
2118  *      Find data from a particular section.
2119  */
2120 void *cf_data_find(CONF_SECTION *cs, const char *name)
2121 {
2122         CONF_DATA *cd = cf_data_find_internal(cs, name, 0);
2123
2124         if (cd) return cd->data;
2125         return NULL;
2126 }
2127
2128
2129 /*
2130  *      Add named data to a configuration section.
2131  */
2132 static int cf_data_add_internal(CONF_SECTION *cs, const char *name,
2133                                 void *data, void (*data_free)(void *),
2134                                 int flag)
2135 {
2136         CONF_DATA *cd;
2137
2138         if (!cs || !name) return -1;
2139
2140         /*
2141          *      Already exists.  Can't add it.
2142          */
2143         if (cf_data_find_internal(cs, name, flag) != NULL) return -1;
2144
2145         cd = cf_data_alloc(cs, name, data, data_free);
2146         if (!cd) return -1;
2147         cd->flag = flag;
2148
2149         cf_item_add(cs, cf_datatoitem(cd));
2150
2151         return 0;
2152 }
2153
2154 /*
2155  *      Add named data to a configuration section.
2156  */
2157 int cf_data_add(CONF_SECTION *cs, const char *name,
2158                 void *data, void (*data_free)(void *))
2159 {
2160         return cf_data_add_internal(cs, name, data, data_free, 0);
2161 }
2162
2163 #if 0
2164 /*
2165  *      Copy CONF_DATA from src to dst
2166  */
2167 static void cf_section_copy_data(CONF_SECTION *s, CONF_SECTION *d)
2168 {
2169
2170         CONF_ITEM *cd, *next, **last;
2171
2172         /*
2173          *      Don't check if s->data_tree is NULL.  It's child
2174          *      sections may have data, even if this section doesn't.
2175          */
2176
2177         rad_assert(d->data_tree == NULL);
2178         d->data_tree = s->data_tree;
2179         s->data_tree = NULL;
2180
2181         /*
2182          *      Walk through src, moving CONF_ITEM_DATA
2183          *      to dst, by hand.
2184          */
2185         last = &(s->children);
2186         for (cd = s->children; cd != NULL; cd = next) {
2187                 next = cd->next;
2188
2189                 /*
2190                  *      Recursively copy data from child sections.
2191                  */
2192                 if (cd->type == CONF_ITEM_SECTION) {
2193                         CONF_SECTION *s1, *d1;
2194
2195                         s1 = cf_itemtosection(cd);
2196                         d1 = cf_section_sub_find_name2(d, s1->name1, s1->name2);
2197                         if (d1) {
2198                                 cf_section_copy_data(s1, d1);
2199                         }
2200                         last = &(cd->next);
2201                         continue;
2202                 }
2203
2204                 /*
2205                  *      Not conf data, remember last ptr.
2206                  */
2207                 if (cd->type != CONF_ITEM_DATA) {
2208                         last = &(cd->next);
2209                         continue;
2210                 }
2211
2212                 /*
2213                  *      Remove it from the src list
2214                  */
2215                 *last = cd->next;
2216                 cd->next = NULL;
2217
2218                 /*
2219                  *      Add it to the dst list
2220                  */
2221                 if (!d->children) {
2222                         rad_assert(d->tail == NULL);
2223                         d->children = cd;
2224                 } else {
2225                         rad_assert(d->tail != NULL);
2226                         d->tail->next = cd;
2227                 }
2228                 d->tail = cd;
2229         }
2230 }
2231
2232 /*
2233  *      For a CONF_DATA element, stat the filename, if necessary.
2234  */
2235 static int filename_stat(void *context, void *data)
2236 {
2237         struct stat buf;
2238         CONF_DATA *cd = data;
2239
2240         context = context;      /* -Wunused */
2241
2242         if (cd->flag != PW_TYPE_FILENAME) return 0;
2243
2244         if (stat(cd->name, &buf) < 0) return -1;
2245
2246         if (buf.st_mtime != *(time_t *) cd->data) return -1;
2247
2248         return 0;
2249 }
2250
2251
2252 /*
2253  *      Compare two CONF_SECTIONS.  The items MUST be in the same
2254  *      order.
2255  */
2256 static int cf_section_cmp(CONF_SECTION *a, CONF_SECTION *b)
2257 {
2258         CONF_ITEM *ca = a->children;
2259         CONF_ITEM *cb = b->children;
2260
2261         while (1) {
2262                 CONF_PAIR *pa, *pb;
2263
2264                 /*
2265                  *      Done.  Stop.
2266                  */
2267                 if (!ca && !cb) break;
2268
2269                 /*
2270                  *      Skip CONF_DATA.
2271                  */
2272                 if (ca && ca->type == CONF_ITEM_DATA) {
2273                         ca = ca->next;
2274                         continue;
2275                 }
2276                 if (cb && cb->type == CONF_ITEM_DATA) {
2277                         cb = cb->next;
2278                         continue;
2279                 }
2280
2281                 /*
2282                  *      One is smaller than the other.  Exit.
2283                  */
2284                 if (!ca || !cb) return 0;
2285
2286                 if (ca->type != cb->type) return 0;
2287
2288                 /*
2289                  *      Deal with subsections.
2290                  */
2291                 if (ca->type == CONF_ITEM_SECTION) {
2292                         CONF_SECTION *sa = cf_itemtosection(ca);
2293                         CONF_SECTION *sb = cf_itemtosection(cb);
2294
2295                         if (!cf_section_cmp(sa, sb)) return 0;
2296                         goto next;
2297                 }
2298
2299                 rad_assert(ca->type == CONF_ITEM_PAIR);
2300
2301                 pa = cf_itemtopair(ca);
2302                 pb = cf_itemtopair(cb);
2303
2304                 /*
2305                  *      Different attr and/or value, Exit.
2306                  */
2307                 if ((strcmp(pa->attr, pb->attr) != 0) ||
2308                     (strcmp(pa->value, pb->value) != 0)) return 0;
2309
2310
2311                 /*
2312                  *      And go to the next element.
2313                  */
2314         next:
2315                 ca = ca->next;
2316                 cb = cb->next;
2317         }
2318
2319         /*
2320          *      Walk over the CONF_DATA, stat'ing PW_TYPE_FILENAME.
2321          */
2322         if (a->data_tree &&
2323             (rbtree_walk(a->data_tree, InOrder, filename_stat, NULL) != 0)) {
2324                 return 0;
2325         }
2326
2327         /*
2328          *      They must be the same, say so.
2329          */
2330         return 1;
2331 }
2332
2333
2334 /*
2335  *      Migrate CONF_DATA from one section to another.
2336  */
2337 int cf_section_migrate(CONF_SECTION *dst, CONF_SECTION *src)
2338 {
2339         CONF_ITEM *ci;
2340         CONF_SECTION *s, *d;
2341
2342         for (ci = src->children; ci != NULL; ci = ci->next) {
2343                 if (ci->type != CONF_ITEM_SECTION)
2344                         continue;
2345
2346                 s = cf_itemtosection(ci);
2347                 d = cf_section_sub_find_name2(dst, s->name1, s->name2);
2348
2349                 if (!d) continue; /* not in new one, don't migrate it */
2350
2351                 /*
2352                  *      A section of the same name is in BOTH src & dst,
2353                  *      compare the CONF_PAIR's.  If they're all the same,
2354                  *      then copy the CONF_DATA from one to the other.
2355                  */
2356                 if (cf_section_cmp(s, d)) {
2357                         cf_section_copy_data(s, d);
2358                 }
2359         }
2360
2361         return 1;               /* rcode means anything? */
2362 }
2363 #endif
2364
2365 int cf_section_template(CONF_SECTION *cs, CONF_SECTION *template)
2366 {
2367         if (!cs || !template || cs->template || template->template) return -1;
2368
2369         cs->template = template;
2370
2371         return 0;
2372 }
2373
2374
2375 /*
2376  *      This is here to make the rest of the code easier to read.  It
2377  *      ties conffile.c to log.c, but it means we don't have to
2378  *      pollute every other function with the knowledge of the
2379  *      configuration internals.
2380  */
2381 void cf_log_err(CONF_ITEM *ci, const char *fmt, ...)
2382 {
2383         va_list ap;
2384         char buffer[256];
2385
2386         va_start(ap, fmt);
2387         vsnprintf(buffer, sizeof(buffer), fmt, ap);
2388         va_end(ap);
2389
2390         radlog(L_ERR, "%s[%d]: %s", ci->filename, ci->lineno, buffer);
2391 }
2392
2393
2394 void cf_log_info(UNUSED CONF_SECTION *cs, const char *fmt, ...)
2395 {
2396         va_list ap;
2397
2398         va_start(ap, fmt);
2399         if (debug_flag > 1 && cf_log_config) vradlog(L_DBG, fmt, ap);
2400         va_end(ap);
2401 }
2402
2403 /*
2404  *      Wrapper to simplify the code.
2405  */
2406 void cf_log_module(UNUSED CONF_SECTION *cs, const char *fmt, ...)
2407 {
2408         va_list ap;
2409         char buffer[256];
2410
2411         va_start(ap, fmt);
2412         if (debug_flag > 1 && cf_log_modules) {
2413                 vsnprintf(buffer, sizeof(buffer), fmt, ap);
2414
2415                 radlog(L_DBG, " Module: %s", buffer);
2416         }
2417         va_end(ap);
2418 }
2419
2420
2421 #if 0
2422 /*
2423  * JMG dump_config tries to dump the config structure in a readable format
2424  *
2425 */
2426
2427 static int dump_config_section(CONF_SECTION *cs, int indent)
2428 {
2429         CONF_SECTION    *scs;
2430         CONF_PAIR       *cp;
2431         CONF_ITEM       *ci;
2432
2433         /* The DEBUG macro doesn't let me
2434          *   for(i=0;i<indent;++i) debugputchar('\t');
2435          * so I had to get creative. --Pac. */
2436
2437         for (ci = cs->children; ci; ci = ci->next) {
2438                 switch (ci->type) {
2439                 case CONF_ITEM_PAIR:
2440                         cp=cf_itemtopair(ci);
2441                         DEBUG("%.*s%s = %s",
2442                                 indent, "\t\t\t\t\t\t\t\t\t\t\t",
2443                                 cp->attr, cp->value);
2444                         break;
2445
2446                 case CONF_ITEM_SECTION:
2447                         scs=cf_itemtosection(ci);
2448                         DEBUG("%.*s%s %s%s{",
2449                                 indent, "\t\t\t\t\t\t\t\t\t\t\t",
2450                                 scs->name1,
2451                                 scs->name2 ? scs->name2 : "",
2452                                 scs->name2 ?  " " : "");
2453                         dump_config_section(scs, indent+1);
2454                         DEBUG("%.*s}",
2455                                 indent, "\t\t\t\t\t\t\t\t\t\t\t");
2456                         break;
2457
2458                 default:        /* FIXME: Do more! */
2459                         break;
2460                 }
2461         }
2462
2463         return 0;
2464 }
2465
2466 int dump_config(CONF_SECTION *cs)
2467 {
2468         return dump_config_section(cs, 0);
2469 }
2470 #endif