# Note that unlike v4, the key does not have to be a string, but could instead
# be an IP address or netmask! For more information, see
#
- # doc/antora/modules/raddb/pages/mods-config/files/users.adoc
+ # doc/antora/modules/raddb/pages/mods-config/files/users.adoc
#
# key = "%{&Stripped-User-Name || &User-Name}"
# Note: the attriubte type should be capable of holding data of the type
# used as key values.
# Particularly useful if matching IP addresses to subnets, since the populated
- # value will be the subnet. In that case it is best to use 0.0.0.0/0 in place
- # of DEFAULT for any catch-all entries.
+ # value will be the subnet. In that case it is best to use `0.0.0.0/0` in place
+ # of `DEFAULT` for any catch-all entries.
#
# match_attr = &control.User-Category
+
+ #
+ # v3_compat:: Version 3 compatibility flag.
+ #
+ # When this flag is set, any enumeration names (e.g. Service-Type := Framed-User)
+ # do not need to have the v4 "::" prefix. This flag helps with migrating v3
+ # configurations to v4.
+ #
+ # Default value "false". Allowerd vlaues, "true' and "false".
+ #
+# v3_compat = false
}
#
fr_sbuff_marker_t m_lhs, m_rhs, m_op;
fr_sbuff_term_t const *tt = p_rules ? p_rules->terminals : NULL;
map_t *parent;
+ tmpl_rules_t our_rhs_rules;
if (parent_p) {
parent = *parent_p;
{
tmpl_rules_t our_lhs_rules;
- if (lhs_rules) {
- our_lhs_rules = *lhs_rules;
- } else {
- memset(&our_lhs_rules, 0, sizeof(our_lhs_rules));
- }
+ our_lhs_rules = *lhs_rules;
/*
* Allow for ".foo" to refer to the current
}
parse_rhs:
+ if (tmpl_is_attr(map->lhs)) {
+ fr_dict_attr_t const *enumv = tmpl_attr_tail_da(map->lhs);
+
+ /*
+ * LHS is a structural type. The RHS is either empty (create empty LHS), or it's a string
+ * containing a list of attributes to create.
+ */
+ if (fr_type_is_leaf(enumv->type)) {
+ our_rhs_rules = *rhs_rules;
+ our_rhs_rules.enumv = enumv;
+ rhs_rules = &our_rhs_rules;
+ }
+ }
+
fr_sbuff_out_by_longest_prefix(&slen, &token, cond_quote_table, &our_in, T_BARE_WORD);
switch (token) {
case T_SOLIDUS_QUOTED_STRING:
(void) tmpl_afrom_value_box(map, &map->rhs, fr_box_strvalue("ANY"), false);
- } else {
- tmpl_rules_t my_rhs_rules;
+ } else if (rhs_rules->attr.bare_word_enum && rhs_rules->enumv) {
+ fr_value_box_t *vb;
+
+ MEM(vb = fr_value_box_alloc(map, rhs_rules->enumv->type, rhs_rules->enumv));
if (!p_rules) p_rules = &value_parse_rules_bareword_quoted;
/*
- * If we parsed an attribute on the LHS, and the RHS looks like an enumerated
- * value, then set the enumv.
- *
- * @todo tmpl_require_enum_prefix - maybe just _always_ set enumv, because the
- * caller shouldn't have set it?
+ * It MUST be the given data type, and it MAY be an enum name.
*/
- if (rhs_rules && !rhs_rules->enumv && tmpl_is_attr(map->lhs) &&
- fr_sbuff_is_str_literal(&our_in, "::")) {
- my_rhs_rules = *rhs_rules;
- my_rhs_rules.enumv = tmpl_attr_tail_da(map->lhs);
- rhs_rules = &my_rhs_rules;
+ slen = fr_value_box_from_substr(map, vb, rhs_rules->enumv->type, rhs_rules->enumv,
+ &our_in, p_rules, false);
+ if (slen < 0) goto error;
+
+ if (tmpl_afrom_value_box(map, &map->rhs, vb, true) < 0) {
+ goto error;
}
+ } else {
+ if (!p_rules) p_rules = &value_parse_rules_bareword_quoted;
+
/*
* Use the RHS termination rules ONLY for bare
* words. For quoted strings we already know how
ssize_t map_afrom_substr(TALLOC_CTX *ctx, map_t **out, map_t **parent_p, fr_sbuff_t *in,
fr_table_num_sorted_t const *op_table, size_t op_table_len,
tmpl_rules_t const *lhs_rules, tmpl_rules_t const *rhs_rules,
- fr_sbuff_parse_rules_t const *p_rules);
+ fr_sbuff_parse_rules_t const *p_rules) CC_HINT(nonnull(1,2,4,5,7,8));
int map_afrom_fields(TALLOC_CTX *ctx, map_t **out, map_t **parent_p, request_t *request,
char const *lhs, char const *op, char const *rhs,
uint8_t disallow_filters:1; //!< disallow filters.
uint8_t xlat:1 ; //!< for %{User-Name}
+
+ uint8_t bare_word_enum:1; //!< for v3 compatibility.
};
struct tmpl_xlat_rules_s {
#include <fcntl.h>
static int pairlist_read_internal(TALLOC_CTX *ctx, fr_dict_t const *dict, char const *file, PAIR_LIST_LIST *list,
- bool complain, int *order);
+ bool complain, bool v3_compat, int *order);
static inline void line_error_marker(char const *src_file, int src_line,
char const *user_file, int user_line,
* Caller saw a $INCLUDE at the start of a line.
*/
static int users_include(TALLOC_CTX *ctx, fr_dict_t const *dict, fr_sbuff_t *sbuff, PAIR_LIST_LIST *list,
- char const *file, int lineno, int *order)
+ char const *file, int lineno, bool v3_compat, int *order)
{
size_t len;
char *newfile, *p, c;
/*
* Read the $INCLUDEd file recursively.
*/
- if (pairlist_read_internal(ctx, dict, newfile, list, false, order) != 0) {
+ if (pairlist_read_internal(ctx, dict, newfile, list, false, v3_compat, order) != 0) {
ERROR("%s[%d]: Could not read included file %s: %s",
file, lineno, newfile, fr_syserror(errno));
talloc_free(newfile);
return 0;
}
-int pairlist_read(TALLOC_CTX *ctx, fr_dict_t const *dict, char const *file, PAIR_LIST_LIST *list)
+int pairlist_read(TALLOC_CTX *ctx, fr_dict_t const *dict, char const *file, PAIR_LIST_LIST *list, bool v3_compat)
{
int order = 0;
- return pairlist_read_internal(ctx, dict, file, list, true, &order);
+ return pairlist_read_internal(ctx, dict, file, list, true, v3_compat, &order);
}
/*
* Read the users file. Return a PAIR_LIST.
*/
-static int pairlist_read_internal(TALLOC_CTX *ctx, fr_dict_t const *dict, char const *file, PAIR_LIST_LIST *list, bool complain, int *order)
+static int pairlist_read_internal(TALLOC_CTX *ctx, fr_dict_t const *dict, char const *file, PAIR_LIST_LIST *list, bool complain, bool v3_compat, int *order)
{
char *q;
int lineno = 1;
.prefix = TMPL_ATTR_REF_PREFIX_YES,
.list_def = request_attr_request,
.list_presence = TMPL_ATTR_LIST_ALLOW,
+ .bare_word_enum = v3_compat,
}
};
* the tail of the current list.
*/
if (fr_sbuff_is_str(&sbuff, "$INCLUDE", 8)) {
- if (users_include(ctx, dict, &sbuff, list, file, lineno, order) < 0) goto fail;
+ if (users_include(ctx, dict, &sbuff, list, file, lineno, v3_compat, order) < 0) goto fail;
if (fr_sbuff_next_if_char(&sbuff, '\n')) {
lineno++;
fr_value_box_t *box; //!< parsed version of "name".
} PAIR_LIST_LIST;
-/* users_file.c */
-int pairlist_read(TALLOC_CTX *ctx, fr_dict_t const *dict, char const *file, PAIR_LIST_LIST *list);
+int pairlist_read(TALLOC_CTX *ctx, fr_dict_t const *dict, char const *file, PAIR_LIST_LIST *list, bool v3_compat);
static inline void pairlist_list_init(PAIR_LIST_LIST *list)
{
PAIR_LIST *entry = NULL;
map_t *map;
- rcode = pairlist_read(ctx, dict_radius, filename, pair_list);
+ rcode = pairlist_read(ctx, dict_radius, filename, pair_list, false);
if (rcode < 0) {
return -1;
}
typedef struct {
char const *filename;
+ bool v3_compat;
} rlm_files_t;
/** Structure produced by custom call_env parser
static const conf_parser_t module_config[] = {
{ FR_CONF_OFFSET_FLAGS("filename", CONF_FLAG_REQUIRED | CONF_FLAG_FILE_INPUT, rlm_files_t, filename) },
+ { FR_CONF_OFFSET("v3_compat", rlm_files_t, v3_compat) },
CONF_PARSER_TERMINATOR
};
}
static int getrecv_filename(TALLOC_CTX *ctx, char const *filename, fr_htrie_t **ptree, PAIR_LIST_LIST **pdefault,
- fr_type_t data_type, fr_dict_attr_t const *key_enum, fr_dict_t const *dict)
+ fr_type_t data_type, fr_dict_attr_t const *key_enum, fr_dict_t const *dict, bool v3_compat)
{
int rcode;
PAIR_LIST_LIST users;
}
pairlist_list_init(&users);
- rcode = pairlist_read(ctx, dict, filename, &users);
+ rcode = pairlist_read(ctx, dict, filename, &users, v3_compat);
if (rcode < 0) {
return -1;
}
}
if (getrecv_filename(files_data, inst->filename, &files_data->htrie, &files_data->def,
- keytype, key_enum, t_rules->attr.dict_def) < 0) goto error;
+ keytype, key_enum, t_rules->attr.dict_def, inst->v3_compat) < 0) goto error;
*(void **)out = files_data;
return 0;
# This should fail, which means that the previous Reply-Message
# gets deleted as part of the "undo" operation.
#
+# Note that the contents of the RHS have to be expanded at run-time,
+# otherwise it's a compile-time error.
+#
undo
- Framed-IP-Address := "this is not an IP address"
+ Framed-IP-Address := "hello %md5('foo')"
#
# Test where additional checks uses the [*] filter