]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Make list_as_attr the default
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 15 Dec 2022 17:38:04 +0000 (11:38 -0600)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 15 Dec 2022 18:09:55 +0000 (12:09 -0600)
34 files changed:
src/bin/unit_test_attribute.c
src/bin/unit_test_module.c
src/lib/ldap/map.c
src/lib/server/cf_parse.c
src/lib/server/cond_eval.c
src/lib/server/cond_tokenize.c
src/lib/server/map.c
src/lib/server/map_async.c
src/lib/server/tmpl.h
src/lib/server/tmpl_dcursor.c
src/lib/server/tmpl_dcursor_tests.c
src/lib/server/tmpl_eval.c
src/lib/server/tmpl_tokenize.c
src/lib/unlang/compile.c
src/lib/unlang/subrequest.c
src/lib/unlang/xlat_builtin.c
src/lib/unlang/xlat_eval.c
src/lib/unlang/xlat_expr.c
src/lib/unlang/xlat_tokenize.c
src/lib/util/pair.h
src/modules/rlm_cache/rlm_cache.c
src/modules/rlm_csv/rlm_csv.c
src/modules/rlm_linelog/rlm_linelog.c
src/modules/rlm_smtp/rlm_smtp.c
src/tests/keywords/unspecified [new file with mode: 0644]
src/tests/unit/condition/base.txt
src/tests/unit/condition/casts.txt
src/tests/unit/condition/groups.txt
src/tests/unit/condition/ip.txt
src/tests/unit/condition/nested.txt
src/tests/unit/condition/regex.txt
src/tests/unit/condition/request_qualifiers.txt [new file with mode: 0644]
src/tests/unit/xlat/base.txt
src/tests/unit/xlat/cond_base.txt

index b922632e8ae6300c8e7327c958a83fdc442ae4a1..d2762b2222677b383596dd9b79799f91292aa1b8 100644 (file)
@@ -58,6 +58,7 @@ typedef struct request_s request_t;
 #ifdef __clangd__
 #  undef HAVE_SANITIZER_LSAN_INTERFACE_H
 #endif
+
 #ifdef HAVE_SANITIZER_LSAN_INTERFACE_H
 #  include <sanitizer/asan_interface.h>
 #endif
@@ -2625,7 +2626,7 @@ static ssize_t command_tmpl_rule_list_def(UNUSED TALLOC_CTX *ctx, tmpl_rules_t *
                fr_strerror_printf("Invalid list specifier \"%pV\"",
                                   fr_box_strvalue_len(fr_sbuff_current(value), fr_sbuff_remaining(value)));
        }
-       
+
        return slen;
 }
 
@@ -2869,7 +2870,6 @@ static size_t command_xlat_expr(command_result_t *result, command_file_ctx_t *cc
                                                        .dict_def = cc->tmpl_rules.attr.dict_def ?
                                                           cc->tmpl_rules.attr.dict_def : cc->config->dict,
                                                        .allow_unresolved = cc->tmpl_rules.attr.allow_unresolved,
-                                                       .list_as_attr = true,
                                                }
                                           });
        if (dec_len <= 0) {
@@ -2909,7 +2909,6 @@ static size_t command_xlat_purify(command_result_t *result, command_file_ctx_t *
                                                        .dict_def = cc->tmpl_rules.attr.dict_def ?
                                                           cc->tmpl_rules.attr.dict_def : cc->config->dict,
                                                        .allow_unresolved = cc->tmpl_rules.attr.allow_unresolved,
-                                                       .list_as_attr = true,
                                                   },
                                           });
        if (dec_len <= 0) {
index 595a23e9c43688801212cdbd3adc3d5ea79c537a..1b363a73df99dc2451eb0f10e37438301efa1115 100644 (file)
@@ -795,6 +795,8 @@ int main(int argc, char *argv[])
                EXIT_WITH_FAILURE;
        }
 
+       request_global_init();
+
        if (log_global_init(&default_log, false) < 0) {
                EXIT_WITH_FAILURE;
        }
@@ -802,7 +804,7 @@ int main(int argc, char *argv[])
        if (map_proc_register(NULL, "test-fail", mod_map_proc, map_proc_verify, 0) < 0) {
                EXIT_WITH_FAILURE;
        }
-
+       
        /*
         *      Initialise the interpreter, registering operations.
         *      This initialises
@@ -1079,6 +1081,8 @@ cleanup:
         */
        log_global_free();
 
+       request_global_free();
+
        server_free();
 
        /*
index be76b8c6070062ba4c0978ed84abd7539a41c88f..51fd6d8338a971133c06c39c01cc608f5296048e 100644 (file)
@@ -48,114 +48,6 @@ int fr_ldap_map_getvalue(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *reques
        fr_pair_list_init(&tmp_list);
 
        switch (map->lhs->type) {
-       /*
-        *      This is a mapping in the form of:
-        *              <list>. += <ldap attr>
-        *
-        *      Where <ldap attr> is:
-        *              <list>.<attr> <op> <value>
-        *
-        *      It is to allow for legacy installations which stored
-        *      RADIUS control and reply attributes in separate LDAP
-        *      attributes.
-        */
-       case TMPL_TYPE_LIST:
-               for (i = 0; i < self->count; i++) {
-                       map_t   *attr = NULL;
-                       char            *attr_str;
-
-                       tmpl_rules_t    lhs_rules = {
-                               .attr = {
-                                       .dict_def = request->dict,
-                                       .request_def = tmpl_request(map->lhs),
-                                       .list_def = tmpl_list(map->lhs),
-                                       .prefix = TMPL_ATTR_REF_PREFIX_AUTO
-                               },
-                               .at_runtime = true,
-                       };
-
-                       tmpl_rules_t rhs_rules = {
-                               .attr = {
-                                       .dict_def = request->dict
-                               },
-                               .at_runtime = true,
-                       };
-
-                       RDEBUG3("Parsing valuepair string \"%pV\"",
-                               fr_box_strvalue_len(self->values[i]->bv_val, self->values[i]->bv_len));
-
-                       /*
-                        *      bv_val is NOT \0 terminated, so we need to make it
-                        *      safe (\0 terminate it) before passing it to any
-                        *      functions which take C strings and no lengths.
-                        */
-                       attr_str = talloc_bstrndup(NULL, self->values[i]->bv_val, self->values[i]->bv_len);
-                       if (!attr_str) {
-                               RWDEBUG("Failed making attribute string safe");
-                               continue;
-                       }
-
-                       if (map_afrom_attr_str(ctx, &attr,
-                                              attr_str,
-                                              &lhs_rules, &rhs_rules) < 0) {
-                               RPWDEBUG("Failed parsing \"%pV\" as valuepair, skipping...",
-                                        fr_box_strvalue_len(self->values[i]->bv_val, self->values[i]->bv_len));
-                               talloc_free(attr_str);
-                               continue;
-                       }
-
-                       talloc_free(attr_str);
-
-                       if (tmpl_is_unresolved(attr->lhs)) {
-                           RWDEBUG("Failed parsing left side of \"%pV\", skipping...",
-                                       fr_box_strvalue_len(self->values[i]->bv_val, self->values[i]->bv_len));
-                               talloc_free(attr);
-                               continue;
-                       }
-
-                       if (tmpl_request_ref_list_cmp(tmpl_request(attr->lhs), tmpl_request(map->lhs)) != 0) {
-                               char *attr_request;
-                               char *map_request;
-
-                               tmpl_request_ref_list_aprint(NULL, &attr_request, tmpl_request(attr->lhs));
-                               tmpl_request_ref_list_aprint(NULL, &map_request, tmpl_request(map->lhs));
-
-                               RWDEBUG("valuepair \"%pV\" has conflicting request qualifier (%s vs %s), skipping...",
-                                       fr_box_strvalue_len(self->values[i]->bv_val, self->values[i]->bv_len),
-                                       attr_request, map_request);
-
-                               talloc_free(attr_request);
-                               talloc_free(map_request);
-
-                       next_pair:
-                               talloc_free(attr);
-                               continue;
-                       }
-
-                       if ((tmpl_list(attr->lhs) != tmpl_list(map->lhs))) {
-                               RWDEBUG("valuepair \"%pV\" has conflicting list qualifier (%s vs %s), skipping...",
-                                       fr_box_strvalue_len(self->values[i]->bv_val, self->values[i]->bv_len),
-                                       fr_table_str_by_value(pair_list_table, tmpl_list(attr->lhs), "<INVALID>"),
-                                       fr_table_str_by_value(pair_list_table, tmpl_list(map->lhs), "<INVALID>"));
-                               goto next_pair;
-                       }
-
-                       if (map_to_vp(ctx, &tmp_list, request, attr, NULL) < 0) {
-                               RWDEBUG("Failed creating attribute for valuepair \"%pV\", skipping...",
-                                       fr_box_strvalue_len(self->values[i]->bv_val, self->values[i]->bv_len));
-                               goto next_pair;
-                       }
-
-                       fr_pair_list_append(&head, &tmp_list);
-                       talloc_free(attr);
-
-                       /*
-                        *      Only process the first value, unless the operator is +=
-                        */
-                       if (map->op != T_OP_ADD_EQ) break;
-               }
-               break;
-
        /*
         *      Iterate over all the retrieved values,
         *      don't try and be clever about changing operators
@@ -202,7 +94,6 @@ int fr_ldap_map_verify(map_t *map, UNUSED void *instance)
         *      create using LDAP values.
         */
        switch (map->lhs->type) {
-       case TMPL_TYPE_LIST:
        case TMPL_TYPE_ATTR:
                break;
 
index bd660e76b910cc7b83920eb7b50185c51b267a8f..978634cc3c076f1c075784b372ec864706311418 100644 (file)
@@ -1085,7 +1085,6 @@ static int cf_parse_tmpl_pass2(UNUSED CONF_SECTION *cs, tmpl_t **out, CONF_PAIR
                break;
 
        case TMPL_TYPE_ATTR:
-       case TMPL_TYPE_LIST:
        case TMPL_TYPE_DATA:
        case TMPL_TYPE_EXEC:
        case TMPL_TYPE_EXEC_UNRESOLVED:
index 82883fc50f878fee8412d36b399a076d6a037f19..f40453682a4c0b5206adb0d78deb3188d539ffd1 100644 (file)
@@ -140,7 +140,6 @@ static bool cond_eval_tmpl(request_t *request, tmpl_t const *in, fr_value_box_t
 
        switch (vpt->type) {
        case TMPL_TYPE_ATTR:
-       case TMPL_TYPE_LIST:
                /*
                 *      No cast means that it's an existence check.
                 */
@@ -361,7 +360,6 @@ static int cond_realize_tmpl(request_t *request,
        /*
         *      These are handled elsewhere.
         */
-       case TMPL_TYPE_LIST:
 #ifdef HAVE_REGEX
        case TMPL_TYPE_REGEX:
 #endif
@@ -735,7 +733,6 @@ check_attrs:
        /*
         *      LHS is an attribute or list
         */
-       case TMPL_TYPE_LIST:
        case TMPL_TYPE_ATTR:
        {
                fr_pair_t               *vp;
index cbfd858e792818af18e952342990138f00b355f0..c30f36af4501b28958956fd495176a9ef9f0a479 100644 (file)
@@ -222,7 +222,6 @@ int fr_cond_promote_types(fr_cond_t *c, fr_sbuff_t *in, fr_sbuff_marker_t *m_lhs
         */
        if (tmpl_contains_regex(c->data.map->rhs)) {
                fr_assert((c->data.map->op == T_OP_REG_EQ) || (c->data.map->op == T_OP_REG_NE));
-               fr_assert(!tmpl_is_list(c->data.map->lhs));
                fr_assert(fr_type_is_null(tmpl_rules_cast(c->data.map->rhs)));
 
                /*
@@ -653,7 +652,6 @@ static int cond_normalise(TALLOC_CTX *ctx, fr_token_t lhs_type, fr_cond_t **c_ou
                case TMPL_TYPE_XLAT_UNRESOLVED:
                case TMPL_TYPE_ATTR:
                case TMPL_TYPE_ATTR_UNRESOLVED:
-               case TMPL_TYPE_LIST:
                case TMPL_TYPE_EXEC:
                        break;
 
@@ -879,21 +877,14 @@ done:
 
 static CC_HINT(nonnull) int cond_forbid_groups(tmpl_t *vpt, fr_sbuff_t *in, fr_sbuff_marker_t *m_lhs)
 {
-       if (tmpl_is_list(vpt)) {
-               fr_strerror_const("Cannot use list references in condition");
-               fr_sbuff_set(in, m_lhs);
-               return -1;
-       }
-
-       if (!tmpl_is_attr(vpt)) return 0;
+       if (!tmpl_is_attr(vpt) || tmpl_attr_tail_is_unspecified(vpt)) return 0;
 
        switch (tmpl_attr_tail_da(vpt)->type) {
        case FR_TYPE_LEAF:
                break;
 
        default:
-               fr_strerror_printf("Nesting types such as groups or TLVs cannot "
-                                  "be used in condition comparisons");
+               fr_strerror_printf("Nesting types such as groups or TLVs cannot be compared");
                fr_sbuff_set(in, m_lhs);
                return -1;
        }
index c090f50d01cd4f7710d2a764a8f9762e68f6a85c..c818e057ef7473ae444d62f051831c62a4401788 100644 (file)
@@ -129,7 +129,6 @@ int map_afrom_cp(TALLOC_CTX *ctx, map_t **out, map_t *parent, CONF_PAIR *cp,
         */
        if (!rhs_rules) {
                rhs_rules = lhs_rules;
-               fr_assert(lhs_rules->attr.list_as_attr); /* so we don't worry about list_def? */
        }
 
        MEM(child_ctx = talloc(map, uint8_t));
@@ -180,7 +179,7 @@ int map_afrom_cp(TALLOC_CTX *ctx, map_t **out, map_t *parent, CONF_PAIR *cp,
                 *      parsed in the context of the LHS, but only if
                 *      the LHS attribute was a group / structural attribute.
                 */
-               if (!input_rhs_rules && lhs_rules->attr.list_as_attr) {
+               if (!input_rhs_rules) {
                        tmpl_rules_child_init(child_ctx, &my_rhs_rules, lhs_rules, map->lhs);
                        rhs_rules = &my_rhs_rules;
                }
@@ -1285,7 +1284,7 @@ int map_afrom_vp(TALLOC_CTX *ctx, map_t **out, fr_pair_t *vp, tmpl_rules_t const
  * @param[in,out] ctx to allocate new #fr_pair_t (s) in.
  * @param[out] out Where to write the #fr_pair_t (s).
  * @param[in] request structure (used only for talloc).
- * @param[in] map the map. The LHS (dst) must be #TMPL_TYPE_ATTR or #TMPL_TYPE_LIST.
+ * @param[in] map the map. The LHS (dst) must be #TMPL_TYPE_ATTR
  *     The RHS (src) must be #TMPL_TYPE_EXEC.
  * @return
  *     - 0 on success.
@@ -1306,7 +1305,7 @@ static int map_exec_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *reque
 
        fr_assert(map->rhs);            /* Quite clang scan */
        fr_assert(tmpl_is_exec(map->rhs));
-       fr_assert(tmpl_is_attr(map->lhs) || tmpl_is_list(map->lhs));
+       fr_assert(tmpl_is_attr(map->lhs));
 
        /*
         *      We always put the request pairs into the environment
@@ -1320,9 +1319,9 @@ static int map_exec_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *reque
         *      call fr_pair_value_from_str on the output of the script.
         */
        result = radius_exec_program_legacy(ctx, answer, sizeof(answer),
-                                    tmpl_is_list(map->lhs) ? &output_pairs : NULL,
-                                    request, map->rhs->name, input_pairs ? input_pairs : NULL,
-                                    true, true, fr_time_delta_from_sec(EXEC_TIMEOUT));
+                                           tmpl_attr_tail_da_is_structural(map->lhs) ? &output_pairs : NULL,
+                                           request, map->rhs->name, input_pairs ? input_pairs : NULL,
+                                           true, true, fr_time_delta_from_sec(EXEC_TIMEOUT));
        talloc_free(expanded);
        if (result != 0) {
                REDEBUG("Exec failed with code (%i)", result);
@@ -1331,14 +1330,6 @@ static int map_exec_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *reque
        }
 
        switch (map->lhs->type) {
-       case TMPL_TYPE_LIST:
-               if (fr_pair_list_empty(&output_pairs)) {
-                       REDEBUG("No valid attributes received from program");
-                       return -2;
-               }
-               fr_pair_list_append(out, &output_pairs);
-               return 0;
-
        case TMPL_TYPE_ATTR:
        {
                fr_pair_t *vp;
@@ -1366,7 +1357,7 @@ static int map_exec_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *reque
  * @param[in,out] ctx to allocate #fr_pair_t (s) in.
  * @param[out] out Where to write the #fr_pair_t (s), which may be NULL if not found
  * @param[in] request The current request.
- * @param[in] map the map. The LHS (dst) has to be #TMPL_TYPE_ATTR or #TMPL_TYPE_LIST.
+ * @param[in] map the map. The LHS (dst) has to be #TMPL_TYPE_ATTR.
  * @param[in] uctx unused.
  * @return
  *     - 0 on success.
@@ -1387,7 +1378,7 @@ int map_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, map_t co
        MAP_VERIFY(map);
        if (!fr_cond_assert(map->lhs != NULL)) return -1;
 
-       fr_assert(tmpl_is_list(map->lhs) || tmpl_is_attr(map->lhs));
+       fr_assert(tmpl_is_attr(map->lhs));
 
        /*
         *      Special case for !*, we don't need to parse RHS as this is a unary operator.
@@ -1457,7 +1448,7 @@ int map_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, map_t co
         *      to allocate any attributes, just finding the current list, and change
         *      the op.
         */
-       if (tmpl_is_list(map->lhs) && tmpl_is_list(map->rhs)) {
+       if (tmpl_attr_tail_da_is_structural(map->lhs) && tmpl_attr_tail_da_is_structural(map->rhs)) {
                fr_pair_list_t *from = NULL;
 
                if (tmpl_request_ptr(&context, tmpl_request(map->rhs)) == 0) {
@@ -1540,8 +1531,7 @@ int map_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, map_t co
                fr_pair_t *vp;
                fr_dcursor_t from;
 
-               fr_assert((tmpl_is_attr(map->lhs) && tmpl_attr_tail_da(map->lhs)) ||
-                          (tmpl_is_list(map->lhs) && !tmpl_attr_tail_da(map->lhs)));
+               fr_assert(tmpl_is_attr(map->lhs) && tmpl_attr_tail_da(map->lhs));
 
                /*
                 * @todo should log error, and return -1 for v3.1 (causes update to fail)
@@ -1697,7 +1687,6 @@ int map_to_request(request_t *request, map_t const *map, radius_map_getvalue_t f
        /*
         *      Already in the correct form.
         */
-       case TMPL_TYPE_LIST:
        case TMPL_TYPE_ATTR:
                break;
 
@@ -1734,7 +1723,7 @@ int map_to_request(request_t *request, map_t const *map, radius_map_getvalue_t f
                        rcode = -1;
                        goto finish;
                }
-               fr_assert(tmpl_is_attr(exp_lhs) || tmpl_is_list(exp_lhs));
+               fr_assert(tmpl_is_attr(exp_lhs));
 
                memcpy(&exp_map, map, sizeof(exp_map));
                exp_map.lhs = exp_lhs;
@@ -1752,8 +1741,7 @@ int map_to_request(request_t *request, map_t const *map, radius_map_getvalue_t f
         *      Sanity check inputs.  We can have a list or attribute
         *      as a destination.
         */
-       if (!tmpl_is_list(map->lhs) &&
-           !tmpl_is_attr(map->lhs)) {
+       if (!tmpl_is_attr(map->lhs)) {
                REDEBUG("Left side \"%.*s\" of map should be an attr or list but is an %s",
                        (int)map->lhs->len, map->lhs->name,
                        tmpl_type_to_str(map->lhs->type));
@@ -1819,7 +1807,7 @@ int map_to_request(request_t *request, map_t const *map, radius_map_getvalue_t f
        /*
         *      The destination is a list (which is a completely different set of operations)
         */
-       if (tmpl_is_list(map->lhs)) {
+       if (tmpl_attr_tail_da_is_structural(map->lhs)) {
                switch (map->op) {
                case T_OP_CMP_FALSE:
                        /* We don't need the src VPs (should just be 'ANY') */
@@ -1830,7 +1818,7 @@ int map_to_request(request_t *request, map_t const *map, radius_map_getvalue_t f
                        goto finish;
 
                case T_OP_SET:
-                       if (tmpl_is_list(map->rhs)) {
+                       if (tmpl_attr_tail_da_is_structural(map->rhs)) {
                                fr_pair_list_free(list);
                                fr_pair_list_append(list, &src_list);
                                fr_pair_list_init(&src_list);
@@ -2266,49 +2254,6 @@ void map_debug_log(request_t *request, map_t const *map, fr_pair_t const *vp)
                fr_pair_aprint_value_quoted(request, &rhs, vp, map->rhs->quote);
                break;
 
-       /*
-        *      For the lists, we can't use the original name, and have to
-        *      rebuild it using tmpl_print, for each attribute we're
-        *      copying.
-        */
-       case TMPL_TYPE_LIST:
-       {
-               tmpl_t          *vpt;
-               fr_token_t      quote;
-
-               switch (vp->vp_type) {
-               case FR_TYPE_QUOTED:
-                       quote = T_DOUBLE_QUOTED_STRING;
-                       break;
-               default:
-                       quote = T_BARE_WORD;
-                       break;
-               }
-
-               vpt = tmpl_alloc(request, TMPL_TYPE_ATTR, quote, map->rhs->name, strlen(map->rhs->name));
-
-               /*
-                *      Fudge a temporary tmpl that describes the attribute we're copying
-                *      this is a combination of the original list tmpl, and values from
-                *      the fr_pair_t.
-                */
-               tmpl_attr_copy(vpt, map->rhs);
-               tmpl_attr_set_leaf_da(vpt, vp->da);
-               tmpl_attr_set_leaf_num(vpt, NUM_UNSPEC);
-
-               /*
-                *      Not appropriate to use map->rhs->quote here, as that's the quoting
-                *      around the list ref. The attribute value has no quoting, so we choose
-                *      the quoting based on the data type.
-                */
-               fr_pair_aprint_value_quoted(request, &value, vp, quote);
-               tmpl_print(&FR_SBUFF_OUT(buffer, sizeof(buffer)), vpt, TMPL_ATTR_REF_PREFIX_YES, NULL);
-               rhs = talloc_typed_asprintf(request, "%s -> %s", buffer, value);
-
-               talloc_free(vpt);
-       }
-               break;
-
        case TMPL_TYPE_ATTR:
        {
                fr_token_t      quote;
@@ -2339,19 +2284,6 @@ void map_debug_log(request_t *request, map_t const *map, fr_pair_t const *vp)
        }
 
        switch (map->lhs->type) {
-       case TMPL_TYPE_LIST:
-               /*
-                *      The MAP may have said "list", but if there's a
-                *      VP, it has it's own name, which isn't in the
-                *      map name.
-                */
-               if (vp) {
-                       tmpl_print(&FR_SBUFF_OUT(buffer, sizeof(buffer)), map->lhs, TMPL_ATTR_REF_PREFIX_YES, NULL);    /* Fixme - bad escaping */
-                       RDEBUG2("%s%s %s %s", buffer, vp->da->name, fr_table_str_by_value(fr_tokens_table, vp->op, "<INVALID>"), rhs);
-                       break;
-               }
-               FALL_THROUGH;
-
        case TMPL_TYPE_ATTR:
                tmpl_print(&FR_SBUFF_OUT(buffer, sizeof(buffer)), map->lhs, TMPL_ATTR_REF_PREFIX_YES, NULL);
                RDEBUG2("%s %s %s", buffer, fr_table_str_by_value(fr_tokens_table, vp ? vp->op : map->op, "<INVALID>"), rhs);
index fdb905e65e9718faa2903876467e10ff5cb230f0..9b1ae5551dd20d753dcbdfe8cf2014bcc17d7282 100644 (file)
@@ -233,7 +233,7 @@ static inline fr_pair_list_t *map_check_src_or_dst(request_t *request, map_t con
  * @param[in,out] ctx          to allocate modification maps in.
  * @param[out] out             Where to write the #fr_pair_t (s), which may be NULL if not found
  * @param[in] request          The current request.
- * @param[in] original         the map. The LHS (dst) has to be #TMPL_TYPE_ATTR or #TMPL_TYPE_LIST.
+ * @param[in] original         the map. The LHS (dst) has to be #TMPL_TYPE_ATTR.
  * @param[in] lhs_result       of previous stack based rhs evaluation.
  *                             Must be provided for rhs types:
  *                             - TMPL_TYPE_XLAT
@@ -265,9 +265,7 @@ int map_to_list_mod(TALLOC_CTX *ctx, vp_list_mod_t **out,
        if (!fr_cond_assert(original->lhs != NULL)) return -1;
        if (!fr_cond_assert(original->rhs != NULL)) return -1;
 
-       fr_assert(tmpl_is_list(original->lhs) ||
-                  tmpl_is_attr(original->lhs) ||
-                  tmpl_is_xlat(original->lhs));
+       fr_assert(tmpl_is_attr(original->lhs) || tmpl_is_xlat(original->lhs));
 
        *out = NULL;
        fr_value_box_list_init(&head);
@@ -279,7 +277,6 @@ int map_to_list_mod(TALLOC_CTX *ctx, vp_list_mod_t **out,
        /*
         *      Already in the correct form.
         */
-       case TMPL_TYPE_LIST:
        case TMPL_TYPE_ATTR:
                break;
 
@@ -332,7 +329,7 @@ int map_to_list_mod(TALLOC_CTX *ctx, vp_list_mod_t **out,
                        fr_value_box_list_talloc_free(lhs_result);
                        goto error;
                }
-               fr_assert(tmpl_is_attr(mutated->lhs) || tmpl_is_list(mutated->lhs));
+               fr_assert(tmpl_is_attr(mutated->lhs));
        }
                break;
 
@@ -361,7 +358,7 @@ int map_to_list_mod(TALLOC_CTX *ctx, vp_list_mod_t **out,
        /*
         *      List to list copy.
         */
-       if (tmpl_is_list(mutated->lhs) && tmpl_is_list(mutated->rhs)) {
+       if (tmpl_attr_tail_da_is_structural(mutated->lhs) && tmpl_attr_tail_da_is_structural(mutated->rhs)) {
                fr_pair_list_t  *list = NULL;
                fr_pair_t       *vp = NULL;
 
@@ -539,8 +536,6 @@ int map_to_list_mod(TALLOC_CTX *ctx, vp_list_mod_t **out,
                int                     err;
 
                fr_assert(fr_value_box_list_empty(rhs_result));
-               fr_assert((tmpl_is_attr(mutated->lhs) && tmpl_attr_tail_da(mutated->lhs)) ||
-                          (tmpl_is_list(mutated->lhs) && !tmpl_attr_tail_da(mutated->lhs)));
 
                /*
                 *      Check source list
@@ -677,8 +672,6 @@ int map_to_list_mod(TALLOC_CTX *ctx, vp_list_mod_t **out,
                 */
                if (tmpl_is_attr(mutated->lhs)) goto assign_values;
 
-               fr_assert(tmpl_is_list(mutated->lhs));
-
                /*
                 *      Empty value - Try and cast an empty string
                 *      to the destination type, and see what
@@ -891,20 +884,6 @@ static inline void map_list_mod_debug(request_t *request,
                rhs = fr_asprintf(request, "%s%pV%s", quote, vb, quote);
                break;
 
-       /*
-        *      For the lists, we can't use the original name, and have to
-        *      rebuild it using tmpl_print, for each attribute we're
-        *      copying.
-        */
-       case TMPL_TYPE_LIST:
-       {
-               char buffer[256];
-
-               tmpl_print(&FR_SBUFF_OUT(buffer, sizeof(buffer)), map->rhs, TMPL_ATTR_REF_PREFIX_YES, NULL);
-               rhs = fr_asprintf(request, "%s -> %s%pV%s", buffer, quote, vb, quote);
-       }
-               break;
-
        case TMPL_TYPE_ATTR:
                rhs = fr_asprintf(request, "%s -> %s%pV%s", map->rhs->name, quote, vb, quote);
                break;
@@ -916,7 +895,6 @@ static inline void map_list_mod_debug(request_t *request,
 
        switch (map->lhs->type) {
        case TMPL_TYPE_ATTR:
-       case TMPL_TYPE_LIST:
                RDEBUG2("%s %s %s", map->lhs->name, fr_table_str_by_value(fr_tokens_table, mod->op, "<INVALID>"), rhs);
                break;
 
@@ -964,7 +942,7 @@ int map_list_mod_apply(request_t *request, vp_list_mod_t const *vlm)
                fr_assert(mod->lhs != NULL);
                fr_assert(mod->rhs != NULL);
 
-               fr_assert(tmpl_is_attr(mod->lhs) || tmpl_is_list(mod->lhs));
+               fr_assert(tmpl_is_attr(mod->lhs));
                fr_assert(((mod->op == T_OP_CMP_FALSE) && tmpl_is_null(mod->rhs)) ||
                           tmpl_is_data(mod->rhs));
 
@@ -994,7 +972,7 @@ int map_list_mod_apply(request_t *request, vp_list_mod_t const *vlm)
        /*
         *      The destination is a list (which is a completely different set of operations)
         */
-       if (tmpl_is_list(map->lhs)) {
+       if (tmpl_attr_tail_da_is_structural(map->lhs)) {
                switch (mod->op) {
                case T_OP_CMP_FALSE:
                        fr_pair_list_free(vp_list);                             /* Clear the entire list */
index 11c3db373f28a7fa7baf1df61635f256aea6c8f8..125438124df8e4c215132794e2f34b08c0ded1bb 100644 (file)
@@ -26,7 +26,7 @@
  * #tmpl_t (VPTs) specify either a data source, or a data sink.
  *
  * Examples of sources are #TMPL_TYPE_XLAT_UNRESOLVED, #TMPL_TYPE_EXEC and #TMPL_TYPE_ATTR.
- * Examples of sinks are #TMPL_TYPE_ATTR, #TMPL_TYPE_LIST.
+ * Examples of sinks are #TMPL_TYPE_ATTR.
  *
  * VPTs are used to gather values or attributes for evaluation, or copying, and to specify
  * where values or #fr_pair_t should be copied to.
@@ -41,7 +41,7 @@
  * @see tmpl_afrom_substr
  * @see tmpl_afrom_attr_str
  *
- * In the case of #TMPL_TYPE_ATTR and #TMPL_TYPE_LIST, there are special cursor overlay
+ * In the case of #TMPL_TYPE_ATTR there are special cursor overlay
  * functions which can be used to iterate over only the #fr_pair_t that match a
  * tmpl_t in a given list.
  *
@@ -67,6 +67,7 @@
  *
  * @copyright 2014-2015 The FreeRADIUS server project
  */
+#include "lib/server/tmpl.h"
 RCSIDH(tmpl_h, "$Id$")
 
 #ifdef __cplusplus
@@ -152,10 +153,6 @@ typedef enum tmpl_type_e {
         */
        TMPL_TYPE_DATA                  = 0x0002,
 
-       /** Reference to an attribute list
-        */
-       TMPL_TYPE_LIST                  = 0x0004 | TMPL_FLAG_ATTR,
-
        /** Reference to one or more attributes
         */
        TMPL_TYPE_ATTR                  = 0x0008 | TMPL_FLAG_ATTR,
@@ -225,7 +222,6 @@ typedef enum tmpl_type_e {
 #define tmpl_is_data(vpt)                      (vpt->type == TMPL_TYPE_DATA)
 
 #define tmpl_is_attr(vpt)                      (vpt->type == TMPL_TYPE_ATTR)
-#define tmpl_is_list(vpt)                      (vpt->type == TMPL_TYPE_LIST)
 
 #define tmpl_is_xlat(vpt)                      (vpt->type == TMPL_TYPE_XLAT)
 #define tmpl_is_exec(vpt)                      (vpt->type == TMPL_TYPE_EXEC)
@@ -259,7 +255,7 @@ typedef struct tmpl_s tmpl_t;
 #include <freeradius-devel/util/packet.h>
 #include <freeradius-devel/util/proto.h>
 #include <freeradius-devel/util/regex.h>
-
+#include <freeradius-devel/server/request.h>
 /*
  *     Allow public and private versions of the same structures
  */
@@ -330,8 +326,6 @@ struct tmpl_attr_rules_s {
        uint8_t                 disallow_qualifiers:1;  //!< disallow request / list qualifiers
 
        uint8_t                 disallow_filters:1;     //!< disallow filters.
-
-       uint8_t                 list_as_attr:1;         //!< return #TMPL_TYPE_ATTR for lists, and not #TMPL_TYPE_LIST
 };
 
 struct tmpl_xlat_rules_s {
@@ -504,6 +498,36 @@ FR_DLIST_FUNCS(tmpl_request_list, tmpl_request_t, entry)
 #define ar_is_unknown(_ar)             ((_ar)->ar_type == TMPL_ATTR_TYPE_UNKNOWN)
 #define ar_is_unresolved(_ar)          ((_ar)->ar_type == TMPL_ATTR_TYPE_UNRESOLVED)
 
+/** Indicate whether an attribute reference is raw
+ *
+ * Determining whether an attribute reference is raw, is slightly more complex
+ * given the raw flag is either coming from the attribute or an internal
+ * "is_raw" flag in the unresolved entry.
+ *
+ * @param[in] ar       to check for rawness.
+ * @return
+ *     - true if the attribute reference is raw.
+ *     - false if the attribute reference is not raw.
+ */
+static inline bool ar_is_raw(tmpl_attr_t const *ar)
+{
+       switch (ar->ar_type) {
+       case TMPL_ATTR_TYPE_NORMAL:
+       case TMPL_ATTR_TYPE_UNKNOWN:
+               return ar->ar_da->flags.is_raw;
+
+       case TMPL_ATTR_TYPE_UNRESOLVED:
+               return ar->ar_unresolved_raw;
+
+       case TMPL_ATTR_TYPE_UNSPEC:
+               return false;
+       }
+
+       fr_assert_fail("ar type (%i) is invalid", (int)ar->ar_type);
+}
+
+bool ar_is_list_attr(tmpl_attr_t const *ar);
+
 #define ar_num                         filter.num
 #define ar_filter_type                 filter.type
 
@@ -518,14 +542,12 @@ FR_DLIST_FUNCS(tmpl_request_list, tmpl_request_t, entry)
  * @section update_maps Use in update map_t
  * When used on the LHS it describes an attribute to create and should be one of these types:
  * - #TMPL_TYPE_ATTR
- * - #TMPL_TYPE_LIST
  *
  * When used on the RHS it describes the value to assign to the attribute being created and
  * should be one of these types:
  * - #TMPL_TYPE_UNRESOLVED
  * - #TMPL_TYPE_XLAT_UNRESOLVED
  * - #TMPL_TYPE_ATTR
- * - #TMPL_TYPE_LIST
  * - #TMPL_TYPE_EXEC
  * - #TMPL_TYPE_DATA
  * - #TMPL_TYPE_XLAT (pre-parsed xlat)
@@ -646,7 +668,7 @@ static inline tmpl_type_t tmpl_type_from_str(char const *type)
 }
 /** @} */
 
-/** @name Field accessors for #TMPL_TYPE_ATTR, #TMPL_TYPE_ATTR_UNRESOLVED, #TMPL_TYPE_LIST
+/** @name Field accessors for #TMPL_TYPE_ATTR, #TMPL_TYPE_ATTR_UNRESOLVED
  *
  * @{
  */
@@ -654,9 +676,7 @@ static inline tmpl_type_t tmpl_type_from_str(char const *type)
 
 static inline FR_DLIST_HEAD(tmpl_request_list) const *tmpl_request(tmpl_t const *vpt)
 {
-       tmpl_assert_type(tmpl_is_attr(vpt) ||
-                        tmpl_is_attr_unresolved(vpt) ||
-                        tmpl_is_list(vpt));
+       tmpl_assert_type(tmpl_contains_attr(vpt));
 
        return &vpt->data.attribute.rr;
 }
@@ -666,13 +686,27 @@ static inline FR_DLIST_HEAD(tmpl_request_list) const *tmpl_request(tmpl_t const
  */
 static inline size_t tmpl_request_ref_count(tmpl_t const *vpt)
 {
-       tmpl_assert_type(tmpl_is_attr(vpt) ||
-                        tmpl_is_attr_unresolved(vpt) ||
-                        tmpl_is_list(vpt));
+       tmpl_assert_type(tmpl_contains_attr(vpt));
 
        return tmpl_request_list_num_elements(&vpt->data.attribute.rr);
 }
 
+/** Return true if the last attribute reference is "normal"
+ *
+ * @hidecallergraph
+ */
+static inline bool tmpl_attr_head_is_list(tmpl_t const *vpt)
+{
+       tmpl_attr_t *ar;
+
+       tmpl_assert_type(tmpl_contains_attr(vpt));
+
+       ar = tmpl_attr_list_head(tmpl_attr(vpt));
+       if (unlikely(!ar)) return false;
+
+       return ar_is_list_attr(ar);
+}
+
 /** Return true if the last attribute reference is "normal"
  *
  * @hidecallergraph
@@ -681,7 +715,7 @@ static inline bool tmpl_attr_tail_is_normal(tmpl_t const *vpt)
 {
        tmpl_attr_t *ar;
 
-       tmpl_assert_type(tmpl_is_attr(vpt));
+       tmpl_assert_type(tmpl_contains_attr(vpt));
 
        ar = tmpl_attr_list_tail(tmpl_attr(vpt));
        if (unlikely(!ar)) return false;
@@ -697,7 +731,7 @@ static inline bool tmpl_attr_tail_is_unspecified(tmpl_t const *vpt)
 {
        tmpl_attr_t *ar;
 
-       tmpl_assert_type(tmpl_is_attr(vpt));
+       tmpl_assert_type(tmpl_contains_attr(vpt));
 
        ar = tmpl_attr_list_tail(tmpl_attr(vpt));
        if (unlikely(!ar)) return false;
@@ -713,7 +747,7 @@ static inline bool tmpl_attr_tail_is_unknown(tmpl_t const *vpt)
 {
        tmpl_attr_t *ar;
 
-       tmpl_assert_type(tmpl_is_attr(vpt));
+       tmpl_assert_type(tmpl_contains_attr(vpt));
 
        ar = tmpl_attr_list_tail(tmpl_attr(vpt));
        if (unlikely(!ar)) return false;
@@ -729,7 +763,7 @@ static inline bool tmpl_attr_tail_is_unresolved(tmpl_t const *vpt)
 {
        tmpl_attr_t *ar;
 
-       tmpl_assert_type(tmpl_is_attr_unresolved(vpt));
+       tmpl_assert_type(tmpl_contains_attr(vpt));
 
        ar = tmpl_attr_list_tail(tmpl_attr(vpt));
        if (unlikely(!ar)) return false;
@@ -737,13 +771,30 @@ static inline bool tmpl_attr_tail_is_unresolved(tmpl_t const *vpt)
        return ar_is_normal(ar);
 }
 
+/** Return true if the last attribute reference is "raw"
+ *
+ * @hidecallergraph
+ */
+static inline bool tmpl_attr_tail_is_raw(tmpl_t const *vpt)
+{
+       tmpl_attr_t *ar;
+
+       tmpl_assert_type(tmpl_contains_attr(vpt));
+
+       ar = tmpl_attr_list_tail(tmpl_attr(vpt));
+       if (unlikely(!ar)) return false;
+
+       return ar_is_raw(ar);
+}
+
+
 /** Return the last attribute reference
  *
  * @hidecallergraph
  */
 static inline tmpl_attr_t const *tmpl_attr_tail(tmpl_t const *vpt)
 {
-       tmpl_assert_type(tmpl_is_attr(vpt));
+       tmpl_assert_type(tmpl_contains_attr(vpt));
 
        return tmpl_attr_list_tail(tmpl_attr(vpt));
 }
@@ -756,7 +807,7 @@ static inline fr_dict_attr_t const *tmpl_attr_tail_da(tmpl_t const *vpt)
 {
        tmpl_attr_t *ar;
 
-       tmpl_assert_type(tmpl_is_attr(vpt));
+       tmpl_assert_type(tmpl_contains_attr(vpt));
 
        ar = tmpl_attr_list_tail(tmpl_attr(vpt));
        if (!ar) return NULL;
@@ -764,6 +815,42 @@ static inline fr_dict_attr_t const *tmpl_attr_tail_da(tmpl_t const *vpt)
        return ar->ar_da;
 }
 
+/** Return true if the the last attribute reference is a leaf attribute
+ *
+ * @hidecallergraph
+ */
+static inline bool tmpl_attr_tail_da_is_leaf(tmpl_t const *vpt)
+{
+       tmpl_attr_t *ar;
+
+       tmpl_assert_type(tmpl_contains_attr(vpt));
+
+       ar = tmpl_attr_list_tail(tmpl_attr(vpt));
+       if (!ar) return false;
+
+       fr_assert(ar_is_normal(ar) || ar_is_unknown(ar));
+
+       return fr_type_is_leaf(ar->ar_da->type);
+}
+
+/** Return true if the the last attribute reference is a structural attribute
+ *
+ * @hidecallergraph
+ */
+static inline bool tmpl_attr_tail_da_is_structural(tmpl_t const *vpt)
+{
+       tmpl_attr_t *ar;
+
+       tmpl_assert_type(tmpl_contains_attr(vpt));
+
+       ar = tmpl_attr_list_tail(tmpl_attr(vpt));
+       if (!ar) return false;
+
+       fr_assert(ar_is_normal(ar) || ar_is_unknown(ar));
+
+       return fr_type_is_structural(ar->ar_da->type);
+}
+
 /** Return the last attribute reference unknown da
  *
  * @hidecallergraph
@@ -772,7 +859,7 @@ static inline fr_dict_attr_t const *tmpl_attr_tail_unknown(tmpl_t const *vpt)
 {
        tmpl_attr_t *ar;
 
-       tmpl_assert_type(tmpl_is_attr(vpt));
+       tmpl_assert_type(tmpl_contains_attr(vpt));
 
        ar = tmpl_attr_list_tail(tmpl_attr(vpt));
        if (!ar) return NULL;
@@ -802,11 +889,7 @@ static inline char const *tmpl_attr_tail_unresolved(tmpl_t const *vpt)
  */
 static inline int16_t tmpl_attr_tail_num(tmpl_t const *vpt)
 {
-       tmpl_assert_type(tmpl_is_attr(vpt) ||
-                        tmpl_is_attr_unresolved(vpt) ||
-                        tmpl_is_list(vpt));
-
-       if (tmpl_is_list(vpt) && (tmpl_attr_list_num_elements(tmpl_attr(vpt)) == 0)) return NUM_ALL;
+       tmpl_assert_type(tmpl_is_attr(vpt) || tmpl_is_attr_unresolved(vpt));
 
        return tmpl_attr_list_tail(tmpl_attr(vpt))->ar_num;
 }
@@ -825,8 +908,7 @@ static inline size_t tmpl_attr_num_elements(tmpl_t const *vpt)
 static inline tmpl_pair_list_t tmpl_list(tmpl_t const *vpt)
 {
        tmpl_assert_type(tmpl_is_attr(vpt) ||
-                        tmpl_is_attr_unresolved(vpt) ||                        /* Remove once list is part of ar dlist */
-                        tmpl_is_list(vpt));
+                        tmpl_is_attr_unresolved(vpt));
 
        return vpt->data.attribute.list;
 }
@@ -872,43 +954,6 @@ void tmpl_attr_verify(char const *file, int line, tmpl_t const *vpt);
 void tmpl_verify(char const *file, int line, tmpl_t const *vpt);
 #endif
 
-/** Produces an initialiser for static #TMPL_TYPE_LIST type #tmpl_t
- *
- * Example:
- @code{.c}
-   static tmpl_t     list = tmpl_init_initialiser_list(CURRENT_REQUEST, PAIR_LIST_REQUEST);
-   fr_dcursor_t      cursor;
-   tmpl_dcursor_ctx_t cc,
-   fr_pair_t        *vp;
-
-   // Iterate over all pairs in the request list
-   for (vp = tmpl_dcursor_init(NULL, &cursor, request, &list);
-       vp;
-       vp = tmpl_cursor_next(&cursor, &list)) {
-       // Do something
-   }
-   tmpl_dcursor_clear(&cc);
- @endcode
- *
- * @param _request to locate the list in.
- * @param _list to set as the target for the template.
- * @see tmpl_dcursor_init
- * @see tmpl_cursor_next
- */
-#define        tmpl_init_initialiser_list(_request, _list)\
-{ \
-       .name = "static", \
-       .len = sizeof("static") - 1, \
-       .type = TMPL_TYPE_LIST, \
-       .quote = T_SINGLE_QUOTED_STRING, \
-       .data = { \
-               .attribute = { \
-                       .request = _request, \
-                       .list = _list \
-               } \
-       } \
-}
-
 /** Determine the correct context and list head
  *
  * Used in conjunction with the fr_dcursor functions to determine the correct list
@@ -1056,6 +1101,11 @@ extern FR_DLIST_HEAD(tmpl_request_list) tmpl_request_def_outer;
  */
 extern FR_DLIST_HEAD(tmpl_request_list) tmpl_request_def_parent;
 
+/** Placeholder attribute for unspecified attribute refs
+ *
+ */
+extern fr_dict_attr_t const *tmpl_attr_unspec;
+
 int                    tmpl_request_ptr(request_t **request, FR_DLIST_HEAD(tmpl_request_list) const *rql) CC_HINT(nonnull);
 
 void                   tmpl_request_ref_list_debug(FR_DLIST_HEAD(tmpl_request_list) const *rql);
index a7467f6386bcd2838e6e1c81c2b34d5b1729c6aa..6ac0cf1e7ef7ec82c10dbf86eae0ba3c963f0fa6 100644 (file)
@@ -104,7 +104,7 @@ void _tmpl_cursor_pair_init(TALLOC_CTX *list_ctx, fr_pair_list_t *list, tmpl_att
        /*
         *      Iterates over attributes of a specific type
         */
-       if (tmpl_is_list(cc->vpt) || ar_is_normal(ar)) {
+       if (ar_is_normal(ar)) {
                fr_pair_dcursor_iter_init(&ns->cursor, list, _tmpl_cursor_child_next, ns);
        /*
         *      Iterates over all attributes at this level
@@ -177,7 +177,7 @@ fr_pair_t *_tmpl_cursor_eval(fr_pair_t *curr, tmpl_dcursor_ctx_t *cc)
                pop = true;
        }
                break;
-       } else goto all_inst;   /* Used for TMPL_TYPE_LIST */
+       } else goto all_inst;
 
        /*
         *      If no pair was found and there is a fill
@@ -206,57 +206,34 @@ static void *_tmpl_cursor_next(UNUSED fr_dlist_head_t *list, void *curr, void *u
 
        fr_pair_t               *vp;
 
-       switch (vpt->type) {
-       case TMPL_TYPE_ATTR:
-       {
-               tmpl_attr_t const       *ar = NULL;
-               tmpl_dcursor_nested_t   *ns = NULL;
-
-               /*
-                *      - Continue until there are no evaluation contexts
-                *      - Push a evaluation context if evaluating the head of the
-                *        stack yields a VP and we're not at the deepest attribute
-                *        reference.
-                *      - Return if we have a VP and there are no more attribute
-                *        references to push, i.e. we're at the deepest attribute
-                *        reference.
-                */
-               while ((ns = fr_dlist_tail(&cc->nested))) {
-                       ar = ns->ar;
-                       vp = _tmpl_cursor_eval(curr, cc);
-                       if (!vp) continue;
-
-                       ar = tmpl_attr_list_next(&vpt->data.attribute.ar, ar);
-                       if (ar) {
-                               fr_pair_list_t          *list_head;
-
-                               list_head = &vp->vp_group;
-                               _tmpl_cursor_pair_init(vp, list_head, ar, cc);
-                               curr = fr_pair_list_head(list_head);
-                               continue;
-                       }
-
-                       return vp;
-               }
-
-       null_result:
-               return NULL;
-       }
+       tmpl_attr_t const       *ar = NULL;
+       tmpl_dcursor_nested_t   *ns = NULL;
 
        /*
-        *      Hacks for evaluating lists
-        *      Hopefully this tmpl type goes away soon...
+        *      - Continue until there are no evaluation contexts
+        *      - Push a evaluation context if evaluating the head of the
+        *        stack yields a VP and we're not at the deepest attribute
+        *        reference.
+        *      - Return if we have a VP and there are no more attribute
+        *        references to push, i.e. we're at the deepest attribute
+        *        reference.
         */
-       case TMPL_TYPE_LIST:
-               if (!fr_dlist_tail(&cc->nested)) goto null_result;      /* end of list */
-
+       while ((ns = fr_dlist_tail(&cc->nested))) {
+               ar = ns->ar;
                vp = _tmpl_cursor_eval(curr, cc);
-               if (!vp) goto null_result;
+               if (!vp) continue;
 
-               return vp;
+               ar = tmpl_attr_list_next(&vpt->data.attribute.ar, ar);
+               if (ar) {
+                       fr_pair_list_t          *list_head;
 
-       default:
-               fr_assert(0);
+                       list_head = &vp->vp_group;
+                       _tmpl_cursor_pair_init(vp, list_head, ar, cc);
+                       curr = fr_pair_list_head(list_head);
+                       continue;
+               }
+
+               return vp;
        }
 
        return NULL;
@@ -347,7 +324,6 @@ fr_pair_t *tmpl_dcursor_init_relative(int *err, TALLOC_CTX *ctx, tmpl_dcursor_ct
         */
        switch (vpt->type) {
        case TMPL_TYPE_ATTR:
-       case TMPL_TYPE_LIST:
                _tmpl_cursor_pair_init(list, cc->list, tmpl_attr_list_head(&vpt->data.attribute.ar), cc);
                break;
 
@@ -367,11 +343,7 @@ fr_pair_t *tmpl_dcursor_init_relative(int *err, TALLOC_CTX *ctx, tmpl_dcursor_ct
        if (!vp) {
                if (err) {
                        *err = -1;
-                       if (tmpl_is_list(vpt)) {
-                               fr_strerror_printf("List \"%s\" is empty", vpt->name);
-                       } else {
-                               fr_strerror_printf("No matching \"%s\" pairs found", tmpl_attr_tail_da(vpt)->name);
-                       }
+                       fr_strerror_printf("No matching \"%s\" pairs found", tmpl_attr_tail_da(vpt)->name);
                }
                return NULL;
        }
@@ -411,7 +383,7 @@ fr_pair_t *_tmpl_dcursor_init(int *err, TALLOC_CTX *ctx, tmpl_dcursor_ctx_t *cc,
 {
        fr_pair_t               *list;
 
-       fr_assert(tmpl_is_attr(vpt) || tmpl_is_list(vpt));
+       fr_assert(tmpl_is_attr(vpt));
 
        if (err) *err = 0;
 
@@ -420,25 +392,11 @@ fr_pair_t *_tmpl_dcursor_init(int *err, TALLOC_CTX *ctx, tmpl_dcursor_ctx_t *cc,
         */
        if (tmpl_request_ptr(&request, tmpl_request(vpt)) < 0) {
                if (err) *err = -3;
-       error:
                memset(cc, 0, sizeof(*cc));     /* so tmpl_dcursor_clear doesn't explode */
                return NULL;
        }
 
-       /*
-        *      Get the right list in the specified context
-        */
-       if (!vpt->rules.attr.list_as_attr) {
-               list = tmpl_get_list(request, vpt);
-               if (!list) {
-                       fr_strerror_printf("List \"%s\" not available in this context",
-                                          fr_table_str_by_value(pair_list_table, tmpl_list(vpt), "<INVALID>"));
-                       if (err) *err = -2;
-                       goto error;
-               }
-       } else {
-               list = request->pair_root;
-       }
+       list = request->pair_root;
 
        return tmpl_dcursor_init_relative(err, ctx, cc, cursor, request, list, vpt, build, uctx);
 }
@@ -536,37 +494,15 @@ int tmpl_extents_find(TALLOC_CTX *ctx,
 
        TMPL_VERIFY(vpt);
 
-       fr_assert(tmpl_is_attr(vpt) || tmpl_is_list(vpt));
+       fr_assert(tmpl_is_attr(vpt));
 
        /*
         *      Navigate to the correct request context
         */
        if (tmpl_request_ptr(&request, tmpl_request(vpt)) < 0) return -3;
 
-       if (!vpt->rules.attr.list_as_attr) {
-               /*
-                *      Get the right list in the specified context
-                */
-               list_head = tmpl_list_head(request, tmpl_list(vpt));
-               if (!list_head) {
-                       fr_strerror_printf("List \"%s\" not available in this context",
-                                          fr_table_str_by_value(pair_list_table, tmpl_list(vpt), "<INVALID>"));
-                       return -2;
-               }
-               list_ctx = tmpl_list_ctx(request, tmpl_list(vpt));
-       } else {
-               list_head = &request->pair_root->vp_group;
-               list_ctx = request->pair_root;
-       }
-
-       /*
-        *      If it's a list, just return the list head
-        */
-       if (vpt->type == TMPL_TYPE_LIST) {
-       do_list:
-               if (existing) EXTENT_ADD(existing, NULL, list_ctx, list_head);
-               return 0;
-       }
+       list_head = &request->pair_root->vp_group;
+       list_ctx = request->pair_root;
 
        /*
         *      If it's a leaf skip all the expensive
@@ -583,7 +519,8 @@ int tmpl_extents_find(TALLOC_CTX *ctx,
                break;
 
        default:
-               goto do_list;
+               if (existing) EXTENT_ADD(existing, NULL, list_ctx, list_head);
+               return 0;
        }
 
        /*
index 1455605e67f1354a16fbc5c986908bcc362fd080..acf6dd4728fde15d1a0a0a84fd0a834f8cd89b4e 100644 (file)
@@ -133,7 +133,13 @@ typedef struct {
 static inline CC_HINT(always_inline)
 int _tmpl_setup_and_cursor_init(fr_pair_t **vp_out, tmpl_dcursor_vars_t *vars, request_t *request, char const *ref)
 {
-       tmpl_afrom_attr_substr(autofree, NULL, &vars->vpt, &FR_SBUFF_IN(ref, strlen(ref)), NULL, &(tmpl_rules_t){.attr = {.dict_def = test_dict}}); 
+       tmpl_afrom_attr_substr(autofree, NULL, &vars->vpt, &FR_SBUFF_IN(ref, strlen(ref)), NULL,
+                              &(tmpl_rules_t){
+                                       .attr = {
+                                               .dict_def = test_dict,
+                                               .list_def = PAIR_LIST_REQUEST
+                                       }
+                               }); 
        TEST_CHECK(vars->vpt!= NULL); 
        TEST_MSG("Failed creating tmpl from %s: %s", ref, fr_strerror()); 
        if (!vars->vpt) { 
@@ -157,8 +163,14 @@ int _tmpl_setup_and_cursor_init(fr_pair_t **vp_out, tmpl_dcursor_vars_t *vars, r
 static inline CC_HINT(always_inline)
 int _tmpl_setup_and_cursor_build_init(fr_pair_t **vp_out, tmpl_dcursor_vars_t *vars, request_t *request, char const *ref)
 {
-       tmpl_afrom_attr_substr(autofree, NULL, &vars->vpt, &FR_SBUFF_IN(ref, strlen(ref)), NULL, &(tmpl_rules_t){.attr = {.dict_def = test_dict}}); 
-       TEST_CHECK(vars->vpt!= NULL); 
+       tmpl_afrom_attr_substr(autofree, NULL, &vars->vpt, &FR_SBUFF_IN(ref, strlen(ref)), NULL,
+                              &(tmpl_rules_t){
+                                       .attr = {
+                                               .dict_def = test_dict,
+                                               .list_def = PAIR_LIST_REQUEST
+                                       }
+                               }); 
+       TEST_CHECK(vars->vpt != NULL); 
        TEST_MSG("Failed creating tmpl from %s: %s", ref, fr_strerror()); 
        if (!vars->vpt) { 
                *vp_out = NULL; 
index ec6b75a3ae598d12f4af0504804b4f489fa601b3..7658538d04bf69b3da5cc0e7d3ee1e062ef62d0f 100644 (file)
@@ -96,44 +96,16 @@ static fr_dict_attr_autoload_t tmpl_dict_attr[] = {
  */
 fr_pair_t *tmpl_get_list(request_t *request, tmpl_t const *vpt)
 {
-       tmpl_pair_list_t list;
+       fr_dict_attr_t const *da;
 
        if (!request) return NULL;
 
-       if (vpt->rules.attr.list_as_attr) {
-               fr_dict_attr_t const *da;
-               da = ((tmpl_attr_t *)tmpl_attr_list_head(&vpt->data.attribute.ar))->ar_da;
+       da = ((tmpl_attr_t *)tmpl_attr_list_head(&vpt->data.attribute.ar))->ar_da;
 
-               if (da == request_attr_request) return request->pair_list.request;
-               if (da == request_attr_reply) return request->pair_list.reply;
-               if (da == request_attr_control) return request->pair_list.control;
-               if (da == request_attr_state) return request->pair_list.state;
-
-               return NULL;
-       }
-
-       list = tmpl_list(vpt);
-
-       switch (list) {
-       /* Don't add default */
-       case PAIR_LIST_UNKNOWN:
-               break;
-
-       case PAIR_LIST_REQUEST:
-               return request->pair_list.request;
-
-       case PAIR_LIST_REPLY:
-               return request->pair_list.reply;
-
-       case PAIR_LIST_CONTROL:
-               return request->pair_list.control;
-
-       case PAIR_LIST_STATE:
-               return request->pair_list.state;
-       }
-
-       RWDEBUG2("List \"%s\" is not available",
-               fr_table_str_by_value(pair_list_table, list, "<INVALID>"));
+       if (da == request_attr_request) return request->pair_list.request;
+       if (da == request_attr_reply) return request->pair_list.reply;
+       if (da == request_attr_control) return request->pair_list.control;
+       if (da == request_attr_state) return request->pair_list.state;
 
        return NULL;
 }
@@ -402,7 +374,6 @@ ssize_t _tmpl_to_type(void *out,
 
        TMPL_VERIFY(vpt);
 
-       fr_assert(!tmpl_is_list(vpt));
        fr_assert(!buff || (bufflen >= 2));
 
        switch (vpt->type) {
@@ -483,7 +454,6 @@ ssize_t _tmpl_to_type(void *out,
         */
        case TMPL_TYPE_UNINITIALISED:
        case TMPL_TYPE_NULL:
-       case TMPL_TYPE_LIST:
        case TMPL_TYPE_EXEC_UNRESOLVED:
        case TMPL_TYPE_ATTR_UNRESOLVED:
        case TMPL_TYPE_XLAT_UNRESOLVED:
@@ -815,7 +785,6 @@ ssize_t _tmpl_to_atype(TALLOC_CTX *ctx, void *out,
         */
        case TMPL_TYPE_UNINITIALISED:
        case TMPL_TYPE_NULL:
-       case TMPL_TYPE_LIST:
        case TMPL_TYPE_EXEC_UNRESOLVED:
        case TMPL_TYPE_REGEX:
        case TMPL_TYPE_REGEX_UNCOMPILED:
@@ -891,7 +860,6 @@ ssize_t _tmpl_to_atype(TALLOC_CTX *ctx, void *out,
  * @param request The current #request_t.
  * @param vpt specifying the #fr_pair_t type or list to copy.
  *     Must be one of the following types:
- *     - #TMPL_TYPE_LIST
  *     - #TMPL_TYPE_ATTR
  * @return
  *     - -1 if no matching #fr_pair_t could be found.
@@ -908,7 +876,7 @@ int tmpl_copy_pairs(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, tm
 
        TMPL_VERIFY(vpt);
 
-       fr_assert(tmpl_is_attr(vpt) || tmpl_is_list(vpt));
+       fr_assert(tmpl_is_attr(vpt));
 
        for (vp = tmpl_dcursor_init(&err, NULL, &cc, &from, request, vpt);
             vp;
@@ -935,7 +903,6 @@ int tmpl_copy_pairs(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, tm
  * @param request The current #request_t.
  * @param vpt specifying the #fr_pair_t type or list to copy.
  *     Must be one of the following types:
- *     - #TMPL_TYPE_LIST
  *     - #TMPL_TYPE_ATTR
  * @return
  *     - -1 if no matching #fr_pair_t could be found.
@@ -952,7 +919,7 @@ int tmpl_copy_pair_children(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *req
 
        TMPL_VERIFY(vpt);
 
-       fr_assert(tmpl_is_attr(vpt) || tmpl_is_list(vpt));
+       fr_assert(tmpl_is_attr(vpt));
 
        fr_pair_list_free(out);
 
@@ -984,7 +951,6 @@ done:
  * @param[in] request The current #request_t.
  * @param[in] vpt specifying the #fr_pair_t type to find.
  *     Must be one of the following types:
- *     - #TMPL_TYPE_LIST
  *     - #TMPL_TYPE_ATTR
  * @return
  *     - 0 on success (found matching #fr_pair_t).
@@ -1337,7 +1303,7 @@ int tmpl_eval_pair(TALLOC_CTX *ctx, FR_DLIST_HEAD(fr_value_box_list) *out, reque
        int                     ret = 0;
        FR_DLIST_HEAD(fr_value_box_list)        list;
 
-       fr_assert(tmpl_is_attr(vpt) || tmpl_is_list(vpt));
+       fr_assert(tmpl_is_attr(vpt));
 
        fr_value_box_list_init(&list);
 
@@ -1492,9 +1458,7 @@ int tmpl_eval(TALLOC_CTX *ctx, FR_DLIST_HEAD(fr_value_box_list) *out, request_t
                return -1;
        }
 
-       if (tmpl_is_attr(vpt) || tmpl_is_list(vpt)) {
-               return tmpl_eval_pair(ctx, out, request, vpt);
-       }
+       if (tmpl_is_attr(vpt)) return tmpl_eval_pair(ctx, out, request, vpt);
 
        if (tmpl_is_data(vpt)) {
                MEM(value = fr_value_box_alloc(ctx, tmpl_value_type(vpt), NULL,
index 4f8180d427c37a8155ef7a90cedbc28fd7a4dab1..b4cbb20bf2f67d4b0cbf66ea8b8f3460baf7f67c 100644 (file)
@@ -24,6 +24,7 @@
  *
  * @copyright 2014-2020 The FreeRADIUS server project
  */
+#include "lib/util/strerror.h"
 RCSID("$Id$")
 
 #define _TMPL_PRIVATE 1
@@ -110,7 +111,6 @@ fr_table_num_ordered_t const tmpl_type_table[] = {
        { L("data"),                    TMPL_TYPE_DATA                  },
 
        { L("attr"),                    TMPL_TYPE_ATTR                  },
-       { L("list"),                    TMPL_TYPE_LIST                  },
 
        { L("exec"),                    TMPL_TYPE_EXEC                  },
        { L("xlat"),                    TMPL_TYPE_XLAT                  },
@@ -284,7 +284,6 @@ void tmpl_attr_debug(tmpl_t const *vpt)
        switch (vpt->type) {
        case TMPL_TYPE_ATTR:
        case TMPL_TYPE_ATTR_UNRESOLVED:
-       case TMPL_TYPE_LIST:
                break;
 
        default:
@@ -320,7 +319,6 @@ void tmpl_debug(tmpl_t const *vpt)
 {
        switch (vpt->type) {
        case TMPL_TYPE_ATTR:
-       case TMPL_TYPE_LIST:
        case TMPL_TYPE_ATTR_UNRESOLVED:
                tmpl_attr_debug(vpt);
                return;
@@ -385,6 +383,22 @@ void tmpl_debug(tmpl_t const *vpt)
        }
 }
 
+/** Indicate whether this attribute reference represents one of packets or legacy lists
+ *
+ * @note This cannot be converted to static inline in tmpl.h because the visibility of
+ *      the dictionary attributes are set to hidden so they can't be accessed by code
+ *      including tmpl.h.
+ */
+bool ar_is_list_attr(tmpl_attr_t const *ar)
+{
+       if (!ar_is_normal(ar)) return false;
+
+       return (ar->ar_da == request_attr_request) ||
+              (ar->ar_da == request_attr_reply) ||
+              (ar->ar_da == request_attr_control) ||
+              (ar->ar_da == request_attr_state);
+}
+
 /** @name Parse list and request qualifiers to #pair_list_t and #tmpl_request_ref_t values
  *
  * These functions also resolve #pair_list_t and #tmpl_request_ref_t values to #request_t
@@ -591,6 +605,7 @@ static fr_slen_t tmpl_request_ref_list_from_substr(TALLOC_CTX *ctx, tmpl_attr_er
        tmpl_request_t          *tail = tmpl_request_list_tail(out);
        unsigned int            depth = 0;
        fr_sbuff_marker_t       m;
+       bool                    seen_outer = false;
 
        if (!at_rules) at_rules = &default_rules.attr;
 
@@ -628,6 +643,36 @@ static fr_slen_t tmpl_request_ref_list_from_substr(TALLOC_CTX *ctx, tmpl_attr_er
                        break;
                }
 
+               switch (ref) {
+               case REQUEST_PARENT:
+               {
+                       if (seen_outer) {
+                               fr_strerror_const("\"parent\" qualifiers not allowed after \"outer\" qualifier");
+                               goto error;
+                       }
+               }
+                       break;
+
+               case REQUEST_OUTER:
+               {
+                       if (seen_outer) {
+                               fr_strerror_const("Duplicate \"outer\" request qualifiers not allowed");
+                       error:
+                               tmpl_request_list_talloc_free_to_tail(out, tail);
+                               FR_SBUFF_ERROR_RETURN(&our_in);                         
+                       }
+                       seen_outer = true;
+               }
+                       break;
+                       
+               case REQUEST_CURRENT:
+                       break;
+                       
+               case REQUEST_UNKNOWN:
+                       fr_assert(0);
+                       goto error;
+               }
+
                /*
                 *      We don't want to misidentify the list
                 *      as being part of an attribute.
@@ -641,9 +686,7 @@ static fr_slen_t tmpl_request_ref_list_from_substr(TALLOC_CTX *ctx, tmpl_attr_er
                        if (err) *err = TMPL_ATTR_ERROR_INVALID_LIST_QUALIFIER;
 
                        fr_sbuff_set(&our_in, in);      /* Marker at the start */
-               error:
-                       tmpl_request_list_talloc_free_to_tail(out, tail);
-                       FR_SBUFF_ERROR_RETURN(&our_in);
+                       goto error;
                }
 
                /*
@@ -748,7 +791,6 @@ static inline CC_HINT(always_inline) void tmpl_type_init(tmpl_t *vpt, tmpl_type_
 
        case TMPL_TYPE_ATTR:
        case TMPL_TYPE_ATTR_UNRESOLVED:
-       case TMPL_TYPE_LIST:
                tmpl_attr_list_talloc_init(tmpl_attr(vpt));
                tmpl_request_list_talloc_init(&vpt->data.attribute.rr);
                break;
@@ -1162,7 +1204,7 @@ void tmpl_attr_set_leaf_num(tmpl_t *vpt, int16_t num)
 {
        tmpl_attr_t *ar;
 
-       tmpl_assert_type(tmpl_is_attr(vpt) || tmpl_is_list(vpt) || tmpl_is_attr_unresolved(vpt));
+       tmpl_assert_type(tmpl_is_attr(vpt) || tmpl_is_attr_unresolved(vpt));
 
        if (tmpl_attr_list_num_elements(tmpl_attr(vpt)) == 0) {
                ar = tmpl_attr_add(vpt, TMPL_ATTR_TYPE_UNKNOWN);
@@ -1182,7 +1224,7 @@ void tmpl_attr_rewrite_leaf_num(tmpl_t *vpt, int16_t from, int16_t to)
 {
        tmpl_attr_t *ref = NULL;
 
-       tmpl_assert_type(tmpl_is_attr(vpt) || tmpl_is_list(vpt) || tmpl_is_attr_unresolved(vpt));
+       tmpl_assert_type(tmpl_is_attr(vpt) || tmpl_is_attr_unresolved(vpt));
 
        if (tmpl_attr_list_num_elements(tmpl_attr(vpt)) == 0) return;
 
@@ -1199,7 +1241,7 @@ void tmpl_attr_rewrite_num(tmpl_t *vpt, int16_t from, int16_t to)
 {
        tmpl_attr_t *ref = NULL;
 
-       tmpl_assert_type(tmpl_is_attr(vpt) || tmpl_is_list(vpt) || tmpl_is_attr_unresolved(vpt));
+       tmpl_assert_type(tmpl_is_attr(vpt) || tmpl_is_attr_unresolved(vpt));
 
        while ((ref = tmpl_attr_list_next(tmpl_attr(vpt), ref))) if (ref->ar_num == from) ref->ar_num = to;
 
@@ -1305,6 +1347,7 @@ static inline CC_HINT(always_inline) void tmpl_attr_insert(tmpl_t *vpt, tmpl_att
                while ((ar = tmpl_attr_list_prev(tmpl_attr(vpt), ar))) ar->resolve_only = true;
                break;
        }
+       TMPL_ATTR_VERIFY(vpt);
 }
 
 /** Parse array subscript and in future other filters
@@ -1397,8 +1440,6 @@ static fr_slen_t tmpl_attr_parse_filter(tmpl_attr_error_t *err, tmpl_attr_t *ar,
        FR_SBUFF_SET_RETURN(name, &our_name);
 }
 
-extern fr_dict_attr_t const *tmpl_attr_unspec;
-
 static inline CC_HINT(nonnull(3,4))
 fr_slen_t tmpl_attr_ref_from_unspecified_substr(tmpl_attr_t *ar, tmpl_attr_error_t *err,
                                                tmpl_t *vpt,
@@ -1949,21 +1990,20 @@ do_suffix:
                tmpl_attr_insert(vpt, ar);
        }
 
-       if (tmpl_is_attr(vpt) && (tmpl_rules_cast(vpt) == tmpl_attr_tail_da(vpt)->type)) vpt->rules.cast = FR_TYPE_NULL;
+       if (tmpl_is_attr(vpt) && tmpl_attr_tail_is_normal(vpt) &&
+           (tmpl_rules_cast(vpt) == tmpl_attr_tail_da(vpt)->type)) vpt->rules.cast = FR_TYPE_NULL;
 
        fr_sbuff_marker_release(&m_s);
        return 0;
 }
 
-/** Parse a string into a TMPL_TYPE_ATTR_* or #TMPL_TYPE_LIST type #tmpl_t
+/** Parse a string into a TMPL_TYPE_ATTR_* of type #tmpl_t
  *
  * @param[in,out] ctx          to allocate #tmpl_t in.
  * @param[out] err             May be NULL.  Provides the exact error that the parser hit
  *                             when processing the attribute ref.
  * @param[out] out             Where to write pointer to new #tmpl_t.
  * @param[in] name             of attribute including #tmpl_request_ref_t and #pair_list_t qualifiers.
- *                             If only #tmpl_request_ref_t #pair_list_t qualifiers are found,
- *                             a #TMPL_TYPE_LIST #tmpl_t will be produced.
  * @param[in] p_rules          Formatting rules used to check for trailing garbage.
  * @param[in] t_rules          Rules which control parsing:
  *                             - dict_def              The default dictionary to use if attributes
@@ -2006,13 +2046,18 @@ ssize_t tmpl_afrom_attr_substr(TALLOC_CTX *ctx, tmpl_attr_error_t *err,
                               tmpl_rules_t const *t_rules)
 {
        int                             ret;
-       size_t                          list_len = 0;
        tmpl_t                          *vpt;
        fr_sbuff_t                      our_name = FR_SBUFF(name);      /* Take a local copy in case we need to back track */
        bool                            ref_prefix = false;
        bool                            is_raw = false;
        tmpl_attr_rules_t const         *at_rules;
        fr_sbuff_marker_t               m_l;
+       tmpl_attr_t                     *ar;
+
+       fr_assert_msg((request_attr_request != NULL) &&
+                     (request_attr_reply != NULL) &&
+                     (request_attr_control != NULL) &&
+                     (request_attr_state != NULL), "missing list attr. request_global_init not called");
 
        if (!t_rules) t_rules = &default_rules;
        at_rules = &t_rules->attr;
@@ -2069,10 +2114,10 @@ ssize_t tmpl_afrom_attr_substr(TALLOC_CTX *ctx, tmpl_attr_error_t *err,
         *      Parse one or more request references
         */
        ret = tmpl_request_ref_list_from_substr(vpt, NULL,
-                                             &vpt->data.attribute.rr,
-                                             &our_name,
-                                             p_rules,
-                                             at_rules);
+                                               &vpt->data.attribute.rr,
+                                               &our_name,
+                                               p_rules,
+                                               at_rules);
        if (ret < 0) {
        error:
                *out = NULL;
@@ -2082,138 +2127,69 @@ ssize_t tmpl_afrom_attr_substr(TALLOC_CTX *ctx, tmpl_attr_error_t *err,
 
        fr_sbuff_marker(&m_l, &our_name);
 
-       if (!at_rules->list_as_attr) {
-               /*
-                *      Parse the list reference
-                *
-                *      This code should be removed when lists
-                *      are integrated into attribute references.
-                */
-               fr_sbuff_out_by_longest_prefix(&list_len, &vpt->data.attribute.list, pair_list_table,
-                                              &our_name, at_rules->list_def);
-
-               /*
-                *      Check if we need to backtrack
-                *
-                *      Lists can be followed by a '.', '[', or the end of the attribute reference
-                *
-                *      If we don't find any of those things it wasn't an actual list match
-                *      but one of the list identifiers matched part of an attribute reference.
-                *
-                *      i.e. reply with reply-message.
-                */
-               if ((list_len > 0) && !fr_sbuff_is_char(&our_name, '.') &&
-                   !fr_sbuff_is_char(&our_name, '[') && !tmpl_substr_terminal_check(&our_name, p_rules)) {
-                       fr_sbuff_set(&our_name, &m_l);
-                       list_len = 0;
-                       vpt->data.attribute.list = at_rules->list_def;
-               }
-
-               if ((at_rules->parent || at_rules->disallow_qualifiers) && (list_len > 0)) {
-                       fr_strerror_const("It is not permitted to specify a pair list here");
-                       if (err) *err = TMPL_ATTR_ERROR_INVALID_LIST_QUALIFIER;
-                       talloc_free(vpt);
-                       FR_SBUFF_ERROR_RETURN(&our_name);
-               }
-       }
-
        /*
-        *      Parse the attribute reference
+        *      Start parsing attribute references
         *
-        *      This will either be after:
-        *      - A zero length list, i.e. just after the prefix '&', in which case we require an attribue
-        *      - '.' and then an allowed char, so we're sure it's not just a bare list ref.
+        *      This includes lists, like request,
+        *      reply, control etc...
         */
-       if ((list_len == 0) ||
-           (fr_sbuff_next_if_char(&our_name, '.') && fr_sbuff_is_in_charset(&our_name, fr_dict_attr_allowed_chars))) {
-               ret = tmpl_attr_afrom_attr_substr(vpt, err,
-                                                 vpt,
-                                                 at_rules->parent, at_rules->parent,
-                                                 &our_name, p_rules, at_rules, 0);
-               if (ret < 0) goto error;
+       ret = tmpl_attr_afrom_attr_substr(vpt, err,
+                                         vpt,
+                                         at_rules->parent, at_rules->parent,
+                                         &our_name, p_rules, at_rules, 0);
+       if (ret < 0) goto error;
 
-               /*
-                *      Check to see if the user wants the leaf
-                *      attribute to be raw.
-                *
-                *      We can only do the conversion now _if_
-                *      the complete hierarchy has been resolved
-                *      otherwise we'll need to do the conversion
-                *      later.
-                */
-               if (tmpl_is_attr(vpt) && is_raw) tmpl_attr_to_raw(vpt);
+       /*
+        *      Check to see if the user wants the leaf
+        *      attribute to be raw.
+        *
+        *      We can only do the conversion now _if_
+        *      the complete hierarchy has been resolved
+        *      otherwise we'll need to do the conversion
+        *      later.
+        */
+       if (tmpl_is_attr(vpt) && is_raw) tmpl_attr_to_raw(vpt);
 
-               /*
-                *      Check to see what the first attribute reference
-                *      was.  If it wasn't a known list group attribute
-                *      and we're parsing in list_as_attr mode, then
-                *      we need to add in a default list.
-                */
-               if (at_rules->list_as_attr) {
-                       tmpl_attr_t *ar;
-
-                       ar = tmpl_attr_list_head(tmpl_attr(vpt));
-                       fr_assert(ar != NULL);
-
-                       if ((ar->ar_type != TMPL_ATTR_TYPE_NORMAL) ||
-                           ((ar->ar_da != request_attr_request) &&
-                            (ar->ar_da != request_attr_reply) &&
-                            (ar->ar_da != request_attr_control) &&
-                            (ar->ar_da != request_attr_state))) {
-                               MEM(ar = talloc(vpt, tmpl_attr_t));
-                               *ar = (tmpl_attr_t){
-                                       .ar_type = TMPL_ATTR_TYPE_NORMAL,
-                                       .ar_parent = fr_dict_root(fr_dict_internal())
-                               };
-
-                               switch (at_rules->list_def) {
-                               default:
-                               case PAIR_LIST_REQUEST:
-                                       ar->ar_da = request_attr_request;
-                                       break;
+       /*
+        *      Add the default list qualifier if a list
+        *      wasn't specified.
+        *
+        *      This will likely go away when we have
+        *      local attributes/variables.
+        */
+       if (!tmpl_attr_head_is_list(vpt)) {
+               MEM(ar = talloc(vpt, tmpl_attr_t));
+               *ar = (tmpl_attr_t){
+                       .ar_type = TMPL_ATTR_TYPE_NORMAL,
+                       .ar_num = NUM_UNSPEC,
+                       .ar_parent = fr_dict_root(fr_dict_internal())
+               };
 
-                               case PAIR_LIST_REPLY:
-                                       ar->ar_da = request_attr_reply;
-                                       break;
+               switch (at_rules->list_def) {
+               default:
+               case PAIR_LIST_REQUEST:
+                       ar->ar_da = request_attr_request;
+                       break;
 
-                               case PAIR_LIST_CONTROL:
-                                       ar->ar_da = request_attr_control;
-                                       break;
+               case PAIR_LIST_REPLY:
+                       ar->ar_da = request_attr_reply;
+                       break;
 
-                               case PAIR_LIST_STATE:
-                                       ar->ar_da = request_attr_state;
-                                       break;
-                               }
+               case PAIR_LIST_CONTROL:
+                       ar->ar_da = request_attr_control;
+                       break;
 
-                               /*
-                                *      Prepend the list ref so it gets evaluated
-                                *      first.
-                                */
-                               tmpl_attr_list_insert_head(tmpl_attr(vpt), ar);
-                       }
+               case PAIR_LIST_STATE:
+                       ar->ar_da = request_attr_state;
+                       break;
                }
-       }
 
-       /*
-        *      If there's no attribute references
-        *      treat this as a list reference.
-        *
-        *      Eventually we'll remove TMPL_TYPE_LIST
-        */
-       if (!at_rules->list_as_attr && (tmpl_attr_list_num_elements(tmpl_attr(vpt)) == 0)) {
-               tmpl_attr_t     *ar;
-               fr_slen_t       slen;
-
-               MEM(ar = talloc_zero(vpt, tmpl_attr_t));
-               slen = tmpl_attr_parse_filter(err, ar, &our_name, at_rules);
-               if (slen == 0) {                        /* No filter */
-                       talloc_free(ar);
-               } else if (slen > 0) {                          /* Found a filter */
-                       tmpl_attr_list_insert_tail(&vpt->data.attribute.ar, ar);
-               } else if (slen < 0) {                          /* Filter error */
-                       goto error;
-               }
-               vpt->type = TMPL_TYPE_LIST;
+               /*
+                *      Prepend the list ref so it gets evaluated
+                *      first.
+                */
+               tmpl_attr_list_insert_head(&vpt->data.attribute.ar, ar);
+               TMPL_ATTR_VERIFY(vpt);
        }
 
        tmpl_set_name(vpt, T_BARE_WORD, fr_sbuff_start(&our_name), fr_sbuff_used(&our_name));
@@ -2237,33 +2213,6 @@ ssize_t tmpl_afrom_attr_substr(TALLOC_CTX *ctx, tmpl_attr_error_t *err,
                if (tmpl_attr_tail_is_normal(vpt) && (tmpl_attr_tail_da(vpt)->type == tmpl_rules_cast(vpt))) {
                        vpt->rules.cast = FR_TYPE_NULL;
                }
-
-               /*
-                *      Ensure that the list is set correctly, so that
-                *      the returned vpt just doesn't just match the
-                *      input rules, it is also internally consistent.
-                */
-               if (at_rules->list_as_attr) {
-                       tmpl_attr_t *ar;
-
-                       ar = tmpl_attr_list_head(tmpl_attr(vpt));
-                       fr_assert(ar != NULL);
-
-                       if (ar->ar_da == request_attr_request) {
-                               vpt->rules.attr.list_def = PAIR_LIST_REQUEST;
-
-                       } else if (ar->ar_da == request_attr_reply) {
-                               vpt->rules.attr.list_def = PAIR_LIST_REPLY;
-
-                       } else if (ar->ar_da == request_attr_control) {
-                               vpt->rules.attr.list_def = PAIR_LIST_CONTROL;
-
-                       } else if (ar->ar_da == request_attr_state) {
-                               vpt->rules.attr.list_def = PAIR_LIST_STATE;
-                       }
-
-                       vpt->data.attribute.list = vpt->rules.attr.list_def;
-               }
        }
 
        if (!tmpl_substr_terminal_check(&our_name, p_rules)) {
@@ -2291,15 +2240,13 @@ ssize_t tmpl_afrom_attr_substr(TALLOC_CTX *ctx, tmpl_attr_error_t *err,
        FR_SBUFF_SET_RETURN(name, &our_name);
 }
 
-/** Parse a string into a TMPL_TYPE_ATTR_* or #TMPL_TYPE_LIST type #tmpl_t
+/** Parse a string into a TMPL_TYPE_ATTR_* #tmpl_t
  *
  * @param[in,out] ctx          to allocate #tmpl_t in.
  * @param[out] err             May be NULL.  Provides the exact error that the parser hit
  *                             when processing the attribute ref.
  * @param[out] out             Where to write pointer to new #tmpl_t.
- * @param[in] name             of attribute including #tmpl_request_ref_t and #pair_list_t qualifiers.
- *                             If only #tmpl_request_ref_t #pair_list_t qualifiers are found,
- *                             a #TMPL_TYPE_LIST #tmpl_t will be produced.
+ * @param[in] name             of attribute including #tmpl_request_ref_t qualifiers.
  * @param[in] t_rules          Rules which control parsing.  See tmpl_afrom_attr_substr() for details.
  *
  * @note Unlike #tmpl_afrom_attr_substr this function will error out if the entire
@@ -4010,7 +3957,6 @@ void tmpl_unresolve(tmpl_t *vpt)
         *      These types contain dynamically allocated
         *      attribute and request references.
         */
-       case TMPL_TYPE_LIST:
        case TMPL_TYPE_ATTR:
        case TMPL_TYPE_ATTR_UNRESOLVED:
                tmpl_attr_list_talloc_free(tmpl_attr(vpt));
@@ -4137,7 +4083,7 @@ int tmpl_attr_unknown_add(tmpl_t *vpt)
 
        TMPL_VERIFY(vpt);
 
-       if (!tmpl_attr_tail_da(vpt)->flags.is_unknown) return 1;        /* Ensure at least the leaf is unknown */
+       if (!tmpl_attr_tail_is_unknown(vpt)) return 1;  /* Ensure at least the leaf is unknown */
 
        while ((ar = tmpl_attr_list_next(tmpl_attr(vpt), ar))) {
                fr_dict_attr_t const    *unknown, *known;
@@ -4329,7 +4275,7 @@ fr_slen_t tmpl_request_ref_list_print(fr_sbuff_t *out, FR_DLIST_HEAD(tmpl_reques
  */
 fr_slen_t tmpl_attr_print(fr_sbuff_t *out, tmpl_t const *vpt, tmpl_attr_prefix_t ar_prefix)
 {
-       tmpl_attr_t             *ar = NULL;
+       tmpl_attr_t const       *ar = NULL;
        fr_da_stack_t           stack;
        char                    printed_rr = false;
        fr_sbuff_t              our_out = FR_SBUFF(out);
@@ -4341,7 +4287,6 @@ fr_slen_t tmpl_attr_print(fr_sbuff_t *out, tmpl_t const *vpt, tmpl_attr_prefix_t
         *      Only print things we can print...
         */
        switch (vpt->type) {
-       case TMPL_TYPE_LIST:
        case TMPL_TYPE_ATTR_UNRESOLVED:
        case TMPL_TYPE_ATTR:
                break;
@@ -4391,26 +4336,14 @@ fr_slen_t tmpl_attr_print(fr_sbuff_t *out, tmpl_t const *vpt, tmpl_attr_prefix_t
         *      we add the .unknown prefix.
         *
         */
-       if (!tmpl_is_list(vpt) && (ar = tmpl_attr_list_tail(tmpl_attr(vpt)))) {
-               switch (ar->type) {
-               case TMPL_ATTR_TYPE_NORMAL:
-               case TMPL_ATTR_TYPE_UNSPEC:
-               case TMPL_ATTR_TYPE_UNKNOWN:
-                       if (ar->ar_da->flags.is_raw) FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "raw.");
-                       break;
-
-               case TMPL_ATTR_TYPE_UNRESOLVED:
-                       if (ar->ar_unresolved_raw) FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "raw.");
-                       break;
-               }
-       }
+       if (tmpl_attr_tail_is_raw(vpt)) FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "raw.");
 
        /*
         *      Print attribute identifiers
         */
        ar = NULL;
        while ((ar = tmpl_attr_list_next(tmpl_attr(vpt), ar))) {
-               if (!tmpl_is_list(vpt)) switch(ar->type) {
+               switch(ar->type) {
                case TMPL_ATTR_TYPE_UNSPEC:
                        break;
 
@@ -4559,7 +4492,6 @@ fr_slen_t tmpl_print(fr_sbuff_t *out, tmpl_t const *vpt,
        TMPL_VERIFY(vpt);
 
        switch (vpt->type) {
-       case TMPL_TYPE_LIST:
        case TMPL_TYPE_ATTR_UNRESOLVED:
        case TMPL_TYPE_ATTR:
                FR_SBUFF_RETURN(tmpl_attr_print, &our_out, vpt, ar_prefix);
@@ -4713,7 +4645,7 @@ void tmpl_attr_verify(char const *file, int line, tmpl_t const *vpt)
        tmpl_attr_t     *seen_unknown = NULL;
        tmpl_attr_t     *seen_unresolved = NULL;
 
-       fr_assert(tmpl_is_attr_unresolved(vpt) || tmpl_is_attr(vpt) || tmpl_is_list(vpt));
+       fr_assert(tmpl_is_attr_unresolved(vpt) || tmpl_is_attr(vpt));
 
        /*
         *      Loop detection
@@ -4739,7 +4671,7 @@ void tmpl_attr_verify(char const *file, int line, tmpl_t const *vpt)
         *      Known attribute cannot come after unresolved or unknown attributes
         *      Unknown attributes cannot come after unresolved attributes
         */
-       if (!tmpl_is_list(vpt)) while ((ar = tmpl_attr_list_next(tmpl_attr(vpt), ar))) {
+       while ((ar = tmpl_attr_list_next(tmpl_attr(vpt), ar))) {
                switch (ar->type) {
                case TMPL_ATTR_TYPE_NORMAL:
                        if (seen_unknown) {
@@ -4765,6 +4697,7 @@ void tmpl_attr_verify(char const *file, int line, tmpl_t const *vpt)
                        fr_fatal_assert_msg(ar->ar_parent,
                                            "CONSISTENCY CHECK FAILED %s[%u]: attr ref missing parent",
                                            file, line);
+                       DA_VERIFY(ar->ar_da);
                        break;
 
                case TMPL_ATTR_TYPE_UNSPEC:
@@ -4973,35 +4906,10 @@ void tmpl_verify(char const *file, int line, tmpl_t const *vpt)
                                                     da, da->name,
                                                     fr_type_to_str(da->type));
                        }
-
-                       if (!vpt->rules.attr.list_as_attr && (tmpl_list(vpt) >= PAIR_LIST_UNKNOWN)) {
-                               fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_ATTR "
-                                                    "attribute \"%s\" has invalid list (%i)",
-                                                    file, line, tmpl_attr_tail_da(vpt)->name, tmpl_list(vpt));
-                       }
-
                        tmpl_attr_verify(file, line, vpt);
                }
                break;
 
-       case TMPL_TYPE_LIST:
-               if ((nz = CHECK_ZEROED(vpt, attribute))) {
-                       PRINT_NON_ZEROED(vpt, attribute, nz);
-                       fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_LIST"
-                                            "has non-zero bytes after the data.attribute struct in the union",
-                                            file, line);
-               }
-
-               if ((tmpl_attr_list_num_elements(tmpl_attr(vpt)) > 0) &&
-                   ((tmpl_attr_t *)tmpl_attr_list_tail(tmpl_attr(vpt)))->da) {
-#ifndef NDEBUG
-                       tmpl_attr_debug(vpt);
-#endif
-                       fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_LIST contains %u "
-                                            "references", file, line, tmpl_attr_list_num_elements(tmpl_attr(vpt)));
-               }
-               break;
-
        case TMPL_TYPE_DATA:
                if ((nz = CHECK_ZEROED(vpt, literal))) {
                        PRINT_NON_ZEROED(vpt, literal, nz);
index 2c42df18d0772972526ef330555afb555c8c3271..67f0bc8c5ff0fccf58416469afe838eb5d680a83 100644 (file)
@@ -851,7 +851,6 @@ int unlang_fixup_update(map_t *map, void *ctx)
        if (!ctx) {
                switch (map->lhs->type) {
                case TMPL_TYPE_ATTR:
-               case TMPL_TYPE_LIST:
                        tmpl_attr_rewrite_leaf_num(map->lhs, NUM_UNSPEC, NUM_ALL);
                        break;
 
@@ -864,7 +863,6 @@ int unlang_fixup_update(map_t *map, void *ctx)
                 */
                switch (map->rhs->type) {
                case TMPL_TYPE_ATTR:
-               case TMPL_TYPE_LIST:
                        tmpl_attr_rewrite_leaf_num(map->rhs, NUM_UNSPEC, NUM_ALL);
                        break;
 
@@ -893,15 +891,6 @@ int unlang_fixup_update(map_t *map, void *ctx)
         *      Lots of sanity checks for insane people...
         */
 
-       /*
-        *      What exactly where you expecting to happen here?
-        */
-       if (tmpl_is_attr(map->lhs) &&
-           tmpl_is_list(map->rhs)) {
-               cf_log_err(map->ci, "Can't copy list into an attribute");
-               return -1;
-       }
-
        /*
         *      Depending on the attribute type, some operators are disallowed.
         */
@@ -918,75 +907,6 @@ int unlang_fixup_update(map_t *map, void *ctx)
                }
        }
 
-       if (tmpl_is_list(map->lhs)) {
-               /*
-                *      Can't copy an xlat expansion or literal into a list,
-                *      we don't know what type of attribute we'd need
-                *      to create.
-                *
-                *      The only exception is where were using a unary
-                *      operator like !*.
-                */
-               if (map->op != T_OP_CMP_FALSE) switch (map->rhs->type) {
-               case TMPL_TYPE_XLAT_UNRESOLVED:
-               case TMPL_TYPE_UNRESOLVED:
-                       cf_log_err(map->ci, "Can't copy value into list (we don't know which attribute to create)");
-                       return -1;
-
-               default:
-                       break;
-               }
-
-               /*
-                *      Only += and :=, and !*, and ^= operators are supported
-                *      for lists.
-                */
-               switch (map->op) {
-               case T_OP_CMP_FALSE:
-                       break;
-
-               case T_OP_ADD_EQ:
-                       if (!tmpl_is_list(map->rhs) &&
-                           !tmpl_is_exec(map->rhs)) {
-                               cf_log_err(map->ci, "Invalid source for list assignment '%s += ...'", map->lhs->name);
-                               return -1;
-                       }
-                       break;
-
-               case T_OP_SET:
-                       if (tmpl_is_exec(map->rhs)) {
-                               WARN("%s[%d]: Please change ':=' to '=' for list assignment",
-                                    cf_filename(cp), cf_lineno(cp));
-                       }
-
-                       if (!tmpl_is_list(map->rhs)) {
-                               cf_log_err(map->ci, "Invalid source for list assignment '%s := ...'", map->lhs->name);
-                               return -1;
-                       }
-                       break;
-
-               case T_OP_EQ:
-                       if (!tmpl_is_exec(map->rhs)) {
-                               cf_log_err(map->ci, "Invalid source for list assignment '%s = ...'", map->lhs->name);
-                               return -1;
-                       }
-                       break;
-
-               case T_OP_PREPEND:
-                       if (!tmpl_is_list(map->rhs) &&
-                           !tmpl_is_exec(map->rhs)) {
-                               cf_log_err(map->ci, "Invalid source for list assignment '%s ^= ...'", map->lhs->name);
-                               return -1;
-                       }
-                       break;
-
-               default:
-                       cf_log_err(map->ci, "Operator \"%s\" not allowed for list assignment",
-                                  fr_table_str_by_value(fr_tokens_table, map->op, "<INVALID>"));
-                       return -1;
-               }
-       }
-
        /*
         *      If the map has a unary operator there's no further
         *      processing we need to, as RHS is unused.
@@ -1035,7 +955,6 @@ int unlang_fixup_update(map_t *map, void *ctx)
        return 0;
 }
 
-
 static unlang_group_t *group_allocate(unlang_t *parent, CONF_SECTION *cs, unlang_ext_t const *ext)
 {
        unlang_group_t  *g;
@@ -1827,7 +1746,6 @@ static unlang_t *compile_edit_section(unlang_t *parent, unlang_compile_t *unlang
         */
        t_rules = *(unlang_ctx->rules);
        t_rules.attr.allow_unknown = true;
-       t_rules.attr.list_as_attr = true;
        RULES_VERIFY(&t_rules);
 
        c = *prev;
@@ -1948,7 +1866,6 @@ static unlang_t *compile_edit_pair(unlang_t *parent, unlang_compile_t *unlang_ct
         */
        t_rules = *(unlang_ctx->rules);
        t_rules.attr.allow_unknown = true;
-       t_rules.attr.list_as_attr = true;
        RULES_VERIFY(&t_rules);
 
        /*
@@ -2968,11 +2885,6 @@ static unlang_t *compile_switch(unlang_t *parent, unlang_compile_t *unlang_ctx,
                return NULL;
        }
 
-       if (tmpl_is_list(gext->vpt)) {
-               cf_log_err(cs, "Cannot use list for 'switch' statement");
-               goto error;
-       }
-
        if (tmpl_contains_regex(gext->vpt)) {
                cf_log_err(cs, "Cannot use regular expression for 'switch' statement");
                goto error;
@@ -3299,11 +3211,6 @@ static unlang_t *compile_timeout(unlang_t *parent, unlang_compile_t *unlang_ctx,
                        return NULL;
                }
 
-               if (tmpl_is_list(vpt)) {
-                       cf_log_err(cs, "Cannot use list as argument for 'timeout' statement");
-                       goto error;
-               }
-
                if (tmpl_contains_regex(vpt)) {
                        cf_log_err(cs, "Cannot use regular expression as argument for 'timeout' statement");
                        goto error;
@@ -3406,11 +3313,6 @@ static unlang_t *compile_limit(unlang_t *parent, unlang_compile_t *unlang_ctx, C
                return NULL;
        }
 
-       if (tmpl_is_list(vpt)) {
-               cf_log_err(cs, "Cannot use list as argument for 'limit' statement");
-               goto error;
-       }
-
        if (tmpl_contains_regex(vpt)) {
                cf_log_err(cs, "Cannot use regular expression as argument for 'limit' statement");
                goto error;
@@ -3521,8 +3423,8 @@ static unlang_t *compile_foreach(unlang_t *parent, unlang_compile_t *unlang_ctx,
         */
        fr_assert(vpt);
 
-       if (!tmpl_is_attr(vpt) && !tmpl_is_list(vpt)) {
-               cf_log_err(cs, "MUST use attribute or list reference (not %s) in 'foreach'",
+       if (!tmpl_is_attr(vpt)) {
+               cf_log_err(cs, "MUST use attribute reference (not %s) in 'foreach'",
                           tmpl_type_to_str(vpt->type));
                talloc_free(vpt);
                return NULL;
@@ -3743,7 +3645,7 @@ static unlang_t *compile_if_subsection(unlang_t *parent, unlang_compile_t *unlan
 
                        fr_canonicalize_error(cs, &spaces, &text, slen, name2);
 
-                       cf_log_err(cs, "Parse error in condition!!!!");
+                       cf_log_err(cs, "Parse error in condition");
                        cf_log_err(cs, "%s", text);
                        cf_log_err(cs, "%s^ %s", spaces, fr_strerror());
 
index 9075708a07aa2002b6244dd263dadda47ac96d53..cd35fc60ea5a95030c2d0254e852e5a21e7bbfd6 100644 (file)
@@ -204,16 +204,9 @@ static unlang_action_t unlang_subrequest_parent_init(rlm_rcode_t *p_result, requ
        fr_pair_append(&child->request_pairs, vp);
 
        if (gext->src) {
-               if (tmpl_is_list(gext->src)) {
-                       if (tmpl_copy_pairs(child->request_ctx, &child->request_pairs, request, gext->src) < -1) {
-                               RPEDEBUG("Failed copying source attributes into subrequest");
-                               goto fail;
-                       }
-               } else {
-                       if (tmpl_copy_pair_children(child->request_ctx, &child->request_pairs, request, gext->src) < -1) {
-                               RPEDEBUG("Failed copying source attributes into subrequest");
-                               goto fail;
-                       }
+               if (tmpl_copy_pair_children(child->request_ctx, &child->request_pairs, request, gext->src) < -1) {
+                       RPEDEBUG("Failed copying source attributes into subrequest");
+                       goto fail;
                }
        }
 
index 8e1e5968b8a417116969a5b858e32721a2775b0e..72102b18a9b6d94619abf75dab5cf86a47e2fd77 100644 (file)
@@ -1556,7 +1556,6 @@ static xlat_action_t xlat_func_map(TALLOC_CTX *ctx, fr_dcursor_t *out,
 
        switch (map->lhs->type) {
        case TMPL_TYPE_ATTR:
-       case TMPL_TYPE_LIST:
        case TMPL_TYPE_XLAT:
                break;
 
@@ -1570,7 +1569,6 @@ static xlat_action_t xlat_func_map(TALLOC_CTX *ctx, fr_dcursor_t *out,
        case TMPL_TYPE_ATTR:
        case TMPL_TYPE_EXEC:
        case TMPL_TYPE_DATA:
-       case TMPL_TYPE_LIST:
        case TMPL_TYPE_REGEX_XLAT_UNRESOLVED:
        case TMPL_TYPE_UNRESOLVED:
        case TMPL_TYPE_XLAT:
index 75f8c23410dd5415a4a09cdc0dde98bb287d8906..40d785812a0c3f3c901183561b912411d39afec3 100644 (file)
@@ -1126,7 +1126,7 @@ xlat_action_t xlat_frame_eval(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_exp_head_
                                fr_value_box_list_move((FR_DLIST_HEAD(fr_value_box_list) *)out->dlist, &result);
                                continue;
 
-                       } else if (tmpl_is_attr(node->vpt) ||  tmpl_is_list(node->vpt)) {
+                       } else if (tmpl_is_attr(node->vpt)) {
                                if (node->fmt[0] == '&') {
                                        XLAT_DEBUG("** [%i] %s(attribute) - %s", unlang_interpret_stack_depth(request), __FUNCTION__,
                                                   node->fmt);
index c19b47e61d35d113c13e957e83cb941651e1b4c5..497a6a96644e7e17cf338623f5ab293df30a290a 100644 (file)
@@ -1564,7 +1564,6 @@ static xlat_action_t xlat_exists_resume(TALLOC_CTX *ctx, fr_dcursor_t *out,
                                                   .prefix = TMPL_ATTR_REF_PREFIX_AUTO,
                                                   .allow_unknown = false,
                                                   .allow_unresolved = false,
-                                                  .list_as_attr = true,
                                           },
                                   });
        if (slen <= 0) goto fail;
@@ -1964,7 +1963,7 @@ static fr_slen_t tokenize_unary(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuf
        /*
         *      Convert raw rcodes to xlat's.
         *
-        *      @todo - if it's '!', and the node is tmpl_is_list, or tmpl_contains_attr
+        *      @todo - if it's '!', and the node is tmpl_contains_attr
         *      re-write it to an existence check function, with node->fmt the node->vpt->name.
         *
         */
@@ -2451,19 +2450,11 @@ static bool valid_type(xlat_exp_t *node)
 
        if (node->type != XLAT_TMPL) return true;
 
-       if (tmpl_is_list(node->vpt)) {
-       list:
-               fr_strerror_const("Cannot use list references in condition");
-               return false;
-       }
-
        if (!tmpl_is_attr(node->vpt)) return true;
 
        da = tmpl_attr_tail_da(node->vpt);
        if (fr_type_is_structural(da->type)) {
-               if (da->dict == fr_dict_internal()) goto list;
-
-               fr_strerror_const("Cannot use structural types in condition");
+               fr_strerror_const("Cannot compare structural types");
                return false;
        }
 
index 841220e44aa3c4b504c068faf699f7acf55186af..8660430b66146aae6c6d26c864d916dcbfdc8243 100644 (file)
@@ -661,8 +661,8 @@ static inline int xlat_tokenize_attribute(xlat_exp_head_t *head, fr_sbuff_t *in,
         *      Deal with virtual attributes.
         */
        if (tmpl_is_attr(vpt) && tmpl_attr_tail_da(vpt)->flags.virtual) {
-               if (tmpl_attr_num_elements(vpt) > (size_t) (1 + vpt->rules.attr.list_as_attr)) {
-                       fr_strerror_const("Virtual attributes cannot be nested.");
+               if (tmpl_attr_num_elements(vpt) > (size_t)(tmpl_attr_head_is_list(vpt) ? 2 : 1)) {
+                       fr_strerror_const("Virtual attributes cannot be nested");
                        goto error;
                }
 
@@ -687,7 +687,7 @@ static inline int xlat_tokenize_attribute(xlat_exp_head_t *head, fr_sbuff_t *in,
                /*
                 *      Could it be a virtual attribute?
                 */
-               if ((tmpl_attr_num_elements(vpt) == (size_t) (1 + vpt->rules.attr.list_as_attr)) && (xlat_resolve_virtual_attribute(node, vpt) == 0)) goto done;
+               if ((tmpl_attr_num_elements(vpt) == (size_t)2) && (xlat_resolve_virtual_attribute(node, vpt) == 0)) goto done;
 
                if (!t_rules || !t_rules->attr.allow_unresolved) {
                        talloc_free(vpt);
@@ -1276,8 +1276,8 @@ ssize_t xlat_print_node(fr_sbuff_t *out, xlat_exp_head_t const *head, xlat_exp_t
                 */
                fr_assert(!tmpl_contains_regex(node->vpt));
 
-               // attr or list
-               fr_assert(tmpl_is_list(node->vpt) || tmpl_is_attr(node->vpt));
+               // attr
+               fr_assert(tmpl_is_attr(node->vpt));
                fr_assert(talloc_parent(node->vpt) == node);
                fr_assert(!node->flags.pure);
 
index fe44edfe25290ce31c94333393edde13751c0dc0..2a448f3c2b688ac7dd9d47f52ae4f6b1c4f65539 100644 (file)
@@ -200,7 +200,6 @@ DIAG_ON(nonnull-compare)
 #  define PAIR_LIST_VERIFY(_x) fr_pair_list_nonnull_assert(_x)
 #endif
 
-
 #ifdef TEST_CHECK
 /** Macro for use in acutest tests
  */
index 32269cde7553f74a173b957e8eb61c8bdecfe4c9..4610e24ed9e891306f2abbe2fe502871e900e9dd 100644 (file)
@@ -360,7 +360,7 @@ static unlang_action_t cache_insert(rlm_rcode_t *p_result,
                         *      Prevent people from accidentally caching
                         *      cache control attributes.
                         */
-                       if (tmpl_is_list(map->rhs)) switch (vp->da->attr) {
+                       switch (vp->da->attr) {
                        case FR_CACHE_TTL:
                        case FR_CACHE_STATUS_ONLY:
                        case FR_CACHE_MERGE_NEW:
@@ -391,7 +391,7 @@ static unlang_action_t cache_insert(rlm_rcode_t *p_result,
                        {
                                fr_token_t      quote;
                                c_map->lhs = map->lhs;  /* lhs shouldn't be touched, so this is ok */
-                       do_rhs:
+
                                if (vp->vp_type == FR_TYPE_STRING) {
                                        quote = is_printable(vp->vp_strvalue, vp->vp_length) ?
                                                             T_SINGLE_QUOTED_STRING : T_DOUBLE_QUOTED_STRING;
@@ -403,7 +403,6 @@ static unlang_action_t cache_insert(rlm_rcode_t *p_result,
                                                            TMPL_TYPE_DATA, quote, map->rhs->name, map->rhs->len));
                                if (fr_value_box_copy(c_map->rhs, tmpl_value(c_map->rhs), &vp->data) < 0) {
                                        REDEBUG("Failed copying attribute value");
-                               error:
                                        talloc_free(pool);
                                        talloc_free(c);
                                        RETURN_MODULE_FAIL;
@@ -411,17 +410,6 @@ static unlang_action_t cache_insert(rlm_rcode_t *p_result,
                        }
                                break;
 
-                       /*
-                        *      Lists are weird... We need to fudge a new LHS template,
-                        *      which is a combination of the LHS list and the attribute.
-                        */
-                       case TMPL_TYPE_LIST:
-                               if (tmpl_attr_afrom_list(c_map, &c_map->lhs, map->lhs, vp->da) < 0) {
-                                       RPERROR("Failed attribute -> list copy");
-                                       goto error;
-                               }
-                               goto do_rhs;
-
                        default:
                                fr_assert(0);
                        }
@@ -522,9 +510,8 @@ static int cache_verify(map_t *map, void *ctx)
 {
        if (unlang_fixup_update(map, ctx) < 0) return -1;
 
-       if (!tmpl_is_attr(map->lhs) &&
-           !tmpl_is_list(map->lhs)) {
-               cf_log_err(map->ci, "Destination must be an attribute ref or a list");
+       if (tmpl_is_attr(map->lhs)) {
+               cf_log_err(map->ci, "Destination must be an attribute ref");
                return -1;
        }
 
index a7a9aab468d84d689c51d21274dbcb25a3c0953f..5471bba15b2bac264bac6077530ddfebd1d3d79f 100644 (file)
@@ -403,9 +403,6 @@ static int csv_map_verify(map_t *map, void *instance)
                type = tmpl_attr_tail_da(map->lhs)->type;
                break;
 
-       case TMPL_TYPE_LIST:
-               break;
-
        case TMPL_TYPE_ATTR_UNRESOLVED:
                cf_log_err(map->ci, "Unknown attribute %s", tmpl_attr_tail_unresolved(map->lhs));
                return -1;
index 5f0c8bcfc99ec5daf93860b61be2491f3d3cd2a9..f09f0d0cfa3aee56bf32dc9e66e452c7098a916d 100644 (file)
@@ -563,7 +563,6 @@ build_vector:
         */
        switch (vpt_p->type) {
        case TMPL_TYPE_ATTR:
-       case TMPL_TYPE_LIST:
        {
                #define VECTOR_INCREMENT 20
                fr_dcursor_t            cursor;
index b282ca32c02942b5775ec4ae607d1f3d388925ed..bb05bd5490fa5dabcd9d7759242f62c526b17a6c 100644 (file)
@@ -159,11 +159,6 @@ static int cf_table_parse_tmpl(TALLOC_CTX *ctx, void *out, UNUSED void *parent,
                goto finish;
        }
 
-       if(tmpl_is_list(vpt)) {
-               ret = -1;
-               goto finish;
-       }
-
        /* Only string values should be used for SMTP components */
        if(tmpl_expanded_type(vpt) != FR_TYPE_STRING) {
                cf_log_err(cp, "Attribute reference must be a string");
diff --git a/src/tests/keywords/unspecified b/src/tests/keywords/unspecified
new file mode 100644 (file)
index 0000000..0f6de11
--- /dev/null
@@ -0,0 +1,16 @@
+#
+#  PRE: if
+#
+
+&reply.Reply-Message = 'foo'
+&reply.User-Name = 'bar'
+
+if (&reply.[0] != 'foo') {
+       test_fail
+}
+
+if (&reply.[1] != 'bar') {
+       test_fail
+}
+
+success
\ No newline at end of file
index da42eb8c9bf0aea42fd77df48984054bab051894..c24050a206ca19ad2244033fa5daa2862577184b 100644 (file)
@@ -8,7 +8,7 @@ proto-dictionary radius
 tmpl-rules allow_unresolved=yes allow_unknown=yes
 
 condition &request.User-Name == &reply.User-Name
-match &User-Name == &reply.User-Name
+match &request.User-Name == &reply.User-Name
 
 # All IP address literals should be parsed as prefixes
 condition ("foo\
@@ -61,8 +61,8 @@ match ok
 #
 #  Extra braces get squashed
 #
-condition (&User-Name == &User-Password)
-match &User-Name == &User-Password
+condition (&request.User-Name == &request.User-Password)
+match &request.User-Name == &request.User-Password
 
 condition (!ok)
 match !ok
@@ -79,82 +79,82 @@ match ok
 #
 #  These next two are identical after normalization
 #
-condition (&User-Name == &User-Password || &Filter-Id == &Reply-Message)
-match &User-Name == &User-Password || &Filter-Id == &Reply-Message
+condition (&request.User-Name == &request.User-Password || &request.Filter-Id == &request.Reply-Message)
+match &request.User-Name == &request.User-Password || &request.Filter-Id == &request.Reply-Message
 
-condition ((&User-Name == &User-Password) || (&Filter-Id == &Reply-Message))
-match (&User-Name == &User-Password) || (&Filter-Id == &Reply-Message)
+condition ((&request.User-Name == &request.User-Password) || (&request.Filter-Id == &request.Reply-Message))
+match (&request.User-Name == &request.User-Password) || (&request.Filter-Id == &request.Reply-Message)
 
-condition (!(&User-Name == &User-Password) || (&Filter-Id == &Reply-Message))
-match !(&User-Name == &User-Password) || (&Filter-Id == &Reply-Message)
+condition (!(&request.User-Name == &request.User-Password) || (&request.Filter-Id == &request.Reply-Message))
+match !(&request.User-Name == &request.User-Password) || (&request.Filter-Id == &request.Reply-Message)
 
 #  different from the previous ones.
-condition (!((&User-Name == &User-Password) || (&Filter-Id == &Reply-Message)))
-match !((&User-Name == &User-Password) || (&Filter-Id == &Reply-Message))
+condition (!((&request.User-Name == &request.User-Password) || (&request.Filter-Id == &request.Reply-Message)))
+match !((&request.User-Name == &request.User-Password) || (&request.Filter-Id == &request.Reply-Message))
 
-condition (!(&User-Name == &User-Password) || (&Filter-Id == &Reply-Message))
-match !(&User-Name == &User-Password) || (&Filter-Id == &Reply-Message)
+condition (!(&request.User-Name == &request.User-Password) || (&request.Filter-Id == &request.Reply-Message))
+match !(&request.User-Name == &request.User-Password) || (&request.Filter-Id == &request.Reply-Message)
 
 condition ((a == b) || (c == d)))
 match ERROR offset 23: Unexpected closing brace
 
-condition (handled && (&Packet-Type == Access-Challenge))
-match  handled && (&Packet-Type == Access-Challenge)
+condition (handled && (&request.Packet-Type == Access-Challenge))
+match  handled && (&request.Packet-Type == Access-Challenge)
 
 # This is OK, without the braces
-condition handled && &Packet-Type == Access-Challenge
-match handled && &Packet-Type == Access-Challenge
+condition handled && &request.Packet-Type == Access-Challenge
+match handled && &request.Packet-Type == Access-Challenge
 
 # and this, though it's not a good idea.
-condition handled &&&Packet-Type == Access-Challenge
-match handled && &Packet-Type == Access-Challenge
+condition handled &&&request.Packet-Type == Access-Challenge
+match handled && &request.Packet-Type == Access-Challenge
 
 condition &reply == &request
-match ERROR offset 1: Cannot use list references in condition
+match ERROR offset 1: Nesting types such as groups or TLVs cannot be compared
 
 condition &reply == "hello"
-match ERROR offset 1: Cannot use list references in condition
+match ERROR offset 1: Nesting types such as groups or TLVs cannot be compared
 
 condition "hello" == &reply
-match ERROR offset 12: Cannot use list references in condition
+match ERROR offset 12: Nesting types such as groups or TLVs cannot be compared
 
 
 #
 #  Convert != to !(COND) for normal checks
 #
-condition &User-Name == &User-Password
-match &User-Name == &User-Password
+condition &request.User-Name == &request.User-Password
+match &request.User-Name == &request.User-Password
 
-condition &User-Name != &User-Password
-match !&User-Name == &User-Password
+condition &request.User-Name != &request.User-Password
+match !&request.User-Name == &request.User-Password
 
-condition !&User-Name != &User-Password
-match &User-Name == &User-Password
+condition !&request.User-Name != &request.User-Password
+match &request.User-Name == &request.User-Password
 
 condition <ipv6addr>::1
 match ERROR offset 1: Invalid cast from ipv6addr to bool.  Unsupported
 
-condition <ipaddr>&Filter-Id == &Framed-IP-Address
-match <ipaddr>&Filter-Id == &Framed-IP-Address
+condition <ipaddr>&request.Filter-Id == &request.Framed-IP-Address
+match <ipaddr>&request.Filter-Id == &request.Framed-IP-Address
 
-condition <ipaddr>&Filter-Id == &Framed-IP-Address
-match <ipaddr>&Filter-Id == &Framed-IP-Address
+condition <ipaddr>&request.Filter-Id == &request.Framed-IP-Address
+match <ipaddr>&request.Filter-Id == &request.Framed-IP-Address
 
 #
 #  We can automatically promote things as needed.  But if the
 #  user forces incompatible types, then that's an error.
 #
-condition <ipaddr>&Filter-Id == <blerg>&Framed-IP-Address
-match ERROR offset 24: Unknown data type
+condition <ipaddr>&request.Filter-Id == <blerg>&request.Framed-IP-Address
+match ERROR offset 32: Unknown data type
 
-condition <blerg>&Filter-Id == "foo"
+condition <blerg>&request.Filter-Id == "foo"
 match ERROR offset 2: Unknown data type
 
 #
 #  Normalize things
 #
-condition <ipaddr>127.0.0.1 < &Framed-IP-Address
-match &Framed-IP-Address > 127.0.0.1
+condition <ipaddr>127.0.0.1 < &request.Framed-IP-Address
+match &request.Framed-IP-Address > 127.0.0.1
 
 # =* and !* are only for attrs / lists
 condition "foo" !* bar
@@ -164,58 +164,58 @@ condition "foo" =* bar
 match ERROR offset 7: Invalid operator =*
 
 # existence checks don't need the RHS
-condition &User-Name =* bar
-match ERROR offset 12: Invalid operator =*
+condition &request.User-Name =* bar
+match ERROR offset 20: Invalid operator =*
 
-condition &User-Name !* bar
-match ERROR offset 12: Invalid operator !*
+condition &request.User-Name !* bar
+match ERROR offset 20: Invalid operator !*
 
-condition !&User-Name =* bar
-match ERROR offset 13: Invalid operator =*
+condition !&request.User-Name =* bar
+match ERROR offset 21: Invalid operator =*
 
-condition !&User-Name !* bar
-match ERROR offset 13: Invalid operator !*
+condition !&request.User-Name !* bar
+match ERROR offset 21: Invalid operator !*
 
 # redundant casts get squashed
-condition <ipaddr>&Framed-IP-Address == 127.0.0.1
-match &Framed-IP-Address == 127.0.0.1
+condition <ipaddr>&request.Framed-IP-Address == 127.0.0.1
+match &request.Framed-IP-Address == 127.0.0.1
 
-condition <cidr>&Framed-IP-Address <= 192.168.0.0/16
-match <ipv4prefix>&Framed-IP-Address <= 192.168.0.0/16
+condition <cidr>&request.Framed-IP-Address <= 192.168.0.0/16
+match <ipv4prefix>&request.Framed-IP-Address <= 192.168.0.0/16
 
 # All IP address literals should be parsed as prefixes
-condition &Framed-IP-Address <= 192.168.0.0/16
-match <ipv4prefix>&Framed-IP-Address <= 192.168.0.0/16
+condition &request.Framed-IP-Address <= 192.168.0.0/16
+match <ipv4prefix>&request.Framed-IP-Address <= 192.168.0.0/16
 
 # string attributes must be string
-condition &User-Name == "bob"
-match &User-Name == "bob"
+condition &request.User-Name == "bob"
+match &request.User-Name == "bob"
 
-condition &User-Name == `bob`
-match &User-Name == `bob`
+condition &request.User-Name == `bob`
+match &request.User-Name == `bob`
 
-condition &User-Name == 'bob'
-match &User-Name == 'bob'
+condition &request.User-Name == 'bob'
+match &request.User-Name == 'bob'
 
-condition &User-Name == bob
-match &User-Name == 'bob'
+condition &request.User-Name == bob
+match &request.User-Name == 'bob'
 
 # Integer (etc.) types must be "bare"
 condition &Session-Timeout == 10
-match &Session-Timeout == 10
+match &request.Session-Timeout == 10
 
 # Automatic type inference means this is fine
 condition &Session-Timeout == '10'
-match &Session-Timeout == 10
+match &request.Session-Timeout == 10
 
 # Except for dates, which can be humanly readable!
 # This one is be an expansion, so it's left as-is.
-condition &Event-Timestamp == "January 1, 2012 %{blah}"
-match &Event-Timestamp == "January 1, 2012 %{blah}"
+condition &request.Event-Timestamp == "January 1, 2012 %{blah}"
+match &request.Event-Timestamp == "January 1, 2012 %{blah}"
 
 # This one is NOT an expansion, so it's parsed into normal form
-condition &Event-Timestamp == 'January 1, 2012'
-#data &Event-Timestamp == 'Jan  1 2012 00:00:00 EST'
+condition &request.Event-Timestamp == 'January 1, 2012'
+#data &request.Event-Timestamp == 'Jan  1 2012 00:00:00 EST'
 
 # literals are parsed when the conditions are parsed
 condition <integer>X == 1
@@ -240,8 +240,8 @@ match 127.0.0.1 == "%{md4: 127.0.0.1}"
 condition <ipaddr>127.0.0.1 == %{md4:127.0.0.1}
 match 127.0.0.1 == %{md4:127.0.0.1}
 
-condition <ipaddr>127.0.0.1 == %{md4: SELECT user FROM table WHERE user='%{User-Name}'}
-match 127.0.0.1 == %{md4: SELECT user FROM table WHERE user='%{User-Name}'}
+condition <ipaddr>127.0.0.1 == %{md4: SELECT user FROM table WHERE user='%{request.User-Name}'}
+match 127.0.0.1 == %{md4: SELECT user FROM table WHERE user='%{request.User-Name}'}
 
 condition <ether> 00:11:22:33:44:55 == "00:11:22:33:44:55"
 match true
@@ -267,16 +267,16 @@ match false
 condition 0
 match false
 
-condition true && (&User-Name == "bob")
-match &User-Name == "bob"
+condition true && (&request.User-Name == "bob")
+match &request.User-Name == "bob"
 
-condition false && (&User-Name == "bob")
+condition false && (&request.User-Name == "bob")
 match false
 
-condition false || (&User-Name == "bob")
-match &User-Name == "bob"
+condition false || (&request.User-Name == "bob")
+match &request.User-Name == "bob"
 
-condition true || (&User-Name == "bob")
+condition true || (&request.User-Name == "bob")
 match true
 
 #
@@ -317,11 +317,11 @@ match false
 #  a double-quoted string.  Except that there's no '%'
 #  in it, so it reverts back to a literal.
 #
-condition (&User-Name == "bob")
-match &User-Name == "bob"
+condition (&request.User-Name == "bob")
+match &request.User-Name == "bob"
 
-condition (&User-Name == "%{md4: blah}")
-match &User-Name == "%{md4: blah}"
+condition (&request.User-Name == "%{md4: blah}")
+match &request.User-Name == "%{md4: blah}"
 
 condition <ipaddr>127.0.0.1 == 2130706433
 match true
@@ -391,12 +391,12 @@ condition (`a`)
 match `a`
 
 condition (&User-name)
-match &User-Name
+match &request.User-Name
 
 #
 #  Forbidden data types in cast
 #
-condition (<vsa>"foo" == &User-Name)
+condition (<vsa>"foo" == &request.User-Name)
 match ERROR offset 3: Forbidden data type 'vsa' in cast
 
 #
@@ -404,32 +404,32 @@ match ERROR offset 3: Forbidden data type 'vsa' in cast
 #  of the same type, then re-write it so that the attribute
 #  is on the LHS of the condition.
 #
-condition <string>"foo" == &User-Name
-match &User-Name == "foo"
+condition <string>"foo" == &request.User-Name
+match &request.User-Name == "foo"
 
 # This used to be expr, but expr isn't a builtin, so it failed...
-condition <integer>"%{md4: 1 + 1}" < &NAS-Port
-match &NAS-Port > <uint32>"%{md4: 1 + 1}"
+condition <integer>"%{md4: 1 + 1}" < &request.NAS-Port
+match &request.NAS-Port > <uint32>"%{md4: 1 + 1}"
 
 #
 #  The string gets parsed as an IP address.
 #
-condition &Filter-Id == &Framed-IP-Address
-match <ipaddr>&Filter-Id == &Framed-IP-Address
+condition &request.Filter-Id == &request.Framed-IP-Address
+match <ipaddr>&request.Filter-Id == &request.Framed-IP-Address
 
-condition <ipaddr>127.0.0.1 == &Filter-Id
-match <ipaddr>&Filter-Id == 127.0.0.1
+condition <ipaddr>127.0.0.1 == &request.Filter-Id
+match <ipaddr>&request.Filter-Id == 127.0.0.1
 
-condition &Tmp-uint64-0 == &request.Foo-Stuff-Bar
-match &Tmp-uint64-0 == &Foo-Stuff-Bar
+condition &request.Tmp-uint64-0 == &request.Foo-Stuff-Bar
+match &request.Tmp-uint64-0 == &request.Foo-Stuff-Bar
 
-condition &Tmp-uint64-0 == &reply.Foo-Stuff-Bar
-match &Tmp-uint64-0 == &reply.Foo-Stuff-Bar
+condition &request.Tmp-uint64-0 == &reply.Foo-Stuff-Bar
+match &request.Tmp-uint64-0 == &reply.Foo-Stuff-Bar
 
 #
 #  Casting attributes of different size
 #
-condition <ipaddr>&Tmp-uint64-0 == &Framed-IP-Address
+condition <ipaddr>&request.Tmp-uint64-0 == &request.Framed-IP-Address
 match ERROR offset 9: Cannot cast type 'uint64' to 'ipaddr'
 
 #
@@ -437,88 +437,88 @@ match ERROR offset 9: Cannot cast type 'uint64' to 'ipaddr'
 #  if the prefix is /32.  We don't know enough at compile time,
 #  so this may be a run-time failure.
 #
-condition <ipaddr>&PMIP6-Home-IPv4-HoA == &Framed-IP-Address
-match <ipaddr>&PMIP6-Home-IPv4-HoA == &Framed-IP-Address
+condition <ipaddr>&request.PMIP6-Home-IPv4-HoA == &request.Framed-IP-Address
+match <ipaddr>&request.PMIP6-Home-IPv4-HoA == &request.Framed-IP-Address
 
 # but these are allowed
-condition <ether>&Tmp-uint64-0 == "%{module: foo}"
-match <ether>&Tmp-uint64-0 == "%{module: foo}"
+condition <ether>&request.Tmp-uint64-0 == "%{module: foo}"
+match <ether>&request.Tmp-uint64-0 == "%{module: foo}"
 
-condition <ipaddr>&Filter-Id == &Framed-IP-Address
-match <ipaddr>&Filter-Id == &Framed-IP-Address
+condition <ipaddr>&request.Filter-Id == &request.Framed-IP-Address
+match <ipaddr>&request.Filter-Id == &request.Framed-IP-Address
 
-condition <ipaddr>&Class == &Framed-IP-Address
-match <ipaddr>&Class == &Framed-IP-Address
+condition <ipaddr>&request.Class == &request.Framed-IP-Address
+match <ipaddr>&request.Class == &request.Framed-IP-Address
 
 #
 #  zero offset into arrays get parsed and ignored
 #
-condition &User-Name[0] == "bob"
-match &User-Name[0] == "bob"
+condition &request.User-Name[0] == "bob"
+match &request.User-Name[0] == "bob"
 
-condition &User-Name[1] == "bob"
-match &User-Name[1] == "bob"
+condition &request.User-Name[1] == "bob"
+match &request.User-Name[1] == "bob"
 
-condition &User-Name[n] == "bob"
-match &User-Name[n] == "bob"
+condition &request.User-Name[n] == "bob"
+match &request.User-Name[n] == "bob"
 
 #
 #  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 an unknown attribute
 #
-condition &Foo-Bar
-match &Foo-Bar
+condition &request.Foo-Bar
+match &request.Foo-Bar
 
 #  Same types are optimized
 #
 #  FIXME: the tests don't currently run the "pass2" checks.
 #  This test should really be:
 #
-#      data &Acct-Input-Octets > &Session-Timeout
+#      data &request.Acct-Input-Octets > &request.Session-Timeout
 #
-condition &Acct-Input-Octets > "%{Session-Timeout}"
-match &Acct-Input-Octets > "%{Session-Timeout}"
+condition &request.Acct-Input-Octets > "%{request.Session-Timeout}"
+match &request.Acct-Input-Octets > "%{request.Session-Timeout}"
 
 #  Separate types aren't optimized
-condition &Acct-Input-Octets-64 > "%{Session-Timeout}"
-match &Acct-Input-Octets-64 > "%{Session-Timeout}"
+condition &request.Acct-Input-Octets-64 > "%{request.Session-Timeout}"
+match &request.Acct-Input-Octets-64 > "%{request.Session-Timeout}"
 
 #
 #  Parse OIDs into known attributes, where possible.
 #
 condition &26.24757.84.9.5.4 == 0x1a99
-match &Vendor-Specific.WiMAX.Packet-Flow-Descriptor-v2.Classifier.Src-Spec.Port == 6809
+match &request.Vendor-Specific.WiMAX.Packet-Flow-Descriptor-v2.Classifier.Src-Spec.Port == 6809
 
 #
 #  This OID is known, but the data is malformed.
 #  Allow it so that we can look for malformed attributes
 #  in packets.
 #
-condition &raw.26.24757.84.9.5.7 == 0x1a99
-match &raw.Vendor-Specific.WiMAX.Packet-Flow-Descriptor-v2.Classifier.Src-Spec.Assigned == 0x1a99
+condition &raw.request.26.24757.84.9.5.7 == 0x1a99
+match &raw.request.Vendor-Specific.WiMAX.Packet-Flow-Descriptor-v2.Classifier.Src-Spec.Assigned == 0x1a99
 
 #  This one is really unknown
-condition &26.24757.84.9.5.15 == 0x1a99
-match &Vendor-Specific.WiMAX.Packet-Flow-Descriptor-v2.Classifier.Src-Spec.15 == 0x1a99
+condition &request.26.24757.84.9.5.15 == 0x1a99
+match &request.Vendor-Specific.WiMAX.Packet-Flow-Descriptor-v2.Classifier.Src-Spec.15 == 0x1a99
 
 #
 #  Invalid array references.
 #
-condition &User-Name[a] == 'bob'
-match ERROR offset 12: Invalid array index
+condition &request.User-Name[a] == 'bob'
+match ERROR offset 20: Invalid array index
 
-condition &User-Name == &Filter-Id[a]
-match ERROR offset 26: Invalid array index
+condition &request.User-Name == &request.Filter-Id[a]
+match ERROR offset 42: Invalid array index
 
 #
 #  Bounds checks...
 #
-condition &User-Name[1001] == 'bob'
-match ERROR offset 12: Invalid array index '1001' (should be between 0-1000)
+condition &request.User-Name[1001] == 'bob'
+match ERROR offset 20: Invalid array index '1001' (should be between 0-1000)
 
-condition &User-Name[-1] == 'bob'
-match ERROR offset 12: Invalid array index '-1' (should be between 0-1000)
+condition &request.User-Name[-1] == 'bob'
+match ERROR offset 20: Invalid array index '-1' (should be between 0-1000)
 
 #
 #  Sometimes the attribute/condition parser needs to fallback to bare words
@@ -544,8 +544,8 @@ condition &not-a-list:User-Name == &not-a-list:User-Name
 match ERROR offset 12: Unexpected text after attribute reference
 
 # . is a valid dictionary name attribute, so we can't error out in pass1
-condition &not-a-packet.User-Name == &not-a-packet.User-Name
-match &not-a-packet.User-Name == &not-a-packet.User-Name
+condition &request.not-a-packet.User-Name == &request.not-a-packet.User-Name
+match &request.not-a-packet.User-Name == &request.not-a-packet.User-Name
 
 #
 #  The LHS is a string with ASCII 5C 30 30 30 inside of it vs the RHS which should contain ASCII 0.
@@ -556,24 +556,24 @@ match false
 #
 #  'Unknown' attributes which are defined in the main dictionary
 #  should be resolved to their real names.
-condition &1 == 0x616263
-match &User-Name == 'abc'
+condition &request.1 == 0x616263
+match &request.User-Name == 'abc'
 
-condition &26.11344.1 == 0x7f000001
-match &Vendor-Specific.FreeRADIUS.Proxied-To == 127.0.0.1
+condition &request.26.11344.1 == 0x7f000001
+match &request.Vendor-Specific.FreeRADIUS.Proxied-To == 127.0.0.1
 
 #
 #  Escape the backslashes correctly
 #  And print them correctly
 #
-condition &User-Name == '\\'
-match &User-Name == '\\'
+condition &request.User-Name == '\\'
+match &request.User-Name == '\\'
 
-condition &User-Name == "@|\\"
-match &User-Name == "@|\\"
+condition &request.User-Name == "@|\\"
+match &request.User-Name == "@|\\"
 
-condition &User-Name != "foo\nbar"
-match !&User-Name == "foo\nbar"
+condition &request.User-Name != "foo\nbar"
+match !&request.User-Name == "foo\nbar"
 
 #
 #  We infer that the LHS is a prefix and the RHS is
@@ -585,22 +585,22 @@ match true
 condition <ipv4prefix>192.168.0.0/16 > 192.168.1.2
 match true
 
-condition <ipv4prefix>&NAS-IP-Address == 192.168.0.0/24
-match <ipv4prefix>&NAS-IP-Address == 192.168.0.0/24
+condition <ipv4prefix>&request.NAS-IP-Address == 192.168.0.0/24
+match <ipv4prefix>&request.NAS-IP-Address == 192.168.0.0/24
 
 #
 #  rewrite so that the attribute is on the LHS
 #  and, move the cast to the attribute, as the RHS
 #  is parsed as ipv4prefix
 #
-condition <ipv4prefix>192.168.0.0/24 > &NAS-IP-Address
-match <ipv4prefix>&NAS-IP-Address < 192.168.0.0/24
+condition <ipv4prefix>192.168.0.0/24 > &request.NAS-IP-Address
+match <ipv4prefix>&request.NAS-IP-Address < 192.168.0.0/24
 
 #
 #  This is allowed and means "the list is not empty"
 #
 condition (&reply.)
-match &reply
+match &reply.
 
 #
 #  Expansions of environment variables
@@ -618,7 +618,7 @@ match &reply
 #  Attributes with a protocol namespace
 #
 condition &radius.User-Name == 'bob'
-match &User-Name == 'bob'
+match &request.User-Name == 'bob'
 
 condition !(!(0))
 match false
@@ -629,10 +629,10 @@ match false
 #
 #  More short-circuit evaluations
 #
-condition (&User-Name == "bob") && (false)
+condition (&request.User-Name == "bob") && (false)
 match false
 
-condition (&User-Name == "bob") || (true)
+condition (&request.User-Name == "bob") || (true)
 match true
 
 #
@@ -641,8 +641,8 @@ match true
 #      0 && (1 || 1) = 0 && 1 == 0
 #      (0 && 1) || 1 = 0 || 1 == 1
 #
-condition (&User-Name == "bob") && ((&User-Password == "bob") || &EAP-Message)
-match (&User-Name == "bob") && ((&User-Password == "bob") || &EAP-Message)
+condition (&request.User-Name == "bob") && ((&request.User-Password == "bob") || &request.EAP-Message)
+match (&request.User-Name == "bob") && ((&request.User-Password == "bob") || &request.EAP-Message)
 
 count
 match 307
index 6a91465a89a203e24718fb68089e369338aad479..ba590ba1a15a24846cad16a624b44a62409f9b40 100644 (file)
@@ -8,28 +8,28 @@ proto-dictionary radius
 tmpl-rules allow_unresolved=yes allow_unknown=yes
 
 # Forcefully cast RHS bareword
-condition &User-Name == <ipaddr>192.168.0.1
-match <ipaddr>&User-Name == 192.168.0.1
+condition &request.User-Name == <ipaddr>192.168.0.1
+match <ipaddr>&request.User-Name == 192.168.0.1
 
 # Forcefully cast LHS bareword
-condition <ipaddr>192.168.0.1 == &User-Name
-match <ipaddr>&User-Name == 192.168.0.1
+condition <ipaddr>192.168.0.1 == &request.User-Name
+match <ipaddr>&request.User-Name == 192.168.0.1
 
 # Forcefully cast RHS single quotes
-#condition &Framed-IP-Address == <ipaddr>'192.168.0.1'
-#match &Framed-IP-Address == <ipaddr>'192.168.0.1'
+#condition &request.Framed-IP-Address == <ipaddr>'192.168.0.1'
+#match &request.Framed-IP-Address == <ipaddr>'192.168.0.1'
 
 # Forcefully cast LHS single quotes
-#condition <ipaddr>'192.168.0.1' == &Framed-IP-Address
-#match <ipaddr>'192.168.0.1' == &Framed-IP-Address
+#condition <ipaddr>'192.168.0.1' == &request.Framed-IP-Address
+#match <ipaddr>'192.168.0.1' == &request.Framed-IP-Address
 
 # Forcefully cast RHS double quotes
-#condition &User-Name == <ipaddr>"192.168.0.1"
-#match &User-Name == <ipaddr>"192.168.0.1"
+#condition &request.User-Name == <ipaddr>"192.168.0.1"
+#match &request.User-Name == <ipaddr>"192.168.0.1"
 
 # Forcefully cast LHS single quotes
-#condition <ipaddr>"192.168.0.1" == &User-Name
-#match <ipaddr>"192.168.0.1" == &User-Name
+#condition <ipaddr>"192.168.0.1" == &request.User-Name
+#match <ipaddr>"192.168.0.1" == &request.User-Name
 
 count
 match 6
index 37c32dbd87ecbe60f56c26c5868aee8304f3ec1e..04d40b9a7c079fda80c08635256abc2b4ec243c0 100644 (file)
@@ -8,12 +8,12 @@
 proto-dictionary dhcpv6
 tmpl-rules allow_unresolved=no allow_unknown=no
 
-condition &IA-NA.Options.Tmp-String-0 == 'foo'
-match &IA-NA.Options.Tmp-String-0 == 'foo'
+condition &request.IA-NA.Options.Tmp-String-0 == 'foo'
+match &request.IA-NA.Options.Tmp-String-0 == 'foo'
 
 # Seen in the wild.  Array subscript on child produces an error
-condition &IA-NA.Options.IA-Addr[0].IPv6-Address == ::
-match &IA-NA.Options.IA-Addr[0].IPv6-Address == ::
+condition &request.IA-NA.Options.IA-Addr[0].IPv6-Address == ::
+match &request.IA-NA.Options.IA-Addr[0].IPv6-Address == ::
 
 count
 match 6
index 7ca6df7a6aa22b042d5b02f4fec64f58d6a8aa53..14cf52da932b2182c2e02ba799cb38554c84ce63 100644 (file)
@@ -7,11 +7,11 @@
 proto-dictionary radius
 
 # Check wildcards are OK
-condition &Packet-Src-IPv6-Address == ::
-match &Packet-Src-IPv6-Address == ::
+condition &request.Packet-Src-IPv6-Address == ::
+match &request.Packet-Src-IPv6-Address == ::
 
-condition &Packet-Src-IP-Address == <ipaddr>*
-match &Packet-Src-IP-Address == 0.0.0.0
+condition &request.Packet-Src-IP-Address == <ipaddr>*
+match &request.Packet-Src-IP-Address == 0.0.0.0
 
-condition &Packet-Src-IP-Address == 0.0.0.0
-match &Packet-Src-IP-Address == 0.0.0.0
+condition &request.Packet-Src-IP-Address == 0.0.0.0
+match &request.Packet-Src-IP-Address == 0.0.0.0
index d10f723b58d21dbe3ac545a9acbda97e7b09deef..292a44ae55465e09aad5c9411968f126967b63c4 100644 (file)
@@ -7,27 +7,27 @@
 proto-dictionary radius
 
 # A nested attribute with partial path
-condition &Vendor-Specific.WiMAX.Packet-Flow-Descriptor.Uplink-QOS-Id
-match &Vendor-Specific.WiMAX.Packet-Flow-Descriptor.Uplink-QOS-Id
+condition &request.Vendor-Specific.WiMAX.Packet-Flow-Descriptor.Uplink-QOS-Id
+match &request.Vendor-Specific.WiMAX.Packet-Flow-Descriptor.Uplink-QOS-Id
 
 # A nested attribute with a full path (and no filters)
-condition &Vendor-Specific.WiMAX.Packet-Flow-Descriptor.Uplink-QOS-Id
-match &Vendor-Specific.WiMAX.Packet-Flow-Descriptor.Uplink-QOS-Id
+condition &request.Vendor-Specific.WiMAX.Packet-Flow-Descriptor.Uplink-QOS-Id
+match &request.Vendor-Specific.WiMAX.Packet-Flow-Descriptor.Uplink-QOS-Id
 
 # A nested attribute with an instance selector
-condition &Vendor-Specific.WiMAX.Packet-Flow-Descriptor[5].Uplink-QOS-Id
-match &Vendor-Specific.WiMAX.Packet-Flow-Descriptor[5].Uplink-QOS-Id
+condition &request.Vendor-Specific.WiMAX.Packet-Flow-Descriptor[5].Uplink-QOS-Id
+match &request.Vendor-Specific.WiMAX.Packet-Flow-Descriptor[5].Uplink-QOS-Id
 
 # A nested attribute with an instance selector at both levels
-condition &Vendor-Specific.WiMAX.Packet-Flow-Descriptor[*].Uplink-QOS-Id[0]
-match &Vendor-Specific.WiMAX.Packet-Flow-Descriptor[*].Uplink-QOS-Id[0]
+condition &request.Vendor-Specific.WiMAX.Packet-Flow-Descriptor[*].Uplink-QOS-Id[0]
+match &request.Vendor-Specific.WiMAX.Packet-Flow-Descriptor[*].Uplink-QOS-Id[0]
 
 # Unparsed child - We won't know this is an error until pass2
 
 tmpl-rules allow_unresolved=yes
 
-condition &Unparsed-Child.Uplink-QOS-Id[0]
-match &Unparsed-Child.Uplink-QOS-Id[0]
+condition &request.Unparsed-Child.Uplink-QOS-Id[0]
+match &request.Unparsed-Child.Uplink-QOS-Id[0]
 
 tmpl-rules allow_unresolved=no
 
@@ -35,16 +35,16 @@ tmpl-rules allow_unresolved=no
 #  Errors
 #
 # Malformed filter
-condition &Vendor-Specific.WiMAX.Packet-Flow-Descriptor[*.Uplink-QOS-Id[0]
-match ERROR offset 48: No closing ']' for array index
+condition &request.Vendor-Specific.WiMAX.Packet-Flow-Descriptor[*.Uplink-QOS-Id[0]
+match ERROR offset 56: No closing ']' for array index
 
 # Too many dots, point to the thing that's wrong
-condition &Vendor-Specific.WiMAX.Packet-Flow-Descriptor..Uplink-QOS-Id[0]
-match ERROR offset 47: Zero length attribute name: Unresolved attributes are not allowed here
+condition &request.Vendor-Specific.WiMAX.Packet-Flow-Descriptor..Uplink-QOS-Id[0]
+match ERROR offset 55: Zero length attribute name: Unresolved attributes are not allowed here
 
 # Trailing dots, point to the dot that's an error
-condition &Vendor-Specific.WiMAX.Packet-Flow-Descriptor.Uplink-QOS-Id[0].
-match ERROR offset 63: Parent type of nested attribute Uplink-QOS-Id must be of type "struct", "tlv", "vendor", "vsa" or "group", got "uint8"
+condition &request.Vendor-Specific.WiMAX.Packet-Flow-Descriptor.Uplink-QOS-Id[0].
+match ERROR offset 71: Parent type of nested attribute Uplink-QOS-Id must be of type "struct", "tlv", "vendor", "vsa" or "group", got "uint8"
 
 count
 match 19
index 24c8bbc794a357589df4941224682cac717afd6e..02fd378aff8b23ee275057c46f5d658e33461543 100644 (file)
@@ -1,7 +1,7 @@
 proto-dictionary radius
 
-condition &User-Name !~ /^foo\nbar$/
-match !&User-Name =~ /^foo\nbar$/
+condition &request.User-Name !~ /^foo\nbar$/
+match !&request.User-Name =~ /^foo\nbar$/
 
 condition (ok =~ handled)
 match ERROR offset 8: Expected regular expression
@@ -50,29 +50,29 @@ match ERROR offset 14: Duplicate regex flag 'i'
 #  And print them correctly
 #
 
-condition &User-Name =~ /@|./
-match &User-Name =~ /@|./
+condition &request.User-Name =~ /@|./
+match &request.User-Name =~ /@|./
 
-condition &User-Name =~ /@|\\/
-match &User-Name =~ /@|\\/
+condition &request.User-Name =~ /@|\\/
+match &request.User-Name =~ /@|\\/
 
-condition &User-Name =~ /^([^\\]*)\\(.*)$/
-match &User-Name =~ /^([^\\]*)\\(.*)$/
+condition &request.User-Name =~ /^([^\\]*)\\(.*)$/
+match &request.User-Name =~ /^([^\\]*)\\(.*)$/
 
 #
 #  Non-integer types get cast to string.
 #
-condition &Tmp-Integer-0 =~ /%{Tmp-Integer-0}/
-match <string>&Tmp-Integer-0 =~ /%{Tmp-Integer-0}/
+condition &request.Tmp-Integer-0 =~ /%{request.Tmp-Integer-0}/
+match <string>&request.Tmp-Integer-0 =~ /%{request.Tmp-Integer-0}/
 
 #
 #  Cannot add a bad cast
 #
-condition <integer>&Tmp-String-0 =~ /foo/
+condition <integer>&request.Tmp-String-0 =~ /foo/
 match ERROR offset 10: Casts cannot be used with regular expressions
 
-condition &Tmp-String-0 =~ <integer>/foo/
-match ERROR offset 28: Casts cannot be used with regular expressions
+condition &request.Tmp-String-0 =~ <integer>/foo/
+match ERROR offset 36: Casts cannot be used with regular expressions
 
 
 xlat %{1}
@@ -81,8 +81,8 @@ match %{1}
 xlat %{33}
 match ERROR offset 3: Invalid regex reference.  Must be in range 0-32
 
-condition &User-Name == /foo/
-match ERROR offset 15: Unexpected regular expression
+condition &request.User-Name == /foo/
+match ERROR offset 23: Unexpected regular expression
 
 count
 match 43
diff --git a/src/tests/unit/condition/request_qualifiers.txt b/src/tests/unit/condition/request_qualifiers.txt
new file mode 100644 (file)
index 0000000..0708813
--- /dev/null
@@ -0,0 +1,43 @@
+proto-dictionary radius
+tmpl-rules allow_unresolved=no allow_unknown=yes
+
+# Our parent is fine
+condition &parent.request.User-Name == &parent.reply.User-Name
+match &parent.request.User-Name == &parent.reply.User-Name
+
+# The parent of our parent is fine
+condition &parent.parent.request.User-Name == &parent.parent.reply.User-Name
+match &parent.parent.request.User-Name == &parent.parent.reply.User-Name
+
+# Current request is fine
+condition &current.request.User-Name == &current.reply.User-Name
+match &current.request.User-Name == &current.reply.User-Name
+
+# Current is pretty much meaningless
+condition &parent.current.parent.request.User-Name == &parent.current.parent.reply.User-Name
+match &parent.current.parent.request.User-Name == &parent.current.parent.reply.User-Name
+
+# Outer lists are fine...
+condition &outer.request.User-Name == &outer.reply.User-Name
+match &outer.request.User-Name == &outer.reply.User-Name
+
+# We _can_ navigate to the parent and _then_ the outer request
+condition &parent.outer.request.User-Name == &parent.outer.reply.User-Name
+match &parent.outer.request.User-Name == &parent.outer.reply.User-Name
+
+# We _can_ navigate to the parent and _then the outer request and then the current request
+condition &parent.outer.current.request.User-Name == &parent.outer.current.reply.User-Name
+match &parent.outer.current.request.User-Name == &parent.outer.current.reply.User-Name
+
+# But we can't go above the outer request
+condition &outer.parent.User-Name == &outer.parent.reply.User-Name
+match ERROR offset 14: "parent" qualifiers not allowed after "outer" qualifier
+
+# ...and we can't have multiple outers
+condition &outer.outer.request.User-Name == &outer.outer.request.User-Name
+match ERROR offset 13: Duplicate "outer" request qualifiers not allowed
+
+# If we don't have a default list, for now, we should default to request, this may change later
+# when we fully implement local variables.
+condition &outer.User-Name == &outer.User-Name
+match &outer.request.User-Name == &outer.request.User-Name
\ No newline at end of file
index 1b8bcd0980d7d062c008906dc39e824d7b76556a..0b9b6fe23e5755ed84497007d77f890b1b38d304 100644 (file)
@@ -25,32 +25,32 @@ match \\
 #
 #  Literals mixed with attributes
 #
-xlat literal%{User-Password}
-match literal%{User-Password}
+xlat literal%{request.User-Password}
+match literal%{request.User-Password}
 
-xlat {literal}%{User-Password}
-match {literal}%{User-Password}
+xlat {literal}%{request.User-Password}
+match {literal}%{request.User-Password}
 
-xlat literal%{User-Password}{literal}
-match literal%{User-Password}{literal}
+xlat literal%{request.User-Password}{literal}
+match literal%{request.User-Password}{literal}
 
-xlat {literal%{User-Password}literal}
-match {literal%{User-Password}literal}
+xlat {literal%{request.User-Password}literal}
+match {literal%{request.User-Password}literal}
 
-xlat \%{literal%{User-Password}literal}
-match \%{literal%{User-Password}literal}
+xlat \%{literal%{request.User-Password}literal}
+match \%{literal%{request.User-Password}literal}
 
-xlat literal%{%{User-Password}:-literal}
-match literal%{%{User-Password}:-literal}
+xlat literal%{%{request.User-Password}:-literal}
+match literal%{%{request.User-Password}:-literal}
 
-xlat literal%{%{User-Password}:-\%{lit}eral}
-match literal%{%{User-Password}:-\%{lit}eral}
+xlat literal%{%{request.User-Password}:-\%{lit}eral}
+match literal%{%{request.User-Password}:-\%{lit}eral}
 
-xlat literal%{%{User-Password}:-%{User-Name}\%literal}
-match literal%{%{User-Password}:-%{User-Name}\%literal}
+xlat literal%{%{request.User-Password}:-%{request.User-Name}\%literal}
+match literal%{%{request.User-Password}:-%{request.User-Name}\%literal}
 
-xlat literal%{%{User-Password}:-\%literal}
-match literal%{%{User-Password}:-\%literal}
+xlat literal%{%{request.User-Password}:-\%literal}
+match literal%{%{request.User-Password}:-\%literal}
 #
 #  Regex capture groups
 #
@@ -75,41 +75,41 @@ match ERROR offset 4: Missing closing brace
 #
 #  Tests for xlat expansion
 #
-xlat %{Tunnel-Password}
-match %{Tunnel-Password}
+xlat %{request.Tunnel-Password}
+match %{request.Tunnel-Password}
 
 xlat %{test:bar}
 match %{test:bar}
 
-xlat %{Tunnel-Password}
-match %{Tunnel-Password}
+xlat %{request.Tunnel-Password}
+match %{request.Tunnel-Password}
 
-xlat %{reply.Tunnel-Password}
-match %{reply.Tunnel-Password}
+xlat %{reply.request.Tunnel-Password}
+match %{reply.request.Tunnel-Password}
 
-xlat %{User-Name[3]}
-match %{User-Name[3]}
+xlat %{request.User-Name[3]}
+match %{request.User-Name[3]}
 
-xlat %{User-Name[*]}
-match %{User-Name[*]}
+xlat %{request.User-Name[*]}
+match %{request.User-Name[*]}
 
-xlat %{User-Name[#]}
-match %{User-Name[#]}
+xlat %{request.User-Name[#]}
+match %{request.User-Name[#]}
 
-xlat %{User-Name[n]}
-match %{User-Name[n]}
+xlat %{request.User-Name[n]}
+match %{request.User-Name[n]}
 
 xlat %{request.User-Name[3]}
-match %{User-Name[3]}
+match %{request.User-Name[3]}
 
 xlat %{request.User-Name[*]}
-match %{User-Name[*]}
+match %{request.User-Name[*]}
 
 xlat %{request.User-Name[#]}
-match %{User-Name[#]}
+match %{request.User-Name[#]}
 
-xlat %{Vendor-Specific.3GPP.SGSN-Address}
-match %{Vendor-Specific.3GPP.SGSN-Address}
+xlat %{request.Vendor-Specific.3GPP.SGSN-Address}
+match %{request.Vendor-Specific.3GPP.SGSN-Address}
 
 xlat \"Hello %S goo\"
 match \"Hello %S goo\"
@@ -121,7 +121,7 @@ match \"%{Foreach-Variable-0}\"
 #  3GPP stuff
 #
 xlat \"%{request.Vendor-Specific.3GPP.IMSI}\"
-match \"%{Vendor-Specific.3GPP.IMSI}\"
+match \"%{request.Vendor-Specific.3GPP.IMSI}\"
 
 xlat \"%{reply.Vendor-Specific.3GPP.IMSI}\"
 match \"%{reply.Vendor-Specific.3GPP.IMSI}\"
@@ -129,8 +129,8 @@ match \"%{reply.Vendor-Specific.3GPP.IMSI}\"
 xlat \"%{reply.Vendor-Specific.3GPP.IMSI[2]}\"
 match \"%{reply.Vendor-Specific.3GPP.IMSI[2]}\"
 
-xlat /([A-Z0-9\\-]*)_%{Calling-Station-Id}/
-match /([A-Z0-9\\-]*)_%{Calling-Station-Id}/
+xlat /([A-Z0-9\\-]*)_%{request.Calling-Station-Id}/
+match /([A-Z0-9\\-]*)_%{request.Calling-Station-Id}/
 
 xlat %(length:)
 match %(length:)
@@ -145,8 +145,8 @@ xlat \"%t\tfoo\"
 match \"%t\tfoo\"
 
 allow-unresolved yes
-xlat \"%t\t%{Client-IP-Address}\"
-match \"%t\t%{Client-IP-Address}\"
+xlat \"%t\t%{request.Client-IP-Address}\"
+match \"%t\t%{request.Client-IP-Address}\"
 allow-unresolved no
 
 xlat \"foo %{test:foo}\"
@@ -158,37 +158,37 @@ match \"foo %{test:foo}\"
 xlat %{%{foo}:-%{bar}}
 match ERROR offset 5: Unresolved attributes not allowed in expansions here
 
-xlat %{%{User-Name}:-%{bar}}
-match ERROR offset 19: Unresolved attributes not allowed in expansions here
+xlat %{%{request.User-Name}:-%{bar}}
+match ERROR offset 27: Unresolved attributes not allowed in expansions here
 
-xlat %{%{User-Name}:-bar}
-match %{%{User-Name}:-bar}
+xlat %{%{request.User-Name}:-bar}
+match %{%{request.User-Name}:-bar}
 
-xlat foo %{%{User-Name}:-bar} baz
-match foo %{%{User-Name}:-bar} baz
+xlat foo %{%{request.User-Name}:-bar} baz
+match foo %{%{request.User-Name}:-bar} baz
 
-xlat %{%{test:bar}:-%{User-Name}}
-match %{%{test:bar}:-%{User-Name}}
+xlat %{%{test:bar}:-%{request.User-Name}}
+match %{%{test:bar}:-%{request.User-Name}}
 
-xlat %{%{test:bar}:-%{%{User-Name}:-bar}}
-match %{%{test:bar}:-%{%{User-Name}:-bar}}
+xlat %{%{test:bar}:-%{%{request.User-Name}:-bar}}
+match %{%{test:bar}:-%{%{request.User-Name}:-bar}}
 
-xlat %{%{User-Name}:-}
-match %{%{User-Name}:-}
+xlat %{%{request.User-Name}:-}
+match %{%{request.User-Name}:-}
 
-xlat %{%{Operator-Name}:-}
-match %{%{Operator-Name}:-}
+xlat %{%{request.Operator-Name}:-}
+match %{%{request.Operator-Name}:-}
 
-xlat %{%{%{User-Name}:-foo}:-bar}
-match %{%{%{User-Name}:-foo}:-bar}
+xlat %{%{%{request.User-Name}:-foo}:-bar}
+match %{%{%{request.User-Name}:-foo}:-bar}
 
-xlat %{%{%{User-Name}:-foo}:-%{%{test:bar}:-%{User-Name}}}
-match %{%{%{User-Name}:-foo}:-%{%{test:bar}:-%{User-Name}}}
+xlat %{%{%{request.User-Name}:-foo}:-%{%{test:bar}:-%{request.User-Name}}}
+match %{%{%{request.User-Name}:-foo}:-%{%{test:bar}:-%{request.User-Name}}}
 
 xlat %{:-}
 match ERROR offset 3: First item in alternation cannot be empty
 
-xlat %{:-%{User-Name}}
+xlat %{:-%{request.User-Name}}
 match ERROR offset 3: First item in alternation cannot be empty
 
 xlat %{%{}:-}
@@ -197,18 +197,18 @@ match ERROR offset 5: Empty expression is invalid
 xlat %{%{}:-foo}
 match ERROR offset 5: Empty expression is invalid
 
-xlat %{%{User-Name}:-
-match ERROR offset 17: Missing closing brace
+xlat %{%{request.User-Name}:-
+match ERROR offset 25: Missing closing brace
 
 # Discuss - Not sure the offset/message is correct here, but not sure if we can determine the correct offset either
-xlat %{%{User-Name}:-foo
-match ERROR offset 20: Missing closing brace
+xlat %{%{request.User-Name}:-foo
+match ERROR offset 28: Missing closing brace
 
-xlat %{%{User-Name}:}
-match ERROR offset 15: Expected ':-' after first expansion
+xlat %{%{request.User-Name}:}
+match ERROR offset 23: Expected ':-' after first expansion
 
-xlat %{%{User-Name}}
-match ERROR offset 15: Expected ':-' after first expansion
+xlat %{%{request.User-Name}}
+match ERROR offset 23: Expected ':-' after first expansion
 
 
 #
@@ -253,12 +253,12 @@ match ERROR offset 6: Invalid char ' ' in expression
 xlat %{test:
 match ERROR offset 8: Missing closing brace
 
-xlat %{test:%{User-Name
-match ERROR offset 19: Missing closing brace
+xlat %{test:%{request.User-Name
+match ERROR offset 27: Missing closing brace
 
 # Discuss - Not sure the offset/message is correct here, but not sure if we can determine the correct offset either
-xlat %{test:%{User-Name}
-match ERROR offset 20: Missing closing brace
+xlat %{test:%{request.User-Name}
+match ERROR offset 28: Missing closing brace
 
 xlat %{myfirstxlat
 match ERROR offset 14: Missing closing brace
@@ -270,35 +270,35 @@ match ERROR offset 26: Expected ':-' after first expansion
 #
 #  API to split xlat strings into argv-style arguments.
 #
-xlat_argv /bin/sh %{User-Name}
-match [0]{ /bin/sh }, [1]{ %{User-Name} }
+xlat_argv /bin/sh %{request.User-Name}
+match [0]{ /bin/sh }, [1]{ %{request.User-Name} }
 
-xlat_argv /bin/sh "%{User-Name}"
-match [0]{ /bin/sh }, [1]{ %{User-Name} }
+xlat_argv /bin/sh "%{request.User-Name}"
+match [0]{ /bin/sh }, [1]{ %{request.User-Name} }
 
 # with quotes
-xlat_argv /bin/sh "foo" "%{User-Name}"
-match [0]{ /bin/sh }, [1]{ foo }, [2]{ %{User-Name} }
+xlat_argv /bin/sh "foo" "%{request.User-Name}"
+match [0]{ /bin/sh }, [1]{ foo }, [2]{ %{request.User-Name} }
 
 # many spaces between arguments
-xlat_argv /bin/sh         "foo"       "%{User-Name}"
-match [0]{ /bin/sh }, [1]{ foo }, [2]{ %{User-Name} }
+xlat_argv /bin/sh         "foo"       "%{request.User-Name}"
+match [0]{ /bin/sh }, [1]{ foo }, [2]{ %{request.User-Name} }
 
 # and spaces in quotes
-xlat_argv /bin/sh "foo bar" "%{User-Name}"
-match [0]{ /bin/sh }, [1]{ foo bar }, [2]{ %{User-Name} }
+xlat_argv /bin/sh "foo bar" "%{request.User-Name}"
+match [0]{ /bin/sh }, [1]{ foo bar }, [2]{ %{request.User-Name} }
 
 # and multiple xlats inside of quotes
-xlat_argv /bin/sh "foo bar" "%{User-Name} %{Filter-Id}"
-match [0]{ /bin/sh }, [1]{ foo bar }, [2]{ %{User-Name} %{Filter-Id} }
+xlat_argv /bin/sh "foo bar" "%{request.User-Name} %{Filter-Id}"
+match [0]{ /bin/sh }, [1]{ foo bar }, [2]{ %{request.User-Name} %{request.Filter-Id} }
 
 # and errors
-xlat_argv /bin/sh "foo bar" "%{User-Name} %{Filter-Id"
-match ERROR offset 45: Missing closing brace
+xlat_argv /bin/sh "foo bar" "%{request.User-Name} %{Filter-Id"
+match ERROR offset 53: Missing closing brace
 
 # and text immediately after a variable expansion
 xlat_argv echo hello %{Tmp-String-0}:1234 world
-match [0]{ echo }, [1]{ hello }, [2]{ %{Tmp-String-0}:1234 }, [3]{ world }
+match [0]{ echo }, [1]{ hello }, [2]{ %{request.Tmp-String-0}:1234 }, [3]{ world }
 
 xlat %(debug: 5)
 match %(debug: 5)
@@ -312,8 +312,8 @@ match %(debug: "foo")
 #
 #  This is correct.
 #
-xlat %(rpad:&User-Name 5 x)
-match %(rpad:&User-Name 5 x)
+xlat %(rpad:&request.User-Name 5 x)
+match %(rpad:&request.User-Name 5 x)
 
 #
 #  The second argument should be an integer.
@@ -321,8 +321,8 @@ match %(rpad:&User-Name 5 x)
 #  @todo - we don't currently track string offsets for intermediate nodes,
 #  so the "offset 23" is wrong.  It also doesn't say *which* string is wrong.  We'll fix that later.
 #
-xlat %(rpad:&User-Name foo x)
-match ERROR offset 24: Failed parsing argument 1 as type 'uint64'
+xlat %(rpad:&request.User-Name foo x)
+match ERROR offset 32: Failed parsing argument 1 as type 'uint64'
 
 count
 match 187
index 839c711d8530a6a734795a6381aec2013ba199f1..e437617ccb34fc4a86c877c1aa87be19ff60abd0 100644 (file)
@@ -139,13 +139,13 @@ xlat_purify 'handled' &&&Packet-Type == Access-Challenge
 match (&Packet-Type == Access-Challenge)
 
 xlat_purify &reply == &request
-match ERROR offset 1: Cannot use list references in condition
+match ERROR offset 1: Cannot compare structural types
 
 xlat_purify &reply == "hello"
-match ERROR offset 1: Cannot use list references in condition
+match ERROR offset 1: Cannot compare structural types
 
 xlat_purify "hello" == &reply
-match ERROR offset 12: Cannot use list references in condition
+match ERROR offset 12: Cannot compare structural types
 
 
 #
@@ -238,8 +238,8 @@ match (&Session-Timeout == '10')
 #
 #  @todo - yuck.  Suppress full path?
 #
-xlat_purify &Event-Timestamp == "January 1, 2012 %{User-Name}"
-match (&Event-Timestamp == %(cast:string "January 1, 2012 %{request[0].User-Name}"))
+xlat_purify &Event-Timestamp == "January 1, 2012 %{request.User-Name}"
+match (&Event-Timestamp == %(cast:string "January 1, 2012 %{request.User-Name}"))
 
 # This one is NOT an expansion, so it's parsed into normal form
 xlat_purify &Event-Timestamp == 'January 1 2012'
@@ -277,8 +277,8 @@ xlat_purify <ipaddr>127.0.0.1 == %{md4:127.0.0.1}
 match NULL
 
 # @todo - yuck, don't print full path?
-xlat_purify <ipaddr>127.0.0.1 == %{md4: SELECT user FROM table WHERE user='%{User-Name}'}
-match (127.0.0.1 == %{md4: SELECT user FROM table WHERE user='%{request[0].User-Name}'})
+xlat_purify <ipaddr>127.0.0.1 == %{md4: SELECT user FROM table WHERE user='%{request.User-Name}'}
+match (127.0.0.1 == %{md4: SELECT user FROM table WHERE user='%{request.User-Name}'})
 
 xlat_purify <ether> 00:11:22:33:44:55 == "00:11:22:33:44:55"
 match true
@@ -521,8 +521,8 @@ match (&User-Name[n] == "bob")
 #xlat_purify &Foo-Bar
 #match &Foo-Bar
 
-xlat_purify &Acct-Input-Octets > "%{Session-Timeout}"
-match (&Acct-Input-Octets > %(cast:string "%{request[0].Session-Timeout}"))
+xlat_purify &Acct-Input-Octets > "%{request.Session-Timeout}"
+match (&Acct-Input-Octets > %(cast:string "%{request.Session-Timeout}"))
 
 xlat_purify &Acct-Input-Octets > &Session-Timeout
 match (&Acct-Input-Octets > &Session-Timeout)