From: Alan T. DeKok Date: Thu, 28 Sep 2023 21:30:17 +0000 (-0400) Subject: allow &Attr references in function mono X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9787575eda4112bcd5d8137484fc4e9b6aec3da8;p=thirdparty%2Ffreeradius-server.git allow &Attr references in function mono not in other ones, as the rest of the functions expect to see an input argument which is a string, and they convert that to a tmpl. The tokenize / eval framework likely needs to be updated to allow for something like &%{...}, which would create the tmpl name at run time. And then the function can get passed a tmpl (in a value-box?) and not a raw value-box. --- diff --git a/src/bin/unit_test_attribute.c b/src/bin/unit_test_attribute.c index 791f0840dd8..29c3cd77a66 100644 --- a/src/bin/unit_test_attribute.c +++ b/src/bin/unit_test_attribute.c @@ -2824,7 +2824,7 @@ static size_t command_xlat_argv(command_result_t *result, command_file_ctx_t *cc .list_def = request_attr_request, .allow_unresolved = cc->tmpl_rules.attr.allow_unresolved }, - }, false); + }, false, false); if (slen <= 0) { fr_strerror_printf_push_head("ERROR offset %d", (int) -slen); RETURN_OK_WITH_ERROR(); diff --git a/src/bin/unit_test_module.c b/src/bin/unit_test_module.c index 198c786154b..e8c7b49bd5c 100644 --- a/src/bin/unit_test_module.c +++ b/src/bin/unit_test_module.c @@ -347,7 +347,10 @@ static request_t *request_from_file(TALLOC_CTX *ctx, FILE *fp, fr_client_t *clie request->log.dst = talloc_zero(request, log_dst_t); request->log.dst->func = vlog_request; request->log.dst->uctx = &default_log; + + request->master_state = REQUEST_ACTIVE; request->log.lvl = fr_debug_lvl; + request->async = talloc_zero(request, fr_async_t); /* @@ -985,7 +988,7 @@ int main(int argc, char *argv[]) EXIT_WITH_FAILURE; } - if (!do_xlats(el, request, input_file, fp)) ret = EXIT_FAILURE; + if (!do_xlats(el, request, xlat_input_file, fp)) ret = EXIT_FAILURE; if (input_file) fclose(fp); goto cleanup; } diff --git a/src/lib/server/tmpl_tokenize.c b/src/lib/server/tmpl_tokenize.c index d5bb2c486dd..c68f2c3931c 100644 --- a/src/lib/server/tmpl_tokenize.c +++ b/src/lib/server/tmpl_tokenize.c @@ -3238,7 +3238,7 @@ fr_slen_t tmpl_afrom_substr(TALLOC_CTX *ctx, tmpl_t **out, * FIXME - We need an ephemeral version of this * too. */ - slen = xlat_tokenize_argv(vpt, &head, &our_in, p_rules, t_rules, false); + slen = xlat_tokenize_argv(vpt, &head, &our_in, p_rules, t_rules, false, false); if (slen < 0) { talloc_free(vpt); FR_SBUFF_ERROR_RETURN(&our_in); diff --git a/src/lib/server/trigger.c b/src/lib/server/trigger.c index e941b611f27..67d2bc06a5d 100644 --- a/src/lib/server/trigger.c +++ b/src/lib/server/trigger.c @@ -430,7 +430,7 @@ int trigger_exec(unlang_interpret_t *intp, trigger->timeout = fr_time_delta_from_sec(5); /* FIXME - Should be configurable? */ slen = xlat_tokenize_argv(trigger, &trigger->xlat, - &FR_SBUFF_IN(trigger->command, talloc_array_length(trigger->command) - 1), NULL, NULL, false); + &FR_SBUFF_IN(trigger->command, talloc_array_length(trigger->command) - 1), NULL, NULL, false, false); if (slen <= 0) { char *spaces, *text; diff --git a/src/lib/unlang/xlat.h b/src/lib/unlang/xlat.h index 08dc70d6575..40fbb4d8f2b 100644 --- a/src/lib/unlang/xlat.h +++ b/src/lib/unlang/xlat.h @@ -402,7 +402,7 @@ fr_slen_t xlat_tokenize_ephemeral(TALLOC_CTX *ctx, xlat_exp_head_t **head, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules); fr_slen_t xlat_tokenize_argv(TALLOC_CTX *ctx, xlat_exp_head_t **head, fr_sbuff_t *in, - fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules, bool comma); + fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules, bool comma, bool allow_attr); fr_slen_t xlat_tokenize(TALLOC_CTX *ctx, xlat_exp_head_t **head, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules); diff --git a/src/lib/unlang/xlat_builtin.c b/src/lib/unlang/xlat_builtin.c index 6c25430a15d..6d490fa7ed2 100644 --- a/src/lib/unlang/xlat_builtin.c +++ b/src/lib/unlang/xlat_builtin.c @@ -1775,7 +1775,7 @@ static xlat_arg_parser_t const xlat_func_md5_arg[] = { */ static xlat_action_t xlat_func_md5(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, - UNUSED request_t *request, fr_value_box_list_t *args) + request_t *request, fr_value_box_list_t *args) { uint8_t digest[MD5_DIGEST_LENGTH]; fr_value_box_t *vb; @@ -1784,6 +1784,8 @@ static xlat_action_t xlat_func_md5(TALLOC_CTX *ctx, fr_dcursor_t *out, XLAT_ARGS(args, &in_head); if (in_head) { + RDEBUG("INPUT IS %pV", in_head); + fr_md5_calc(digest, in_head->vb_octets, in_head->vb_length); } else { /* Digest of empty string */ diff --git a/src/lib/unlang/xlat_tokenize.c b/src/lib/unlang/xlat_tokenize.c index 00bfc0dc010..f1124ec6353 100644 --- a/src/lib/unlang/xlat_tokenize.c +++ b/src/lib/unlang/xlat_tokenize.c @@ -610,7 +610,7 @@ int xlat_tokenize_function_args(xlat_exp_head_t *head, fr_sbuff_t *in, * Now parse the child nodes that form the * function's arguments. */ - if (xlat_tokenize_argv(node, &node->call.args, in, &xlat_multi_arg_rules, t_rules, false) < 0) { + if (xlat_tokenize_argv(node, &node->call.args, in, &xlat_multi_arg_rules, t_rules, false, false) < 0) { goto error; } xlat_flags_merge(&node->flags, &node->call.args->flags); @@ -755,7 +755,7 @@ static int xlat_tokenize_function_new(xlat_exp_head_t *head, fr_sbuff_t *in, tmp * Now parse the child nodes that form the * function's arguments. */ - if (xlat_tokenize_argv(node, &node->call.args, in, &xlat_new_arg_rules, t_rules, true) < 0) { + if (xlat_tokenize_argv(node, &node->call.args, in, &xlat_new_arg_rules, t_rules, true, (node->call.input_type == XLAT_INPUT_MONO)) < 0) { error: talloc_free(node); return -1; @@ -810,8 +810,8 @@ static int xlat_resolve_virtual_attribute(xlat_exp_t *node, tmpl_t *vpt) /** Parse an attribute ref or a virtual attribute * */ -static inline int xlat_tokenize_attribute(xlat_exp_head_t *head, fr_sbuff_t *in, - fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules) +static int xlat_tokenize_attribute(xlat_exp_head_t *head, fr_sbuff_t *in, + fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules, tmpl_attr_prefix_t attr_prefix) { tmpl_attr_error_t err; tmpl_t *vpt = NULL; @@ -837,7 +837,7 @@ static inline int xlat_tokenize_attribute(xlat_exp_head_t *head, fr_sbuff_t *in, } our_t_rules.attr.allow_unresolved = true; /* So we can check for virtual attributes later */ - our_t_rules.attr.prefix = TMPL_ATTR_REF_PREFIX_NO; /* Must be NO to stop %{&User-Name} */ + our_t_rules.attr.prefix = attr_prefix; /* Must be NO to stop %{&User-Name} */ fr_sbuff_marker(&m_s, in); @@ -900,11 +900,6 @@ done: */ node->flags.pure = false; - if (!fr_sbuff_next_if_char(in, '}')) { - fr_strerror_const("Missing closing brace"); - goto error; - } - xlat_exp_insert_tail(head, node); fr_sbuff_marker_release(&m_s); @@ -1035,7 +1030,14 @@ int xlat_tokenize_expansion(xlat_exp_head_t *head, fr_sbuff_t *in, fr_sbuff_set(in, &s_m); /* backtrack */ fr_sbuff_marker_release(&s_m); - return xlat_tokenize_attribute(head, in, &attr_p_rules, t_rules); + if (xlat_tokenize_attribute(head, in, &attr_p_rules, t_rules, TMPL_ATTR_REF_PREFIX_NO) < 0) return -1; + + if (!fr_sbuff_next_if_char(in, '}')) { + fr_strerror_const("Missing closing brace"); + return -1; + } + + return 0; /* * Hint token was whitespace @@ -1672,12 +1674,13 @@ fr_slen_t xlat_tokenize_ephemeral(TALLOC_CTX *ctx, xlat_exp_head_t **out, * any expansions. * @param[in] t_rules controlling how attribute references are parsed. * @param[in] comma whether the arguments are delimited by commas + * @param[in] allow_attr allow attribute references as arguments * @return * - < 0 on error. * - >0 on success which is the number of characters parsed. */ fr_slen_t xlat_tokenize_argv(TALLOC_CTX *ctx, xlat_exp_head_t **out, fr_sbuff_t *in, - fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules, bool comma) + fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules, bool comma, bool allow_attr) { int argc = 0; fr_sbuff_t our_in = FR_SBUFF(in); @@ -1734,6 +1737,24 @@ fr_slen_t xlat_tokenize_argv(TALLOC_CTX *ctx, xlat_exp_head_t **out, fr_sbuff_t case T_BARE_WORD: XLAT_DEBUG("ARGV bare word <-- %.*s", (int) fr_sbuff_remaining(&our_in), fr_sbuff_current(&our_in)); + /* + * &User-Name is an attribute reference + * + * @todo - only the mono functions allow this automatic conversion. + * The input args ones (e.g. immutable) take an input string, and parse the tmpl from that. + * + * We need to signal the tokenize / eval code that the parameter here is a tmpl, and not a string. + * + * Perhaps &"foo" can dynamically create the string, and then pass it to the the + * tmpl tokenizer, and then pass the tmpl to the function. Which also means that + * we need to be able to have a fr_value_box_t which holds a ptr to a tmpl. And + * update the function arguments to say "we want a tmpl, not a string". + */ + if (allow_attr && fr_sbuff_is_char(&our_in, '&')) { + if (xlat_tokenize_attribute(node->group, &our_in, our_p_rules, t_rules, TMPL_ATTR_REF_PREFIX_YES) < 0) goto error; + break; + } + if (xlat_tokenize_input(node->group, &our_in, our_p_rules, t_rules) < 0) { error: diff --git a/src/tests/unit/xlat/purify.txt b/src/tests/unit/xlat/purify.txt index 4de530afdce..1a258eb035e 100644 --- a/src/tests/unit/xlat/purify.txt +++ b/src/tests/unit/xlat/purify.txt @@ -244,10 +244,10 @@ xlat_purify %md5('%md5(foo)') match 0x5e153571422b69cf5c5f7ce5f03985b5 # -# Because this isn't a reference to the contents of &User-Name +# This is a reference to the contents of &User-Name # xlat_purify %md5(&User-Name) -match 0x14d23a6ed8e7d19fcb3a38dc86c1fc0b +match %{md5:&User-Name} xlat_purify %md5('foo') @@ -256,8 +256,5 @@ match 0xacbd18db4cc2f85cedef654fccc4a4d8 xlat_purify %md5("foo") match 0xacbd18db4cc2f85cedef654fccc4a4d8 -xlat_purify %md5(&User-Name) -match 0x14d23a6ed8e7d19fcb3a38dc86c1fc0b - count -match 116 +match 114 diff --git a/src/tests/xlat/expr.txt b/src/tests/xlat/expr.txt index f590009e4fb..38d117956a9 100644 --- a/src/tests/xlat/expr.txt +++ b/src/tests/xlat/expr.txt @@ -131,14 +131,30 @@ match true xlat_expr "foo " + "baz" + " bar" match foo baz bar -xlat_expr "foo " + &User-Name + " bar" -match foo bob bar +#xlat_expr "foo " + &User-Name + " bar" +#match foo bob bar +# +# The User-Name has to exist +# +xlat_expr %{User-Name} +match {bob} + +# +# We're not hashing the string value of the attribute reference +# +xlat_expr (octets) %md5('&User-Name') +match 0x14d23a6ed8e7d19fcb3a38dc86c1fc0b + +# +# We're hashing the string contained by the User-Name +# xlat_expr (octets) %md5('bob') match 0x9f9d51bc70ef21ca5c14f307980a29d8 # -# @todo - not done yet! +# And if we take it from the &User-Name ref, we get the same thing +# as hashing the bare string. # -#xlat_expr (octets) %md5(&User-Name) -#match 0x9f9d51bc70ef21ca5c14f307980a29d8 +xlat_expr (octets) %md5(&User-Name) +match 0x9f9d51bc70ef21ca5c14f307980a29d8