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