Always free string pointers, to catch stupid modules which don't
[freeradius.git] / src / main / conffile.c
1 /*
2  * conffile.c   Read the radiusd.conf file.
3  *
4  *              Yep I should learn to use lex & yacc, or at least
5  *              write a decent parser. I know how to do that, really :)
6  *              miquels@cistron.nl
7  *
8  * Version:     $Id$
9  *
10  *   This program is free software; you can redistribute it and/or modify
11  *   it under the terms of the GNU General Public License as published by
12  *   the Free Software Foundation; either version 2 of the License, or
13  *   (at your option) any later version.
14  *
15  *   This program is distributed in the hope that it will be useful,
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *   GNU General Public License for more details.
19  *
20  *   You should have received a copy of the GNU General Public License
21  *   along with this program; if not, write to the Free Software
22  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  *
24  * Copyright 2000  The FreeRADIUS server project
25  * Copyright 2000  Miquel van Smoorenburg <miquels@cistron.nl>
26  * Copyright 2000  Alan DeKok <aland@ox.org>
27  */
28
29 #include "autoconf.h"
30 #include "libradius.h"
31
32 #include <stdlib.h>
33 #include <string.h>
34
35 #if HAVE_NETINET_IN_H
36 #       include <netinet/in.h>
37 #endif
38
39 #include "radiusd.h"
40 #include "rad_assert.h"
41 #include "conffile.h"
42 #include "token.h"
43 #include "modules.h"
44
45 static const char rcsid[] =
46 "$Id$";
47
48 #define xstrdup strdup
49
50 typedef enum conf_type {
51         CONF_ITEM_PAIR,
52         CONF_ITEM_SECTION
53 } CONF_ITEM_TYPE;
54
55 struct conf_item {
56         struct conf_item *next;
57         struct conf_part *parent;
58         int lineno;
59         CONF_ITEM_TYPE type;
60 };
61 struct conf_pair {
62         CONF_ITEM item;
63         char *attr;
64         char *value;
65         LRAD_TOKEN operator;
66 };
67 struct conf_part {
68         CONF_ITEM item;
69         char *name1;
70         char *name2;
71         struct conf_item *children;
72 };
73
74 /*
75  *      Isolate the scary casts in these tiny provably-safe functions
76  */
77 CONF_PAIR *cf_itemtopair(CONF_ITEM *ci)
78 {
79         if (ci == NULL)
80                 return NULL;
81         rad_assert(ci->type == CONF_ITEM_PAIR);
82         return (CONF_PAIR *)ci;
83 }
84 CONF_SECTION *cf_itemtosection(CONF_ITEM *ci)
85 {
86         if (ci == NULL)
87                 return NULL;
88         rad_assert(ci->type == CONF_ITEM_SECTION);
89         return (CONF_SECTION *)ci;
90 }
91 CONF_ITEM *cf_pairtoitem(CONF_PAIR *cp)
92 {
93         if (cp == NULL)
94                 return NULL;
95         return (CONF_ITEM *)cp;
96 }
97 CONF_ITEM *cf_sectiontoitem(CONF_SECTION *cs)
98 {
99         if (cs == NULL)
100                 return NULL;
101         return (CONF_ITEM *)cs;
102 }
103
104 /*
105  *      Create a new CONF_PAIR
106  */
107 static CONF_PAIR *cf_pair_alloc(const char *attr, const char *value,
108                 LRAD_TOKEN operator, CONF_SECTION *parent)
109 {
110         CONF_PAIR *cp;
111
112         cp = (CONF_PAIR *)rad_malloc(sizeof(CONF_PAIR));
113         memset(cp, 0, sizeof(CONF_PAIR));
114         cp->item.type = CONF_ITEM_PAIR;
115         cp->item.parent = parent;
116         cp->attr = xstrdup(attr);
117         cp->value = xstrdup(value);
118         cp->operator = operator;
119
120         return cp;
121 }
122
123 /*
124  *      Free a CONF_PAIR
125  */
126 void cf_pair_free(CONF_PAIR **cp)
127 {
128         if (!cp || !*cp) return;
129
130         if ((*cp)->attr)
131                 free((*cp)->attr);
132         if ((*cp)->value)
133                 free((*cp)->value);
134
135 #ifndef NDEBUG
136         memset(*cp, 0, sizeof(*cp));
137 #endif
138         free(*cp);
139
140         *cp = NULL;
141 }
142
143 /*
144  *      Allocate a CONF_SECTION
145  */
146 static CONF_SECTION *cf_section_alloc(const char *name1, const char *name2,
147                 CONF_SECTION *parent)
148 {
149         CONF_SECTION    *cs;
150
151         if (name1 == NULL || !name1[0]) 
152                 name1 = "main";
153
154         cs = (CONF_SECTION *)rad_malloc(sizeof(CONF_SECTION));
155         memset(cs, 0, sizeof(CONF_SECTION));
156         cs->item.type = CONF_ITEM_SECTION;
157         cs->item.parent = parent;
158         cs->name1 = strdup(name1);
159         cs->name2 = (name2 && *name2) ? xstrdup(name2) : NULL;
160
161         return cs;
162 }
163
164 /*
165  *      Free a CONF_SECTION
166  */
167 void cf_section_free(CONF_SECTION **cs)
168 {
169         CONF_ITEM       *ci, *next;
170
171         if (!cs || !*cs) return;
172
173         for (ci = (*cs)->children; ci; ci = next) {
174                 next = ci->next;
175                 if (ci->type==CONF_ITEM_PAIR) {
176                         CONF_PAIR *pair = cf_itemtopair(ci);
177                         cf_pair_free(&pair);
178                 } else {
179                         CONF_SECTION *section = cf_itemtosection(ci);
180                         cf_section_free(&section);
181                 }
182         }
183
184         if ((*cs)->name1) 
185                 free((*cs)->name1);
186         if ((*cs)->name2) 
187                 free((*cs)->name2);
188
189         /*
190          * And free the section
191          */
192 #ifndef NDEBUG
193         memset(*cs, 0, sizeof(*cs));
194 #endif
195         free(*cs);
196
197         *cs = NULL;
198 }
199
200 /*
201  *      Add an item to a configuration section.
202  */
203 static void cf_item_add(CONF_SECTION *cs, CONF_ITEM *ci_new)
204 {
205         CONF_ITEM *ci;
206         
207         for (ci = cs->children; ci && ci->next; ci = ci->next)
208                 ;
209
210         if (ci == NULL)
211                 cs->children = ci_new;
212         else
213                 ci->next = ci_new;
214 }
215
216 /*
217  *      Expand the variables in an input string.
218  */
219 static const char *cf_expand_variables(const char *cf, int *lineno,
220                                        CONF_SECTION *cs,
221                                        char *output, const char *input)
222 {
223         char *p;
224         const char *end, *ptr;
225         char name[8192];
226         CONF_PAIR *cpn;
227         CONF_SECTION *outercs;
228
229         p = output;
230         ptr = input;
231         while (*ptr) {
232                 /*
233                  *      Ignore anything other than "${"
234                  */
235                 if ((*ptr == '$') && (ptr[1] == '{')) {
236                         /*
237                          *      Look for trailing '}', and log a
238                          *      warning for anything that doesn't match,
239                          *      and exit with a fatal error.
240                          */
241                         end = strchr(ptr, '}');
242                         if (end == NULL) {
243                                 *p = '\0';
244                                 radlog(L_INFO, "%s[%d]: Variable expansion missing }",
245                                        cf, *lineno);
246                                 return NULL;
247                         }
248                         
249                         ptr += 2;
250                         
251                         memcpy(name, ptr, end - ptr);
252                         name[end - ptr] = '\0';
253                         
254                         cpn = cf_pair_find(cs, name);
255                         
256                         /*
257                          *      Also look recursively up the section tree,
258                          *      so things like ${confdir} can be defined
259                          *      there and used inside the module config
260                          *      sections.
261                          */
262                         for (outercs=cs->item.parent; 
263                              (cpn == NULL) && (outercs != NULL);
264                              outercs=outercs->item.parent) {
265                                 cpn = cf_pair_find(outercs, name);
266                         }
267                         if (!cpn) {
268                                 radlog(L_ERR, "%s[%d]: Unknown variable \"%s\"",
269                                        cf, *lineno, name);
270                                 return NULL;
271                         }
272                         
273                         /*
274                          *  Substitute the value of the variable.
275                          */
276                         strcpy(p, cpn->value);
277                         p += strlen(p);
278                         ptr = end + 1;
279
280                 } else if (memcmp(ptr, "$ENV{", 5) == 0) {
281                         char *env;
282
283                         ptr += 5;
284
285                         /*
286                          *      Look for trailing '}', and log a
287                          *      warning for anything that doesn't match,
288                          *      and exit with a fatal error.
289                          */
290                         end = strchr(ptr, '}');
291                         if (end == NULL) {
292                                 *p = '\0';
293                                 radlog(L_INFO, "%s[%d]: Environment variable expansion missing }",
294                                        cf, *lineno);
295                                 return NULL;
296                         }
297                         
298                         memcpy(name, ptr, end - ptr);
299                         name[end - ptr] = '\0';
300                         
301                         /*
302                          *      Get the environment variable.
303                          *      If none exists, then make it an empty string.
304                          */
305                         env = getenv(name);
306                         if (env == NULL) {
307                                 *name = '\0';
308                                 env = name;
309                         }
310
311                         strcpy(p, env);
312                         p += strlen(p);
313                         ptr = end + 1;
314
315                 } else {
316                         /*
317                          *      Copy it over verbatim.
318                          */
319                         *(p++) = *(ptr++);
320                 }
321         } /* loop over all of the input string. */
322                 
323         *p = '\0';
324
325         return output;
326 }
327
328 /*
329  *      Parse a configuration section into user-supplied variables.
330  */
331 int cf_section_parse(CONF_SECTION *cs, void *base,
332                      const CONF_PARSER *variables)
333 {
334         int i;
335         int rcode;
336         char **q;
337         CONF_PAIR *cp;
338         CONF_SECTION *subsection;
339         uint32_t ipaddr;
340         char buffer[8192];
341         const char *value;
342         void *data;
343
344         /*
345          *      Handle the user-supplied variables.
346          */
347         for (i = 0; variables[i].name != NULL; i++) {
348                 value = variables[i].dflt;
349                 if (base) {
350                         data = ((char *)base) + variables[i].offset;
351                 } else {
352                         data = variables[i].data;
353                 }
354
355                 cp = cf_pair_find(cs, variables[i].name);
356                 if (cp) {
357                         value = cp->value;
358                 }
359                 
360                 switch (variables[i].type)
361                 {
362                 case PW_TYPE_SUBSECTION:
363                         subsection = cf_section_sub_find(cs,variables[i].name);
364
365                         /*
366                          *      If the configuration section is NOT there,
367                          *      then ignore it.
368                          *
369                          *      FIXME! This is probably wrong... we should
370                          *      probably set the items to their default values.
371                          */
372                         if (subsection == NULL) {
373                                 break;
374                         }
375
376                         rcode = cf_section_parse(subsection, base,
377                                         (CONF_PARSER *) data);
378                         if (rcode < 0) {
379                                 return -1;
380                         }
381                         break;
382
383                 case PW_TYPE_BOOLEAN:
384                         /*
385                          *      Allow yes/no and on/off
386                          */
387                         if ((strcasecmp(value, "yes") == 0) ||
388                                         (strcasecmp(value, "on") == 0)) {
389                                 *(int *)data = 1;
390                         } else if ((strcasecmp(value, "no") == 0) ||
391                                                 (strcasecmp(value, "off") == 0)) {
392                                 *(int *)data = 0;
393                         } else {
394                                 *(int *)data = 0;
395                                 radlog(L_ERR, "Bad value \"%s\" for boolean variable %s", value, variables[i].name);
396                                 return -1;
397                         }
398                         DEBUG2(" %s: %s = %s",
399                                         cs->name1,
400                                         variables[i].name,
401                                         value);
402                         break;
403
404                 case PW_TYPE_INTEGER:
405                         *(int *)data = strtol(value, 0, 0);
406                         DEBUG2(" %s: %s = %d",
407                                         cs->name1,
408                                         variables[i].name,
409                                         *(int *)data);
410                         break;
411                         
412                 case PW_TYPE_STRING_PTR:
413                         q = (char **) data;
414                         if (*q != NULL) {
415                                 free(*q);
416                         }
417
418                         /*
419                          *      Expand variables while parsing,
420                          *      but ONLY expand ones which haven't already
421                          *      been expanded.
422                          */
423                         if (value && (value == variables[i].dflt)) {
424                                 value = cf_expand_variables("?",
425                                                             &cs->item.lineno,
426                                                             cs, buffer, value);
427                                 if (!value) {
428                                         return -1;
429                                 }
430                         }
431
432                         DEBUG2(" %s: %s = \"%s\"",
433                                         cs->name1,
434                                         variables[i].name,
435                                         value ? value : "(null)");
436                         *q = value ? strdup(value) : NULL;
437                         break;
438
439                 case PW_TYPE_IPADDR:
440                         /*
441                          *      Allow '*' as any address
442                          */
443                         if (strcmp(value, "*") == 0) {
444                                 *(uint32_t *) data = 0;
445                                 break;
446                         }
447                         ipaddr = ip_getaddr(value);
448                         if (ipaddr == 0) {
449                                 radlog(L_ERR, "Can't find IP address for host %s", value);
450                                 return -1;
451                         }
452                         DEBUG2(" %s: %s = %s IP address [%s]",
453                                         cs->name1,
454                                         variables[i].name,
455                                         value, ip_ntoa(buffer, ipaddr));
456                         *(uint32_t *) data = ipaddr;
457                         break;
458                         
459                 default:
460                         radlog(L_ERR, "type %d not supported yet", variables[i].type);
461                         return -1;
462                         break;
463                 } /* switch over variable type */
464         } /* for all variables in the configuration section */
465         
466         return 0;
467 }
468
469 /*
470  *      Read a part of the config file.
471  */
472 static CONF_SECTION *cf_section_read(const char *cf, int *lineno, FILE *fp,
473                 const char *name1, const char *name2,
474                 CONF_SECTION *parent)
475 {
476         CONF_SECTION *cs, *css;
477         CONF_PAIR *cpn;
478         char *ptr;
479         const char *value;
480         char buf[8192];
481         char buf1[8192];
482         char buf2[8192];
483         char buf3[8192];
484         int t1, t2, t3;
485         char *cbuf = buf;
486         int len;
487         
488         /*
489          *      Ensure that the user can't add CONF_SECTIONs
490          *      with 'internal' names;
491          */
492         if ((name1 != NULL) && (name1[0] == '_')) {
493                 radlog(L_ERR, "%s[%d]: Illegal configuration section name",
494                         cf, *lineno);
495                 return NULL;
496         }
497
498         /*
499          *      Allocate new section.
500          */
501         cs = cf_section_alloc(name1, name2, parent);
502         cs->item.lineno = *lineno;
503
504         /*
505          *      Read, checking for line continuations ('\\' at EOL)
506          */
507         for (;;) {
508                 int eof;
509
510                 /*
511                  *      Get data, and remember if we are at EOF.
512                  */
513                 eof = (fgets(cbuf, sizeof(buf) - (cbuf - buf), fp) == NULL);
514                 (*lineno)++;
515
516                 len = strlen(cbuf);
517
518                 /*
519                  *      We've filled the buffer, and there isn't
520                  *      a CR in it.  Die!
521                  */
522                 if ((len == sizeof(buf)) &&
523                     (cbuf[len - 1] != '\n')) {
524                         radlog(L_ERR, "%s[%d]: Line too long",
525                                cf, *lineno);
526                         cf_section_free(&cs);
527                         return NULL;
528                 }
529
530                 /*
531                  *  Check for continuations.
532                  */
533                 if (cbuf[len - 1] == '\n') len--;
534
535                 /*
536                  *      Last character is '\\'.  Over-write it,
537                  *      and read another line.
538                  */
539                 if ((len > 0) && (cbuf[len - 1] == '\\')) {
540                         cbuf[len - 1] = '\0';
541                         cbuf += len - 1;
542                         continue;
543                 }
544
545                 /*
546                  *  We're at EOF, and haven't read anything.  Stop.
547                  */
548                 if (eof && (cbuf == buf)) {
549                         break;
550                 }
551
552                 ptr = cbuf = buf;
553                 t1 = gettoken(&ptr, buf1, sizeof(buf1));
554
555                 /*
556                  *      Skip comments and blank lines immediately.
557                  */
558                 if ((*buf1 == '#') || (*buf1 == '\0')) {
559                         continue;
560                 }
561
562                 /*
563                  *      Allow for $INCLUDE files
564                  *
565                  *      This *SHOULD* work for any level include.  
566                  *      I really really really hate this file.  -cparker
567                  */
568                 if (strcasecmp(buf1, "$INCLUDE") == 0) {
569
570                         CONF_SECTION      *is;
571
572                         t2 = getword(&ptr, buf2, sizeof(buf2));
573
574                         value = cf_expand_variables(cf, lineno, cs, buf, buf2);
575                         if (value == NULL) {
576                                 cf_section_free(&cs);
577                                 return NULL;
578                         }
579
580                         DEBUG2( "Config:   including file: %s", value );
581
582                         if ((is = conf_read(cf, *lineno, value, parent)) == NULL) {
583                                 cf_section_free(&cs);
584                                 return NULL;
585                         }
586
587                         /*
588                          *      Add the included conf to our CONF_SECTION
589                          */
590                         if (is != NULL) {
591                                 if (is->children != NULL) {
592                                         CONF_ITEM *ci;
593                         
594                                         /*
595                                          *      Re-write the parent of the
596                                          *      moved children to be the
597                                          *      upper-layer section.
598                                          */
599                                         for (ci = is->children; ci; ci = ci->next) {
600                                                 ci->parent = cs;
601                                         }
602
603                                         /*
604                                          *      If there are children, then
605                                          *      move them up a layer.
606                                          */
607                                         if (is->children) {
608                                                 cf_item_add(cs, is->children);
609                                         }
610                                         is->children = NULL;
611                                 }
612                                 /*
613                                  *      Always free the section for the
614                                  *      $INCLUDEd file.
615                                  */
616                                 cf_section_free(&is);
617                         }
618
619                         continue;
620                 }
621
622                 /*
623                  *      No '=': must be a section or sub-section.
624                  */
625                 if (strchr(ptr, '=') == NULL) {
626                         t2 = gettoken(&ptr, buf2, sizeof(buf2));
627                         t3 = gettoken(&ptr, buf3, sizeof(buf3));
628                 } else {
629                         t2 = gettoken(&ptr, buf2, sizeof(buf2));
630                         t3 = getword(&ptr, buf3, sizeof(buf3));
631                 }
632
633                 /*
634                  *      See if it's the end of a section.
635                  */
636                 if (t1 == T_RCBRACE) {
637                         if (name1 == NULL || buf2[0]) {
638                                 radlog(L_ERR, "%s[%d]: Unexpected end of section",
639                                                 cf, *lineno);
640                                 cf_section_free(&cs);
641                                 return NULL;
642                         }
643                         return cs;
644                 }
645
646                 /*
647                  * Perhaps a subsection.
648                  */
649                 if (t2 == T_LCBRACE || t3 == T_LCBRACE) {
650                         css = cf_section_read(cf, lineno, fp, buf1,
651                                         t2==T_LCBRACE ? NULL : buf2, cs);
652                         if (css == NULL) {
653                                 cf_section_free(&cs);
654                                 return NULL;
655                         }
656                         cf_item_add(cs, cf_sectiontoitem(css));
657
658                         continue;
659                 }
660
661                 /*
662                  *      Ignore semi-colons.
663                  */
664                 if (*buf2 == ';') 
665                         *buf2 = '\0';
666
667                 /*
668                  *      Must be a normal attr = value line.
669                  */
670                 if (buf1[0] != 0 && buf2[0] == 0 && buf3[0] == 0) {
671                         t2 = T_OP_EQ;
672                 } else if (buf1[0] == 0 || buf2[0] == 0 || 
673                            (t2 < T_EQSTART || t2 > T_EQEND)) {
674                         radlog(L_ERR, "%s[%d]: Line is not in 'attribute = value' format",
675                                         cf, *lineno);
676                         cf_section_free(&cs);
677                         return NULL;
678                 }
679
680                 /*
681                  *      Ensure that the user can't add CONF_PAIRs
682                  *      with 'internal' names;
683                  */
684                 if (buf1[0] == '_') {
685                         radlog(L_ERR, "%s[%d]: Illegal configuration pair name \"%s\"",
686                                         cf, *lineno, buf1);
687                         cf_section_free(&cs);
688                         return NULL;
689                 }
690
691                 /*
692                  *      Handle variable substitution via ${foo}
693                  */
694                 value = cf_expand_variables(cf, lineno, cs, buf, buf3);
695                 if (!value) {
696                         cf_section_free(&cs);
697                         return NULL;
698                 }
699
700
701                 /*
702                  *      Add this CONF_PAIR to our CONF_SECTION
703                  */
704                 cpn = cf_pair_alloc(buf1, value, t2, parent);
705                 cpn->item.lineno = *lineno;
706                 cf_item_add(cs, cf_pairtoitem(cpn));
707         }
708
709         /*
710          *      See if EOF was unexpected ..
711          */
712         if (name1 != NULL) {
713                 radlog(L_ERR, "%s[%d]: Unexpected end of file", cf, *lineno);
714                 cf_section_free(&cs);
715                 return NULL;
716         }
717
718         return cs;
719 }
720
721 /*
722  *      Read the config file.
723  */
724 CONF_SECTION *conf_read(const char *fromfile, int fromline, 
725                         const char *conffile, CONF_SECTION *parent)
726 {
727         FILE            *fp;
728         int             lineno = 0;
729         CONF_SECTION    *cs;
730         
731         if ((fp = fopen(conffile, "r")) == NULL) {
732                 if (fromfile) {
733                         radlog(L_ERR|L_CONS, "%s[%d]: Unable to open file \"%s\": %s",
734                                         fromfile, fromline, conffile, strerror(errno));
735                 } else {
736                         radlog(L_ERR|L_CONS, "Unable to open file \"%s\": %s",
737                                         conffile, strerror(errno));
738                 }
739                 return NULL;
740         }
741
742         if(parent) {
743             cs = cf_section_read(conffile, &lineno, fp, NULL, NULL, parent);
744         } else {
745             cs = cf_section_read(conffile, &lineno, fp, NULL, NULL, NULL);
746         }
747
748         fclose(fp);
749
750         return cs;
751 }
752
753
754 /* 
755  * Return a CONF_PAIR within a CONF_SECTION.
756  */
757 CONF_PAIR *cf_pair_find(CONF_SECTION *section, const char *name)
758 {
759         CONF_ITEM       *ci;
760
761         if (section == NULL) {
762                 section = mainconfig.config;
763         }
764
765         for (ci = section->children; ci; ci = ci->next) {
766                 if (ci->type != CONF_ITEM_PAIR)
767                         continue;
768                 if (name == NULL || strcmp(cf_itemtopair(ci)->attr, name) == 0)
769                         break;
770         }
771
772         return cf_itemtopair(ci);
773 }
774
775 /*
776  * Return the attr of a CONF_PAIR
777  */
778
779 char *cf_pair_attr(CONF_PAIR *pair)
780 {
781         return (pair ? pair->attr : NULL);
782 }
783
784 /*
785  * Return the value of a CONF_PAIR
786  */
787
788 char *cf_pair_value(CONF_PAIR *pair)
789 {
790         return (pair ? pair->value : NULL);
791 }
792
793 /*
794  * Return the first label of a CONF_SECTION
795  */
796
797 char *cf_section_name1(CONF_SECTION *section)
798 {
799         return (section ? section->name1 : NULL);
800 }
801
802 /*
803  * Return the second label of a CONF_SECTION
804  */
805
806 char *cf_section_name2(CONF_SECTION *section)
807 {
808         return (section ? section->name2 : NULL);
809 }
810
811 /* 
812  * Find a value in a CONF_SECTION
813  */
814 char *cf_section_value_find(CONF_SECTION *section, const char *attr)
815 {
816         CONF_PAIR       *cp;
817
818         cp = cf_pair_find(section, attr);
819
820         return (cp ? cp->value : NULL);
821 }
822
823 /*
824  * Return the next pair after a CONF_PAIR
825  * with a certain name (char *attr) If the requested
826  * attr is NULL, any attr matches.
827  */
828
829 CONF_PAIR *cf_pair_find_next(CONF_SECTION *section, CONF_PAIR *pair, const char *attr)
830 {
831         CONF_ITEM       *ci;
832
833         /*
834          * If pair is NULL this must be a first time run
835          * Find the pair with correct name
836          */
837
838         if (pair == NULL){
839                 return cf_pair_find(section, attr);
840         }
841
842         ci = cf_pairtoitem(pair)->next;
843
844         for (; ci; ci = ci->next) {
845                 if (ci->type != CONF_ITEM_PAIR)
846                         continue;
847                 if (attr == NULL || strcmp(cf_itemtopair(ci)->attr, attr) == 0)
848                         break;
849         }
850
851         return cf_itemtopair(ci);
852 }
853
854 /*
855  * Find a CONF_SECTION, or return the root if name is NULL
856  */
857
858 CONF_SECTION *cf_section_find(const char *name)
859 {
860         if (name)
861                 return cf_section_sub_find(mainconfig.config, name);
862         else
863                 return mainconfig.config;
864 }
865
866 /*
867  * Find a sub-section in a section
868  */
869
870 CONF_SECTION *cf_section_sub_find(CONF_SECTION *section, const char *name)
871 {
872         CONF_ITEM *ci;
873
874         for (ci = section->children; ci; ci = ci->next) {
875                 if (ci->type != CONF_ITEM_SECTION)
876                         continue;
877                 if (strcmp(cf_itemtosection(ci)->name1, name) == 0)
878                         break;
879         }
880
881         return cf_itemtosection(ci);
882
883 }
884
885 /*
886  * Return the next subsection after a CONF_SECTION
887  * with a certain name1 (char *name1). If the requested
888  * name1 is NULL, any name1 matches.
889  */
890
891 CONF_SECTION *cf_subsection_find_next(CONF_SECTION *section,
892                 CONF_SECTION *subsection,
893                 const char *name1)
894 {
895         CONF_ITEM       *ci;
896
897         /*
898          * If subsection is NULL this must be a first time run
899          * Find the subsection with correct name
900          */
901
902         if (subsection == NULL){
903                 ci = section->children;
904         } else {
905                 ci = cf_sectiontoitem(subsection)->next;
906         }
907
908         for (; ci; ci = ci->next) {
909                 if (ci->type != CONF_ITEM_SECTION)
910                         continue;
911                 if ((name1 == NULL) || 
912                                 (strcmp(cf_itemtosection(ci)->name1, name1) == 0))
913                         break;
914         }
915
916         return cf_itemtosection(ci);
917 }
918
919 /*
920  * Return the next item after a CONF_ITEM.
921  */
922
923 CONF_ITEM *cf_item_find_next(CONF_SECTION *section, CONF_ITEM *item)
924 {
925         /*
926          * If item is NULL this must be a first time run
927          * Return the first item
928          */
929
930         if (item == NULL) {
931                 return section->children;
932         } else {
933                 return item->next;
934         }
935 }
936
937 int cf_section_lineno(CONF_SECTION *section)
938 {
939         return cf_sectiontoitem(section)->lineno;
940 }
941
942 int cf_pair_lineno(CONF_PAIR *pair)
943 {
944         return cf_pairtoitem(pair)->lineno;
945 }
946
947 int cf_item_is_section(CONF_ITEM *item)
948 {
949         return item->type == CONF_ITEM_SECTION;
950 }
951
952
953 #if 0
954 /* 
955  * JMG dump_config tries to dump the config structure in a readable format
956  * 
957 */
958
959 static int dump_config_section(CONF_SECTION *cs, int indent)
960 {
961         CONF_SECTION    *scs;
962         CONF_PAIR       *cp;
963         CONF_ITEM       *ci;
964
965         /* The DEBUG macro doesn't let me
966          *   for(i=0;i<indent;++i) debugputchar('\t');
967          * so I had to get creative. --Pac. */
968
969         for (ci = cs->children; ci; ci = ci->next) {
970                 if (ci->type == CONF_ITEM_PAIR) {
971                         cp=cf_itemtopair(ci);
972                         DEBUG("%.*s%s = %s",
973                                 indent, "\t\t\t\t\t\t\t\t\t\t\t",
974                                 cp->attr, cp->value);
975                 } else {
976                         scs=cf_itemtosection(ci);
977                         DEBUG("%.*s%s %s%s{",
978                                 indent, "\t\t\t\t\t\t\t\t\t\t\t",
979                                 scs->name1,
980                                 scs->name2 ? scs->name2 : "",
981                                 scs->name2 ?  " " : "");
982                         dump_config_section(scs, indent+1);
983                         DEBUG("%.*s}",
984                                 indent, "\t\t\t\t\t\t\t\t\t\t\t");
985                 }
986         }
987
988         return 0;
989 }
990
991 int dump_config(void)
992 {
993         return dump_config_section(mainconfig.config, 0);
994 }
995 #endif