Allow delayed references to attributes. Helps with #711
[freeradius.git] / src / main / parser.c
index 0ba3a83..5ceaeed 100644 (file)
@@ -47,11 +47,12 @@ static const FR_NAME_NUMBER allowed_return_codes[] = {
  *     This file shouldn't use any functions from the server core.
  */
 
-size_t fr_cond_sprint(char *buffer, size_t bufsize, fr_cond_t const *c)
+size_t fr_cond_sprint(char *buffer, size_t bufsize, fr_cond_t const *in)
 {
        size_t len;
        char *p = buffer;
        char *end = buffer + bufsize - 1;
+       fr_cond_t const *c = in;
 
 next:
        if (c->negate) {
@@ -292,7 +293,7 @@ static ssize_t condition_tokenize_cast(char const *start, DICT_ATTR const **pda,
 #ifdef WITH_ASCEND_BINARY
        case PW_TYPE_ABINARY:
 #endif
-       case PW_TYPE_COMBO_IP:
+       case PW_TYPE_IP_ADDR:
        case PW_TYPE_TLV:
        case PW_TYPE_EXTENDED:
        case PW_TYPE_LONG_EXTENDED:
@@ -339,7 +340,8 @@ static ssize_t condition_tokenize_cast(char const *start, DICT_ATTR const **pda,
  *  @param[out] error the parse error (if any)
  *  @return length of the string skipped, or when negative, the offset to the offending error
  */
-static ssize_t condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *start, int brace, fr_cond_t **pcond, char const **error, int flags)
+static ssize_t condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *start, int brace,
+                                 fr_cond_t **pcond, char const **error, int flags)
 {
        ssize_t slen;
        char const *p = start;
@@ -476,7 +478,8 @@ static ssize_t condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *st
                        rad_assert(c->data.vpt->type != VPT_TYPE_REGEX);
 
                } else { /* it's an operator */
-                       int regex;
+                       bool regex;
+                       bool i_flag = false;
 
                        /*
                         *      The next thing should now be a comparison operator.
@@ -612,7 +615,7 @@ static ssize_t condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *st
                                 *      Allow /foo/i
                                 */
                                if (p[slen] == 'i') {
-                                       c->regex_i = true;
+                                       i_flag = true;
                                        slen++;
                                }
 
@@ -630,10 +633,23 @@ static ssize_t condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *st
                                 *      defined.  Create the template(s) as literals, and
                                 *      fix them up in pass2.
                                 */
-                               if (*lhs == '&') {
+                               if ((*lhs != '&') ||
+                                   (lhs_type != T_BARE_WORD)) {
+                                       return_0("Syntax error");
+                               }
+                               c->data.map = radius_str2map(c, lhs, lhs_type + 1, op, rhs, rhs_type,
+                                                            REQUEST_CURRENT, PAIR_LIST_REQUEST,
+                                                            REQUEST_CURRENT, PAIR_LIST_REQUEST);
+                               if (!c->data.map) {
                                        return_0("Unknown attribute");
                                }
-                               return_0("Syntax error");
+                               rad_const_free(c->data.map->dst->name);
+                               c->data.map->dst->name = talloc_strdup(c->data.map->dst, lhs);
+                               c->pass2_fixup = PASS2_FIXUP_ATTR;
+                       }
+
+                       if (c->data.map->src->type == VPT_TYPE_REGEX) {
+                               c->data.map->src->vpt_iflag = i_flag;
                        }
 
                        /*
@@ -725,16 +741,16 @@ static ssize_t condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *st
                                        /*
                                         *      ipaddr to ipv4prefix is OK
                                         */
-                                       if ((c->data.map->dst->vpt_da->type == PW_TYPE_IPADDR) &&
-                                           (c->cast->type == PW_TYPE_IPV4PREFIX)) {
+                                       if ((c->data.map->dst->vpt_da->type == PW_TYPE_IPV4_ADDR) &&
+                                           (c->cast->type == PW_TYPE_IPV4_PREFIX)) {
                                                goto cast_ok;
                                        }
 
                                        /*
                                         *      ipv6addr to ipv6prefix is OK
                                         */
-                                       if ((c->data.map->dst->vpt_da->type == PW_TYPE_IPV6ADDR) &&
-                                           (c->cast->type == PW_TYPE_IPV6PREFIX)) {
+                                       if ((c->data.map->dst->vpt_da->type == PW_TYPE_IPV6_ADDR) &&
+                                           (c->cast->type == PW_TYPE_IPV6_PREFIX)) {
                                                goto cast_ok;
                                        }
 
@@ -1073,7 +1089,6 @@ done:
                        rcode = radius_evaluate_map(NULL, 0, 0, c);
                        TALLOC_FREE(c->data.map);
                        c->cast = NULL;
-                       c->regex_i = false;
                        if (rcode) {
                                c->type = COND_TYPE_TRUE;
                        } else {
@@ -1092,16 +1107,19 @@ done:
                 *      doesn't need to be done at run time
                 */
                if ((c->data.map->src->type == VPT_TYPE_LITERAL) &&
-                   (c->data.map->dst->type == VPT_TYPE_LITERAL)) {
+                   (c->data.map->dst->type == VPT_TYPE_LITERAL) &&
+                   !c->pass2_fixup) {
                        int rcode;
 
                        rad_assert(c->cast == NULL);
-                       rad_assert(c->regex_i == false);
 
                        rcode = radius_evaluate_map(NULL, 0, 0, c);
                        if (rcode) {
                                c->type = COND_TYPE_TRUE;
                        } else {
+                               DEBUG("OPTIMIZING %s %s --> FALSE",
+                                     c->data.map->dst->name,
+                                     c->data.map->src->name);
                                c->type = COND_TYPE_FALSE;
                        }