Make cf_reference_item public, so it can be used in
authoraland <aland>
Sun, 11 Nov 2007 21:20:59 +0000 (21:20 +0000)
committeraland <aland>
Sun, 11 Nov 2007 21:20:59 +0000 (21:20 +0000)
%{config:...}

Made internal configuration code reference sub-sections by
instances, too.  This allows ${foo.bar[baz]} references.

Added internal "confdir" directive in cf_file_read, which
adds "confdir" as the FIRST configuration item in "main".
This allows the rest of the configuration files and directives
to be tied to ${confdir}, meaning the server can be built
with one target directory, but still run out of another

src/include/conffile.h
src/main/conffile.c
src/main/mainconfig.c

index f1d6e2e..26ba12e 100644 (file)
@@ -93,7 +93,9 @@ CONF_ITEM *cf_pairtoitem(CONF_PAIR *cp);
 CONF_ITEM *cf_sectiontoitem(CONF_SECTION *cs);
 int cf_section_template(CONF_SECTION *cs, CONF_SECTION *template);
 void cf_log_err(CONF_ITEM *ci, const char *fmt, ...);
-
+CONF_ITEM *cf_reference_item(const CONF_SECTION *parentcs,
+                            const CONF_SECTION *outercs,
+                            const char *ptr);
 /*
  *     Big magic.
  */
index 64ceb18..689022e 100644 (file)
@@ -509,9 +509,9 @@ static void cf_item_add(CONF_SECTION *cs, CONF_ITEM *ci)
 }
 
 
-static const CONF_ITEM *cf_reference_item(const CONF_SECTION *parentcs,
-                                         const CONF_SECTION *outercs,
-                                         const char *ptr)
+CONF_ITEM *cf_reference_item(const CONF_SECTION *parentcs,
+                            const CONF_SECTION *outercs,
+                            const char *ptr)
 {
        CONF_PAIR *cp;
        const CONF_SECTION *cs = outercs, *next;
@@ -545,13 +545,49 @@ static const CONF_ITEM *cf_reference_item(const CONF_SECTION *parentcs,
        }
 
        while (*p) {
-               char *q = strchr(p, '.');
+               char *q, *r;
 
-               if (!q) break;
+               r = strchr(p, '[');
+               q = strchr(p, '.');
+               if (!r && !q) break;
 
-               *q = '\0';
-               next = cf_section_sub_find(cs, p);
-               *q = '.';
+               if (r && q > r) q = NULL;
+               if (q && q < r) r = NULL;
+
+               /*
+                *      Split off name2.
+                */
+               if (r) {
+                       q = strchr(r + 1, ']');
+                       if (!q) return NULL; /* parse error */
+
+                       /*
+                        *      Points to foo[bar]xx: parse error,
+                        *      it should be foo[bar] or foo[bar].baz
+                        */
+                       if (q[1] && q[1] != '.') goto no_such_item;
+
+                       *r = '\0';
+                       *q = '\0';
+                       next = cf_section_sub_find_name2(cs, p, r + 1);
+                       *r = '[';
+                       *q = ']';
+
+                       /*
+                        *      Points to a named instance of a section.
+                        */
+                       if (!q[1]) {
+                               if (!next) goto no_such_item;
+                               return cf_sectiontoitem(next);
+                       }
+
+                       q++;    /* ensure we skip the ']' and '.' */
+
+               } else {
+                       *q = '\0';
+                       next = cf_section_sub_find(cs, p);
+                       *q = '.';
+               }
 
                if (!next) break; /* it MAY be a pair in this section! */
 
@@ -559,7 +595,7 @@ static const CONF_ITEM *cf_reference_item(const CONF_SECTION *parentcs,
                p = q + 1;
        }
 
-       if (!*p) return NULL;
+       if (!*p) goto no_such_item;
 
  retry:
        /*
@@ -580,6 +616,8 @@ static const CONF_ITEM *cf_reference_item(const CONF_SECTION *parentcs,
                goto retry;
        }
 
+no_such_item:
+       DEBUG2("WARNING: No such configuration item %s", ptr);
        return NULL;
 }
 
@@ -1570,11 +1608,23 @@ int cf_file_include(const char *filename, CONF_SECTION *cs)
  */
 CONF_SECTION *cf_file_read(const char *filename)
 {
+       char *p;
+       CONF_PAIR *cp;
        CONF_SECTION *cs;
 
        cs = cf_section_alloc("main", NULL, NULL);
        if (!cs) return NULL;
 
+       cp = cf_pair_alloc("confdir", filename, T_OP_SET, T_BARE_WORD, cs);
+       if (!cp) return NULL;
+
+       p = strrchr(cp->value, '/');
+       if (p) *p = '\0';
+
+       cp->item.filename = "internal";
+       cp->item.lineno = 0;
+       cf_item_add(cs, cf_pairtoitem(cp));
+
        if (cf_file_include(filename, cs) < 0) {
                cf_section_free(&cs);
                return NULL;
index 38cafc4..0c68006 100644 (file)
@@ -202,192 +202,27 @@ static int xlat_config(void *instance, REQUEST *request,
                       size_t outlen,
                       RADIUS_ESCAPE_STRING func)
 {
-       CONF_SECTION *cs;
-       CONF_PAIR *cp;
-       int i, argc, left;
-       const char *from, *value;
-       char *to;
-       char myfmt[1024];
-       char argv_buf[1024];
-       char *argv[MAX_ARGV];
+       const char *value;
+       const CONF_PAIR *cp;
+       const CONF_ITEM *ci;
 
        request = request;      /* -Wunused */
        instance = instance;    /* -Wunused */
 
-       cp = NULL;
-       cs = NULL;
-
        /*
-        *      Split the string into argv's BEFORE doing radius_xlat...
-        *      Copied from exec.c
+        *      FIXME: radius_xlat, with a function that escapes
+        *      "%{[].\\\'"\`".
         */
-       from = fmt;
-       to = myfmt;
-       argc = 0;
-       while (*from) {
-               int flag, length;
-
-               flag = 0;
-               argv[argc] = to;
-               argc++;
-
-               if (argc >= (MAX_ARGV - 1)) break;
-
-               /*
-                *      Copy the argv over to our buffer.
-                */
-               while (*from) {
-                       if (to >= myfmt + sizeof(myfmt) - 1) {
-                               return 0; /* no error msg */
-                       }
-
-                       switch (*from) {
-                       case '%':
-                               if (from[1] == '{') {
-                                       *(to++) = *(from++);
-
-                                       length = rad_copy_variable(to, from);
-                                       if (length < 0) {
-                                               return -1;
-                                       }
-                                       from += length;
-                                       to += length;
-                               } else { /* FIXME: catch %%{ ? */
-                                       *(to++) = *(from++);
-                               }
-                               break;
-
-                       case '[':
-                               if (flag != 0) {
-                                       radlog(L_ERR, "config: Unexpected nested '[' in \"%s\"", fmt);
-                                       return 0;
-                               }
-                               flag++;
-                               *(to++) = *(from++);
-                               break;
-
-                       case ']':
-                               if (flag == 0) {
-                                       radlog(L_ERR, "config: Unbalanced ']' in \"%s\"", fmt);
-                                       return 0;
-                               }
-                               if (from[1] != '.') {
-                                       radlog(L_ERR, "config: Unexpected text after ']' in \"%s\"", fmt);
-                                       return 0;
-                               }
-
-                               flag--;
-                               *(to++) = *(from++);
-                               break;
-
-                       case '.':
-                               if (flag == 0) break;
-                               /* FALL-THROUGH */
-
-                       default:
-                               *(to++) = *(from++);
-                               break;
-                       }
-
-                       if ((*from == '.') && (flag == 0)) {
-                               from++;
-                               break;
-                       }
-               } /* end of string, or found a period */
 
-               if (flag != 0) {
-                       radlog(L_ERR, "config: Unbalanced '[' in \"%s\"", fmt);
-                       return 0;
-               }
-
-               *(to++) = '\0'; /* terminate the string. */
-       }
-
-       /*
-        *      Expand each string, as appropriate
-        */
-       to = argv_buf;
-       left = sizeof(argv_buf);
-       for (i = 0; i < argc; i++) {
-               int sublen;
-
-               /*
-                *      Don't touch argv's which won't be translated.
-                */
-               if (strchr(argv[i], '%') == NULL) continue;
-
-               sublen = radius_xlat(to, left - 1, argv[i], request, NULL);
-               if (sublen <= 0) {
-                       /*
-                        *      Fail to be backwards compatible.
-                        *
-                        *      It's yucky, but it won't break anything,
-                        *      and it won't cause security problems.
-                        */
-                       sublen = 0;
-               }
-
-               argv[i] = to;
-               to += sublen;
-               *(to++) = '\0';
-               left -= sublen;
-               left--;
-
-               if (left <= 0) {
-                       return 0;
-               }
-       }
-       argv[argc] = NULL;
-
-       cs = request->root->config;
-
-       /*
-        *      Root through section & subsection references.
-        *      The last entry of argv MUST be the CONF_PAIR.
-        */
-       for (i = 0; i < argc - 1; i++) {
-               char *name2 = NULL;
-               CONF_SECTION *subcs;
-
-               /*
-                *      FIXME: What about RADIUS attributes containing '['?
-                */
-               name2 = strchr(argv[i], '[');
-               if (name2) {
-                       char *p = strchr(name2, ']');
-                       rad_assert(p != NULL);
-                       rad_assert(p[1] =='\0');
-                       *p = '\0';
-                       *name2 = '\0';
-                       name2++;
-               }
-
-               if (name2) {
-                       subcs = cf_section_sub_find_name2(cs, argv[i],
-                                                         name2);
-                       if (!subcs) {
-                         radlog(L_ERR, "config: section \"%s %s {}\" not found while dereferencing \"%s\"", argv[i], name2, fmt);
-                         return 0;
-                       }
-               } else {
-                       subcs = cf_section_sub_find(cs, argv[i]);
-                       if (!subcs) {
-                         radlog(L_ERR, "config: section \"%s {}\" not found while dereferencing \"%s\"", argv[i], fmt);
-                         return 0;
-                       }
-               }
-               cs = subcs;
-       } /* until argc - 1 */
-
-       /*
-        *      This can now have embedded periods in it.
-        */
-       cp = cf_pair_find(cs, argv[argc - 1]);
-       if (!cp) {
-               radlog(L_ERR, "config: item \"%s\" not found while dereferencing \"%s\"", argv[argc], fmt);
+       ci = cf_reference_item(request->root->config,
+                              request->root->config, fmt);
+       if (!ci || !cf_item_is_pair(ci)) {
+               *out = '\0';
                return 0;
        }
 
+       cp = cf_itemtopair(ci);
+
        /*
         *  Ensure that we only copy what's necessary.
         *