*/
#define DEFAULT_BUFFER_SIZE 1024
+#define CURRENT_DICT(_cc) (tmpl_attr_ctx_rules_default_dict(&(_cc)->tmpl_rules.attr) ? tmpl_attr_ctx_rules_default_dict(&(_cc)->tmpl_rules.attr) : (_cc)->config->dict)
+
typedef enum {
RESULT_OK = 0, //!< Not an error - Result as expected.
RESULT_NOOP, //!< Not an error - Did nothing...
/*
* Decrease ref count if we're loading in a new dictionary
*/
- if (cc->tmpl_rules.attr.dict_def) {
- if (fr_dict_const_free(&cc->tmpl_rules.attr.dict_def, __FILE__) < 0) RETURN_COMMAND_ERROR();
+ if (tmpl_attr_ctx_rules_default_dict(&cc->tmpl_rules.attr)) {
+ fr_dict_t const *attr_dict = tmpl_attr_ctx_rules_default_dict(&cc->tmpl_rules.attr);
+ if (fr_dict_const_free(&attr_dict, __FILE__) < 0) RETURN_COMMAND_ERROR();
}
q = strchr(in, ' ');
talloc_free(tmp);
if (ret < 0) RETURN_COMMAND_ERROR();
- cc->tmpl_rules.attr.dict_def = dict;
+
+ cc->tmpl_rules.attr.ctx = tmpl_attr_ctx_rules_default(tmpl_attr_ctx_rules_default_request(&cc->tmpl_rules.attr),
+ tmpl_attr_ctx_rules_default_list(&cc->tmpl_rules.attr),
+ dict);
/*
* Dump the dictionary if we're in super debug mode
*/
- if (fr_debug_lvl > 5) fr_dict_debug(cc->tmpl_rules.attr.dict_def);
+ if (fr_debug_lvl > 5) fr_dict_debug(dict);
RETURN_OK(0);
}
ssize_t slen;
char *p, *end;
fr_pair_t *vp;
- fr_dict_t const *dict = cc->tmpl_rules.attr.dict_def ? cc->tmpl_rules.attr.dict_def : cc->config->dict;
+ fr_dict_t const *dict = CURRENT_DICT(cc);
fr_pair_list_init(&head);
ssize_t dec_len;
fr_cond_t *cond;
CONF_SECTION *cs;
- size_t len;
+ ssize_t slen;
cs = cf_section_alloc(NULL, NULL, "if", "condition");
if (!cs) {
goto return_error;
}
- len = cond_print(&FR_SBUFF_OUT(data, COMMAND_OUTPUT_MAX), cond);
+ slen = cond_print(&FR_SBUFF_OUT(data, COMMAND_OUTPUT_MAX), cond);
talloc_free(cs);
- RETURN_OK(len);
+ if (slen < 0) {
+ fr_strerror_printf_push_head("ERROR OOB offset %d", (int) -slen);
+ RETURN_COMMAND_ERROR();
+ }
+ RETURN_OK((size_t)slen);
}
static size_t command_count(command_result_t *result, command_file_ctx_t *cc,
* point to produce fr_pair_ts.
*/
while (to_dec < to_dec_end) {
- slen = tp->func(cc->tmp_ctx, &head, fr_dict_root(cc->tmpl_rules.attr.dict_def ? cc->tmpl_rules.attr.dict_def : cc->config->dict),
+ slen = tp->func(cc->tmp_ctx, &head, fr_dict_root(CURRENT_DICT(cc)),
(uint8_t *)to_dec, (to_dec_end - to_dec), decode_ctx);
cc->last_ret = slen;
if (slen <= 0) {
static size_t command_dictionary_dump(command_result_t *result, command_file_ctx_t *cc,
UNUSED char *data, size_t data_used, UNUSED char *in, UNUSED size_t inlen)
{
- fr_dict_debug(cc->tmpl_rules.attr.dict_def ? cc->tmpl_rules.attr.dict_def : cc->config->dict);
+ fr_dict_debug(CURRENT_DICT(cc));
/*
* Don't modify the contents of the data buffer
RETURN_COMMAND_ERROR();
}
- dict = cc->tmpl_rules.attr.dict_def ? cc->tmpl_rules.attr.dict_def : cc->config->dict;
+ dict = CURRENT_DICT(cc);
if (fr_pair_list_afrom_str(cc->tmp_ctx, fr_dict_root(dict),
p, in + inlen - p, &head) != T_EOL) {
CLEAR_TEST_POINT(cc);
for (vp = fr_pair_dcursor_iter_init(&cursor, &head,
tp->next_encodable ? tp->next_encodable : fr_proto_next_encodable,
- cc->tmpl_rules.attr.dict_def ? cc->tmpl_rules.attr.dict_def : cc->config->dict);
+ CURRENT_DICT(cc));
vp;
vp = fr_dcursor_current(&cursor)) {
slen = tp->func(&FR_DBUFF_TMP(enc_p, enc_end), &cursor, encode_ctx);
{
fr_dict_attr_t const *da;
fr_pair_t *head;
- fr_dict_t const *dict = cc->tmpl_rules.attr.dict_def ? cc->tmpl_rules.attr.dict_def : cc->config->dict;
+ fr_dict_t const *dict = CURRENT_DICT(cc);
da = fr_dict_attr_by_name(NULL, fr_dict_root(fr_dict_internal()), "request");
fr_assert(da != NULL);
{
fr_dict_attr_t const *da;
fr_pair_t *head;
- fr_dict_t const *dict = cc->tmpl_rules.attr.dict_def ? cc->tmpl_rules.attr.dict_def : cc->config->dict;
+ fr_dict_t const *dict = CURRENT_DICT(cc);
da = fr_dict_attr_by_name(NULL, fr_dict_root(fr_dict_internal()), "request");
fr_assert(da != NULL);
RETURN_COMMAND_ERROR();
}
- dict = cc->tmpl_rules.attr.dict_def ? cc->tmpl_rules.attr.dict_def : cc->config->dict;
+ dict = CURRENT_DICT(cc);
if (fr_pair_list_afrom_str(cc->tmp_ctx, fr_dict_root(dict),
p, in + inlen - p, &head) != T_EOL) {
CLEAR_TEST_POINT(cc);
dir = cc->path;
}
- ret = fr_dict_read(UNCONST(fr_dict_t *, cc->tmpl_rules.attr.dict_def), dir, name);
+ ret = fr_dict_read(UNCONST(fr_dict_t *, tmpl_attr_ctx_rules_default_dict(&cc->tmpl_rules.attr)), dir, name);
talloc_free(tmp);
if (ret < 0) RETURN_COMMAND_ERROR();
fr_pair_list_init(&head);
ctx.ctx = cc->tmp_ctx;
- ctx.parent = fr_dict_root(cc->tmpl_rules.attr.dict_def);
+ ctx.parent = fr_dict_root(tmpl_attr_ctx_rules_default_dict(&cc->tmpl_rules.attr));
ctx.list = &head;
p = in;
{
fr_dict_attr_err_t err;
fr_slen_t slen;
+ fr_dict_attr_t const *da;
- slen = fr_dict_attr_by_oid_substr(&err,
- &rules->attr.parent,
- rules->attr.dict_def ? fr_dict_root(rules->attr.dict_def) :
- fr_dict_root(fr_dict_internal()),
+ slen = fr_dict_attr_by_oid_substr(&err, &da,
+ tmpl_attr_ctx_rules_default_dict(&rules->attr) ?
+ fr_dict_root(tmpl_attr_ctx_rules_default_dict(&rules->attr)) :
+ fr_dict_root(fr_dict_internal()),
value, NULL);
if (err != FR_DICT_ATTR_OK) FR_SBUFF_ERROR_RETURN(value);
+
+ rules->attr.ctx = tmpl_attr_ctx_rules_nested(da);
+
return slen;
}
static ssize_t command_tmpl_rule_list_def(UNUSED TALLOC_CTX *ctx, tmpl_rules_t *rules, fr_sbuff_t *value)
{
- ssize_t slen;
-
- fr_sbuff_out_by_longest_prefix(&slen, &rules->attr.list_def, pair_list_table, value, PAIR_LIST_UNKNOWN);
+ ssize_t slen;
+ fr_dict_attr_t const *list;
- if (rules->attr.list_def == PAIR_LIST_UNKNOWN) {
+ slen = tmpl_attr_list_from_substr(&list, value);
+ if (slen == 0) {
fr_strerror_printf("Invalid list specifier \"%pV\"",
fr_box_strvalue_len(fr_sbuff_current(value), fr_sbuff_remaining(value)));
}
+ rules->attr.ctx = tmpl_attr_ctx_rules_default(tmpl_attr_ctx_rules_default_request(&rules->attr),
+ list,
+ tmpl_attr_ctx_rules_default_dict(&rules->attr));
+
return slen;
}
static ssize_t command_tmpl_rule_request_def(TALLOC_CTX *ctx, tmpl_rules_t *rules, fr_sbuff_t *value)
{
- fr_slen_t slen;
+ fr_slen_t slen;
+ FR_DLIST_HEAD(tmpl_request_list) const *request_def;
slen = tmpl_request_ref_list_afrom_substr(ctx, NULL,
- &rules->attr.request_def,
+ &request_def,
value,
NULL,
NULL);
fr_box_strvalue_len(fr_sbuff_current(value), fr_sbuff_remaining(value)));
}
+ rules->attr.ctx = tmpl_attr_ctx_rules_default(request_def,
+ tmpl_attr_ctx_rules_default_list(&rules->attr),
+ tmpl_attr_ctx_rules_default_dict(&rules->attr));
+
return slen;
}
dec_len = xlat_tokenize(cc->tmp_ctx, &head, &FR_SBUFF_IN(in, input_len), &p_rules,
&(tmpl_rules_t) {
.attr = {
- .dict_def = cc->tmpl_rules.attr.dict_def ?
- cc->tmpl_rules.attr.dict_def : cc->config->dict,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, CURRENT_DICT(cc)),
.allow_unresolved = cc->tmpl_rules.attr.allow_unresolved
},
});
dec_len = xlat_tokenize_expression(cc->tmp_ctx, &head, &FR_SBUFF_IN(in, input_len), NULL,
&(tmpl_rules_t) {
.attr = {
- .dict_def = cc->tmpl_rules.attr.dict_def ?
- cc->tmpl_rules.attr.dict_def : cc->config->dict,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, CURRENT_DICT(cc)),
.allow_unresolved = cc->tmpl_rules.attr.allow_unresolved,
}
});
dec_len = xlat_tokenize_ephemeral_expression(cc->tmp_ctx, &head, el, &FR_SBUFF_IN(in, input_len), NULL,
&(tmpl_rules_t) {
.attr = {
- .dict_def = cc->tmpl_rules.attr.dict_def ?
- cc->tmpl_rules.attr.dict_def : cc->config->dict,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, CURRENT_DICT(cc)),
.allow_unresolved = cc->tmpl_rules.attr.allow_unresolved,
},
});
NULL,
&(tmpl_rules_t) {
.attr = {
- .dict_def = cc->tmpl_rules.attr.dict_def ?
- cc->tmpl_rules.attr.dict_def : cc->config->dict,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, CURRENT_DICT(cc)),
.allow_unresolved = cc->tmpl_rules.attr.allow_unresolved
},
});
size_t match_len;
char *p;
+ /*
+ * Don't accidentally print irrelevant errors
+ */
+ fr_strerror_clear();
+
p = in;
fr_skip_whitespace(p);
if (*p == '\0') RETURN_NOOP(data_used);
*/
if (result->error_to_data) data_used = strerror_concat(data, COMMAND_OUTPUT_MAX);
- fr_assert((size_t)data_used < COMMAND_OUTPUT_MAX);
+ fr_assert_msg((size_t)data_used < COMMAND_OUTPUT_MAX,
+ "Command printed %zu bytes, buffer max was %zu bytes", data_used, (size_t)COMMAND_OUTPUT_MAX);
data[data_used] = '\0'; /* Ensure the data buffer is \0 terminated */
if (data_used) {
finish:
if (fp && (fp != stdin)) fclose(fp);
- /*
- * Free any residual resources we loaded.
- */
- if (cc && (fr_dict_const_free(&cc->tmpl_rules.attr.dict_def, __FILE__) < 0)) {
- fr_perror("unit_test_attribute");
- ret = -1;
+ {
+ fr_dict_t const *dict = tmpl_attr_ctx_rules_default_dict(&cc->tmpl_rules.attr);
+
+ /*
+ * Free any residual resources we loaded.
+ */
+ if (cc && (fr_dict_const_free(&dict, __FILE__) < 0)) {
+ fr_perror("unit_test_attribute");
+ ret = -1;
+ }
}
fr_dict_global_ctx_set(config->dict_gctx); /* Switch back to the main dict ctx */
tmpl_rules_t parse_rules = {
.attr = {
- .dict_def = dict_radius,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, dict_radius),
.allow_foreign = false, /* tests are in the RADIUS dictionary */
}
};
&FR_SBUFF_IN(fmt, talloc_array_length(fmt) - 1),
NULL,
&(tmpl_rules_t) {
- .attr = {
- .dict_def = dict_protocol,
- .allow_unresolved = true,
- }
- }
+ .attr = {
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, dict_protocol),
+ .allow_unresolved = true,
+ }
+ }
);
if (slen <= 0) {
talloc_free(xlat_ctx);
if (app_process->compile_list) {
tmpl_rules_t parse_rules = {
.attr = {
- .dict_def = virtual_server_dict_by_name(cf_section_name2(inst->server_cs))
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, virtual_server_dict_by_name(cf_section_name2(inst->server_cs)))
}
};
tmpl_rules_t parse_rules = {
.attr = {
- .dict_def = request->dict,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, request->dict),
.prefix = TMPL_ATTR_REF_PREFIX_AUTO
}
};
* @copyright 2000,2006,2015 The FreeRADIUS server project
* @copyright 2011 TekSavvy Solutions (gabe@teksavvy.com)
*/
+#include "lib/server/tmpl.h"
#include <freeradius-devel/redis/base.h>
#include <freeradius-devel/util/debug.h>
#include <freeradius-devel/util/value.h>
&(tmpl_rules_t){
.attr = {
.prefix = TMPL_ATTR_REF_PREFIX_NO,
- .dict_def = request->dict
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, request->dict)
}
});
if (slen <= 0) {
static inline CC_HINT(always_inline) int cf_tmpl_rules_verify(CONF_SECTION *cs, tmpl_rules_t const *rules)
{
+ fr_dict_t const *dict;
+
+ /*
+ * Only validate if we're parsing with defaults
+ */
+ if (!tmpl_attr_ctx_rules_is_default(&rules->attr)) return 0;
+
+ dict = tmpl_attr_ctx_rules_default_dict(&rules->attr);
if (cf_section_has_parent(cs, "policy", NULL)) {
- if (!fr_cond_assert_msg(!rules->attr.dict_def || (rules->attr.dict_def == fr_dict_internal()),
+ if (!fr_cond_assert_msg(!dict || (dict == fr_dict_internal()),
"Protocol dictionary must be NULL not %s",
- fr_dict_root(rules->attr.dict_def)->name)) return -1;
+ fr_dict_root(dict)->name)) return -1;
} else {
- if (!fr_cond_assert_msg(rules->attr.dict_def, "No protocol dictionary set")) return -1;
- if (!fr_cond_assert_msg(rules->attr.dict_def != fr_dict_internal(), "rules->attr.dict_def must not be the internal dictionary")) return -1;
+ if (!fr_cond_assert_msg(dict, "No protocol dictionary set")) return -1;
+ if (!fr_cond_assert_msg(dict != fr_dict_internal(), "rules->attr.dict_def must not be the internal dictionary")) return -1;
}
if (!fr_cond_assert_msg(!rules->attr.allow_foreign, "rules->allow_foreign must be false")) return -1;
was_regex = false;
continue;
}
-
+
if (*p == ')') {
if (!depth) {
fr_strerror_const("Too many ')'");
*/
if ((*p == '$') || (*p == '%')) {
if (end && ((p + 2) >= end)) goto fail;
-
+
if ((p[1] == '{') || ((p[0] == '$') && (p[1] == '('))) {
slen = fr_skip_xlat(p, end);
* condition is done when it reaches end of string, or CR LF.
*/
if (!expect_section && (depth == 0) && ((end && (p == end)) || (*p < ' '))) return p - start;
-
+
/*
* Unexpected end of condition.
*/
t_rules = (tmpl_rules_t) {
.attr = {
- .dict_def = dict,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, dict),
.allow_unresolved = true,
.allow_unknown = true
}
slen = xlat_tokenize(cs, &xlat,
&FR_SBUFF_IN(cp->value, talloc_array_length(cp->value) - 1), NULL,
&(tmpl_rules_t) {
- .attr = {
- .dict_def = dict,
- .allow_unknown = false,
- .allow_unresolved = false,
- .allow_foreign = (dict == NULL)
- },
+ .attr = {
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, dict),
+ .allow_unknown = false,
+ .allow_unresolved = false,
+ .allow_foreign = (dict == NULL)
+ },
});
if (slen < 0) {
char *spaces, *text;
* @copyright 2013 Alan DeKok (aland@freeradius.org)
*/
+
+#include "tmpl.h"
RCSID("$Id$")
+
#include <freeradius-devel/server/cond.h>
#include <freeradius-devel/server/exec.h>
#include <freeradius-devel/server/exec_legacy.h>
#include <freeradius-devel/server/map.h>
#include <freeradius-devel/server/paircmp.h>
#include <freeradius-devel/server/tmpl.h>
+#include <freeradius-devel/server/tmpl.h>
#include <freeradius-devel/server/tmpl_dcursor.h>
-
-#include <freeradius-devel/util/debug.h>
#include <freeradius-devel/util/base16.h>
-#include <freeradius-devel/util/pair_legacy.h>
+#include <freeradius-devel/util/debug.h>
#include <freeradius-devel/util/misc.h>
+#include <freeradius-devel/util/pair_legacy.h>
+#include <freeradius-devel/util/sbuff.h>
#include <freeradius-devel/protocol/radius/rfc2865.h>
#include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
*/
if (is_child) {
fr_assert(tmpl_is_attr(parent->lhs));
- our_lhs_rules.attr.parent = tmpl_attr_tail_da(parent->lhs);
+ our_lhs_rules.attr.ctx = tmpl_attr_ctx_rules_nested(tmpl_attr_tail_da(parent->lhs));
slen = tmpl_afrom_attr_substr(map, NULL, &map->lhs, &our_in,
&map_parse_rules_bareword_quoted, &our_lhs_rules);
*/
if (update) {
fr_slen_t slen;
- char const *p;
+ char const *name2;
+ FR_DLIST_HEAD(tmpl_request_list) const *rql;
+ fr_dict_attr_t const *list = NULL;
+ fr_sbuff_t qual;
- p = cf_section_name2(cs);
- if (!p) goto do_children;
+ name2 = cf_section_name2(cs);
+ if (!name2) goto do_children;
+
+ qual = FR_SBUFF_IN(name2, strlen(name2));
MEM(tmp_ctx = talloc_init_const("tmp"));
- slen = tmpl_request_ref_list_afrom_substr(ctx, NULL, &our_lhs_rules.attr.request_def,
- &FR_SBUFF_IN(p, strlen(p)), NULL, NULL);
+ slen = tmpl_request_ref_list_afrom_substr(ctx, NULL, &rql, &qual, NULL, NULL);
if (slen < 0) {
cf_log_err(ci, "Default request specified in mapping section is invalid");
talloc_free(tmp_ctx);
return -1;
}
- p += slen;
-
- our_lhs_rules.attr.list_def = fr_table_value_by_str(pair_list_table, p, PAIR_LIST_UNKNOWN);
- if (our_lhs_rules.attr.list_def == PAIR_LIST_UNKNOWN) {
- cf_log_err(ci, "Default list \"%s\" specified in mapping section is invalid", p);
+ slen = tmpl_attr_list_from_substr(&list, &qual);
+ if (slen == 0) {
+ cf_log_err(ci, "Default list \"%.*s\" specified in mapping section is invalid", (unsigned int)fr_sbuff_remaining(&qual), fr_sbuff_current(&qual));
talloc_free(tmp_ctx);
return -1;
}
+
+ our_lhs_rules.attr.ctx = tmpl_attr_ctx_rules_default(rql, list, NULL);
}
do_children:
* inner section.
*/
our_lhs_rules.attr.prefix = TMPL_ATTR_REF_PREFIX_NO;
- our_lhs_rules.attr.parent = tmpl_attr_tail_da(map->lhs);
-
- /*
- * Groups MAY change dictionaries. If so, then swap the dictionary and the parent.
- */
- if (our_lhs_rules.attr.parent->type == FR_TYPE_GROUP) {
- fr_dict_attr_t const *ref;
- fr_dict_t const *dict, *internal;
-
- ref = fr_dict_attr_ref(our_lhs_rules.attr.parent);
- dict = fr_dict_by_da(ref);
- internal = fr_dict_internal();
-
- if ((dict != internal) && (dict != our_lhs_rules.attr.dict_def)) {
- our_lhs_rules.attr.dict_def = dict;
- our_lhs_rules.attr.parent = ref;
- }
- }
+ our_lhs_rules.attr.ctx = tmpl_attr_ctx_rules_nested(tmpl_attr_tail_da(map->lhs));
/*
* This prints out any relevant error
tmpl_attr_set_leaf_da(map->lhs, vp->da);
tmpl_attr_set_leaf_num(map->lhs, NUM_UNSPEC);
- tmpl_attr_set_request_ref(map->lhs, rules->attr.request_def);
- tmpl_attr_set_list(map->lhs, rules->attr.list_def);
-
+ tmpl_attr_set_request_ref(map->lhs, tmpl_attr_ctx_rules_default_request(&rules->attr));
+ tmpl_attr_set_list(map->lhs, tmpl_attr_ctx_rules_default_list(&rules->attr));
+
tmpl_print(&FR_SBUFF_OUT(buffer, sizeof(buffer)), map->lhs, TMPL_ATTR_REF_PREFIX_YES, NULL);
tmpl_set_name(map->lhs, T_BARE_WORD, buffer, -1);
/*
* We always put the request pairs into the environment
*/
- input_pairs = tmpl_list_head(request, PAIR_LIST_REQUEST);
+ input_pairs = &request->pair_list.request->vp_group;
/*
* Automagically switch output type depending on our destination
fr_pair_list_t *from = NULL;
if (tmpl_request_ptr(&context, tmpl_request(map->rhs)) == 0) {
- from = tmpl_list_head(context, tmpl_list(map->rhs));
+ from = tmpl_list_head(context, map->rhs);
}
if (!from) return 0;
map_t exp_map;
tmpl_t *exp_lhs;
- tmpl_pair_list_t list_ref;
tmpl_dcursor_ctx_t cc = {};
slen = tmpl_afrom_attr_str(tmp_ctx, NULL, &exp_lhs, attr_str,
&(tmpl_rules_t){
.attr = {
- .dict_def = request->dict,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, request->dict),
.prefix = TMPL_ATTR_REF_PREFIX_NO
}
});
goto finish;
}
- list_ref = tmpl_list(map->lhs);
- list = tmpl_list_head(context, list_ref);
+ list = tmpl_list_head(context, map->lhs);
if (!list) {
- REDEBUG("Mapping \"%.*s\" -> \"%.*s\" cannot be performed due to to invalid list qualifier \"%s\" in left side of map",
- (int)map->rhs->len, map->rhs->name, (int)map->lhs->len, map->lhs->name,
- fr_table_str_by_value(pair_list_table, list_ref, "<INVALID>"));
+ REDEBUG("Mapping \"%.*s\" -> \"%.*s\" cannot be performed due to to invalid list qualifier in left side of map",
+ (int)map->rhs->len, map->rhs->name, (int)map->lhs->len, map->lhs->name);
rcode = -2;
goto finish;
}
- parent = tmpl_list_ctx(context, tmpl_list(map->lhs));
+ parent = tmpl_list_ctx(context, map->lhs);
fr_assert(parent);
/*
{
request_t *context = request;
fr_pair_list_t *list;
- tmpl_pair_list_t list_ref;
if (tmpl_request_ptr(&context, tmpl_request(src_dst)) < 0) {
RPEDEBUG("Mapping \"%.*s\" -> \"%.*s\" cannot be performed",
return NULL;
}
- list_ref = tmpl_list(src_dst);
- list = tmpl_list_head(context, list_ref);
+ list = tmpl_list_head(request, src_dst);
if (!list) {
- REDEBUG("Mapping \"%.*s\" -> \"%.*s\" cannot be performed due to to invalid list qualifier \"%s\"",
- (int)map->rhs->len, map->rhs->name, (int)map->lhs->len, map->lhs->name,
- fr_table_str_by_value(pair_list_table, list_ref, "<INVALID>"));
+ REDEBUG("Mapping \"%.*s\" -> \"%.*s\" cannot be performed due to to invalid list qualifier",
+ (int)map->rhs->len, map->rhs->name, (int)map->lhs->len, map->lhs->name);
return NULL;
}
slen = tmpl_afrom_attr_str(tmp_ctx, NULL, &map_tmp.lhs, lhs_result_head->vb_strvalue,
&(tmpl_rules_t){
.attr = {
- .dict_def = request->dict,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, request->dict),
.prefix = TMPL_ATTR_REF_PREFIX_NO
}
});
n_mod->lhs = tmpl_alloc(n, TMPL_TYPE_ATTR, T_BARE_WORD, mutated->lhs->name, mutated->lhs->len);
if (!n_mod->lhs) goto error;
- if (tmpl_attr_copy(n_mod->lhs, mutated->lhs) < 0) goto error;
+ tmpl_attr_replace(n_mod->lhs, tmpl_attr(mutated->lhs));
+ tmpl_request_ref_replace(n_mod->lhs, tmpl_request(mutated->lhs));
tmpl_attr_set_leaf_da(n_mod->lhs, vp->da);
map_t *mod;
tmpl_rules_t rules = {
.attr = {
- .request_def = tmpl_request(mutated->lhs),
- .list_def = tmpl_list(mutated->lhs)
+ .ctx = tmpl_attr_ctx_rules_default(tmpl_request(mutated->lhs), tmpl_list(mutated->lhs), NULL)
}
};
context = request;
if (!fr_cond_assert(mod && tmpl_request_ptr(&context, tmpl_request(mod->lhs)) == 0)) return -1;
- vp_list = tmpl_list_head(context, tmpl_list(mod->lhs));
+ vp_list = tmpl_list_head(context, mod->lhs);
if (!fr_cond_assert(vp_list)) return -1;
- parent = tmpl_list_ctx(context, tmpl_list(mod->lhs));
+ parent = tmpl_list_ctx(context, mod->lhs);
fr_assert(parent);
/*
*/
#define TMPL_MAX_REQUEST_REF_NESTING 10
-/*
- * Forward declarations
- */
-typedef enum pair_list_e {
- PAIR_LIST_REQUEST = 0, //!< Attributes in incoming or internally proxied
- ///< request (default).
- PAIR_LIST_REPLY, //!< Attributes to send in the response.
- PAIR_LIST_CONTROL, //!< Attributes that change the behaviour of
- ///< modules.
- PAIR_LIST_STATE, //!< Attributes to store multiple rounds of
- ///< challenges/responses.
- PAIR_LIST_UNKNOWN //!< Unknown list.
-} tmpl_pair_list_t;
-
-extern fr_table_num_ordered_t const pair_list_table[];
-extern size_t pair_list_table_len;
-
typedef enum requests_ref_e {
REQUEST_CURRENT = 0, //!< The current request (default).
REQUEST_OUTER, //!< #request_t containing the outer layer of the EAP
extern size_t tmpl_type_table_len;
typedef struct tmpl_rules_s tmpl_rules_t;
+typedef struct tmpl_attr_ctx_rules_s tmpl_attr_ctx_rules_t;
typedef struct tmpl_attr_rules_s tmpl_attr_rules_t;
typedef struct tmpl_xlat_rules_s tmpl_xlat_rules_t;
typedef struct tmpl_res_rules_s tmpl_res_rules_t;
typedef struct tmpl_s tmpl_t;
+typedef struct tmpl_attr_s tmpl_attr_t;
#include <freeradius-devel/unlang/xlat.h>
#include <freeradius-devel/unlang/xlat_ctx.h>
# define _CONST
#endif
+/** Define entry and head types for tmpl request references
+ */
+FR_DLIST_TYPES(tmpl_request_list)
+#define tmpl_request_list_foreach(_list_head, _iter) fr_dlist_foreach(tmpl_request_list_dlist_head(_list_head), tmpl_request_t, _iter)
+#define tmpl_request_list_foreach_safe(_list_head, _iter) fr_dlist_foreach_safe(tmpl_request_list_dlist_head(_list_head), tmpl_request_t, _iter)
+#define tmpl_request_list_verify(_list_head) _tmpl_request_list_verify(__FILE__, __LINE__, _list_head)
+
+/** Define entry and head types for attribute reference lists
+ */
+FR_DLIST_TYPES(tmpl_attr_list)
+#define tmpl_attr_list_foreach(_list_head, _iter) fr_dlist_foreach(tmpl_attr_list_dlist_head(_list_head), tmpl_attr_t, _iter)
+#define tmpl_attr_list_foreach_safe(_list_head, _iter) fr_dlist_foreach_safe(tmpl_attr_list_dlist_head(_list_head), tmpl_attr_t, _iter)
+#define tmpl_attr_list_verify(_list_head) _tmpl_attr_list_verify(__FILE__, __LINE__, _list_head)
+
+/** Different ctx types in which attribute references can be resolved
+ */
+typedef enum {
+ TMPL_ATTR_RULES_CTX_DEFAULTS = 0, //!< Start resolving references with a default dictionary
+ ///< a default list, and a default request.
+ TMPL_ATTR_RULES_CTX_INHERIT, //!< Copy request refs and attr refs from another tmpl.
+ TMPL_ATTR_RULES_CTX_NESTED //!< Resove references within the context of another attribute.
+} tmpl_attr_ctx_rules_type_t;
+
+/** Context in which to evaluate other attribute references
+ */
+struct tmpl_attr_ctx_rules_s {
+ union {
+ /** Outer, un-nested references
+ */
+ struct {
+
+ FR_DLIST_HEAD(tmpl_request_list) _CONST *request; //!< Default request to use with
+ ///< unqualified attribute references.
+ ///< If NULL the request is assumed to
+ ///< but the current request.
+ ///< Usually this will be one of
+ ///< - tmpl_request_def_current
+ ///< - tmpl_request_def_outer
+ ///< - tmpl_request_def_parent
+ ///< If a custom list needs to be
+ ///< used it should be allocated on
+ ///< the stack and a pointer to it
+ ///< placed here.
+
+ fr_dict_attr_t const *list; //!< A default list prefix, used if no context
+ ///< has been specified, and no list qualifiers
+ ///< were found.
+
+ fr_dict_t const *dict; //!< Default dictionary to use
+ ///< with unqualified attribute references.
+ } defaults;
+
+ /** Context is derived from another tmpl
+ *
+ * Usually when a LHS attribute is used as the context for a RHS attribute
+ */
+ struct {
+ FR_DLIST_HEAD(tmpl_request_list) _CONST *request; //!< Request qualifiers to copy
+
+ FR_DLIST_HEAD(tmpl_attr_list) _CONST *attr; //!< Attr qualifiers to copy into the attribute
+ ///< list. We
+ } inherit;
+
+ /** Context is derived from nesting i.e. one tmpl inside another
+ */
+ fr_dict_attr_t const *nested; //!< Resume parsing using this
+ };
+
+ tmpl_attr_ctx_rules_type_t type; //!< What type of context was specified.
+};
+
/** Specify whether attribute references require a prefix
*
*/
TMPL_ATTR_REF_PREFIX_AUTO //!< Attribute refs may have a '&' prefix.
} tmpl_attr_prefix_t;
-/** Define entry and head types for tmpl request references
- *
- */
-FR_DLIST_TYPES(tmpl_request_list)
-
struct tmpl_attr_rules_s {
- fr_dict_t const *dict_def; //!< Default dictionary to use
- ///< with unqualified attribute references.
-
- fr_dict_attr_t const *parent; //!< Point in dictionary tree to resume parsing
- ///< from. If this is provided then dict_def
- ///< request_def and list_def will be ignored
- ///< and the presence of any of those qualifiers
- ///< will be treated as an error.
-
- FR_DLIST_HEAD(tmpl_request_list) _CONST *request_def; //!< Default request to use with
- ///< unqualified attribute references.
- ///< If NULL the request is assumed to
- ///< but the current request.
- ///< Usually this will be one of
- ///< - tmpl_request_def_current
- ///< - tmpl_request_def_outer
- ///< - tmpl_request_def_parent
- ///< If a custom list needs to be
- ///< used it should be allocated on
- ///< the stack and a pointer to it
- ///< placed here.
-
- tmpl_pair_list_t list_def; //!< Default list to use with unqualified
- ///< attribute reference.
+ tmpl_attr_ctx_rules_t ctx; //!< Parsing context for attribute tmpls.
tmpl_attr_prefix_t prefix; //!< Whether the attribute reference requires
///< a prefix.
///< This should be used as part of a multi-pass
///< approach to parsing.
- uint8_t allow_foreign:1; //!< Allow arguments not found in dict_def.
+ uint8_t allow_foreign:1; //!< Allow arguments not found in dict_def.
uint8_t disallow_internal:1; //!< Allow/fallback to internal attributes.
uint8_t disallow_filters:1; //!< disallow filters.
};
+/** Initialise a defaults ctx with request/list/dict qualifiers
+ *
+ * @param[in] _request May be NULL or one of the following static request qualifier lists:
+ * - tmpl_request_def_current
+ * - tmpl_request_def_outer
+ * - tmpl_request_def_parent
+ * @param[in] _list May be NULL or one of the following static attr ref lists:
+ * - request_attr_request
+ * - request_attr_reply
+ * - request_attr_control
+ * - request_attr_state
+ * @param[in] _dict May be NULL or any valid dictionary
+ */
+#define tmpl_attr_ctx_rules_default(_request, _list, _dict) \
+ (tmpl_attr_ctx_rules_t){ \
+ .defaults = { \
+ .request = _request, \
+ .list = _list, \
+ .dict = _dict \
+ }, \
+ .type = TMPL_ATTR_RULES_CTX_DEFAULTS \
+ }
+
+/** Initialise an inehrit ctx from a tmpl
+ *
+ * @param[in] _tmpl To copy request qualifiers and attr references from
+ */
+#define tmpl_attr_ctx_rules_inherit(_tmpl) \
+ (tmpl_attr_ctx_rules_t){ \
+ .copy = { \
+ .request = tmpl_request(_tmpl), \
+ .attr = tmpl_attr(_tmpl) \
+ }, \
+ .type = TMPL_ATTR_RULES_CTX_COPY \
+ }
+
+/** Initialise a nested ctx from a da
+ *
+ * @param[in] _da to use for namespacing.
+ */
+#define tmpl_attr_ctx_rules_nested(_da) \
+ (tmpl_attr_ctx_rules_t){ \
+ .nested = _da, \
+ .type = TMPL_ATTR_RULES_CTX_NESTED \
+ }
+
+/** Does this attr_rules structure contain a "default" ctx?
+ */
+#define tmpl_attr_ctx_rules_is_default(_attr_rules) ((_attr_rules)->ctx.type == TMPL_ATTR_RULES_CTX_DEFAULTS)
+
+/** Does this attr_rules structure contain an "inherit" ctx
+ */
+#define tmpl_attr_ctx_rules_is_inherit(_attr_rules) ((_attr_rules)->ctx.type == TMPL_ATTR_RULES_CTX_INHERIT)
+
+/** Does this attr_rules structure contain a "nested" ctx
+ */
+#define tmpl_attr_ctx_rules_is_nested(_attr_rules) ((_attr_rules)->ctx.type == TMPL_ATTR_RULES_CTX_NESTED)
+
+/** Return the list of request qualifiers from a "default" ctx
+ *
+ * @param[in] a_rules An attribute rules structure
+ */
+static inline FR_DLIST_HEAD(tmpl_request_list) const *tmpl_attr_ctx_rules_default_request(tmpl_attr_rules_t const *a_rules)
+{
+ if (unlikely(!fr_cond_assert_msg(tmpl_attr_ctx_rules_is_default(a_rules), "Attempted to access default.request, but not a default ctx"))) return NULL;
+
+ return a_rules->ctx.defaults.request;
+}
+
+/** Return the attribute list from a "default" ctx
+ *
+ * @param[in] a_rules An attribute rules structure
+ */
+static inline fr_dict_attr_t const *tmpl_attr_ctx_rules_default_list(tmpl_attr_rules_t const *a_rules)
+{
+ if (unlikely(!fr_cond_assert_msg(tmpl_attr_ctx_rules_is_default(a_rules), "Attempted to access default.list, but not a default ctx"))) return NULL;
+
+ return a_rules->ctx.defaults.list;
+}
+
+/** Return the dictionary from a "default" ctx
+ *
+ * @param[in] a_rules An attribute rules structure
+ */
+static inline fr_dict_t const *tmpl_attr_ctx_rules_default_dict(tmpl_attr_rules_t const *a_rules)
+{
+ if (unlikely(!fr_cond_assert_msg(tmpl_attr_ctx_rules_is_default(a_rules), "Attempted to access default.dict, but not a default ctx"))) return NULL;
+
+ return a_rules->ctx.defaults.dict;
+}
+
+/** Return the list of request qualifiers from an "inherit" ctx
+ *
+ * @param[in] a_rules An attribute rules structure
+ */
+static inline FR_DLIST_HEAD(tmpl_request_list) const *tmpl_attr_ctx_rules_inherit_request(tmpl_attr_rules_t const *a_rules)
+{
+ if (unlikely(!fr_cond_assert_msg(tmpl_attr_ctx_rules_is_inherit(a_rules), "Attempted to access inherit.request, but not an inherit ctx"))) return NULL;
+
+ return a_rules->ctx.inherit.request;
+}
+
+/** Return the attribute reference list qualifiers from an "inherit" ctx
+ *
+ * @param[in] a_rules An attribute rules structure
+ */
+static inline FR_DLIST_HEAD(tmpl_attr_list) const *tmpl_attr_ctx_rules_inherit_attr(tmpl_attr_rules_t const *a_rules)
+{
+ fr_assert_msg(tmpl_attr_ctx_rules_is_inherit(a_rules), "Attempted to access inherit.attr, but not an inherit ctx");
+
+ return a_rules->ctx.inherit.attr;
+}
+
+/** Return the attribute reference list qualifiers from a "nested" ctx
+ *
+ * @param[in] a_rules An attribute rules structure
+ */
+static inline fr_dict_attr_t const *tmpl_attr_ctx_rules_nested_da(tmpl_attr_rules_t const *a_rules)
+{
+ fr_assert_msg(tmpl_attr_ctx_rules_is_nested(a_rules), "Attempted to access nested, but not a nested ctx");
+
+ return a_rules->ctx.nested;
+}
+
struct tmpl_xlat_rules_s {
fr_event_list_t *runtime_el; //!< The eventlist to use for runtime instantiation
///< of xlats.
#define NUM_COUNT (INT16_MIN + 2)
#define NUM_LAST (INT16_MIN + 3)
-/** Define entry and head types for attribute reference lists
- *
- */
-FR_DLIST_TYPES(tmpl_attr_list)
-
/** Different types of filter that can be applied to an attribute reference
*
*/
/** An element in a list of nested attribute references
*
*/
-typedef struct {
+struct tmpl_attr_s {
FR_DLIST_ENTRY(tmpl_attr_list) _CONST entry; //!< Entry in the doubly linked list
///< of attribute references.
tmpl_attr_type_t _CONST type; //!< Type of attribute reference.
tmpl_attr_filter_t _CONST filter; //!< Filter associated with the attribute reference.
-} tmpl_attr_t;
+};
/** Define manipulation functions for the attribute reference list
*
return false;
}
-bool ar_is_list_attr(tmpl_attr_t const *ar);
+bool tmpl_attr_is_list_attr(tmpl_attr_t const *ar);
#define ar_num filter.num
#define ar_filter_type filter.type
char *unescaped; //!< Unescaped form of the name, used for TMPL_TYPE_UNRESOLVED
///< and TMPL_TYPE_REGEX_UNCOMPILED.
- _CONST struct {
+ struct {
bool ref_prefix; //!< true if the reference was prefixed
///< with a '&'.
bool was_oid; //!< Was originally a numeric OID.
- tmpl_pair_list_t list; //!< List to search or insert in.
- ///< deprecated.
-
FR_DLIST_HEAD(tmpl_request_list) rr; //!< Request to search or insert in.
FR_DLIST_HEAD(tmpl_attr_list) ar; //!< Head of the attribute reference list.
} attribute;
*/
#define tmpl_attr(_tmpl) &(_tmpl)->data.attribute.ar
-static inline FR_DLIST_HEAD(tmpl_request_list) const *tmpl_request(tmpl_t const *vpt)
+static inline FR_DLIST_HEAD(tmpl_request_list) _CONST *tmpl_request(tmpl_t const *vpt)
{
tmpl_assert_type(tmpl_contains_attr(vpt));
- return &vpt->data.attribute.rr;
+ return &UNCONST(tmpl_t *, vpt)->data.attribute.rr;
}
/** The number of request references contained within a tmpl
ar = tmpl_attr_list_head(tmpl_attr(vpt));
if (unlikely(!ar)) return false;
- return ar_is_list_attr(ar);
+ return tmpl_attr_is_list_attr(ar);
}
/** Return true if the last attribute reference is "normal"
return tmpl_attr_list_num_elements(tmpl_attr(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));
-
- return vpt->data.attribute.list;
-}
/** @} */
/** @name Field accessors for #TMPL_TYPE_XLAT
void tmpl_debug(tmpl_t const *vpt) CC_HINT(nonnull);
-fr_pair_list_t *tmpl_list_head(request_t *request, tmpl_pair_list_t list);
+static inline CC_HINT(nonnull) fr_dict_attr_t const *tmpl_list(tmpl_t const *vpt)
+{
+ if (!tmpl_attr_head_is_list(vpt)) return NULL;
-fr_radius_packet_t *tmpl_packet_ptr(request_t *request, tmpl_pair_list_t list_name) CC_HINT(nonnull);
+ return tmpl_attr_list_head(tmpl_attr(vpt))->ar_da;
+}
+
+TALLOC_CTX *tmpl_list_ctx(request_t *request, tmpl_t const *vpt) CC_HINT(nonnull);
-TALLOC_CTX *tmpl_list_ctx(request_t *request, tmpl_pair_list_t list_name);
+fr_pair_list_t *tmpl_list_head(request_t *request, tmpl_t const *vpt) CC_HINT(nonnull);
-size_t tmpl_pair_list_name(tmpl_pair_list_t *out, char const *name, tmpl_pair_list_t default_list) CC_HINT(nonnull);
+fr_radius_packet_t *tmpl_packet_ptr(request_t *request, tmpl_t const *vpt) CC_HINT(nonnull);
tmpl_t *tmpl_init_printf(tmpl_t *vpt, tmpl_type_t type, fr_token_t quote, char const *fmt, ...) CC_HINT(nonnull(1,4));
*
* @{
*/
+bool tmpl_attr_is_list_attr(tmpl_attr_t const *ar);
+
+fr_slen_t tmpl_attr_list_from_substr(fr_dict_attr_t const **da_p, fr_sbuff_t *in);
+
/** Static default request ref list for the current request
*
* Passed as request_def in tmpl_attr_rules_t.
int tmpl_request_ptr(request_t **request, FR_DLIST_HEAD(tmpl_request_list) const *rql) CC_HINT(nonnull);
+void tmpl_request_ref_replace(tmpl_t *dst, FR_DLIST_HEAD(tmpl_request_list) const *src);
+
void tmpl_request_ref_list_debug(FR_DLIST_HEAD(tmpl_request_list) const *rql);
int8_t tmpl_request_ref_list_cmp(FR_DLIST_HEAD(tmpl_request_list) const *a,
void tmpl_attr_debug(tmpl_t const *vpt) CC_HINT(nonnull);
-int tmpl_attr_copy(tmpl_t *dst, tmpl_t const *src) CC_HINT(nonnull);
+void tmpl_attr_replace(tmpl_t *dst, FR_DLIST_HEAD(tmpl_attr_list) const *src) CC_HINT(nonnull);
int tmpl_attr_set_da(tmpl_t *vpt, fr_dict_attr_t const *da) CC_HINT(nonnull);
void tmpl_attr_set_request_ref(tmpl_t *vpt, FR_DLIST_HEAD(tmpl_request_list) const *request_def) CC_HINT(nonnull);
-void tmpl_attr_set_list(tmpl_t *vpt, tmpl_pair_list_t list) CC_HINT(nonnull);
+void tmpl_attr_set_list(tmpl_t *vpt, fr_dict_attr_t const *list_da) CC_HINT(nonnull);
int tmpl_attr_afrom_list(TALLOC_CTX *ctx, tmpl_t **out, tmpl_t const *list,
fr_dict_attr_t const *da) CC_HINT(nonnull);
bool tmpl_async_required(tmpl_t const *vpt) CC_HINT(nonnull);
-fr_pair_t *tmpl_get_list(request_t *request, tmpl_t const *vpt) CC_HINT(nonnull(2)); /* temporary hack */
-
int tmpl_value_list_insert_tail(FR_DLIST_HEAD(fr_value_box_list) *list, fr_value_box_t *vb, tmpl_t const *vpt) CC_HINT(nonnull);
void tmpl_rules_child_init(TALLOC_CTX *ctx, tmpl_rules_t *out, tmpl_rules_t const *parent, tmpl_t *vpt) CC_HINT(nonnull);
#define TEST_INIT test_init()
#endif
+/*
+ * Must come first
+ */
#include <freeradius-devel/util/acutest.h>
#include <freeradius-devel/util/acutest_helpers.h>
-#include <freeradius-devel/util/dict_test.h>
-#include <freeradius-devel/server/tmpl_dcursor.h>
-#include <freeradius-devel/server/pair.h>
+#include <freeradius-devel/server/pair.h>
+#include <freeradius-devel/server/tmpl.h>
+#include <freeradius-devel/server/tmpl_dcursor.h>
+#include <freeradius-devel/util/dict_test.h>
+#include <freeradius-devel/util/pair.h>
static TALLOC_CTX *autofree;
static fr_dict_t *test_dict;
fr_pair_t *leaf_int32_vp ## _x
#define pair_populate(_x) \
- pair_append_request(&int32_vp ## _x, fr_dict_attr_test_int32); \
+ pair_append_## request(&int32_vp ## _x, fr_dict_attr_test_int32); \
pair_append_request(&string_vp ## _x, fr_dict_attr_test_string); \
pair_append_request(&group_vp ## _x, fr_dict_attr_test_group); \
fr_pair_append_by_da(group_vp ## _x, &child_vp ## _x, &group_vp ## _x->children, fr_dict_attr_test_int16); \
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
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, 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
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, test_dict)
}
});
TEST_CHECK(vars->vpt != NULL);
{ NULL }
};
-/** Resolve a #tmpl_t into an #fr_pair_t
+/** Resolve a #tmpl_t into the head of a pair list
*
* @param[in] request containing the target lists.
* @param[in] vpt tmpl to resolve
* @return a pointer to the list in the #request_t.
- *
- * @This is just a temporary hack.
*/
-fr_pair_t *tmpl_get_list(request_t *request, tmpl_t const *vpt)
+fr_pair_list_t *tmpl_list_head(request_t *request, tmpl_t const *vpt)
{
fr_dict_attr_t const *da;
+ fr_pair_t *vp = NULL;
- if (!request) return NULL;
+ if (!request || !tmpl_attr_head_is_list(vpt)) return NULL;
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;
-}
-
-
-/** Resolve attribute #pair_list_t value to an attribute list.
- *
- * The value returned is a pointer to the pointer of the HEAD of a #fr_pair_t list in the
- * #request_t. If the head of the list changes, the pointer will still be valid.
- *
- * @param[in] request containing the target lists.
- * @param[in] list #pair_list_t value to resolve to #fr_pair_t list. Will be NULL if list
- * name couldn't be resolved.
- * @return a pointer to the HEAD of a list in the #request_t.
- *
- * @see tmpl_dcursor_init
- */
-fr_pair_list_t *tmpl_list_head(request_t *request, tmpl_pair_list_t list)
-{
- if (!request) return NULL;
-
- switch (list) {
- /* Don't add default */
- case PAIR_LIST_UNKNOWN:
- break;
-
- case PAIR_LIST_REQUEST:
- if (!request->packet) return NULL;
- return &request->request_pairs;
-
- case PAIR_LIST_REPLY:
- if (!request->reply) return NULL;
- return &request->reply_pairs;
+ if (da == request_attr_request) vp = request->pair_list.request;
+ if (da == request_attr_reply) vp = request->pair_list.reply;
+ if (da == request_attr_control) vp = request->pair_list.control;
+ if (da == request_attr_state) vp = request->pair_list.state;
- case PAIR_LIST_CONTROL:
- return &request->control_pairs;
+ if (!vp) RWDEBUG2("List \"%s\" is not available", da->name);
- case PAIR_LIST_STATE:
- return &request->session_state_pairs;
- }
-
- RWDEBUG2("List \"%s\" is not available",
- fr_table_str_by_value(pair_list_table, list, "<INVALID>"));
-
- return NULL;
+ return &vp->vp_group;
}
/** Return the correct TALLOC_CTX to alloc #fr_pair_t in, for a list
* freed too.
*
* @param[in] request containing the target lists.
- * @param[in] list #pair_list_t value to resolve to TALLOC_CTX.
+ * @param[in] vpt to resolve to a TALLOC_CTX.
* @return
* - TALLOC_CTX on success.
* - NULL on failure.
*
* @see tmpl_pair_list
*/
-TALLOC_CTX *tmpl_list_ctx(request_t *request, tmpl_pair_list_t list)
+TALLOC_CTX *tmpl_list_ctx(request_t *request, tmpl_t const *vpt)
{
- if (!request) return NULL;
-
- switch (list) {
- case PAIR_LIST_REQUEST:
- return request->request_ctx;
-
- case PAIR_LIST_REPLY:
- return request->reply_ctx;
-
- case PAIR_LIST_CONTROL:
- return request->control_ctx;
-
- case PAIR_LIST_STATE:
- return request->session_state_ctx;
+ fr_dict_attr_t const *da;
+
+ if (!request || !tmpl_attr_head_is_list(vpt)) return NULL;
- /* Don't add default */
- case PAIR_LIST_UNKNOWN:
- break;
- }
+ da = ((tmpl_attr_t *)tmpl_attr_list_head(&vpt->data.attribute.ar))->ar_da;
+ if (da == request_attr_request) return request->request_ctx;
+ if (da == request_attr_reply) return request->reply_ctx;;
+ if (da == request_attr_control) return request->control_ctx;
+ if (da == request_attr_state) return request->session_state_ctx;
+
return NULL;
}
* for the current #request_t.
*
* @param[in] request To resolve list in.
- * @param[in] list #pair_list_t value to resolve to #fr_radius_packet_t.
+ * @param[in] vpt #pair_list_t value to resolve to #fr_radius_packet_t.
* @return
* - #fr_radius_packet_t on success.
* - NULL on failure.
*
* @see tmpl_pair_list
*/
-fr_radius_packet_t *tmpl_packet_ptr(request_t *request, tmpl_pair_list_t list)
+fr_radius_packet_t *tmpl_packet_ptr(request_t *request, tmpl_t const *vpt)
{
- switch (list) {
- /* Don't add default */
- case PAIR_LIST_STATE:
- case PAIR_LIST_CONTROL:
- case PAIR_LIST_UNKNOWN:
- return NULL;
-
- case PAIR_LIST_REQUEST:
- return request->packet;
-
- case PAIR_LIST_REPLY:
- return request->reply;
- }
+ fr_dict_attr_t const *da;
+
+ if (!request || !tmpl_attr_head_is_list(vpt)) return NULL;
+
+ da = ((tmpl_attr_t *)tmpl_attr_list_head(&vpt->data.attribute.ar))->ar_da;
+
+ if (da == request_attr_request) return request->packet;
+ if (da == request_attr_reply) return request->reply;
return NULL;
}
TALLOC_CTX *ctx;
fr_pair_list_t *head;
- tmpl_pair_list_and_ctx(ctx, head, request, tmpl_request(vpt), tmpl_list(vpt));
+ tmpl_pair_list_and_ctx(ctx, head, request, tmpl_request(vpt), vpt);
if (!head) return -1;
MEM(vp = fr_pair_afrom_da(ctx, tmpl_attr_tail_da(vpt)));
* If there's no packet, we can't print any attribute
* referencing it.
*/
- packet = tmpl_packet_ptr(request, tmpl_list(vpt));
+ packet = tmpl_packet_ptr(request, vpt);
if (!packet) return 0;
if (tmpl_attr_tail_da(vpt) == attr_packet_type) {
*
* @copyright 2014-2020 The FreeRADIUS server project
*/
+#include "lib/server/request.h"
+#include "lib/util/sbuff.h"
#include "lib/util/strerror.h"
+#include "talloc.h"
RCSID("$Id$")
#define _TMPL_PRIVATE 1
*/
TMPL_REQUEST_REF_DEF(tmpl_request_def_outer, REQUEST_OUTER);
-/** Use the parent request as the default
- *
- * Used as .attr.request_def = &tmpl_request_def_parent;
- */
-TMPL_REQUEST_REF_DEF(tmpl_request_def_parent, REQUEST_PARENT);
-
/** Default parser rules
*
* Because this is getting to be a ridiculous number of parsing rules
};
static size_t attr_table_len = NUM_ELEMENTS(attr_table);
-/** Map keywords to #pair_list_t values
- */
-fr_table_num_ordered_t const pair_list_table[] = {
- { L("request"), PAIR_LIST_REQUEST },
- { L("reply"), PAIR_LIST_REPLY },
- { L("control"), PAIR_LIST_CONTROL }, /* New name should have priority */
- { L("config"), PAIR_LIST_CONTROL },
- { L("session-state"), PAIR_LIST_STATE },
-};
-size_t pair_list_table_len = NUM_ELEMENTS(pair_list_table);
-
/** Map keywords to #tmpl_request_ref_t values
*/
fr_table_num_sorted_t const tmpl_request_ref_table[] = {
i++;
}
- FR_FAULT_LOG("list: %s", fr_table_str_by_value(pair_list_table, vpt->data.attribute.list, "<INVALID>"));
tmpl_attr_ref_list_debug(tmpl_attr(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
* @{
*/
-/** Resolve attribute name to a #pair_list_t value.
- *
- * Check the name string for #pair_list_t qualifiers and write a #pair_list_t value
- * for that list to out. This value may be passed to #tmpl_pair_list, along with the current
- * #request_t, to get a pointer to the actual list in the #request_t.
- *
- * If we're sure we've definitely found a list qualifier token delimiter (``:``) but the
- * string doesn't match a #tmpl_pair_list qualifier, return 0 and write #PAIR_LIST_UNKNOWN
- * to out.
- *
- * If we can't find a string that looks like a request qualifier, set out to def, and
- * return 0.
- *
- * @note #tmpl_pair_list_name should be called before passing a name string that may
- * contain qualifiers to #fr_dict_attr_by_name.
- *
- * @param[out] out Where to write the list qualifier.
- * @param[in] name String containing list qualifiers to parse.
- * @param[in] def the list to return if no qualifiers were found.
- * @return 0 if no valid list qualifier could be found, else the number of bytes consumed.
- * The caller may then advanced the name pointer by the value returned, to get the
- * start of the attribute name (if any).
+
+/** Indicate whether this attribute reference represents one of packets or legacy lists
*
- * @see pair_list
- * @see tmpl_pair_list
+ * @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.
*/
-size_t tmpl_pair_list_name(tmpl_pair_list_t *out, char const *name, tmpl_pair_list_t def)
+bool tmpl_attr_is_list_attr(tmpl_attr_t const *ar)
{
- char const *p = name;
- char const *q;
-
- /*
- * Try and determine the end of the token
- */
- for (q = p; fr_dict_attr_allowed_chars[(uint8_t) *q]; q++);
-
- switch (*q) {
- /*
- * It's a bareword made up entirely of dictionary chars
- * check and see if it's a list qualifier, and if it's
- * not, return the def and say we couldn't parse
- * anything.
- */
- case '\0':
- *out = fr_table_value_by_substr(pair_list_table, p, (q - p), PAIR_LIST_UNKNOWN);
- if (*out != PAIR_LIST_UNKNOWN) return q - p;
- *out = def;
- return 0;
-
- /*
- * It may be a list qualifier delimiter
- */
- case ':':
- {
- char const *d = q + 1;
+ if (!ar_is_normal(ar)) return false;
- if (isdigit((int) *d)) {
- while (isdigit((int) *d)) d++;
+ 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);
+}
- if (!fr_dict_attr_allowed_chars[(uint8_t) *d]) {
- *out = def;
- return 0;
- }
- }
- *out = fr_table_value_by_substr(pair_list_table, p, (q - p), PAIR_LIST_UNKNOWN);
- if (*out == PAIR_LIST_UNKNOWN) return 0;
+/** Parse one a single list reference
+ *
+ * @param[out] da_p attribute representing a list.
+ * @param[in] in Sbuff to read request references from.
+ * @return
+ * - > 0 the number of bytes parsed.
+ * - 0 no list qualifier found.
+ */
+fr_slen_t tmpl_attr_list_from_substr(fr_dict_attr_t const **da_p, fr_sbuff_t *in)
+{
+ fr_dict_attr_t const *da;
+ fr_sbuff_t our_in = FR_SBUFF(in);
- return (q + 1) - name; /* Consume the list and delimiter */
+ if ((da = fr_sbuff_adv_past_strcase(&our_in, request_attr_request->name, request_attr_request->name_len)) ||
+ (da = fr_sbuff_adv_past_strcase(&our_in, request_attr_reply->name, request_attr_reply->name_len)) ||
+ (da = fr_sbuff_adv_past_strcase(&our_in, request_attr_control->name, request_attr_control->name_len)) ||
+ (da = fr_sbuff_adv_past_strcase(&our_in, request_attr_state->name, request_attr_state->name_len))) {
+ *da_p = da;
+ FR_SBUFF_SET_RETURN(in, &our_in);
}
- default:
- *out = def;
- return 0;
- }
+ return 0;
}
/** Allocate a new request reference and add it to the end of the attribute reference list
*out = rql;
}
+/** Replace all existing request references
+ *
+ */
+void tmpl_request_ref_replace(tmpl_t *dst, FR_DLIST_HEAD(tmpl_request_list) const *src)
+{
+ tmpl_request_list_talloc_reverse_free(&dst->data.attribute.rr);
+ tmpl_request_ref_list_copy(dst, &dst->data.attribute.rr, src);
+}
+
/** Dump a request list to stderr
*
*/
fr_sbuff_marker_t m;
bool seen_outer = false;
- if (!at_rules) at_rules = &default_rules.attr;
+ if (!at_rules) {
+ at_rules = &default_rules.attr;
+ } else {
+ fr_assert_msg(tmpl_attr_ctx_rules_is_default(at_rules), "attr rules ctx must be of type \"defaults\" to parse request qualifiers");
+ }
/*
* We could make the caller do this but as this
for (depth = 0; depth < TMPL_MAX_REQUEST_REF_NESTING; depth++) {
bool end;
-
/*
* Search for a known request reference like
* 'current', or 'parent'.
* reference.
*/
default_ref:
- if ((depth == 0) && at_rules->request_def) {
- tmpl_request_ref_list_copy(ctx, out, at_rules->request_def);
+ if ((depth == 0) && at_rules->ctx.defaults.request) {
+ tmpl_request_ref_list_copy(ctx, out, at_rules->ctx.defaults.request);
}
break;
}
goto default_ref;
}
- if (at_rules->parent || at_rules->disallow_qualifiers) {
+ if (at_rules->disallow_qualifiers) {
fr_strerror_const("It is not permitted to specify a request reference here");
if (err) *err = TMPL_ATTR_ERROR_INVALID_LIST_QUALIFIER;
}
FR_SBUFF_SET_RETURN(in, &m);
-
}
/** Parse one or more request references, allocing a new list and adding the references to it
*/
void tmpl_set_dict_def(tmpl_t *vpt, fr_dict_t const *dict)
{
- vpt->rules.attr.dict_def = dict;
+ fr_assert_msg(tmpl_attr_ctx_rules_is_default(&vpt->rules.attr), "can only set default dictionary on \"defaults\" ctx");
+ vpt->rules.attr.ctx.defaults.dict = dict;
}
/** Initialise a tmpl using a format string to create the name
*
* @{
*/
+static inline CC_HINT(always_inline)
+tmpl_attr_t *tmpl_attr_alloc(TALLOC_CTX *ctx, tmpl_attr_type_t type)
+{
+ tmpl_attr_t *ar;
+ MEM(ar = talloc(ctx, tmpl_attr_t));
+ *ar = (tmpl_attr_t){
+ .type = type,
+ .filter = {
+ .num = NUM_UNSPEC
+ }
+ };
+ return ar;
+}
/** Allocate a new attribute reference and add it to the end of the attribute reference list
*
*/
-static tmpl_attr_t *tmpl_attr_add(tmpl_t *vpt, tmpl_attr_type_t type)
+static tmpl_attr_t *tmpl_attr_ainsert_tail(tmpl_t *vpt, tmpl_attr_type_t type)
{
tmpl_attr_t *ar;
TALLOC_CTX *ctx;
ctx = tmpl_attr_list_tail(tmpl_attr(vpt));
}
- MEM(ar = talloc(ctx, tmpl_attr_t));
- *ar = (tmpl_attr_t){
- .type = type,
- .filter = {
- .num = NUM_UNSPEC
- }
- };
+ ar = tmpl_attr_alloc(ctx, type);
tmpl_attr_list_insert_tail(tmpl_attr(vpt), ar);
-
return ar;
}
return 0;
}
-/** Copy a list of attribute and request references from one tmpl to another
- *
+/** Copy an attribute reference
*/
-int tmpl_attr_copy(tmpl_t *dst, tmpl_t const *src)
+static tmpl_attr_t *tmpl_attr_acopy(TALLOC_CTX *ctx, tmpl_attr_t const *src_ar)
{
- tmpl_attr_t *src_ar = NULL, *dst_ar;
+ tmpl_attr_t *dst_ar;
- /*
- * Clear any existing attribute references
- */
- if (tmpl_attr_list_num_elements(tmpl_attr(dst)) > 0) tmpl_attr_list_talloc_reverse_free(tmpl_attr(dst));
+ dst_ar = tmpl_attr_alloc(ctx, src_ar->ar_type);
+ switch (src_ar->type) {
+ case TMPL_ATTR_TYPE_NORMAL:
+ dst_ar->ar_da = src_ar->ar_da;
+ break;
- while ((src_ar = tmpl_attr_list_next(tmpl_attr(src), src_ar))) {
- dst_ar = tmpl_attr_add(dst, src_ar->type);
+ case TMPL_ATTR_TYPE_UNSPEC: /* Nothing to copy */
+ break;
- switch (src_ar->type) {
- case TMPL_ATTR_TYPE_NORMAL:
- dst_ar->ar_da = src_ar->ar_da;
- break;
+ case TMPL_ATTR_TYPE_UNKNOWN:
+ dst_ar->ar_unknown = fr_dict_unknown_afrom_da(dst_ar, src_ar->ar_unknown);
+ break;
- case TMPL_ATTR_TYPE_UNSPEC: /* Nothing to copy */
- break;
+ case TMPL_ATTR_TYPE_UNRESOLVED:
+ dst_ar->ar_unresolved = talloc_bstrdup(dst_ar, src_ar->ar_unresolved);
+ break;
- case TMPL_ATTR_TYPE_UNKNOWN:
- dst_ar->ar_unknown = fr_dict_unknown_afrom_da(dst_ar, src_ar->ar_unknown);
- break;
+ default:
+ if (!fr_cond_assert(0)) return -1;
+ }
+ dst_ar->ar_num = src_ar->ar_num;
- case TMPL_ATTR_TYPE_UNRESOLVED:
- dst_ar->ar_unresolved = talloc_bstrdup(dst_ar, src_ar->ar_unresolved);
- break;
+ return dst_ar;
+}
- default:
- if (!fr_cond_assert(0)) return -1;
- }
- dst_ar->ar_num = src_ar->ar_num;
+static void tmpl_attr_list_copy(TALLOC_CTX *ctx, FR_DLIST_HEAD(tmpl_attr_list) *dst, FR_DLIST_HEAD(tmpl_attr_list) const *src)
+{
+ tmpl_attr_t *tail = tmpl_attr_list_tail(dst);
+ TALLOC_CTX *ar_ctx = tail ? tail : ctx;
+
+ tmpl_attr_list_foreach(src, src_ar) {
+ tmpl_attr_t *dst_ar;
+
+ ar_ctx = dst_ar = tmpl_attr_acopy(ar_ctx, src_ar);
+ tmpl_attr_list_insert_tail(dst, dst_ar);
}
+}
+/** Replace the list of attribute references in one tmpl with the attribute refereces from another
+ *
+ */
+void tmpl_attr_replace(tmpl_t *dst, FR_DLIST_HEAD(tmpl_attr_list) const *src)
+{
/*
- * Clear any existing request references
- * and copy the ones from the source.
- */
- tmpl_request_list_talloc_reverse_free(&dst->data.attribute.rr);
- tmpl_request_ref_list_copy(dst, &dst->data.attribute.rr, &src->data.attribute.rr);
-
- /*
- * Remove me...
+ * Clear any existing attribute references
*/
- dst->data.attribute.list = src->data.attribute.list;
+ if (tmpl_attr_list_num_elements(tmpl_attr(dst)) > 0) tmpl_attr_list_talloc_reverse_free(tmpl_attr(dst));
+ tmpl_attr_list_copy(dst, tmpl_attr(dst), src);
TMPL_ATTR_VERIFY(dst);
-
- return 0;
}
/** Replace the current attribute reference
* Unknown attributes get copied
*/
if (da->flags.is_unknown) {
- ref = tmpl_attr_add(vpt, TMPL_ATTR_TYPE_UNKNOWN);
+ ref = tmpl_attr_ainsert_tail(vpt, TMPL_ATTR_TYPE_UNKNOWN);
ref->da = ref->ar_unknown = fr_dict_unknown_afrom_da(vpt, da);
} else {
- ref = tmpl_attr_add(vpt, TMPL_ATTR_TYPE_NORMAL);
+ ref = tmpl_attr_ainsert_tail(vpt, TMPL_ATTR_TYPE_NORMAL);
ref->da = da;
}
ref->ar_parent = fr_dict_root(fr_dict_by_da(da)); /* Parent is the root of the dictionary */
*/
talloc_free_children(ref);
} else {
- ref = tmpl_attr_add(vpt, da->flags.is_unknown ? TMPL_ATTR_TYPE_UNKNOWN : TMPL_ATTR_TYPE_NORMAL);
+ ref = tmpl_attr_ainsert_tail(vpt, da->flags.is_unknown ? TMPL_ATTR_TYPE_UNKNOWN : TMPL_ATTR_TYPE_NORMAL);
}
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);
+ ar = tmpl_attr_ainsert_tail(vpt, TMPL_ATTR_TYPE_UNKNOWN);
} else {
ar = tmpl_attr_list_tail(tmpl_attr(vpt));
}
TMPL_ATTR_VERIFY(vpt);
}
-void tmpl_attr_set_list(tmpl_t *vpt, tmpl_pair_list_t list)
+void tmpl_attr_set_list(tmpl_t *vpt, fr_dict_attr_t const *list_da)
{
- vpt->data.attribute.list = list;
+ if (tmpl_attr_head_is_list(vpt)) {
+ tmpl_attr_t *ar, *next;
+
+ tmpl_attr_list_pop_head(tmpl_attr(vpt));
+
+ ar = tmpl_attr_alloc(vpt, TMPL_ATTR_TYPE_NORMAL);
+ ar->ar_da = list_da;
+
+ tmpl_attr_list_insert_head(tmpl_attr(vpt), ar);
+
+ /*
+ * Fixup the attribute hierarchy
+ */
+ next = tmpl_attr_list_next(tmpl_attr(vpt), ar);
+ if (next) talloc_steal(ar, next);
+ }
TMPL_ATTR_VERIFY(vpt);
}
ssize_t slen;
MEM(vpt = tmpl_alloc(ctx, TMPL_TYPE_ATTR, T_BARE_WORD, NULL, 0));
-
+
/*
* Copies request refs and the list ref
*/
- tmpl_attr_copy(vpt, list);
- tmpl_attr_set_list(vpt, tmpl_list(list)); /* Remove when lists are attributes */
+ tmpl_attr_replace(vpt, tmpl_attr(list));
+ tmpl_request_ref_replace(vpt, tmpl_request(list));
+
tmpl_attr_set_leaf_da(vpt, da); /* This should add a new da when lists are attributes */
tmpl_attr_set_leaf_num(vpt, tmpl_attr_tail_num(list));
}
/** @} */
+/** Safely duplicate a set of attribute rules
+ */
+static void tmpl_attr_rules_copy(TALLOC_CTX *ctx, tmpl_attr_rules_t *dst, tmpl_attr_rules_t const *src)
+{
+ memcpy(dst, src, sizeof(*dst));
+
+ if (tmpl_attr_ctx_rules_is_default(src)) {
+ /*
+ * If there are actual requests, duplicate them
+ * and move them into the list.
+ *
+ * A NULL request_def pointer is equivalent to the
+ * current request.
+ */
+ if (tmpl_attr_ctx_rules_default_request(src)) {
+ tmpl_request_ref_list_acopy(ctx, &dst->ctx.defaults.request, src->ctx.defaults.request);
+ }
+ }
+}
+
/** Insert an attribute reference into a tmpl
*
* Not all attribute references can be used to create new attributes,
fr_sbuff_marker_t m_s;
fr_dict_attr_err_t dict_err;
fr_dict_attr_t const *our_parent = parent;
+ fr_dict_t const *dict_def = NULL;
fr_sbuff_marker(&m_s, name);
goto error;
}
+ if (tmpl_attr_ctx_rules_is_default(at_rules)) dict_def = tmpl_attr_ctx_rules_default_dict(at_rules);
+
/*
* No parent means we need to go hunting through all the dictionaries
*/
if (!our_parent) {
(void)fr_dict_attr_search_by_qualified_name_substr(&dict_err, &da,
- at_rules->dict_def,
+ dict_def,
name, p_rules ? p_rules->terminals : NULL,
!at_rules->disallow_internal,
at_rules->allow_foreign);
* first, and then run the rest of the logic in this
* function.
*/
- if (!namespace && at_rules->dict_def) our_parent = namespace = fr_dict_root(at_rules->dict_def);
+ if (!namespace && dict_def) our_parent = namespace = fr_dict_root(dict_def);
if (!namespace && !at_rules->disallow_internal) our_parent = namespace = fr_dict_root(fr_dict_internal());
if (!namespace) {
fr_strerror_const("Attribute references must be qualified with a protocol when used here");
*/
if (!at_rules->allow_foreign || at_rules->disallow_internal) {
fr_dict_t const *found_in = fr_dict_by_da(da);
- fr_dict_t const *dict_def = at_rules->dict_def ? at_rules->dict_def : fr_dict_internal();
+ fr_dict_t const *our_dict_def = dict_def ? dict_def : fr_dict_internal();
/*
* Parent is the dict root if this is the first ref in the
* chain.
*/
- if (!our_parent) our_parent = fr_dict_root(dict_def);
+ if (!our_parent) our_parent = fr_dict_root(our_dict_def);
/*
* Even if allow_foreign is false, if disallow_internal is not
!at_rules->allow_foreign && !fr_dict_compatible(found_in, fr_dict_by_da(our_parent))) {
fr_strerror_printf("Foreign %s attribute found. Only %s attributes are allowed here",
fr_dict_root(found_in)->name,
- fr_dict_root(dict_def)->name);
+ fr_dict_root(our_dict_def)->name);
if (err) *err = TMPL_ATTR_ERROR_FOREIGN_NOT_ALLOWED;
fr_sbuff_set(name, &m_s);
goto error;
* if there's a real dictionary, and this reference is to group which is in fact
* the internal dict, then just keep using our dict_def.
*/
- if (at_rules->dict_def && (namespace == fr_dict_root(fr_dict_internal()))) {
- our_parent = namespace = fr_dict_root(at_rules->dict_def);
+ if (dict_def && (namespace == fr_dict_root(fr_dict_internal()))) {
+ our_parent = namespace = fr_dict_root(dict_def);
}
break;
* are unqualified.
* - request_def The default #request_t to set if no
* #tmpl_request_ref_t qualifiers are found in name.
- * - list_def The default list to set if no #pair_list_t
+ * - context The default list to set if no #pair_list_t
* qualifiers are found in the name.
* - allow_unknown If true attributes in the format accepted by
* #fr_dict_unknown_afrom_oid_substr will be allowed,
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) &&
/*
* Check to see if we expect a reference prefix
+ *
+ * FIXME - These should probably only be allowed
+ * in the defaults context.
*/
switch (at_rules->prefix) {
case TMPL_ATTR_REF_PREFIX_YES:
if (fr_sbuff_adv_past_strcase_literal(&our_name, "raw.")) is_raw = true;
/*
- * Parse one or more request references
+ * Defaults ctx allow request and list
+ * qualifiers.
+ *
+ * First parse any request references,
+ * then start on attribute references.
+ *
+ * Finally if no list was added, prepend that.
*/
- ret = tmpl_request_ref_list_from_substr(vpt, NULL,
- &vpt->data.attribute.rr,
- &our_name,
- p_rules,
- at_rules);
- if (ret < 0) {
- error:
- *out = NULL;
- talloc_free(vpt);
- FR_SBUFF_ERROR_RETURN(&our_name);
- }
+ if (tmpl_attr_ctx_rules_is_default(at_rules)) {
+ ret = tmpl_request_ref_list_from_substr(vpt, NULL,
+ &vpt->data.attribute.rr,
+ &our_name,
+ p_rules,
+ at_rules);
+ if (ret < 0) {
+ error:
+ *out = NULL;
+ talloc_free(vpt);
+ FR_SBUFF_ERROR_RETURN(&our_name);
+ }
+
+ ret = tmpl_attr_afrom_attr_substr(vpt, err,
+ vpt,
+ NULL, NULL,
+ &our_name, p_rules, at_rules, 0);
+ if (ret < 0) goto error;
- fr_sbuff_marker(&m_l, &our_name);
+ /*
+ * 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_ctx_rules_is_default(at_rules) && !tmpl_attr_head_is_list(vpt)) {
+ fr_dict_attr_t const *list_da;
+ 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())
+ };
+
+ /*
+ * If there's no default list, then we default
+ * to the request list.
+ */
+ list_da = tmpl_attr_ctx_rules_default_list(at_rules);
+ if (list_da) {
+ ar->ar_da = list_da;
+ } else {
+ ar->ar_da = request_attr_request;
+ }
+
+ /*
+ * Prepend the list ref so it gets evaluated
+ * first.
+ */
+ tmpl_attr_list_insert_head(&vpt->data.attribute.ar, ar);
+ }
/*
- * Start parsing attribute references
- *
- * This includes lists, like request,
- * reply, control etc...
+ * Inherited ctx copy all the attribute
+ * and request references from another
+ * tmpl, and resume parsing in the context
+ * of the final attr.
+ */
+ } else if (tmpl_attr_ctx_rules_is_inherit(at_rules)) {
+ FR_DLIST_HEAD(tmpl_request_list) const *src_rq_list = tmpl_attr_ctx_rules_inherit_request(at_rules);
+ FR_DLIST_HEAD(tmpl_attr_list) const *src_ar_list = tmpl_attr_ctx_rules_inherit_attr(at_rules);
+ FR_DLIST_HEAD(tmpl_request_list) *dst_rq_list = tmpl_request(vpt);
+ FR_DLIST_HEAD(tmpl_attr_list) *dst_ar_list = tmpl_attr(vpt);
+ fr_dict_attr_t const *parent;
+
+ if (src_rq_list) tmpl_request_ref_list_copy(vpt, dst_rq_list, src_rq_list);
+ if (src_ar_list) tmpl_attr_list_copy(vpt, dst_ar_list, src_ar_list);
+
+ if (!tmpl_attr_list_empty(dst_ar_list)) parent = tmpl_attr_list_tail(dst_ar_list)->ar_da;
+
+ ret = tmpl_attr_afrom_attr_substr(vpt, err,
+ vpt,
+ parent, parent,
+ &our_name, p_rules, at_rules, 0);
+ if (ret < 0) goto error;
+ /*
+ * Nested ctx resume parsing in the
+ * context of the DA passed in.
*/
- 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;
+ } else if (tmpl_attr_ctx_rules_is_nested(at_rules)) {
+ fr_dict_attr_t const *parent = tmpl_attr_ctx_rules_nested_da(at_rules);
+
+ ret = tmpl_attr_afrom_attr_substr(vpt, err,
+ vpt,
+ parent, parent,
+ &our_name, p_rules, at_rules, 0);
+ if (ret < 0) goto error;
+ }
/*
* Check to see if the user wants the leaf
*/
if (tmpl_is_attr(vpt) && is_raw) tmpl_attr_to_raw(vpt);
- /*
- * 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())
- };
-
- switch (at_rules->list_def) {
- default:
- case PAIR_LIST_REQUEST:
- ar->ar_da = request_attr_request;
- break;
-
- case PAIR_LIST_REPLY:
- ar->ar_da = request_attr_reply;
- break;
-
- case PAIR_LIST_CONTROL:
- ar->ar_da = request_attr_control;
- break;
-
- case PAIR_LIST_STATE:
- ar->ar_da = request_attr_state;
- break;
- }
-
- /*
- * 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));
- vpt->rules = *t_rules; /* Record the rules */
-
- /*
- * If there are actual requests, duplicate them
- * and move them into the list.
- *
- * A NULL request_def pointer is equivalent to the
- * current request.
- */
- if (t_rules->attr.request_def) {
- tmpl_request_ref_list_acopy(vpt, &vpt->rules.attr.request_def, t_rules->attr.request_def);
- }
+
+ vpt->rules = *t_rules;
+ tmpl_attr_rules_copy(vpt, &vpt->rules.attr, &t_rules->attr);
if (tmpl_is_attr(vpt)) {
/*
/*
* Copy attribute references
*/
- if (tmpl_contains_attr(vpt) && unlikely(tmpl_attr_copy(vpt, in) < 0)) goto error;
+ if (tmpl_contains_attr(vpt)) tmpl_attr_replace(vpt, tmpl_attr(in));
/*
* Copy flags for all regex flavours (and possibly recompile the regex)
{
tmpl_attr_t *ar = NULL, *next, *prev;
fr_dict_attr_t const *da;
- fr_dict_t const *dict_def;
+ fr_dict_t const *dict_def = NULL;
fr_assert(tmpl_is_attr_unresolved(vpt));
TMPL_VERIFY(vpt);
- dict_def = vpt->rules.attr.dict_def;
- if (!dict_def || tr_rules->force_dict_def) dict_def = tr_rules->dict_def;
-
- /*
- * First component is special becase we may need
- * to search for it in multiple dictionaries.
- *
- * This emulates what's done in the initial
- * tokenizer function.
- */
- ar = tmpl_attr_list_head(tmpl_attr(vpt));
- if (ar->type == TMPL_ATTR_TYPE_UNRESOLVED) {
- (void)fr_dict_attr_search_by_name_substr(NULL,
- &da,
- dict_def,
- &FR_SBUFF_IN(ar->ar_unresolved,
- talloc_array_length(ar->ar_unresolved) - 1),
- NULL,
- !vpt->rules.attr.disallow_internal,
- vpt->rules.attr.allow_foreign);
- if (!da) return -2; /* Can't resolve, maybe the caller can resolve later */
-
- ar->ar_type = TMPL_ATTR_TYPE_NORMAL;
- ar->ar_da = da;
- ar->ar_parent = fr_dict_root(fr_dict_by_da(da));
+ if (tmpl_attr_ctx_rules_is_default(&vpt->rules.attr)) {
+ dict_def = tmpl_attr_ctx_rules_default_dict(&vpt->rules.attr);
+ if (!dict_def || tr_rules->force_dict_def) dict_def = tr_rules->dict_def;
/*
- * Record the dictionary that was
- * successfully used for resolution.
- */
- vpt->rules.attr.dict_def = tr_rules->dict_def;
+ * First component is special becase we may need
+ * to search for it in multiple dictionaries.
+ *
+ * This emulates what's done in the initial
+ * tokenizer function.
+ */
+ ar = tmpl_attr_list_head(tmpl_attr(vpt));
+ if (ar->type == TMPL_ATTR_TYPE_UNRESOLVED) {
+ (void)fr_dict_attr_search_by_name_substr(NULL,
+ &da,
+ dict_def,
+ &FR_SBUFF_IN(ar->ar_unresolved,
+ talloc_array_length(ar->ar_unresolved) - 1),
+ NULL,
+ !vpt->rules.attr.disallow_internal,
+ vpt->rules.attr.allow_foreign);
+ if (!da) return -2; /* Can't resolve, maybe the caller can resolve later */
+
+ ar->ar_type = TMPL_ATTR_TYPE_NORMAL;
+ ar->ar_da = da;
+ ar->ar_parent = fr_dict_root(fr_dict_by_da(da));
- /*
- * Reach into the next reference
- * and correct its parent and
- * namespace.
- */
- next = tmpl_attr_list_next(tmpl_attr(vpt), ar);
- if (next) {
- next->ar_parent = da;
- next->ar_unresolved_namespace = da;
+ /*
+ * Record the dictionary that was
+ * successfully used for resolution.
+ */
+ vpt->rules.attr.ctx.defaults.dict = tr_rules->dict_def;
+
+ /*
+ * Reach into the next reference
+ * and correct its parent and
+ * namespace.
+ */
+ next = tmpl_attr_list_next(tmpl_attr(vpt), ar);
+ if (next) {
+ next->ar_parent = da;
+ next->ar_unresolved_namespace = da;
+ }
}
}
*
* If it was, then we may be able to
* fall back to resolving the attribute
- * in the internal dictionary.
+ * in the group attribute's dictionary.
*/
if (!da) {
prev = tmpl_attr_list_prev(tmpl_attr(vpt), ar);
if (!vpt->rules.attr.disallow_internal && prev && (prev->ar_da->type == FR_TYPE_GROUP)) {
(void)fr_dict_attr_by_name_substr(NULL,
&da,
- fr_dict_root(fr_dict_internal()),
+ fr_dict_root(fr_dict_by_da(prev->ar_da)),
&FR_SBUFF_IN(ar->ar_unresolved,
talloc_array_length(ar->ar_unresolved) - 1),
NULL);
fr_slen_t tmpl_request_ref_list_print(fr_sbuff_t *out, FR_DLIST_HEAD(tmpl_request_list) const *rql)
{
fr_sbuff_t our_out = FR_SBUFF(out);
- tmpl_request_t *rr = tmpl_request_list_head(rql);
/*
* Print request references
*/
- while (rr) {
+ tmpl_request_list_foreach(rql, rr) {
FR_SBUFF_IN_TABLE_STR_RETURN(&our_out, tmpl_request_ref_table, rr->request, "<INVALID>");
- rr = tmpl_request_list_next(rql, rr);
- if (rr) FR_SBUFF_IN_CHAR_RETURN(&our_out, '.');
+ if (tmpl_request_list_next(rql, rr)) FR_SBUFF_IN_CHAR_RETURN(&our_out, '.');
}
FR_SBUFF_SET_RETURN(out, &our_out);
{
tmpl_attr_t const *ar = NULL;
fr_da_stack_t stack;
- char printed_rr = false;
fr_sbuff_t our_out = FR_SBUFF(out);
fr_slen_t slen;
FR_SBUFF_IN_CHAR_RETURN(&our_out, '&');
}
- /*
- * Print request references
- */
- slen = tmpl_request_ref_list_print(&our_out, &vpt->data.attribute.rr);
- if (slen > 0) printed_rr = true;
- if (slen < 0) return slen;
-
- /*
- * Print list
- */
- if (tmpl_list(vpt) != PAIR_LIST_REQUEST) { /* Don't print the default list */
- if (printed_rr) FR_SBUFF_IN_CHAR_RETURN(&our_out, '.');
-
- FR_SBUFF_IN_TABLE_STR_RETURN(&our_out, pair_list_table, tmpl_list(vpt), "<INVALID>");
- if (tmpl_attr_list_num_elements(tmpl_attr(vpt))) FR_SBUFF_IN_CHAR_RETURN(&our_out, '.');
-
- /*
- * Request qualifier with no list qualifier
- */
- } else if (printed_rr) {
- if (tmpl_attr_list_num_elements(tmpl_attr(vpt))) FR_SBUFF_IN_CHAR_RETURN(&our_out, '.');
- }
-
/*
*
* If the leaf attribute is unknown and raw we
*/
if (tmpl_attr_tail_is_raw(vpt)) FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "raw.");
+ /*
+ * Print request references
+ */
+ slen = tmpl_request_ref_list_print(&our_out, &vpt->data.attribute.rr);
+ if ((slen > 0) && tmpl_attr_list_num_elements(tmpl_attr(vpt))) FR_SBUFF_IN_CHAR_RETURN(&our_out, '.');
+ if (slen < 0) return slen;
+
/*
* Print attribute identifiers
*/
void tmpl_rules_child_init(TALLOC_CTX *ctx, tmpl_rules_t *out, tmpl_rules_t const *parent, tmpl_t *vpt)
{
fr_dict_attr_t const *da;
- fr_dict_attr_t const *ref;
- fr_dict_t const *dict, *internal;
*out = *parent;
out->parent = parent;
* The input tmpl is a leaf. We must parse the child as
* a normal attribute reference (as with the parent tmpl).
*/
- if (!fr_type_structural[da->type]) {
- return;
- }
-
- if (vpt->rules.attr.request_def) {
- tmpl_request_ref_list_acopy(ctx, &out->attr.request_def, vpt->rules.attr.request_def);
- }
- out->attr.list_def = tmpl_list(vpt);
+ if (!fr_type_structural[da->type]) return;
/*
- * Parse the child attributes in the context of the parent struct / tlv / whatever.
+ * Copy the base rules...
*/
- if (da->type != FR_TYPE_GROUP) {
- out->attr.dict_def = fr_dict_by_da(da);
- out->attr.parent = da;
- return;
- }
-
- ref = fr_dict_attr_ref(da);
- dict = fr_dict_by_da(ref);
- internal = fr_dict_internal();
+ tmpl_attr_rules_copy(ctx, &out->attr, &parent->attr);
/*
- * Groups MAY change dictionaries. If so, then swap the dictionary and the parent.
+ * Parse the child attributes in the context of the parent struct / tlv / whatever.
*/
- if ((dict != internal) && (dict != out->attr.dict_def)) {
- out->attr.dict_def = dict;
- out->attr.parent = ref;
+ if (tmpl_attr_ctx_rules_is_default(&out->attr)) {
+ FR_DLIST_HEAD(tmpl_request_list) *rql = out->attr.ctx.defaults.request;
+ if (rql) tmpl_request_list_talloc_reverse_free(rql); /* Will have been copied*/
+ out->attr.ctx = tmpl_attr_ctx_rules_nested(da);
}
-
- /*
- * Otherwise the reference is swapping FROM a protocol
- * dictionary TO the internal dictionary, and TO an
- * internal group. We fall back to leaving well enough
- * alone, and leave things as-is. This allows internal
- * grouping attributes to appear anywhere.
- */
}
* @copyright 2000 Alan DeKok (aland@freeradius.org)
*/
+#include "lib/server/tmpl.h"
RCSID("$Id$")
#include <freeradius-devel/server/log.h>
lhs_rules = (tmpl_rules_t) {
.attr = {
- .dict_def = dict,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, dict),
.prefix = TMPL_ATTR_REF_PREFIX_NO,
.disallow_qualifiers = true, /* for now, until more tests are made */
};
rhs_rules = (tmpl_rules_t) {
.attr = {
- .dict_def = dict,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, dict),
.prefix = TMPL_ATTR_REF_PREFIX_YES,
.disallow_qualifiers = true, /* for now, until rlm_files supports it */
}
}
t->name = q;
- lhs_rules.attr.list_def = PAIR_LIST_CONTROL;
+ lhs_rules.attr.ctx = tmpl_attr_ctx_rules_default(NULL, request_attr_control, dict);
comma = false;
check_item:
* for regexes we want to look at the
* request list.
*/
- tmpl_attr_set_list(new_map->lhs, PAIR_LIST_REQUEST);
+ tmpl_attr_set_list(new_map->lhs, request_attr_request);
if (tmpl_is_regex_uncompiled(new_map->rhs) &&
(tmpl_regex_compile(new_map->rhs, false) < 0)) {
/*
* Setup the reply items.
*/
- lhs_rules.attr.list_def = PAIR_LIST_REPLY;
+ lhs_rules.attr.ctx = tmpl_attr_ctx_rules_default(NULL, request_attr_reply, dict);
comma = false;
reply_item:
}
}
- fr_assert(tmpl_list(new_map->lhs) == PAIR_LIST_REPLY);
+ fr_assert(tmpl_list(new_map->lhs) == request_attr_reply);
if (!new_map->parent) map_list_insert_tail(&t->reply, new_map);
tmpl_rules_t parse_rules;
memset(&parse_rules, 0, sizeof(parse_rules));
- parse_rules.attr.dict_def = *(process->dict);
- fr_assert(parse_rules.attr.dict_def != NULL);
+
+ fr_assert(*(process->dict) != NULL);
+ parse_rules.attr.ctx = tmpl_attr_ctx_rules_default(NULL, NULL, *(process->dict));
if (virtual_server_compile_sections(server_cs, process->compile_list, &parse_rules,
vs->process_mi->dl_inst->data) < 0) {
*
* @copyright 2006-2016 The FreeRADIUS server project
*/
+#include "lib/server/request.h"
+#include "lib/server/tmpl.h"
RCSID("$Id$")
#include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
static inline CC_HINT(always_inline) int unlang_attr_rules_verify(tmpl_attr_rules_t const *rules)
{
- if (!fr_cond_assert_msg(rules->dict_def, "No protocol dictionary set")) return -1;
- if (!fr_cond_assert_msg(rules->dict_def != fr_dict_internal(), "rules->attr.dict_def must not be the internal dictionary")) return -1;
+ if (!fr_cond_assert_msg(tmpl_attr_ctx_rules_default_dict(rules), "No protocol dictionary set")) return -1;
+ if (!fr_cond_assert_msg(tmpl_attr_ctx_rules_default_dict(rules) != fr_dict_internal(), "rules->attr.dict_def must not be the internal dictionary")) return -1;
if (!fr_cond_assert_msg(!rules->allow_foreign, "rules->attr.allow_foreign must be false")) return -1;
return 0;
* We may now know the correct dictionary
* where we didn't before...
*/
- if (!vpt->rules.attr.dict_def) tmpl_set_dict_def(vpt, dict);
+ if (!tmpl_attr_ctx_rules_default_dict(&vpt->rules.attr)) tmpl_set_dict_def(vpt, dict);
/*
* Convert virtual &Attr-Foo to "%{Attr-Foo}"
*/
if (!tmpl_is_attr(map->lhs) ||
!tmpl_request_ref_is_current(tmpl_request(map->lhs)) ||
- (tmpl_list(map->lhs) != PAIR_LIST_REQUEST)) {
+ (tmpl_list(map->lhs) != request_attr_request)) {
return true;
}
RULES_VERIFY(rules);
if (tmpl_is_unresolved(map->lhs)) {
- if (!pass2_fixup_tmpl(map, &map->lhs, map->ci, rules->attr.dict_def)) {
+ if (!pass2_fixup_tmpl(map, &map->lhs, map->ci, tmpl_attr_ctx_rules_default_dict(&rules->attr))) {
return false;
}
}
if (tmpl_is_unresolved(map->rhs)) {
fr_assert(!tmpl_is_regex_xlat_unresolved(map->rhs));
- if (!pass2_fixup_tmpl(map, &map->rhs, map->ci, rules->attr.dict_def)) {
+ if (!pass2_fixup_tmpl(map, &map->rhs, map->ci, tmpl_attr_ctx_rules_default_dict(&rules->attr))) {
return false;
}
}
if (!gext->vpt) return true;
return pass2_fixup_tmpl(map_list_head(&gext->map)->ci, &gext->vpt,
- cf_section_to_item(g->cs), rules->attr.dict_def);
+ cf_section_to_item(g->cs), tmpl_attr_ctx_rules_default_dict(&rules->attr));
}
static void unlang_dump(unlang_t *instruction, int depth)
*/
if (name2) {
snprintf(list_buffer, sizeof(list_buffer), "&%s", name2);
- } else {
- snprintf(list_buffer, sizeof(list_buffer), "&%s", fr_table_str_by_value(pair_list_table, unlang_ctx->rules->attr.list_def, "???"));
+ } else if (tmpl_attr_ctx_rules_default_list(&unlang_ctx->rules->attr)) {
+ fr_dict_attr_t const *list_da = tmpl_attr_ctx_rules_default_list(&unlang_ctx->rules->attr);
+ snprintf(list_buffer, sizeof(list_buffer), "&%s", list_da->name);
}
/*
*
* @todo - add support for &config?
*/
+
if (fr_table_value_by_substr(pair_list_table, p, q - p, PAIR_LIST_UNKNOWN) != PAIR_LIST_UNKNOWN) {
if (*q) {
p = q + 1;
var_free = var;
- var->dict = fr_dict_protocol_alloc(unlang_ctx->rules->attr.dict_def);
+ var->dict = fr_dict_protocol_alloc(tmpl_attr_ctx_rules_default_dict(&unlang_ctx->rules->attr));
if (!var->dict) {
talloc_free(var);
return NULL;
*t_rules = *unlang_ctx->rules;
t_rules->parent = unlang_ctx->rules;
- t_rules->attr.dict_def = var->dict;
- t_rules->attr.parent = NULL;
+ t_rules->attr.ctx = tmpl_attr_ctx_rules_default(NULL, NULL, var->dict);
unlang_ctx->rules = t_rules;
}
* in var->root will also check the protocol dictionary,
* so the check here is really only for better error messages.
*/
- da = fr_dict_attr_by_name(NULL, fr_dict_root(t_rules->parent->attr.dict_def), value);
+ da = fr_dict_attr_by_name(NULL, fr_dict_root(tmpl_attr_ctx_rules_default_dict(&t_rules->parent->attr)), value);
if (da) {
talloc_free(var_free);
cf_log_err(cp, "Local variable '%s' duplicates a dictionary attribute.", value);
* This is so that compile_case() can do attribute type
* checks / casts against us.
*/
- if (!pass2_fixup_tmpl(g, &gext->vpt, cf_section_to_item(cs), unlang_ctx->rules->attr.dict_def)) {
+ if (!pass2_fixup_tmpl(g, &gext->vpt, cf_section_to_item(cs), tmpl_attr_ctx_rules_default_dict(&unlang_ctx->rules->attr))) {
error:
talloc_free(g);
return NULL;
/*
* Fixup the tmpl so that we know it's somewhat sane.
*/
- if (!pass2_fixup_tmpl(gext, &vpt, cf_section_to_item(cs), unlang_ctx->rules->attr.dict_def)) {
+ if (!pass2_fixup_tmpl(gext, &vpt, cf_section_to_item(cs), tmpl_attr_ctx_rules_default_dict(&unlang_ctx->rules->attr))) {
error:
talloc_free(g);
return NULL;
/*
* Fixup the tmpl so that we know it's somewhat sane.
*/
- if (!pass2_fixup_tmpl(gext, &vpt, cf_section_to_item(cs), unlang_ctx->rules->attr.dict_def)) {
+ if (!pass2_fixup_tmpl(gext, &vpt, cf_section_to_item(cs), tmpl_attr_ctx_rules_default_dict(&unlang_ctx->rules->attr))) {
error:
talloc_free(g);
return NULL;
bool is_truthy = false, value = false;
xlat_res_rules_t xr_rules = {
.tr_rules = &(tmpl_res_rules_t) {
- .dict_def = unlang_ctx->rules->attr.dict_def,
+ .dict_def = tmpl_attr_ctx_rules_default_dict(&unlang_ctx->rules->attr),
},
};
tmpl_rules_t t_rules = (tmpl_rules_t) {
.attr = {
- .dict_def = xr_rules.tr_rules->dict_def,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, xr_rules.tr_rules->dict_def),
.allow_unresolved = true,
.allow_unknown = true
}
case COND_TYPE_TMPL:
fr_assert(!tmpl_is_regex_xlat_unresolved(leaf->data.vpt));
if (!pass2_fixup_tmpl(leaf, &leaf->data.vpt, cf_section_to_item(cs),
- unlang_ctx->rules->attr.dict_def)) return false;
+ tmpl_attr_ctx_rules_default_dict(&unlang_ctx->rules->attr))) return false;
break;
/*
*/
case COND_TYPE_MAP:
if (!pass2_fixup_cond_map(leaf, cf_section_to_item(cs),
- unlang_ctx->rules->attr.dict_def)) return false;
+ tmpl_attr_ctx_rules_default_dict(&unlang_ctx->rules->attr))) return false;
break;
default:
/*
* Fixup the templates
*/
- if (!pass2_fixup_tmpl(g, &gext->vpt, cf_section_to_item(cs), unlang_ctx->rules->attr.dict_def)) {
+ if (!pass2_fixup_tmpl(g, &gext->vpt, cf_section_to_item(cs), tmpl_attr_ctx_rules_default_dict(&unlang_ctx->rules->attr))) {
talloc_free(g);
return NULL;
}
*/
name2 = cf_section_name2(cs);
if (!name2) {
- dict = unlang_ctx->rules->attr.dict_def;
+ dict = tmpl_attr_ctx_rules_default_dict(&unlang_ctx->rules->attr);
packet_name = name2 = unlang_ctx->section_name2;
goto get_packet_type;
}
return NULL;
}
- dict = unlang_ctx->rules->attr.dict_def;
+ dict = tmpl_attr_ctx_rules_default_dict(&unlang_ctx->rules->attr);
packet_name = NULL;
goto get_packet_type;
}
*/
p = strchr(name2, '.');
if (!p) {
- dict = unlang_ctx->rules->attr.dict_def;
+ dict = tmpl_attr_ctx_rules_default_dict(&unlang_ctx->rules->attr);
packet_name = name2;
} else {
t_rules = *unlang_ctx->rules;
t_rules.parent = unlang_ctx->rules;
- t_rules.attr.dict_def = dict;
+ t_rules.attr.ctx = tmpl_attr_ctx_rules_default(NULL, NULL, dict);
t_rules.attr.allow_foreign = false;
/*
return NULL;
}
if ((dict != fr_dict_internal()) && fr_dict_internal() &&
- unlang_ctx->rules->attr.dict_def && (unlang_ctx->rules->attr.dict_def != dict)) {
+ tmpl_attr_ctx_rules_default_dict(&unlang_ctx->rules->attr) && (tmpl_attr_ctx_rules_default_dict(&unlang_ctx->rules->attr)!= dict)) {
cf_log_err(cs, "Cannot call server %s with namespace '%s' from namespaces '%s' - they have incompatible protocols",
- server, fr_dict_root(dict)->name, fr_dict_root(unlang_ctx->rules->attr.dict_def)->name);
+ server, fr_dict_root(dict)->name, fr_dict_root(tmpl_attr_ctx_rules_default_dict(&unlang_ctx->rules->attr))->name);
return NULL;
}
*/
memcpy(&parent_rules, unlang_ctx->rules, sizeof(parent_rules));
memcpy(&t_rules, unlang_ctx->rules, sizeof(t_rules));
- parent_rules.attr.dict_def = dict;
+
+ parent_rules.attr.ctx = tmpl_attr_ctx_rules_default(NULL, NULL, dict);
t_rules.parent = &parent_rules;
/*
/*
* Can't use "chap" in "dhcp".
*/
- if (mrlm->dict && *mrlm->dict && unlang_ctx->rules && unlang_ctx->rules->attr.dict_def &&
- (unlang_ctx->rules->attr.dict_def != fr_dict_internal()) &&
- !fr_dict_compatible(*(mrlm->dict), unlang_ctx->rules->attr.dict_def)) {
+ if (mrlm->dict && *mrlm->dict && unlang_ctx->rules && tmpl_attr_ctx_rules_default_dict(&unlang_ctx->rules->attr) &&
+ (tmpl_attr_ctx_rules_default_dict(&unlang_ctx->rules->attr) != fr_dict_internal()) &&
+ !fr_dict_compatible(*(mrlm->dict), tmpl_attr_ctx_rules_default_dict(&unlang_ctx->rules->attr))) {
cf_log_err(ci, "The \"%s\" module can only be used with 'namespace = %s'. It cannot be used with 'namespace = %s'.",
inst->module->name,
fr_dict_root(*mrlm->dict)->name,
- fr_dict_root(unlang_ctx->rules->attr.dict_def)->name);
+ fr_dict_root(tmpl_attr_ctx_rules_default_dict(&unlang_ctx->rules->attr))->name);
return NULL;
}
#include <freeradius-devel/server/base.h>
#include <freeradius-devel/server/tmpl_dcursor.h>
+#undef NO_ASSERT
+
#include <freeradius-devel/util/debug.h>
#include <freeradius-devel/util/edit.h>
#include <freeradius-devel/util/calc.h>
#include <freeradius-devel/unlang/unlang_priv.h>
#include "edit_priv.h"
+
+
typedef struct {
FR_DLIST_HEAD(fr_value_box_list) result; //!< result of expansion
tmpl_t const *vpt; //!< expanded tmpl
slen = tmpl_afrom_attr_str(ctx, NULL, &out->to_free, box->vb_strvalue,
&(tmpl_rules_t){
.attr = {
- .dict_def = request->dict,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, request->dict),
.prefix = TMPL_ATTR_REF_PREFIX_NO
}
});
if (tmpl_afrom_attr_str(request, NULL, &vpt, name,
&(tmpl_rules_t){
.attr = {
- .dict_def = request->dict,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, request->dict),
.prefix = TMPL_ATTR_REF_PREFIX_AUTO
}
}) <= 0) return -4;
if (tmpl_afrom_attr_str(request, NULL, &vpt, fmt,
&(tmpl_rules_t){
.attr = {
- .dict_def = request->dict,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, request->dict),
.prefix = TMPL_ATTR_REF_PREFIX_AUTO
}
}) <= 0) {
if (tmpl_afrom_attr_str(request, NULL, &vpt, fmt,
&(tmpl_rules_t){
.attr = {
- .dict_def = request->dict,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, request->dict),
.prefix = TMPL_ATTR_REF_PREFIX_AUTO
}
}) <= 0) {
if (tmpl_afrom_attr_str(request, NULL, &vpt, fmt,
&(tmpl_rules_t){
.attr = {
- .dict_def = request->dict,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, request->dict),
.prefix = TMPL_ATTR_REF_PREFIX_AUTO
}
}) <= 0) {
tmpl_rules_t attr_rules = {
.attr = {
- .dict_def = request->dict,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, request->dict),
.prefix = TMPL_ATTR_REF_PREFIX_AUTO
}
};
.allow_unknown = false,
.allow_unresolved = false,
.allow_foreign = false,
- .dict_def = request->dict
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, request->dict)
},
.at_runtime = true
}) < 0) {
.allow_unknown = false,
.allow_unresolved = false,
.allow_foreign = false,
- .dict_def = request->dict
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, request->dict)
},
.at_runtime = true
}) < 0) {
if (tmpl_afrom_attr_str(ctx, NULL, &vpt, in_head->vb_strvalue,
&(tmpl_rules_t){
.attr = {
- .dict_def = request->dict,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, request->dict),
.prefix = TMPL_ATTR_REF_PREFIX_AUTO
}
}) <= 0) {
if (tmpl_afrom_attr_str(ctx, NULL, &vpt, in_head->vb_strvalue,
&(tmpl_rules_t){
.attr = {
- .dict_def = request->dict,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, request->dict),
.prefix = TMPL_ATTR_REF_PREFIX_AUTO
}
}) <= 0) {
NULL,
&(tmpl_rules_t){
.attr = {
- .dict_def = request->dict
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, request->dict),
}
});
if (len == 0) {
slen = tmpl_afrom_attr_str(ctx, NULL, &vpt, vb->vb_strvalue,
&(tmpl_rules_t) {
.attr = {
- .dict_def = request->dict,
- .request_def = &tmpl_request_def_current,
- .list_def = PAIR_LIST_REQUEST,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, request->dict),
.prefix = TMPL_ATTR_REF_PREFIX_AUTO,
.allow_unknown = false,
.allow_unresolved = false,
MEM(head = xlat_exp_head_alloc(ctx));
if (t_rules) {
- head->dict = t_rules->attr.dict_def;
+ head->dict = tmpl_attr_ctx_rules_default_dict(&t_rules->attr);
} else {
t_rules = &my_rules;
}
if (t_rules) {
my_rules = *t_rules;
- head->dict = t_rules->attr.dict_def;
+ head->dict = tmpl_attr_ctx_rules_default_dict(&t_rules->attr);
}
my_rules.xlat.runtime_el = el;
while ((rr = tmpl_request_list_next(list, rr))) {
INFO_INDENT("ref %d", rr->request);
}
- INFO_INDENT("list %d", tmpl_list(node->vpt));
+ INFO_INDENT("list %s", tmpl_list(node->vpt)->name);
if (tmpl_attr_tail_num(node->vpt) != NUM_UNSPEC) {
if (tmpl_attr_tail_num(node->vpt) == NUM_COUNT) {
INFO_INDENT("[#]");
MEM(head = xlat_exp_head_alloc(ctx));
if (t_rules) {
- head->dict = t_rules->attr.dict_def;
+ head->dict = tmpl_attr_ctx_rules_default_dict(&t_rules->attr);
our_t_rules = *t_rules;
}
xlat_exp_head_t *head;
MEM(head = xlat_exp_head_alloc(ctx));
- if (t_rules) head->dict = t_rules->attr.dict_def;
+ if (t_rules) head->dict = tmpl_attr_ctx_rules_default_dict(&t_rules->attr);
if (p_rules && p_rules->terminals) {
tmp_p_rules = (fr_sbuff_parse_rules_t){ /* Stack allocated due to CL scope */
xlat_exp_head_t *head;
MEM(head = xlat_exp_head_alloc(ctx));
- if (t_rules) head->dict = t_rules->attr.dict_def;
+ if (t_rules) head->dict = tmpl_attr_ctx_rules_default_dict(&t_rules->attr);
fr_strerror_clear(); /* Clear error buffer */
vpt = tmpl_alloc(ctx, TMPL_TYPE_ATTR, T_BARE_WORD, node->fmt, talloc_array_length(node->fmt) - 1);
if (!vpt) return NULL;
- tmpl_attr_copy(vpt, node->vpt);
+ tmpl_attr_replace(vpt, tmpl_attr(node->vpt));
+ tmpl_request_ref_replace(vpt, tmpl_request(node->vpt));
TMPL_VERIFY(vpt);
#include <freeradius-devel/missing.h>
#include <freeradius-devel/util/fring.h>
-#ifdef NO_ASSERT
+/*
+ * Setting this causes clangd to throw lots of errors, because it doesn't
+ * seem to re-evaluate headers in the contexts of the files which include
+ * them.
+ */
+#if defined(NO_ASSERT) && !defined(__clangd__)
# define MEM(x) error "Use of MEM() not allowed in this source file. Deal with memory allocation failure gracefully"
#else
# define MEM(x) do { if (!(x)) { fr_cond_assert_msg((x), "OUT OF MEMORY"); _fr_exit(__FILE__, __LINE__, EXIT_FAILURE, true); } } while (0)
tmpl_rules_t parse_rules = {
/* Strict rules for the update map as it's processed with limited functionality */
.attr = {
- .dict_def = dict_ldap_sync,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, dict_ldap_sync),
.allow_foreign = false,
.allow_unknown = false,
.allow_unresolved = false,
NULL,
&(tmpl_rules_t){
.attr = {
- .dict_def = request->dict,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, request->dict),
.prefix = TMPL_ATTR_REF_PREFIX_AUTO
}
});
map_t *map = NULL;
tmpl_rules_t parse_rules = {
.attr = {
- .dict_def = dict,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, dict),
.prefix = TMPL_ATTR_REF_PREFIX_NO
}
};
* @param[in] out Cursor to append maps to.
* @param[in] request The request to which the generated pairs should be added.
* @param[in] json The JSON object representation of the user document.
- * @param[in] list The pair list PAIR_LIST_CONTROL or PAIR_LIST_REPLY.
+ * @param[in] context Prepended to all references in this map.
* @return
* - 1 if no section found.
* - 0 on success.
* - <0 on error.
*/
-int mod_json_object_to_map(TALLOC_CTX *ctx, fr_dcursor_t *out, request_t *request, json_object *json, tmpl_pair_list_t list)
+int mod_json_object_to_map(TALLOC_CTX *ctx, fr_dcursor_t *out, request_t *request, json_object *json, FR_DLIST_HEAD(tmpl_attr_list) *context)
{
json_object *list_obj;
char const *list_name = fr_table_str_by_value(pair_list_table, list, "<INVALID>");
&(tmpl_rules_t){
.attr = {
.dict_def = request->dict,
- .list_def = list
+ .context = list
}
},
op,
int mod_attribute_to_element(const char *name, json_object *map, void *buf);
-int mod_json_object_to_map(TALLOC_CTX *ctx, fr_dcursor_t *out, request_t *request, json_object *json, tmpl_pair_list_t list);
+int mod_json_object_to_map(TALLOC_CTX *ctx, fr_dcursor_t *out, request_t *request, json_object *json, FR_DLIST_HEAD(tmpl_attr_list) *context);
json_object *mod_value_pair_to_json_object(request_t *request, fr_pair_t *vp);
/*
* Convert JSON data into maps
*/
- if ((mod_json_object_to_map(pool, &maps, request, cookie->jobj, PAIR_LIST_CONTROL) < 0) ||
- (mod_json_object_to_map(pool, &maps, request, cookie->jobj, PAIR_LIST_REPLY) < 0) ||
- (mod_json_object_to_map(pool, &maps, request, cookie->jobj, PAIR_LIST_REQUEST) < 0) ||
- (mod_json_object_to_map(pool, &maps, request, cookie->jobj, PAIR_LIST_STATE) < 0)) {
+ if ((mod_json_object_to_map(pool, &maps, request, cookie->jobj, &tmpl_list_ctx_rcontrol) < 0) ||
+ (mod_json_object_to_map(pool, &maps, request, cookie->jobj, &tmpl_attr_def_reply) < 0) ||
+ (mod_json_object_to_map(pool, &maps, request, cookie->jobj, &tmpl_attr_def_request) < 0) ||
+ (mod_json_object_to_map(pool, &maps, request, cookie->jobj, &tmpl_attr_def_state) < 0)) {
invalid:
talloc_free(pool);
rcode = RLM_MODULE_INVALID;
char const *program;
char const *input;
char const *output;
- tmpl_pair_list_t input_list;
- tmpl_pair_list_t output_list;
+ tmpl_t *input_list;
+ tmpl_t *output_list;
bool shell_escape;
bool env_inherit;
fr_time_delta_t timeout;
rlm_exec_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_exec_t);
CONF_SECTION *conf = mctx->inst->conf;
xlat_t *xlat;
- char const *p;
xlat = xlat_register_module(NULL, mctx, mctx->inst->name, exec_xlat, FR_TYPE_STRING, XLAT_FLAG_NEEDS_ASYNC);
xlat_func_args(xlat, exec_xlat_args);
if (inst->input) {
- p = inst->input;
- p += tmpl_pair_list_name(&inst->input_list, p, PAIR_LIST_UNKNOWN);
- if ((inst->input_list == PAIR_LIST_UNKNOWN) || (*p != '\0')) {
- cf_log_err(conf, "Invalid input list '%s'", inst->input);
+ if (tmpl_afrom_attr_substr(inst, NULL, &inst->input_list, &FR_SBUFF_IN(inst->input, strlen(inst->input)), NULL, NULL) < 0) {
+ cf_log_perr(conf, "Invalid input list '%s'", inst->input);
return -1;
}
}
if (inst->output) {
- p = inst->output;
- p += tmpl_pair_list_name(&inst->output_list, p, PAIR_LIST_UNKNOWN);
- if ((inst->output_list == PAIR_LIST_UNKNOWN) || (*p != '\0')) {
- cf_log_err(conf, "Invalid output list '%s'", inst->output);
+ if (tmpl_afrom_attr_substr(inst, NULL, &inst->output_list, &FR_SBUFF_IN(inst->input, strlen(inst->output)), NULL, NULL) < 0) {
+ cf_log_perr(conf, "Invalid output list '%s'", inst->input);
return -1;
}
}
* assertion that they do not get out of
* sync.
*/
- fr_assert(tmpl_list(map->lhs) == PAIR_LIST_REPLY);
+ fr_assert(tmpl_list(map->lhs) == request_attr_reply);
}
}
&json_arg_parse_rules,
&(tmpl_rules_t){
.attr = {
- .dict_def = request->dict
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, request->dict)
}
});
if (slen <= 0) {
NULL,
&(tmpl_rules_t){
.attr = {
- .dict_def = request->dict,
+ .ctx = tmpl_attr_ctx_rules_default(NULL, NULL, request->dict),
.allow_unknown = true,
.allow_unresolved = false,
},
&(tmpl_rules_t){
.attr = {
.dict_def = request->dict,
- .list_def = PAIR_LIST_REPLY
+ .list_def = &tmpl_attr_def_reply
}
}) <= 0) {
ERROR("Failed to find attribute %s", ckey);
if (tmpl_afrom_attr_str(ctx, NULL, &dst, s1,
&(tmpl_rules_t){
.attr = {
- .dict_def = request->dict,
- .list_def = PAIR_LIST_REPLY
+ .ctx = tmpl_attr_ctx_rules_default(NULL, request_attr_reply, request->dict)
}
}) <= 0) {
ERROR("%s - Failed to find attribute %s.%s", funcname, list_name, s1);
&(tmpl_rules_t){
.attr = {
.prefix = TMPL_ATTR_REF_PREFIX_NO,
- .dict_def = request->dict,
- .list_def = PAIR_LIST_REPLY
+ .ctx = tmpl_attr_ctx_rules_default(NULL, request_attr_reply, request->dict)
}
}) <= 0) {
RPWDEBUG("Failed parsing attribute (skipping)");
goto skip;
}
- vps = tmpl_list_head(current, tmpl_list(dst));
+ vps = tmpl_list_head(current, dst);
if (!vps) {
RWDEBUG("List not valid in this context (skipping)");
talloc_free(dst);
goto skip;
}
- ctx = tmpl_list_ctx(current, tmpl_list(dst));
+ ctx = tmpl_list_ctx(current, dst);
da = tmpl_attr_tail_da(dst);
fr_assert(vps);
&(tmpl_rules_t){
.attr = {
.prefix = TMPL_ATTR_REF_PREFIX_NO,
- .dict_def = request->dict,
- .list_def = PAIR_LIST_REPLY
+ .ctx = tmpl_attr_ctx_rules_default(NULL, request_attr_reply, request->dict)
}
}) <= 0) {
RPWDEBUG("Failed parsing attribute (skipping)");
continue;
}
- vps = tmpl_list_head(current, tmpl_list(dst));
+ vps = tmpl_list_head(current, dst);
if (!vps) {
RWDEBUG("List not valid in this context (skipping)");
continue;
}
- ctx = tmpl_list_ctx(current, tmpl_list(dst));
+ ctx = tmpl_list_ctx(current, dst);
/*
* Alternative JSON structure which allows operator,