### EAP-PWD (Secure password-based authentication)
-In v4, the "known good" password is taken from the `&request.control.Password.Cleartext` list,
+In v4, the "known good" password is taken from the `request.control.Password.Cleartext` list,
as is done by other modules. The change from v3 is that the `inner-tunnel` virtual server
is no not used.
The file should be provided as the attribute:
- &control.TLS-Session-Cert-File
+ control.TLS-Session-Cert-File
If there are any errors loading or verifying the
certificate, then authentication will fail.
`virtual_server`.
Attributes created during certificate processing
-will be placed in the `&session-state` list.
+will be placed in the `session-state` list.
This is to simplify session-resumption, as the
contents of this list also contains session data
for stateful resumption, and this list is encoded
====
Attribute generation is only performed on full
handshake, or where we detect that attributes
-are missing from the &session-state list during
+are missing from the `session-state` list during
stateful session-resumption.
Certificate attributes will usually be retrieved
You must ensure that any attributes required for policy
decisions are cached along with the TLS session
data. This is usually done by placing policy attributes in the
-`&session-state` list, or in the case of EAP-PEAP, EAP-TTLS and
-EAP-FAST, the `&parent.session-state` list (i.e. in the request
+`session-state` list, or in the case of EAP-PEAP, EAP-TTLS and
+EAP-FAST, the `parent.session-state` list (i.e. in the request
which sets up the TLS part of the authentication attempt).
Caching this data means that the policies are cached at the
You can override this configuration item at run-time by setting:
- &control.EAP-TLS-Require-Client-Cert = Yes/No
+ control.EAP-TLS-Require-Client-Cert = Yes/No
following option. You can also override this option by
setting:
- &control.EAP-TLS-Require-Client-Cert = Yes
+ control.EAP-TLS-Require-Client-Cert = Yes
NOTE: The majority of supplicants do not support using a
client certificate with `EAP-TTLS`, so this option is unlikely
However, you can require one by setting the following
option. You can also override this option by setting
-&control.EAP-TLS-Require-Client-Cert = Yes
+control.EAP-TLS-Require-Client-Cert = Yes
NOTE: The majority of supplicants do not support using a
client certificate with `PEAP`, so this option is unlikely to
}
session {
# mode = auto
-# name = "%{EAP-Type}%interpreter(server)"
+# name = "%{EAP-Type}%interpreter('server')"
# lifetime = 86400
# require_extended_master_secret = yes
# require_perfect_forward_secrecy = no
# the value provided here is first hashed with SHA256
# before being passed to OpenSSL.
#
-# name = "%{EAP-Type}%interpreter(server)"
+# name = "%{EAP-Type}%interpreter('server')"
#
# lifetime:: The period for which a resumable session remains vali.d
# Outputs the contents of the control list in debugging (-X) mode
#
debug_control {
- if (%debug_attr(control)) {
+ if (%debug_attr('control')) {
noop
}
}
# Outputs the contents of the request list in debugging (-X) mode
#
debug_request {
- if (%debug_attr(request)) {
+ if (%debug_attr('request')) {
noop
}
}
# Outputs the contents of the reply list in debugging (-X) mode
#
debug_reply {
- if (%debug_attr(reply)) {
+ if (%debug_attr('reply')) {
noop
}
}
# Outputs the contents of the session state list in debugging (-X) mode
#
debug_session_state {
- if (%debug_attr(session-state)) {
+ if (%debug_attr('session-state')) {
noop
}
}
}
extern bool tmpl_require_enum_prefix;
+extern bool xlat_func_bare_words;
/** Set or clear migration flags.
*
default_log.fd = STDOUT_FILENO;
default_log.print_level = false;
+ /*
+ * Migration option - it's enabled by default in
+ * src/lib/server/main_config.c, until we have time to
+ * update all of the default configuration files and
+ * tests.
+ */
+ xlat_func_bare_words = false;
+
while ((c = getopt(argc, argv, "cd:D:F:fxMhpr:S:w:")) != -1) switch (c) {
case 'c':
do_commands = true;
* Migration configuration.
*/
extern bool tmpl_require_enum_prefix;
-bool xlat_func_bare_words = false;
+bool xlat_func_bare_words = true;
static const conf_parser_t migrate_config[] = {
{ FR_CONF_OFFSET_FLAGS("rewrite_update", CONF_FLAG_HIDDEN, main_config_t, rewrite_update) },
},
.dflt = "auto" },
{ FR_CONF_OFFSET_HINT_TYPE("name", FR_TYPE_STRING, fr_tls_cache_conf_t, id_name),
- .dflt = "%{EAP-Type}%interpreter(server)", .quote = T_DOUBLE_QUOTED_STRING },
+ .dflt = "%{EAP-Type}%interpreter('server')", .quote = T_DOUBLE_QUOTED_STRING },
{ FR_CONF_OFFSET("lifetime", fr_tls_cache_conf_t, lifetime), .dflt = "1d" },
{ FR_CONF_OFFSET("require_extended_master_secret", fr_tls_cache_conf_t, require_extms), .dflt = "yes" },
# define XLAT_HEXDUMP(...)
#endif
-extern bool tmpl_require_enum_prefix;
+extern const bool tmpl_require_enum_prefix;
+extern const bool xlat_func_bare_words;
/** These rules apply to literal values and function arguments inside of an expansion
*
xlat_t const *xlat,
fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules, bool spaces)
{
- int argc = 0;
+ int argc;
fr_sbuff_t our_in = FR_SBUFF(in);
ssize_t slen;
fr_sbuff_marker_t m;
*/
fr_sbuff_adv_past_whitespace(in, SIZE_MAX, NULL);
fr_sbuff_marker(&m, &our_in);
+ argc = 1;
while (fr_sbuff_extend(&our_in)) {
xlat_exp_t *node = NULL;
size_t len;
fr_sbuff_set(&m, &our_in); /* Record start of argument */
- argc++;
/*
* Whitespace isn't significant for comma-separated argvs
* tmpl. And update the function arguments to say "we want a tmpl, not a
* string".
*/
- if (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 (spaces && !tmpl_require_enum_prefix && fr_sbuff_is_char(&our_in, '&')) {
+ slen = xlat_tokenize_attribute(node->group, &our_in, our_p_rules, t_rules, TMPL_ATTR_REF_PREFIX_YES);
- if (xlat_tokenize_input(node->group, &our_in,
- our_p_rules, t_rules, arg->safe_for) < 0) {
+ } else if (spaces || xlat_func_bare_words) {
+ /*
+ * Spaces - each argument is a bare word all by itself, OR an xlat thing all by itself.
+ *
+ * No spaces - each arugment is an expression, which can have embedded spaces.
+ */
+ slen = xlat_tokenize_input(node->group, &our_in, our_p_rules, t_rules, arg->safe_for);
+
+ } else if (fr_sbuff_is_char(&our_in, ')')) {
+ /*
+ * %foo()
+ */
+ slen = 0;
+
+ } else {
+ slen = xlat_tokenize_expression(node, &node->group, &our_in, our_p_rules, t_rules);
+ }
+ if (slen < 0) {
error:
if (our_p_rules == &tmp_p_rules) talloc_const_free(our_p_rules->terminals);
talloc_free(head);
FR_SBUFF_ERROR_RETURN(&our_in); /* error */
}
+
+ /*
+ * No data, but the argument was required. Complain.
+ */
+ if (!slen && arg->required) {
+ fr_strerror_printf("Missing required arg %u", argc);
+ goto error;
+ }
break;
/*
next:
if (!arg->variadic) {
arg++;
+ argc++;
+
if (arg->type == FR_TYPE_NULL) {
fr_strerror_printf("Too many arguments, expected %zu, got %d",
- (size_t) (arg - arg_start), argc - 1);
+ (size_t) (arg - arg_start), argc);
goto error;
}
}
#
# MD5 HMAC with missing key should fail
#
-result_octets := %hmacmd5(%{test_string}, )
+result_octets := %hmacmd5(%{test_string}, ) # ERROR
if result_octets {
test_fail
}
# Outputs the contents of the control list in debugging (-X) mode
#
debug_control {
- %debug_attr(control.[*])
+ %debug_attr('control.[*]')
}
#
# Outputs the contents of the request list in debugging (-X) mode
#
debug_request {
- %debug_attr(request.[*])
+ %debug_attr('request.[*]')
}
#
# Outputs the contents of the reply list in debugging (-X) mode
#
debug_reply {
- %debug_attr(reply.[*])
+ %debug_attr('reply.[*]')
}
#
test_fail {
reply += {
- Result-Status = "Failure in test file %interpreter(...filename)[%interpreter(...line)]"
+ Result-Status = "Failure in test file %interpreter('...filename')[%interpreter('...line')]"
}
if (parent.request) {
parent.reply += {
- Result-Status = "Failure in test file %interpreter(...filename)[%interpreter(...line)]"
+ Result-Status = "Failure in test file %interpreter('...filename')[%interpreter('...line')]"
}
}
}
@echo "MODULE-TEST $(TEST)"
${Q}mkdir -p $(dir $@)
${Q}cp $(if $(wildcard $(basename $<).attrs),$(basename $<).attrs,src/tests/modules/default-input.attrs) $@.attrs
- ${Q}if ! MODULE_TEST_DIR=$(dir $<) MODULE_TEST_UNLANG=$< TEST="$(TEST)" $(TEST_BIN)/unit_test_module -D share/dictionary -d src/tests/modules/ -i "$@.attrs" -f "$@.attrs" -r "$@" -xxx > "$@.log" 2>&1 || ! test -f "$@"; then \
+ ${Q}if ! MODULE_TEST_DIR=$(dir $<) MODULE_TEST_UNLANG=$< TEST="$(TEST)" $(TEST_BIN)/unit_test_module -D share/dictionary -d src/tests/modules/ -i "$@.attrs" -f "$@.attrs" -r "$@" -S xlat_func_bare_words=yes -xxx > "$@.log" 2>&1 || ! test -f "$@"; then \
if ! grep ERROR $< 2>&1 > /dev/null; then \
if grep 'LeakSanitizer has encountered a fatal error' $@.log 2>&1 > /dev/null; then \
echo "MODULE-TEST $(TEST) - ignoring LeakSanitizer fatal error."; \
if [ "$$EXPECTED" != "$$FOUND" ]; then \
cat "$@.log"; \
echo "# $@.log"; \
- echo "MODULE_TEST_DIR=$(dir $<) MODULE_TEST_UNLANG=$< $(TEST_BIN)/unit_test_module -D share/dictionary -d src/tests/modules/ -i \"$@.attrs\" -f \"$@.attrs\" -r \"$@\" -xx"; \
+ echo "MODULE_TEST_DIR=$(dir $<) MODULE_TEST_UNLANG=$< $(TEST_BIN)/unit_test_module -D share/dictionary -d src/tests/modules/ -i \"$@.attrs\" -f \"$@.attrs\" -r \"$@\" -S xlat_func_bare_words=yes -xx"; \
exit 1; \
else \
touch "$@"; \
xlat foo %{%{User-Name} || 'bar'} baz
match foo %{(%{User-Name} || 'bar')} baz
-xlat %{%test(bar) || %{User-Name}}
-match %{(%test(bar) || %{User-Name})}
+xlat %{%test('bar') || %{User-Name}}
+match %{(%test('bar') || %{User-Name})}
-xlat %{%test(bar) || %{%{User-Name} || 'bar'}}
-match %{(%test(bar) || %{(%{User-Name} || 'bar')})}
+xlat %{%test('bar') || %{%{User-Name} || 'bar'}}
+match %{(%test('bar') || %{(%{User-Name} || 'bar')})}
xlat %{%{User-Name} || }
match ERROR offset 19: Zero length attribute name: Unresolved attributes are not allowed here
xlat %{%{%{User-Name} || 'foo'} || 'bar'}
match %{(%{(%{User-Name} || 'foo')} || 'bar')}
-xlat %{%{%{User-Name} || 'foo'} || %{%test(bar) || %{User-Name}}}
-match %{(%{(%{User-Name} || 'foo')} || %{(%test(bar) || %{User-Name})})}
+xlat %{%{%{User-Name} || 'foo'} || %{%test('bar') || %{User-Name}}}
+match %{(%{(%{User-Name} || 'foo')} || %{(%test('bar') || %{User-Name})})}
xlat %{ || }
match ERROR offset 4: Zero length attribute name: Unresolved attributes are not allowed here
# The second argument should be an integer.
#
# @todo - parsing - we don't currently track string offsets for intermediate nodes,
-# so the "offset 23" is wrong. It also doesn't say *which* string is wrong. We'll fix that later.
+# so the "offset" is wrong. It also doesn't say *which* string is wrong. We'll fix that later.
#
-xlat %rpad(User-Name, foo, 'x')
-match ERROR offset 27: Failed parsing argument 1 as type 'uint64'
+xlat %rpad(User-Name, 'foo', 'x')
+match ERROR offset 29: Failed parsing argument 1 as type 'uint64'
#
# Argument quoting
#
# @todo - bare words should probably be disallowed
#
-xlat_purify %md5(foo)
+xlat_purify %md5('foo')
match 0xacbd18db4cc2f85cedef654fccc4a4d8
-xlat_purify %md5(%md5(foo))
+xlat_purify %md5(%md5('foo'))
match 0x47847ae721df523d6388aebc9c94d656
xlat_purify %md5('%md5(foo)')
# this is "foo" + PRINTABLE version of the packet authentication vector
-xlat_expr "foo%bin(000000)"
+
+#
+# 1 argument
+#
+xlat_expr %file.exists()
+match ERROR offset 24 'Missing required arg 1'
+
+#
+# Only one argument
+#
+xlat_expr %file.exists("foo", "bar")
+match ERROR offset 30 'Too many arguments, expected 1, got 2'
+
+xlat_expr "foo%bin('000000')"
match foo\000\000\000
xlat_expr 1 && 2
# This just casts the octets to 'string', without
# any escaping.
#
-xlat_expr "foo" + (string)%bin(0x0001020304)
+xlat_expr "foo" + (string)%bin('0x0001020304')
match foo\000\001\002\003\004
# string + octets gets promoted to octets
-xlat_expr "foo" + %bin(0x0001020304)
+xlat_expr "foo" + %bin('0x0001020304')
match 0x666f6f0001020304
# no escaping!