Don't start if radius_dir is globally writable
[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/autoconf.h>
33
34 #include <stdlib.h>
35 #include <string.h>
36
37 #ifdef HAVE_NETINET_IN_H
38 #       include <netinet/in.h>
39 #endif
40
41 #ifdef HAVE_DIRENT_H
42 #include <dirent.h>
43
44 #ifdef HAVE_SYS_STAT_H
45 #include <sys/stat.h>
46 #endif
47 #endif
48
49 #include <ctype.h>
50
51 #include <freeradius-devel/radiusd.h>
52 #include <freeradius-devel/rad_assert.h>
53 #include <freeradius-devel/modules.h>
54
55 typedef enum conf_type {
56         CONF_ITEM_INVALID = 0,
57         CONF_ITEM_PAIR,
58         CONF_ITEM_SECTION,
59         CONF_ITEM_DATA
60 } CONF_ITEM_TYPE;
61
62 struct conf_item {
63         struct conf_item *next;
64         struct conf_part *parent;
65         int lineno;
66         CONF_ITEM_TYPE type;
67 };
68 struct conf_pair {
69         CONF_ITEM item;
70         char *attr;
71         char *value;
72         LRAD_TOKEN operator;
73 };
74 struct conf_part {
75         CONF_ITEM item;
76         const char *name1;
77         const char *name2;
78         struct conf_item *children;
79         struct conf_item *tail; /* for speed */
80         rbtree_t        *pair_tree; /* and a partridge.. */
81         rbtree_t        *section_tree; /* no jokes here */
82         rbtree_t        *name2_tree; /* for sections of the same name2 */
83         rbtree_t        *data_tree;
84 };
85
86
87 /*
88  *      Internal data that is associated with a configuration section,
89  *      so that we don't have to track it separately.
90  */
91 struct conf_data {
92         CONF_ITEM  item;
93         const char *name;
94         int        flag;
95         void       *data;       /* user data */
96         void       (*free)(void *); /* free user data function */
97 };
98
99
100 static int cf_data_add_internal(CONF_SECTION *cs, const char *name,
101                                 void *data, void (*data_free)(void *),
102                                 int flag);
103 static void *cf_data_find_internal(CONF_SECTION *cs, const char *name,
104                                    int flag);
105
106 /*
107  *      Isolate the scary casts in these tiny provably-safe functions
108  */
109 CONF_PAIR *cf_itemtopair(CONF_ITEM *ci)
110 {
111         if (ci == NULL)
112                 return NULL;
113         rad_assert(ci->type == CONF_ITEM_PAIR);
114         return (CONF_PAIR *)ci;
115 }
116 CONF_SECTION *cf_itemtosection(CONF_ITEM *ci)
117 {
118         if (ci == NULL)
119                 return NULL;
120         rad_assert(ci->type == CONF_ITEM_SECTION);
121         return (CONF_SECTION *)ci;
122 }
123 CONF_ITEM *cf_pairtoitem(CONF_PAIR *cp)
124 {
125         if (cp == NULL)
126                 return NULL;
127         return (CONF_ITEM *)cp;
128 }
129 CONF_ITEM *cf_sectiontoitem(CONF_SECTION *cs)
130 {
131         if (cs == NULL)
132                 return NULL;
133         return (CONF_ITEM *)cs;
134 }
135
136 static CONF_DATA *cf_itemtodata(CONF_ITEM *ci)
137 {
138         if (ci == NULL)
139                 return NULL;
140         rad_assert(ci->type == CONF_ITEM_DATA);
141         return (CONF_DATA *)ci;
142 }
143 static CONF_ITEM *cf_datatoitem(CONF_DATA *cd)
144 {
145         if (cd == NULL)
146                 return NULL;
147         return (CONF_ITEM *)cd;
148 }
149
150 /*
151  *      Create a new CONF_PAIR
152  */
153 static CONF_PAIR *cf_pair_alloc(const char *attr, const char *value,
154                                 LRAD_TOKEN operator, CONF_SECTION *parent)
155 {
156         CONF_PAIR *cp;
157
158         cp = rad_malloc(sizeof(*cp));
159         memset(cp, 0, sizeof(*cp));
160         cp->item.type = CONF_ITEM_PAIR;
161         cp->item.parent = parent;
162         cp->attr = strdup(attr);
163         cp->value = strdup(value);
164         cp->operator = operator;
165
166         return cp;
167 }
168
169 /*
170  *      Free a CONF_PAIR
171  */
172 void cf_pair_free(CONF_PAIR **cp)
173 {
174         if (!cp || !*cp) return;
175
176         if ((*cp)->attr)
177                 free((*cp)->attr);
178         if ((*cp)->value)
179                 free((*cp)->value);
180
181 #ifndef NDEBUG
182         memset(*cp, 0, sizeof(*cp));
183 #endif
184         free(*cp);
185
186         *cp = NULL;
187 }
188
189
190 static void cf_data_free(CONF_DATA **cd)
191 {
192         if (!cd || !*cd) return;
193
194         free((*cd)->name);
195         if (!(*cd)->free) {
196                 free((*cd)->data);
197         } else {
198                 ((*cd)->free)((*cd)->data);
199         }
200 #ifndef NDEBUG
201         memset(*cd, 0, sizeof(*cd));
202 #endif
203         free(*cd);
204         *cd = NULL;
205 }
206
207 /*
208  *      rbtree callback function
209  */
210 static int pair_cmp(const void *a, const void *b)
211 {
212         const CONF_PAIR *one = a;
213         const CONF_PAIR *two = b;
214
215         return strcmp(one->attr, two->attr);
216 }
217
218
219 /*
220  *      rbtree callback function
221  */
222 static int section_cmp(const void *a, const void *b)
223 {
224         const CONF_SECTION *one = a;
225         const CONF_SECTION *two = b;
226
227         return strcmp(one->name1, two->name1);
228 }
229
230
231 /*
232  *      rbtree callback function
233  */
234 static int name2_cmp(const void *a, const void *b)
235 {
236         const CONF_SECTION *one = a;
237         const CONF_SECTION *two = b;
238
239         rad_assert(strcmp(one->name1, two->name1) == 0);
240
241         if (!one->name2 && !two->name2) return 0;
242         if (!one->name2) return -1;
243         if (!two->name2) return +1;
244
245         return strcmp(one->name2, two->name2);
246 }
247
248
249 /*
250  *      rbtree callback function
251  */
252 static int data_cmp(const void *a, const void *b)
253 {
254         int rcode;
255
256         const CONF_DATA *one = a;
257         const CONF_DATA *two = b;
258
259         rcode = one->flag - two->flag;
260         if (rcode != 0) return rcode;
261
262         return strcmp(one->name, two->name);
263 }
264
265 /*
266  *      Free a CONF_SECTION
267  */
268 void cf_section_free(CONF_SECTION **cs)
269 {
270         CONF_ITEM       *ci, *next;
271
272         if (!cs || !*cs) return;
273
274         for (ci = (*cs)->children; ci; ci = next) {
275                 next = ci->next;
276
277                 switch (ci->type) {
278                 case CONF_ITEM_PAIR: {
279                                 CONF_PAIR *pair = cf_itemtopair(ci);
280                                 cf_pair_free(&pair);
281                         }
282                         break;
283
284                 case CONF_ITEM_SECTION: {
285                                 
286                                 CONF_SECTION *section = cf_itemtosection(ci);
287                                 cf_section_free(&section);
288                         }
289                         break;
290
291                 case CONF_ITEM_DATA: {
292                                 CONF_DATA *data = cf_itemtodata(ci);
293                                 cf_data_free(&data);
294                         }
295                         break;
296
297                 default:        /* should really be an error. */
298                         break;
299                 }
300         }
301
302         if ((*cs)->name1)
303                 free((*cs)->name1);
304         if ((*cs)->name2)
305                 free((*cs)->name2);
306         if ((*cs)->pair_tree)
307                 rbtree_free((*cs)->pair_tree);
308         if ((*cs)->section_tree)
309                 rbtree_free((*cs)->section_tree);
310         if ((*cs)->name2_tree)
311                 rbtree_free((*cs)->name2_tree);
312         if ((*cs)->data_tree)
313                 rbtree_free((*cs)->data_tree);
314
315         /*
316          * And free the section
317          */
318 #ifndef NDEBUG
319         memset(*cs, 0, sizeof(*cs));
320 #endif
321         free(*cs);
322
323         *cs = NULL;
324 }
325
326
327 /*
328  *      Allocate a CONF_SECTION
329  */
330 static CONF_SECTION *cf_section_alloc(const char *name1, const char *name2,
331                                       CONF_SECTION *parent)
332 {
333         CONF_SECTION    *cs;
334
335         if (!name1) return NULL;
336
337         cs = rad_malloc(sizeof(*cs));
338         memset(cs, 0, sizeof(*cs));
339         cs->item.type = CONF_ITEM_SECTION;
340         cs->item.parent = parent;
341         cs->name1 = strdup(name1);
342         if (!cs->name1) {
343                 cf_section_free(&cs);
344                 return NULL;
345         }
346         
347         if (name2 && *name2) {
348                 cs->name2 = strdup(name2);
349                 if (!cs->name2) {
350                         cf_section_free(&cs);
351                         return NULL;
352                 }
353         }
354         cs->pair_tree = rbtree_create(pair_cmp, NULL, 0);
355         if (!cs->pair_tree) {
356                 cf_section_free(&cs);
357                 return NULL;
358         }
359
360         /*
361          *      Don't create a data tree, it may not be needed.
362          */
363
364         /*
365          *      Don't create the section tree here, it may not
366          *      be needed.
367          */
368         return cs;
369 }
370
371
372 /*
373  *      Add an item to a configuration section.
374  */
375 static void cf_item_add(CONF_SECTION *cs, CONF_ITEM *ci)
376 {
377         if (!cs->children) {
378                 rad_assert(cs->tail == NULL);
379                 cs->children = ci;
380         } else {
381                 rad_assert(cs->tail != NULL);
382                 cs->tail->next = ci;
383         }
384
385         /*
386          *      Update the trees (and tail) for each item added.
387          */
388         for (/* nothing */; ci != NULL; ci = ci->next) {
389                 cs->tail = ci;
390
391                 /*
392                  *      For fast lookups, pair's and sections get
393                  *      added to rbtree's.
394                  */
395                 switch (ci->type) {
396                         case CONF_ITEM_PAIR:
397                                 rbtree_insert(cs->pair_tree, ci);
398                                 break;
399                                 
400                         case CONF_ITEM_SECTION: {
401                                 const CONF_SECTION *cs_new = cf_itemtosection(ci);
402                                 
403                                 if (!cs->section_tree) {
404                                         cs->section_tree = rbtree_create(section_cmp, NULL, 0);
405                                         /* ignore any errors */
406                                 }
407                                 
408                                 if (cs->section_tree) {
409                                         rbtree_insert(cs->section_tree, cs_new);                                }
410                                 
411                                 /*
412                                  *      Two names: find the named instance.
413                                  */
414                                 if (cs_new->name2) {
415                                         CONF_SECTION *old_cs;
416                                         
417                                         /*
418                                          *      Find the FIRST
419                                          *      CONF_SECTION having
420                                          *      the given name1, and
421                                          *      create a new tree
422                                          *      under it.
423                                          */
424                                         old_cs = rbtree_finddata(cs->section_tree, cs_new);
425                                         if (!old_cs) return; /* this is a bad error! */
426                                         
427                                         if (!old_cs->name2_tree) {
428                                                 old_cs->name2_tree = rbtree_create(name2_cmp,
429                                                                                    NULL, 0);
430                                         }
431                                         if (old_cs->name2_tree) {
432                                                 rbtree_insert(old_cs->name2_tree, cs_new);
433                                         }
434                                 } /* had a name2 */
435                                 break;
436                         } /* was a section */
437
438                         case CONF_ITEM_DATA:
439                                 if (!cs->data_tree) {
440                                         cs->data_tree = rbtree_create(data_cmp, NULL, 0);
441                                 }
442                                 if (cs->data_tree) {
443                                         rbtree_insert(cs->data_tree, ci);
444                                 }
445                                 break;
446
447                         default: /* FIXME: assert & error! */
448                                 break;
449
450                 } /* switch over conf types */
451         } /* loop over ci */
452 }
453
454 /*
455  *      Expand the variables in an input string.
456  */
457 static const char *cf_expand_variables(const char *cf, int *lineno,
458                                        const CONF_SECTION *outercs,
459                                        char *output, const char *input)
460 {
461         char *p;
462         const char *end, *ptr;
463         char name[8192];
464         const CONF_SECTION *parentcs;
465
466         /*
467          *      Find the master parent conf section.
468          *      We can't use mainconfig.config, because we're in the
469          *      process of re-building it, and it isn't set up yet...
470          */
471         for (parentcs = outercs;
472              parentcs->item.parent != NULL;
473              parentcs = parentcs->item.parent) {
474                 /* do nothing */
475         }
476
477         p = output;
478         ptr = input;
479         while (*ptr) {
480                 /*
481                  *      Ignore anything other than "${"
482                  */
483                 if ((*ptr == '$') && (ptr[1] == '{')) {
484                         int up;
485                         CONF_PAIR *cp;
486                         const CONF_SECTION *cs;
487
488                         /*
489                          *      FIXME: Add support for ${foo:-bar},
490                          *      like in xlat.c
491                          */
492
493                         /*
494                          *      Look for trailing '}', and log a
495                          *      warning for anything that doesn't match,
496                          *      and exit with a fatal error.
497                          */
498                         end = strchr(ptr, '}');
499                         if (end == NULL) {
500                                 *p = '\0';
501                                 radlog(L_INFO, "%s[%d]: Variable expansion missing }",
502                                        cf, *lineno);
503                                 return NULL;
504                         }
505
506                         ptr += 2;
507
508                         cp = NULL;
509                         up = 0;
510
511                         /*
512                          *      ${.foo} means "foo from the current section"
513                          */
514                         if (*ptr == '.') {
515                                 up = 1;
516                                 cs = outercs;
517                                 ptr++;
518
519                                 /*
520                                  *      ${..foo} means "foo from the section
521                                  *      enclosing this section" (etc.)
522                                  */
523                                 while (*ptr == '.') {
524                                         if (cs->item.parent)
525                                                 cs = cs->item.parent;
526                                         ptr++;
527                                 }
528
529                         } else {
530                                 const char *q;
531                                 /*
532                                  *      ${foo} is local, with
533                                  *      main as lower priority
534                                  */
535                                 cs = outercs;
536
537                                 /*
538                                  *      ${foo.bar.baz} is always rooted
539                                  *      from the top.
540                                  */
541                                 for (q = ptr; *q && q != end; q++) {
542                                         if (*q == '.') {
543                                                 cs = parentcs;
544                                                 up = 1;
545                                                 break;
546                                         }
547                                 }
548                         }
549
550                         while (cp == NULL) {
551                                 char *q;
552                                 /*
553                                  *      Find the next section.
554                                  */
555                                 for (q = name;
556                                      (*ptr != 0) && (*ptr != '.') &&
557                                              (ptr != end);
558                                      q++, ptr++) {
559                                         *q = *ptr;
560                                 }
561                                 *q = '\0';
562
563                                 /*
564                                  *      The character is a '.', find a
565                                  *      section (as the user has given
566                                  *      us a subsection to find)
567                                  */
568                                 if (*ptr == '.') {
569                                         CONF_SECTION *next;
570
571                                         ptr++;  /* skip the period */
572
573                                         /*
574                                          *      Find the sub-section.
575                                          */
576                                         next = cf_section_sub_find(cs, name);
577                                         if (next == NULL) {
578                                                 radlog(L_ERR, "config: No such section %s in variable %s", name, input);
579                                                 return NULL;
580                                         }
581                                         cs = next;
582
583                                 } else { /* no period, must be a conf-part */
584                                         /*
585                                          *      Find in the current referenced
586                                          *      section.
587                                          */
588                                         cp = cf_pair_find(cs, name);
589                                         if (cp == NULL) {
590                                                 /*
591                                                  *      It it was NOT ${..foo}
592                                                  *      then look in the
593                                                  *      top-level config items.
594                                                  */
595                                                 if (!up) cp = cf_pair_find(parentcs, name);
596                                         }
597                                         if (cp == NULL) {
598                                                 radlog(L_ERR, "config: No such configuration item %s in section %s when expanding string \"%s\"", name,
599                                                        cf_section_name1(cs),
600                                                        input);
601                                                 return NULL;
602                                         }
603                                 }
604                         } /* until cp is non-NULL */
605
606                         /*
607                          *  Substitute the value of the variable.
608                          */
609                         strcpy(p, cp->value);
610                         p += strlen(p);
611                         ptr = end + 1;
612
613                 } else if (memcmp(ptr, "$ENV{", 5) == 0) {
614                         char *env;
615
616                         ptr += 5;
617
618                         /*
619                          *      Look for trailing '}', and log a
620                          *      warning for anything that doesn't match,
621                          *      and exit with a fatal error.
622                          */
623                         end = strchr(ptr, '}');
624                         if (end == NULL) {
625                                 *p = '\0';
626                                 radlog(L_INFO, "%s[%d]: Environment variable expansion missing }",
627                                        cf, *lineno);
628                                 return NULL;
629                         }
630
631                         memcpy(name, ptr, end - ptr);
632                         name[end - ptr] = '\0';
633
634                         /*
635                          *      Get the environment variable.
636                          *      If none exists, then make it an empty string.
637                          */
638                         env = getenv(name);
639                         if (env == NULL) {
640                                 *name = '\0';
641                                 env = name;
642                         }
643
644                         strcpy(p, env);
645                         p += strlen(p);
646                         ptr = end + 1;
647
648                 } else {
649                         /*
650                          *      Copy it over verbatim.
651                          */
652                         *(p++) = *(ptr++);
653                 }
654         } /* loop over all of the input string. */
655
656         *p = '\0';
657
658         return output;
659 }
660
661
662 /*
663  *      Parses an item (not a CONF_ITEM) into the specified format,
664  *      with a default value.
665  *
666  *      Returns -1 on error, 0 for correctly parsed, and 1 if the
667  *      default value was used.  Note that the default value will be
668  *      used ONLY if the CONF_PAIR is NULL.
669  */
670 int cf_item_parse(CONF_SECTION *cs, const char *name,
671                   int type, void *data, const char *dflt)
672 {
673         int rcode = 0;
674         char **q;
675         const char *value;
676         lrad_ipaddr_t ipaddr;
677         const CONF_PAIR *cp;
678         char ipbuf[128];
679
680         cp = cf_pair_find(cs, name);
681         if (cp) {
682                 value = cp->value;
683
684         } else if (!dflt) {
685                 return 1;       /* nothing to parse, return default value */
686
687         } else {
688                 rcode = 1;
689                 value = dflt;
690         }
691
692         switch (type) {
693         case PW_TYPE_BOOLEAN:
694                 /*
695                  *      Allow yes/no and on/off
696                  */
697                 if ((strcasecmp(value, "yes") == 0) ||
698                     (strcasecmp(value, "on") == 0)) {
699                         *(int *)data = 1;
700                 } else if ((strcasecmp(value, "no") == 0) ||
701                            (strcasecmp(value, "off") == 0)) {
702                         *(int *)data = 0;
703                 } else {
704                         *(int *)data = 0;
705                         radlog(L_ERR, "Bad value \"%s\" for boolean variable %s", value, name);
706                         return -1;
707                 }
708                 DEBUG2(" %s: %s = %s", cs->name1, name, value);
709                 break;
710                 
711         case PW_TYPE_INTEGER:
712                 *(int *)data = strtol(value, 0, 0);
713                 DEBUG2(" %s: %s = %d",
714                        cs->name1, name,
715                        *(int *)data);
716                 break;
717                 
718         case PW_TYPE_STRING_PTR:
719                 q = (char **) data;
720                 if (*q != NULL) {
721                         free(*q);
722                 }
723                 
724                 /*
725                  *      Expand variables which haven't already been
726                  *      expanded automagically when the configuration
727                  *      file was read.
728                  */
729                 if (value == dflt) {
730                         char buffer[8192];
731
732                         int lineno = cs->item.lineno;
733
734                         /*
735                          *      FIXME: sizeof(buffer)?
736                          */
737                         value = cf_expand_variables("?",
738                                                     &lineno,
739                                                     cs, buffer, value);
740                         if (!value) return -1;
741                 }
742                 
743                 DEBUG2(" %s: %s = \"%s\"",
744                        cs->name1, name,
745                        value ? value : "(null)");
746                 *q = value ? strdup(value) : NULL;
747                 break;
748                 
749                 /*
750                  *      This is the same as PW_TYPE_STRING_PTR,
751                  *      except that we also "stat" the file, and
752                  *      cache the result.
753                  */
754         case PW_TYPE_FILENAME:
755                 q = (char **) data;
756                 if (*q != NULL) {
757                         free(*q);
758                 }
759                 
760                 /*
761                  *      Expand variables which haven't already been
762                  *      expanded automagically when the configuration
763                  *      file was read.
764                  */
765                 if (value == dflt) {
766                         char buffer[8192];
767
768                         int lineno = cs->item.lineno;
769
770                         /*
771                          *      FIXME: sizeof(buffer)?
772                          */
773                         value = cf_expand_variables("?",
774                                                     &lineno,
775                                                     cs, buffer, value);
776                         if (!value) return -1;
777                 }
778                 
779                 DEBUG2(" %s: %s = \"%s\"",
780                        cs->name1, name,
781                        value ? value : "(null)");
782                 *q = value ? strdup(value) : NULL;
783
784                 /*
785                  *      And now we "stat" the file.
786                  */
787                 if (*q) {
788                         struct stat buf;
789
790                         if (stat(*q, &buf) == 0) {
791                                 time_t *mtime;
792
793                                 mtime = rad_malloc(sizeof(*mtime));
794                                 *mtime = buf.st_mtime;
795                                 /* FIXME: error? */
796                                 cf_data_add_internal(cs, *q, mtime, free,
797                                                      PW_TYPE_FILENAME);
798                         }
799                 }
800                 break;
801
802         case PW_TYPE_IPADDR:
803                 /*
804                  *      Allow '*' as any address
805                  */
806                 if (strcmp(value, "*") == 0) {
807                         *(uint32_t *) data = htonl(INADDR_ANY);
808                         DEBUG2(" %s: %s = *", cs->name1, name);
809                         break;
810                 }
811                 if (ip_hton(value, AF_INET, &ipaddr) < 0) {
812                         radlog(L_ERR, "Can't find IP address for host %s", value);
813                         return -1;
814                 }
815                 DEBUG2(" %s: %s = %s IP address [%s]",
816                        cs->name1, name, value,
817                        ip_ntoh(&ipaddr, ipbuf, sizeof(ipbuf)));
818                 *(uint32_t *) data = ipaddr.ipaddr.ip4addr.s_addr;
819                 break;
820                 
821         case PW_TYPE_IPV6ADDR:
822                 if (ip_hton(value, AF_INET6, &ipaddr) < 0) {
823                         radlog(L_ERR, "Can't find IPv6 address for host %s", value);
824                         return -1;
825                 }
826                 DEBUG2(" %s: %s = %s IPv6 address [%s]",
827                        cs->name1, name, value,
828                        ip_ntoh(&ipaddr, ipbuf, sizeof(ipbuf)));
829                 memcpy(data, &ipaddr.ipaddr.ip6addr,
830                        sizeof(ipaddr.ipaddr.ip6addr));
831                 break;
832                 
833         default:
834                 radlog(L_ERR, "type %d not supported yet", type);
835                 return -1;
836                 break;
837         } /* switch over variable type */
838         
839         return rcode;
840 }
841
842 /*
843  *      Parse a configuration section into user-supplied variables.
844  */
845 int cf_section_parse(const CONF_SECTION *cs, void *base,
846                      const CONF_PARSER *variables)
847 {
848         int i;
849         void *data;
850
851         /*
852          *      Handle the known configuration parameters.
853          */
854         for (i = 0; variables[i].name != NULL; i++) {
855                 /*
856                  *      Handle subsections specially
857                  */
858                 if (variables[i].type == PW_TYPE_SUBSECTION) {
859                         const CONF_SECTION *subcs;
860                         subcs = cf_section_sub_find(cs, variables[i].name);
861                         
862                         /*
863                          *      If the configuration section is NOT there,
864                          *      then ignore it.
865                          *
866                          *      FIXME! This is probably wrong... we should
867                          *      probably set the items to their default values.
868                          */
869                         if (!subcs) continue;
870
871                         if (!variables[i].dflt) {
872                                 DEBUG2("Internal sanity check 1 failed in cf_section_parse");
873                                 return -1;
874                         }
875                         
876                         if (cf_section_parse(subcs, base,
877                                              (const CONF_PARSER *) variables[i].dflt) < 0) {
878                                 return -1;
879                         }
880                         continue;
881                 } /* else it's a CONF_PAIR */
882                 
883                 if (variables[i].data) {
884                         data = variables[i].data; /* prefer this. */
885                 } else if (base) {
886                         data = ((char *)base) + variables[i].offset;
887                 } else {
888                         DEBUG2("Internal sanity check 2 failed in cf_section_parse");
889                         return -1;
890                 }
891
892                 /*
893                  *      Parse the pair we found, or a default value.
894                  */
895                 if (cf_item_parse(cs, variables[i].name, variables[i].type,
896                                   data, variables[i].dflt) < 0) {
897                         return -1;
898                 }
899         } /* for all variables in the configuration section */
900
901         return 0;
902 }
903
904
905 /*
906  *      Free strings we've parsed into data structures.
907  */
908 void cf_section_parse_free_strings(void *base, const CONF_PARSER *variables)
909 {
910         int i;
911
912         if (!variables) return;
913         
914         /*
915          *      Free up dynamically allocated string pointers.
916          */
917         for (i = 0; variables[i].name != NULL; i++) {
918                 char **p;
919
920                 if ((variables[i].type != PW_TYPE_STRING_PTR) &&
921                     (variables[i].type != PW_TYPE_FILENAME)) {
922                         continue;
923                 }
924                 
925                 /*
926                  *      Prefer the data, if it's there.
927                  *      Else use the base + offset.
928                  */
929                 if (variables[i].data) {
930                         p = (char **) &(variables[i].data);
931                 } else {
932                         p = (char **) (((char *)base) + variables[i].offset);
933                 }
934                 free(*p);
935                 *p = NULL;
936         }
937 }
938
939
940 /*
941  *      Read a part of the config file.
942  */
943 static int cf_section_read(const char *file, int *lineno, FILE *fp,
944                            CONF_SECTION *current)
945
946 {
947         CONF_SECTION *this, *css;
948         CONF_PAIR *cpn;
949         char *ptr;
950         const char *value;
951         char buf[8192];
952         char buf1[8192];
953         char buf2[8192];
954         char buf3[8192];
955         int t1, t2, t3;
956         char *cbuf = buf;
957         int len;
958
959         this = current;         /* add items here */
960
961         /*
962          *      Read, checking for line continuations ('\\' at EOL)
963          */
964         for (;;) {
965                 int eof;
966
967                 /*
968                  *      Get data, and remember if we are at EOF.
969                  */
970                 eof = (fgets(cbuf, sizeof(buf) - (cbuf - buf), fp) == NULL);
971                 (*lineno)++;
972
973                 len = strlen(cbuf);
974
975                 /*
976                  *      We've filled the buffer, and there isn't
977                  *      a CR in it.  Die!
978                  */
979                 if ((len == (sizeof(buf) - 1)) &&
980                     (cbuf[len - 1] != '\n')) {
981                         radlog(L_ERR, "%s[%d]: Line too long",
982                                file, *lineno);
983                         return -1;
984                 }
985
986                 /*
987                  *  Check for continuations.
988                  */
989                 if (cbuf[len - 1] == '\n') len--;
990
991                 /*
992                  *      Last character is '\\'.  Over-write it,
993                  *      and read another line.
994                  */
995                 if ((len > 0) && (cbuf[len - 1] == '\\')) {
996                         cbuf[len - 1] = '\0';
997                         cbuf += len - 1;
998                         continue;
999                 }
1000
1001                 /*
1002                  *  We're at EOF, and haven't read anything.  Stop.
1003                  */
1004                 if (eof && (cbuf == buf)) {
1005                         break;
1006                 }
1007
1008                 ptr = cbuf = buf;
1009                 t1 = gettoken(&ptr, buf1, sizeof(buf1));
1010
1011                if ((*buf1 == '#') || (*buf1 == '\0')) {
1012                        continue;
1013                }
1014
1015                 /*
1016                  *      The caller eats "name1 name2 {", and calls us
1017                  *      for the data inside of the section.  So if we
1018                  *      receive a closing brace, then it must mean the
1019                  *      end of the section.
1020                  */
1021                if (t1 == T_RCBRACE) {
1022                        if (this == current) {
1023                                radlog(L_ERR, "%s[%d]: Too many closing braces",
1024                                       file, *lineno);
1025                                return -1;
1026                                
1027                        }
1028                        this = this->item.parent;
1029                        continue;
1030                 }
1031
1032                 /*
1033                  *      Allow for $INCLUDE files
1034                  *
1035                  *      This *SHOULD* work for any level include.
1036                  *      I really really really hate this file.  -cparker
1037                  */
1038                 if (strcasecmp(buf1, "$INCLUDE") == 0) {
1039                         t2 = getword(&ptr, buf2, sizeof(buf2));
1040
1041                         value = cf_expand_variables(file, lineno, this, buf, buf2);
1042                         if (!value) return -1;
1043
1044 #ifdef HAVE_DIRENT_H
1045                         /*
1046                          *      $INCLUDE foo/
1047                          *
1048                          *      Include ALL non-"dot" files in the directory.
1049                          *      careful!
1050                          */
1051                         if (value[strlen(value) - 1] == '/') {
1052                                 DIR             *dir;
1053                                 struct dirent   *dp;
1054                                 struct stat stat_buf;
1055
1056                                 DEBUG2( "Config:   including files in directory: %s", value );
1057                                 dir = opendir(value);
1058                                 if (!dir) {
1059                                         radlog(L_ERR, "%s[%d]: Error reading directory %s: %s",
1060                                                file, *lineno, value,
1061                                                strerror(errno));
1062                                         return -1;
1063                                 }
1064
1065                                 /*
1066                                  *      Read the directory, ignoring "." files.
1067                                  */
1068                                 while ((dp = readdir(dir)) != NULL) {
1069                                         const char *p;
1070
1071                                         if (dp->d_name[0] == '.') continue;
1072
1073                                         /*
1074                                          *      Check for valid characters
1075                                          */
1076                                         for (p = dp->d_name; *p != '\0'; p++) {
1077                                                 if (isalpha((int)*p) ||
1078                                                     isdigit((int)*p) ||
1079                                                     (*p == '_') ||
1080                                                     (*p == '.')) continue;
1081                                                 break;
1082                                         }
1083                                         if (*p != '\0') continue;
1084
1085                                         snprintf(buf2, sizeof(buf2), "%s%s",
1086                                                  value, dp->d_name);
1087                                         if ((stat(buf2, &stat_buf) != 0) ||
1088                                             S_ISDIR(stat_buf.st_mode)) continue;
1089                                         /*
1090                                          *      Read the file into the current
1091                                          *      configuration sectoin.
1092                                          */
1093                                         if (cf_file_include(buf2, this) < 0) {
1094                                                 closedir(dir);
1095                                                 return -1;
1096                                         }
1097                                 }
1098                                 closedir(dir);
1099                         }  else
1100 #endif
1101                         { /* it was a normal file */
1102                                 if (cf_file_include(value, this) < 0) {
1103                                         return -1;
1104                                 }
1105                         }
1106                         continue;
1107                 } /* we were in an include */
1108
1109                 /*
1110                  *      No '=': must be a section or sub-section.
1111                  */
1112                 if (strchr(ptr, '=') == NULL) {
1113                         t2 = gettoken(&ptr, buf2, sizeof(buf2));
1114                         t3 = gettoken(&ptr, buf3, sizeof(buf3));
1115                 } else {
1116                         t2 = gettoken(&ptr, buf2, sizeof(buf2));
1117                         t3 = getword(&ptr, buf3, sizeof(buf3));
1118                 }
1119
1120                 /*
1121                  * Perhaps a subsection.
1122                  */
1123                 if (t2 == T_LCBRACE || t3 == T_LCBRACE) {
1124                         css = cf_section_alloc(buf1,
1125                                                t2 == T_LCBRACE ? NULL : buf2,
1126                                                this);
1127                         if (!css) {
1128                                 radlog(L_ERR, "%s[%d]: Failed allocating memory for section",
1129                                                 file, *lineno);
1130                         }
1131                         cf_item_add(this, cf_sectiontoitem(css));
1132                         css->item.lineno = *lineno;
1133
1134                         /*
1135                          *      The current section is now the child section.
1136                          */
1137                         this = css;
1138                         continue;
1139                 }
1140
1141                 /*
1142                  *      Ignore semi-colons.
1143                  */
1144                 if (*buf2 == ';')
1145                         *buf2 = '\0';
1146
1147                 /*
1148                  *      Must be a normal attr = value line.
1149                  */
1150                 if (buf1[0] != 0 && buf2[0] == 0 && buf3[0] == 0) {
1151                         t2 = T_OP_EQ;
1152                 } else if (buf1[0] == 0 || buf2[0] == 0 ||
1153                            (t2 < T_EQSTART || t2 > T_EQEND)) {
1154                         radlog(L_ERR, "%s[%d]: Line is not in 'attribute = value' format",
1155                                         file, *lineno);
1156                         return -1;
1157                 }
1158
1159                 /*
1160                  *      Ensure that the user can't add CONF_PAIRs
1161                  *      with 'internal' names;
1162                  */
1163                 if (buf1[0] == '_') {
1164                         radlog(L_ERR, "%s[%d]: Illegal configuration pair name \"%s\"",
1165                                         file, *lineno, buf1);
1166                         return -1;
1167                 }
1168
1169                 /*
1170                  *      Handle variable substitution via ${foo}
1171                  */
1172                 value = cf_expand_variables(file, lineno, this, buf, buf3);
1173                 if (!value) return -1;
1174
1175
1176                 /*
1177                  *      Add this CONF_PAIR to our CONF_SECTION
1178                  */
1179                 cpn = cf_pair_alloc(buf1, value, t2, this);
1180                 cpn->item.lineno = *lineno;
1181                 cf_item_add(this, cf_pairtoitem(cpn));
1182         }
1183
1184         /*
1185          *      See if EOF was unexpected ..
1186          */
1187         if (feof(fp) && (this != current)) {
1188                 radlog(L_ERR, "%s[%d]: EOF reached without closing brace for section %s starting at line %d",
1189                        file, *lineno,
1190                        cf_section_name1(this), cf_section_lineno(this));
1191                 return -1;
1192         }
1193
1194         return 0;
1195 }
1196
1197 /*
1198  *      Include one config file in another.
1199  */
1200 int cf_file_include(const char *file, CONF_SECTION *cs)
1201 {
1202         FILE            *fp;
1203         int             lineno = 0;
1204         struct stat     statbuf;
1205         time_t          *mtime;
1206
1207         DEBUG2( "Config:   including file: %s", file);
1208
1209         if (stat(file, &statbuf) == 0) {
1210                 if ((statbuf.st_mode & S_IWOTH) != 0) {
1211                         radlog(L_ERR|L_CONS, "Configuration file %s is globally writable.  Refusing to start due to insecure configuration.",
1212                                file);
1213                         return -1;
1214                 }
1215
1216                 if (0 && (statbuf.st_mode & S_IROTH) != 0) {
1217                         radlog(L_ERR|L_CONS, "Configuration file %s is globally readable.  Refusing to start due to insecure configuration.",
1218                                file);
1219                         return -1;
1220                 }
1221         }
1222
1223         fp = fopen(file, "r");
1224         if (!fp) {
1225                 radlog(L_ERR|L_CONS, "Unable to open file \"%s\": %s",
1226                        file, strerror(errno));
1227                 return -1;
1228         }
1229
1230         /*
1231          *      Read the section.  It's OK to have EOF without a
1232          *      matching close brace.
1233          */
1234         if (cf_section_read(file, &lineno, fp, cs) < 0) {
1235                 fclose(fp);
1236                 return -1;
1237         }
1238
1239         /*
1240          *      Add the filename to the section
1241          */
1242         mtime = rad_malloc(sizeof(*mtime));
1243         *mtime = statbuf.st_mtime;
1244         /* FIXME: error? */
1245         cf_data_add_internal(cs, file, mtime, free,
1246                              PW_TYPE_FILENAME);
1247
1248         fclose(fp);
1249         return 0;
1250 }
1251
1252 /*
1253  *      Bootstrap a config file.
1254  */
1255 CONF_SECTION *cf_file_read(const char *file)
1256 {
1257         CONF_SECTION *cs;
1258
1259         cs = cf_section_alloc("main", NULL, NULL);
1260         if (!cs) return NULL;
1261
1262         if (cf_file_include(file, cs) < 0) {
1263                 cf_section_free(&cs);
1264                 return NULL;
1265         }
1266
1267         return cs;
1268 }
1269
1270 /*
1271  * Return a CONF_PAIR within a CONF_SECTION.
1272  */
1273 CONF_PAIR *cf_pair_find(const CONF_SECTION *cs, const char *name)
1274 {
1275         CONF_ITEM       *ci;
1276
1277         if (!cs) cs = mainconfig.config;
1278
1279         /*
1280          *      Find the name in the tree, for speed.
1281          */
1282         if (name) {
1283                 CONF_PAIR mycp;
1284
1285                 mycp.attr = name;
1286                 return rbtree_finddata(cs->pair_tree, &mycp);
1287         }
1288
1289         /*
1290          *      Else find the first one
1291          */
1292         for (ci = cs->children; ci; ci = ci->next) {
1293                 if (ci->type == CONF_ITEM_PAIR)
1294                         return cf_itemtopair(ci);
1295         }
1296         
1297         return NULL;
1298 }
1299
1300 /*
1301  * Return the attr of a CONF_PAIR
1302  */
1303
1304 char *cf_pair_attr(CONF_PAIR *pair)
1305 {
1306         return (pair ? pair->attr : NULL);
1307 }
1308
1309 /*
1310  * Return the value of a CONF_PAIR
1311  */
1312
1313 char *cf_pair_value(CONF_PAIR *pair)
1314 {
1315         return (pair ? pair->value : NULL);
1316 }
1317
1318 /*
1319  * Return the first label of a CONF_SECTION
1320  */
1321
1322 const char *cf_section_name1(const CONF_SECTION *cs)
1323 {
1324         return (cs ? cs->name1 : NULL);
1325 }
1326
1327 /*
1328  * Return the second label of a CONF_SECTION
1329  */
1330
1331 const char *cf_section_name2(const CONF_SECTION *cs)
1332 {
1333         return (cs ? cs->name2 : NULL);
1334 }
1335
1336 /*
1337  * Find a value in a CONF_SECTION
1338  */
1339 char *cf_section_value_find(const CONF_SECTION *cs, const char *attr)
1340 {
1341         CONF_PAIR       *cp;
1342
1343         cp = cf_pair_find(cs, attr);
1344
1345         return (cp ? cp->value : NULL);
1346 }
1347
1348 /*
1349  * Return the next pair after a CONF_PAIR
1350  * with a certain name (char *attr) If the requested
1351  * attr is NULL, any attr matches.
1352  */
1353
1354 CONF_PAIR *cf_pair_find_next(const CONF_SECTION *cs,
1355                              const CONF_PAIR *pair, const char *attr)
1356 {
1357         CONF_ITEM       *ci;
1358
1359         /*
1360          * If pair is NULL this must be a first time run
1361          * Find the pair with correct name
1362          */
1363
1364         if (pair == NULL){
1365                 return cf_pair_find(cs, attr);
1366         }
1367
1368         ci = cf_pairtoitem(pair)->next;
1369
1370         for (; ci; ci = ci->next) {
1371                 if (ci->type != CONF_ITEM_PAIR)
1372                         continue;
1373                 if (attr == NULL || strcmp(cf_itemtopair(ci)->attr, attr) == 0)
1374                         break;
1375         }
1376
1377         return cf_itemtopair(ci);
1378 }
1379
1380 /*
1381  * Find a CONF_SECTION, or return the root if name is NULL
1382  */
1383
1384 CONF_SECTION *cf_section_find(const char *name)
1385 {
1386         if (name)
1387                 return cf_section_sub_find(mainconfig.config, name);
1388         else
1389                 return mainconfig.config;
1390 }
1391
1392 /*
1393  * Find a sub-section in a section
1394  */
1395
1396 CONF_SECTION *cf_section_sub_find(const CONF_SECTION *cs, const char *name)
1397 {
1398         CONF_ITEM *ci;
1399
1400         /*
1401          *      Do the fast lookup if possible.
1402          */
1403         if (name && cs->section_tree) {
1404                 CONF_SECTION mycs;
1405
1406                 mycs.name1 = name;
1407                 mycs.name2 = NULL;
1408                 return rbtree_finddata(cs->section_tree, &mycs);
1409         }
1410
1411         for (ci = cs->children; ci; ci = ci->next) {
1412                 if (ci->type != CONF_ITEM_SECTION)
1413                         continue;
1414                 if (strcmp(cf_itemtosection(ci)->name1, name) == 0)
1415                         break;
1416         }
1417
1418         return cf_itemtosection(ci);
1419
1420 }
1421
1422
1423 /*
1424  *      Find a CONF_SECTION with both names.
1425  */
1426 CONF_SECTION *cf_section_sub_find_name2(const CONF_SECTION *cs,
1427                                         const char *name1, const char *name2)
1428 {
1429         CONF_ITEM    *ci;
1430
1431         if (!name2) return cf_section_sub_find(cs, name1);
1432
1433         if (!cs) cs = mainconfig.config;
1434
1435         if (name1 && (cs->section_tree)) {
1436                 CONF_SECTION mycs, *master_cs;
1437                 
1438                 mycs.name1 = name1;
1439                 mycs.name2 = name2;
1440                 
1441                 master_cs = rbtree_finddata(cs->section_tree, &mycs);
1442                 if (master_cs) {
1443                         return rbtree_finddata(master_cs->name2_tree, &mycs);
1444                 }
1445         }
1446
1447         /*
1448          *      Else do it the old-fashioned way.
1449          */
1450         for (ci = cs->children; ci; ci = ci->next) {
1451                 CONF_SECTION *subcs;
1452
1453                 if (ci->type != CONF_ITEM_SECTION)
1454                         continue;
1455
1456                 subcs = cf_itemtosection(ci);
1457                 if (!name1) {
1458                         if (!subcs->name2) {
1459                                 if (strcmp(subcs->name1, name2) == 0) break;
1460                         } else {
1461                                 if (strcmp(subcs->name2, name2) == 0) break;
1462                         }
1463                         continue; /* don't do the string comparisons below */
1464                 }
1465
1466                 if ((strcmp(subcs->name1, name1) == 0) &&
1467                     (subcs->name2 != NULL) &&
1468                     (strcmp(subcs->name2, name2) == 0))
1469                         break;
1470         }
1471
1472         return cf_itemtosection(ci);
1473 }
1474
1475 /*
1476  * Return the next subsection after a CONF_SECTION
1477  * with a certain name1 (char *name1). If the requested
1478  * name1 is NULL, any name1 matches.
1479  */
1480
1481 CONF_SECTION *cf_subsection_find_next(CONF_SECTION *section,
1482                                       CONF_SECTION *subsection,
1483                                       const char *name1)
1484 {
1485         CONF_ITEM       *ci;
1486
1487         /*
1488          * If subsection is NULL this must be a first time run
1489          * Find the subsection with correct name
1490          */
1491
1492         if (subsection == NULL){
1493                 ci = section->children;
1494         } else {
1495                 ci = cf_sectiontoitem(subsection)->next;
1496         }
1497
1498         for (; ci; ci = ci->next) {
1499                 if (ci->type != CONF_ITEM_SECTION)
1500                         continue;
1501                 if ((name1 == NULL) ||
1502                     (strcmp(cf_itemtosection(ci)->name1, name1) == 0))
1503                         break;
1504         }
1505
1506         return cf_itemtosection(ci);
1507 }
1508
1509 /*
1510  * Return the next item after a CONF_ITEM.
1511  */
1512
1513 CONF_ITEM *cf_item_find_next(CONF_SECTION *section, CONF_ITEM *item)
1514 {
1515         /*
1516          * If item is NULL this must be a first time run
1517          * Return the first item
1518          */
1519
1520         if (item == NULL) {
1521                 return section->children;
1522         } else {
1523                 return item->next;
1524         }
1525 }
1526
1527 int cf_section_lineno(CONF_SECTION *section)
1528 {
1529         return cf_sectiontoitem(section)->lineno;
1530 }
1531
1532 int cf_pair_lineno(CONF_PAIR *pair)
1533 {
1534         return cf_pairtoitem(pair)->lineno;
1535 }
1536
1537 int cf_item_is_section(CONF_ITEM *item)
1538 {
1539         return item->type == CONF_ITEM_SECTION;
1540 }
1541 int cf_item_is_pair(CONF_ITEM *item)
1542 {
1543         return item->type == CONF_ITEM_PAIR;
1544 }
1545
1546
1547 static CONF_DATA *cf_data_alloc(CONF_SECTION *parent, const char *name,
1548                                 void *data, void (*data_free)(void *))
1549 {
1550         CONF_DATA *cd;
1551
1552         cd = rad_malloc(sizeof(*cd));
1553         memset(cd, 0, sizeof(*cd));
1554
1555         cd->item.type = CONF_ITEM_DATA;
1556         cd->item.parent = parent;
1557         cd->name = strdup(name);
1558         cd->data = data;
1559         cd->free = data_free;
1560
1561         return cd;
1562 }
1563
1564
1565 static void *cf_data_find_internal(CONF_SECTION *cs, const char *name,
1566                                    int flag)
1567 {
1568         if (!cs || !name) return NULL;
1569         
1570         /*
1571          *      Find the name in the tree, for speed.
1572          */
1573         if (cs->data_tree) {
1574                 CONF_DATA mycd, *cd;
1575
1576                 mycd.name = name;
1577                 mycd.flag = flag;
1578                 cd = rbtree_finddata(cs->data_tree, &mycd);
1579                 if (cd) return cd->data;
1580         }
1581
1582         return NULL;
1583 }
1584
1585 /*
1586  *      Find data from a particular section.
1587  */
1588 void *cf_data_find(CONF_SECTION *cs, const char *name)
1589 {
1590         return cf_data_find_internal(cs, name, 0);
1591 }
1592
1593
1594 /*
1595  *      Add named data to a configuration section.
1596  */
1597 static int cf_data_add_internal(CONF_SECTION *cs, const char *name,
1598                                 void *data, void (*data_free)(void *),
1599                                 int flag)
1600 {
1601         CONF_DATA *cd;
1602
1603         if (!cs || !name) return -1;
1604
1605         /*
1606          *      Already exists.  Can't add it.
1607          */
1608         if (cf_data_find_internal(cs, name, flag) != NULL) return -1;
1609
1610         cd = cf_data_alloc(cs, name, data, data_free);
1611         if (!cd) return -1;
1612         cd->flag = flag;
1613
1614         cf_item_add(cs, cf_datatoitem(cd));
1615
1616         return 0;
1617 }
1618
1619 /*
1620  *      Add named data to a configuration section.
1621  */
1622 int cf_data_add(CONF_SECTION *cs, const char *name,
1623                 void *data, void (*data_free)(void *))
1624 {
1625         return cf_data_add_internal(cs, name, data, data_free, 0);
1626 }
1627
1628
1629 /*
1630  *      Copy CONF_DATA from src to dst
1631  */
1632 static void cf_section_copy_data(CONF_SECTION *s, CONF_SECTION *d)
1633 {
1634         
1635         CONF_ITEM *cd, *next, **last;
1636
1637         /*
1638          *      Don't check if s->data_tree is NULL.  It's child
1639          *      sections may have data, even if this section doesn't.
1640          */
1641
1642         rad_assert(d->data_tree == NULL);
1643         d->data_tree = s->data_tree;
1644         s->data_tree = NULL;
1645         
1646         /*
1647          *      Walk through src, moving CONF_ITEM_DATA
1648          *      to dst, by hand.
1649          */
1650         last = &(s->children);
1651         for (cd = s->children; cd != NULL; cd = next) {
1652                 next = cd->next;
1653                 
1654                 /*
1655                  *      Recursively copy data from child sections.
1656                  */
1657                 if (cd->type == CONF_ITEM_SECTION) {
1658                         CONF_SECTION *s1, *d1;
1659                         
1660                         s1 = cf_itemtosection(cd);
1661                         d1 = cf_section_sub_find_name2(d, s1->name1, s1->name2);
1662                         if (d1) {
1663                                 cf_section_copy_data(s1, d1);
1664                         }
1665                         last = &(cd->next);
1666                         continue;
1667                 }
1668
1669                 /*
1670                  *      Not conf data, remember last ptr.
1671                  */
1672                 if (cd->type != CONF_ITEM_DATA) {
1673                         last = &(cd->next);
1674                         continue;
1675                 }
1676                 
1677                 /*
1678                  *      Remove it from the src list
1679                  */
1680                 *last = cd->next;
1681                 cd->next = NULL;
1682                 
1683                 /*
1684                  *      Add it to the dst list
1685                  */
1686                 if (!d->children) {
1687                         rad_assert(d->tail == NULL);
1688                         d->children = cd;
1689                 } else {
1690                         rad_assert(d->tail != NULL);
1691                         d->tail->next = cd;
1692                 }
1693                 d->tail = cd;
1694         }
1695 }
1696
1697 /*
1698  *      For a CONF_DATA element, stat the filename, if necessary.
1699  */
1700 static int filename_stat(void *context, void *data)
1701 {
1702         struct stat buf;
1703         CONF_DATA *cd = data;
1704
1705         context = context;      /* -Wunused */
1706
1707         if (cd->flag != PW_TYPE_FILENAME) return 0;
1708
1709         if (stat(cd->name, &buf) < 0) return -1;
1710
1711         if (buf.st_mtime != *(time_t *) cd->data) return -1;
1712
1713         return 0;
1714 }
1715
1716
1717 /*
1718  *      Compare two CONF_SECTIONS.  The items MUST be in the same
1719  *      order.
1720  */
1721 static int cf_section_cmp(CONF_SECTION *a, CONF_SECTION *b)
1722 {
1723         CONF_ITEM *ca = a->children;
1724         CONF_ITEM *cb = b->children;
1725
1726         while (1) {
1727                 CONF_PAIR *pa, *pb;
1728
1729                 /*
1730                  *      Done.  Stop.
1731                  */
1732                 if (!ca && !cb) break;
1733
1734                 /*
1735                  *      Skip CONF_DATA.
1736                  */
1737                 if (ca && ca->type == CONF_ITEM_DATA) {
1738                         ca = ca->next;
1739                         continue;
1740                 }
1741                 if (cb && cb->type == CONF_ITEM_DATA) {
1742                         cb = cb->next;
1743                         continue;
1744                 }
1745
1746                 /*
1747                  *      One is smaller than the other.  Exit.
1748                  */
1749                 if (!ca || !cb) return 0;
1750
1751                 if (ca->type != cb->type) return 0;
1752
1753                 /*
1754                  *      Deal with subsections.
1755                  */
1756                 if (ca->type == CONF_ITEM_SECTION) {
1757                         CONF_SECTION *sa = cf_itemtosection(ca);
1758                         CONF_SECTION *sb = cf_itemtosection(cb);
1759
1760                         if (!cf_section_cmp(sa, sb)) return 0;
1761                         goto next;
1762                 }
1763
1764                 rad_assert(ca->type == CONF_ITEM_PAIR);
1765
1766                 pa = cf_itemtopair(ca);
1767                 pb = cf_itemtopair(cb);
1768
1769                 /*
1770                  *      Different attr and/or value, Exit.
1771                  */
1772                 if ((strcmp(pa->attr, pb->attr) != 0) ||
1773                     (strcmp(pa->value, pb->value) != 0)) return 0;
1774                 
1775
1776                 /*
1777                  *      And go to the next element.
1778                  */
1779         next:
1780                 ca = ca->next;
1781                 cb = cb->next;
1782         }
1783
1784         /*
1785          *      Walk over the CONF_DATA, stat'ing PW_TYPE_FILENAME.
1786          */
1787         if (a->data_tree &&
1788             (rbtree_walk(a->data_tree, InOrder, filename_stat, NULL) != 0)) {
1789                 return 0;
1790         }
1791
1792         /*
1793          *      They must be the same, say so.
1794          */
1795         return 1;
1796 }
1797
1798
1799
1800
1801 /*
1802  *      Migrate CONF_DATA from one section to another.
1803  */
1804 int cf_section_migrate(CONF_SECTION *dst, CONF_SECTION *src)
1805 {
1806         CONF_ITEM *ci;
1807         CONF_SECTION *s, *d;
1808
1809         for (ci = src->children; ci != NULL; ci = ci->next) {
1810                 if (ci->type != CONF_ITEM_SECTION)
1811                         continue;
1812
1813                 s = cf_itemtosection(ci);
1814                 d = cf_section_sub_find_name2(dst, s->name1, s->name2);
1815
1816                 if (!d) continue; /* not in new one, don't migrate it */
1817
1818                 /*
1819                  *      A section of the same name is in BOTH src & dst,
1820                  *      compare the CONF_PAIR's.  If they're all the same,
1821                  *      then copy the CONF_DATA from one to the other.
1822                  */
1823                 if (cf_section_cmp(s, d)) {
1824                         cf_section_copy_data(s, d);
1825                 }
1826         }
1827
1828         return 1;               /* rcode means anything? */
1829 }
1830
1831
1832 #if 0
1833 /*
1834  * JMG dump_config tries to dump the config structure in a readable format
1835  *
1836 */
1837
1838 static int dump_config_section(CONF_SECTION *cs, int indent)
1839 {
1840         CONF_SECTION    *scs;
1841         CONF_PAIR       *cp;
1842         CONF_ITEM       *ci;
1843
1844         /* The DEBUG macro doesn't let me
1845          *   for(i=0;i<indent;++i) debugputchar('\t');
1846          * so I had to get creative. --Pac. */
1847
1848         for (ci = cs->children; ci; ci = ci->next) {
1849                 switch (ci->type) {
1850                 case CONF_ITEM_PAIR:
1851                         cp=cf_itemtopair(ci);
1852                         DEBUG("%.*s%s = %s",
1853                                 indent, "\t\t\t\t\t\t\t\t\t\t\t",
1854                                 cp->attr, cp->value);
1855                         break;
1856
1857                 case CONF_ITEM_SECTION:
1858                         scs=cf_itemtosection(ci);
1859                         DEBUG("%.*s%s %s%s{",
1860                                 indent, "\t\t\t\t\t\t\t\t\t\t\t",
1861                                 scs->name1,
1862                                 scs->name2 ? scs->name2 : "",
1863                                 scs->name2 ?  " " : "");
1864                         dump_config_section(scs, indent+1);
1865                         DEBUG("%.*s}",
1866                                 indent, "\t\t\t\t\t\t\t\t\t\t\t");
1867                         break;
1868
1869                 default:        /* FIXME: Do more! */
1870                         break;
1871                 }
1872         }
1873
1874         return 0;
1875 }
1876
1877 int dump_config(void)
1878 {
1879         return dump_config_section(mainconfig.config, 0);
1880 }
1881 #endif