Pass2 for attributes in existence checks
authorAlan T. DeKok <aland@freeradius.org>
Thu, 26 Jun 2014 12:17:30 +0000 (08:17 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Thu, 26 Jun 2014 12:18:34 +0000 (08:18 -0400)
if (&foo-LDAP-Group) {
...
}

src/main/modcall.c
src/main/parser.c
src/tests/unit/condition.txt

index d106e09..e0e6536 100644 (file)
@@ -2880,6 +2880,7 @@ static bool pass2_callback(UNUSED void *ctx, fr_cond_t *c)
        value_pair_map_t *map;
 
        if (c->type == COND_TYPE_EXISTS) {
+
                if (c->data.vpt->type == VPT_TYPE_XLAT) {
                        return pass2_xlat_compile(c->ci, &c->data.vpt, true);
                }
@@ -2887,8 +2888,21 @@ static bool pass2_callback(UNUSED void *ctx, fr_cond_t *c)
                rad_assert(c->data.vpt->type != VPT_TYPE_REGEX);
 
                /*
-                *      FIXME: fix up attribute references, too!
+                *      The existence check might have been &Foo-Bar,
+                *      where Foo-Bar is defined by a module.
                 */
+               if (c->pass2_fixup == PASS2_FIXUP_ATTR) {
+                       value_pair_tmpl_t *vpt;
+                       vpt = radius_str2tmpl(c, c->data.vpt->name, T_BARE_WORD, REQUEST_CURRENT, PAIR_LIST_REQUEST);
+                       if (!vpt) {
+                               cf_log_err(c->ci, "Unknown attribute '%s'", c->data.vpt->name + 1);
+                               return false;
+                       }
+
+                       talloc_free(c->data.vpt);
+                       c->data.vpt = vpt;
+                       c->pass2_fixup = PASS2_FIXUP_NONE;
+               }
                return true;
        }
 
index 5ceaeed..e1e5581 100644 (file)
@@ -472,7 +472,23 @@ static ssize_t condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *st
 
                        c->data.vpt = radius_str2tmpl(c, lhs, lhs_type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
                        if (!c->data.vpt) {
-                               return_P("Failed creating exists");
+                               /*
+                                *      If strings are T_BARE_WORD and they start with '&',
+                                *      then they refer to attributes which have not yet been
+                                *      defined.  Create the template(s) as literals, and
+                                *      fix them up in pass2.
+                                */
+                               if ((*lhs != '&') ||
+                                   (lhs_type != T_BARE_WORD)) {
+                                       return_P("Failed creating exists");
+                               }
+                               c->data.vpt = radius_str2tmpl(c, lhs + 1, lhs_type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
+                               if (!c->data.vpt) {
+                                       return_P("Failed creating exists");
+                               }
+                               rad_const_free(c->data.vpt->name);
+                               c->data.vpt->name = talloc_strdup(c->data.vpt, lhs);
+                               c->pass2_fixup = PASS2_FIXUP_ATTR;
                        }
 
                        rad_assert(c->data.vpt->type != VPT_TYPE_REGEX);
@@ -628,7 +644,7 @@ static ssize_t condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *st
                                                     REQUEST_CURRENT, PAIR_LIST_REQUEST);
                        if (!c->data.map) {
                                /*
-                                *      FIXME: if strings are T_BARE_WORD and they start with '&',
+                                *      If strings are T_BARE_WORD and they start with '&',
                                 *      then they refer to attributes which have not yet been
                                 *      defined.  Create the template(s) as literals, and
                                 *      fix them up in pass2.
@@ -1052,6 +1068,9 @@ done:
                /*
                 *      FOO =* BAR --> FOO
                 *      FOO !* BAR --> !FOO
+                *
+                *      FOO may be a string, or a delayed attribute
+                *      reference.
                 */
                if ((c->data.map->op == T_OP_CMP_TRUE) ||
                    (c->data.map->op == T_OP_CMP_FALSE)) {
@@ -1182,6 +1201,11 @@ done:
        /*
         *      Existence checks.  We short-circuit static strings,
         *      too.
+        *
+        *      FIXME: the data types should be in the template, too.
+        *      So that we know where a literal came from.
+        *
+        *      "foo" is NOT the same as 'foo' or a bare foo.
         */
        if (c->type == COND_TYPE_EXISTS) {
                switch (c->data.vpt->type) {
@@ -1233,6 +1257,7 @@ done:
 
                        } else if (lhs_type == T_BARE_WORD) {
                                int rcode;
+                               bool zeros = true;
                                char const *q;
 
                                for (q = c->data.vpt->name;
@@ -1241,6 +1266,7 @@ done:
                                        if (!isdigit((int) *q)) {
                                                break;
                                        }
+                                       if (*q != '0') zeros = false;
                                }
 
                                /*
@@ -1248,11 +1274,23 @@ done:
                                 *      'true'.
                                 */
                                if (!*q) {
-                                       c->type = COND_TYPE_TRUE;
+                                       if (zeros) {
+                                               c->type = COND_TYPE_TRUE;
+                                       } else {
+                                               c->type = COND_TYPE_TRUE;
+                                       }
                                        TALLOC_FREE(c->data.vpt);
                                        break;
                                }
 
+                               /*
+                                *      Allow &Foo-Bar where Foo-Bar is an attribute
+                                *      defined by a module.
+                                */
+                               if (c->pass2_fixup == PASS2_FIXUP_ATTR) {
+                                       break;
+                               }
+
                                rcode = fr_str2int(allowed_return_codes,
                                                   c->data.vpt->name, 0);
                                if (!rcode) {
index b2f1aaf..90520ec 100644 (file)
@@ -473,3 +473,11 @@ data &Tunnel-Password:1[0] == "Hello"
 
 condition &Tunnel-Password:1[3] == "Hello"
 data &Tunnel-Password:1[3] == "Hello"
+
+#
+#  This is allowed for pass2-fixups.  Foo-Bar MAY be an attribute.
+#  If so allow it so that pass2 can fix it up.  Until then,
+#  it's a literal.
+#
+condition &Foo-Bar
+data '&Foo-Bar'