From: Nick Porter Date: Fri, 21 May 2021 13:05:48 +0000 (+0100) Subject: v4: Convert %(mschap: ) to new xlat API (#4082) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9e0f90c7c293fb641f86df230810509300f2992b;p=thirdparty%2Ffreeradius-server.git v4: Convert %(mschap: ) to new xlat API (#4082) * Convert %(mschap: ) to new xlat API * Add extra safety checks to %(mschap: ) attribute parsing * Add tests for %(mschap: ) xlat * Update docs for new syntax of %(mschap: ) * Update other code use of %(mschap: ) --- diff --git a/doc/antora/modules/howto/pages/modules/mschap/index.adoc b/doc/antora/modules/howto/pages/modules/mschap/index.adoc index 180eb000dca..192d8ae34de 100644 --- a/doc/antora/modules/howto/pages/modules/mschap/index.adoc +++ b/doc/antora/modules/howto/pages/modules/mschap/index.adoc @@ -43,7 +43,7 @@ several options for the arguments, in particular username and domain: * `–username=%{User-Name}` - this will fail if you’re using realms or host-based auth -* `–username=%{mschap:User-Name}` - this will fail if using using suffix +* `–username=%(mschap:User-Name)` - this will fail if using using suffix i.e. user@domain You’ll need to fit this to your local needs. @@ -81,8 +81,8 @@ mschap { # initial data to send # this MUST be supplied - ntlm_auth_username = "username: %{mschap:User-Name}" - ntlm_auth_domain = "nt-domain: %{%{mschap:NT-Domain}:-YOURDOMAIN}" + ntlm_auth_username = "username: %(mschap:User-Name)" + ntlm_auth_domain = "nt-domain: %{%(mschap:NT-Domain):-YOURDOMAIN}" # Or, you could try: ntlm_auth_username = "full-username: %{User-Name}" diff --git a/doc/antora/modules/raddb/pages/mods-available/mschap.adoc b/doc/antora/modules/raddb/pages/mods-available/mschap.adoc index 5b5fd3fa4ff..af5ddc37bcc 100644 --- a/doc/antora/modules/raddb/pages/mods-available/mschap.adoc +++ b/doc/antora/modules/raddb/pages/mods-available/mschap.adoc @@ -102,7 +102,7 @@ module will do the authentication itself, without calling `ntlm_auth`. You can also try setting the user name as: -`... --username=%{mschap:User-Name} ...` +`... --username=%(mschap:User-Name) ...` In that case, the `mschap` module will look at the `link:https://freeradius.org/rfc/rfc2865.html#User-Name[User-Name]` attribute, and do prefix/suffix checks in order to obtain the _best_ @@ -320,11 +320,11 @@ mschap { # require_encryption = yes # require_strong = yes # with_ntdomain_hack = no -# ntlm_auth = "/path/to/ntlm_auth --request-nt-key --username=%{%{Stripped-User-Name}:-%{%{User-Name}:-None}} --challenge=%{%{mschap:Challenge}:-00} --nt-response=%{%{mschap:NT-Response}:-00}" +# ntlm_auth = "/path/to/ntlm_auth --request-nt-key --username=%{%{Stripped-User-Name}:-%{%{User-Name}:-None}} --challenge=%{%(mschap:Challenge):-00} --nt-response=%{%(mschap:NT-Response):-00}" # ntlm_auth_timeout = 10 winbind { -# username = "%{mschap:User-Name}" -# domain = "%{mschap:NT-Domain}" +# username = "%(mschap:User-Name)" +# domain = "%(mschap:NT-Domain)" # retry_with_normalised_username = no } pool { @@ -340,9 +340,9 @@ mschap { } passchange { # ntlm_auth = "/usr/bin/ntlm_auth --helper-protocol=ntlm-change-password-1" -# ntlm_auth_username = "username: %{mschap:User-Name}" -# ntlm_auth_domain = "nt-domain: %{mschap:NT-Domain}" -# local_cpw = "%{exec:/path/to/script %{mschap:User-Name} %{MS-CHAP-New-Password.Cleartext}}" +# ntlm_auth_username = "username: %(mschap:User-Name)" +# ntlm_auth_domain = "nt-domain: %(mschap:NT-Domain)" +# local_cpw = "%{exec:/path/to/script %(mschap:User-Name) %{MS-CHAP-New-Password.Cleartext}}" # local_cpw = "%{sql:UPDATE radcheck set value='%{MS-CHAP-New-NT-Password}' where username='%{User-Name}' and attribute='NT-Password'}" } # use_open_directory = yes diff --git a/doc/antora/modules/raddb/pages/mods-available/ntlm_auth.adoc b/doc/antora/modules/raddb/pages/mods-available/ntlm_auth.adoc index be978d9bfb1..a7bc565cf93 100644 --- a/doc/antora/modules/raddb/pages/mods-available/ntlm_auth.adoc +++ b/doc/antora/modules/raddb/pages/mods-available/ntlm_auth.adoc @@ -39,6 +39,6 @@ local system. The other fields can be left alone. # http://deployingradius.com/documents/configuration/active_directory.html exec ntlm_auth { wait = yes - program = "/path/to/ntlm_auth --request-nt-key --domain=MYDOMAIN --username=%{mschap:User-Name} --password=%{User-Password}" + program = "/path/to/ntlm_auth --request-nt-key --domain=MYDOMAIN --username=%(mschap:User-Name) --password=%{User-Password}" } ``` diff --git a/raddb/mods-available/mschap b/raddb/mods-available/mschap index f1764a3e698..905bfa59777 100644 --- a/raddb/mods-available/mschap +++ b/raddb/mods-available/mschap @@ -111,7 +111,7 @@ mschap { # # You can also try setting the user name as: # - # `... --username=%{mschap:User-Name} ...` + # `... --username=%(mschap:User-Name) ...` # # In that case, the `mschap` module will look at the `User-Name` # attribute, and do prefix/suffix checks in order to obtain the _best_ @@ -126,7 +126,7 @@ mschap { # WARNING: Be VERY careful when editing the following line! # Change the path, and ideally nothing else. # -# ntlm_auth = "/path/to/ntlm_auth --request-nt-key --username=%{%{Stripped-User-Name}:-%{%{User-Name}:-None}} --challenge=%{%{mschap:Challenge}:-00} --nt-response=%{%{mschap:NT-Response}:-00}" +# ntlm_auth = "/path/to/ntlm_auth --request-nt-key --username=%{%{Stripped-User-Name}:-%{%{User-Name}:-None}} --challenge=%{%(mschap:Challenge):-00} --nt-response=%{%(mschap:NT-Response):-00}" # # ntlm_auth_timeout:: Time to wait for `ntlm_auth` to run. @@ -163,8 +163,8 @@ mschap { # later to be installed. Make sure that `ntlm_auth` above is # commented out. # -# username = "%{mschap:User-Name}" -# domain = "%{mschap:NT-Domain}" +# username = "%(mschap:User-Name)" +# domain = "%(mschap:NT-Domain)" # # retry_with_normalised_username:: @@ -309,8 +309,8 @@ mschap { # Uncomment the three lines below, and change the path to `ntlm_auth. # # ntlm_auth = "/usr/bin/ntlm_auth --helper-protocol=ntlm-change-password-1" -# ntlm_auth_username = "username: %{mschap:User-Name}" -# ntlm_auth_domain = "nt-domain: %{mschap:NT-Domain}" +# ntlm_auth_username = "username: %(mschap:User-Name)" +# ntlm_auth_domain = "nt-domain: %(mschap:NT-Domain)" # # local_cpw:: @@ -322,7 +322,7 @@ mschap { # # TIP: We give both examples here, but *only one should be used*. # -# local_cpw = "%{exec:/path/to/script %{mschap:User-Name} %{MS-CHAP-New-Password.Cleartext}}" +# local_cpw = "%{exec:/path/to/script %(mschap:User-Name) %{MS-CHAP-New-Password.Cleartext}}" # local_cpw = "%{sql:UPDATE radcheck set value='%{MS-CHAP-New-NT-Password}' where username='%{User-Name}' and attribute='NT-Password'}" } diff --git a/raddb/mods-available/ntlm_auth b/raddb/mods-available/ntlm_auth index 7e0ada9ba4e..3806a5e46fc 100644 --- a/raddb/mods-available/ntlm_auth +++ b/raddb/mods-available/ntlm_auth @@ -38,5 +38,5 @@ exec ntlm_auth { # You will need to edit the path and domain to match your # local system. The other fields can be left alone. # - program = "/path/to/ntlm_auth --request-nt-key --domain=MYDOMAIN --username=%{mschap:User-Name} --password=%{User-Password}" + program = "/path/to/ntlm_auth --request-nt-key --domain=MYDOMAIN --username=%(mschap:User-Name) --password=%{User-Password}" } diff --git a/src/modules/rlm_mschap/rlm_mschap.c b/src/modules/rlm_mschap/rlm_mschap.c index f5ea4e2f659..252a365d719 100644 --- a/src/modules/rlm_mschap/rlm_mschap.c +++ b/src/modules/rlm_mschap/rlm_mschap.c @@ -286,6 +286,17 @@ static int pdb_decode_acct_ctrl(char const *p) return acct_ctrl; } +static int mod_xlat_instantiate(void *xlat_inst, UNUSED xlat_exp_t const *exp, void *uctx) +{ + *((void **)xlat_inst) = talloc_get_type_abort(uctx, rlm_mschap_t); + return 0; +} + +static xlat_arg_parser_t const mschap_xlat_args[] = { + { .required = true, .single = true, .type = FR_TYPE_STRING }, + { .concat = true, .type = FR_TYPE_STRING }, + XLAT_ARG_PARSER_TERMINATOR +}; /** Get data from MSCHAP attributes * @@ -294,16 +305,23 @@ static int pdb_decode_acct_ctrl(char const *p) * * @ingroup xlat_functions */ -static ssize_t mschap_xlat(UNUSED TALLOC_CTX *ctx, char **out, size_t outlen, - void const *mod_inst, UNUSED void const *xlat_inst, - request_t *request, char const *fmt) +static xlat_action_t mschap_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, request_t *request, + void const *xlat_inst, UNUSED void *xlat_thread_inst, + fr_value_box_list_t *in) { - size_t i, data_len; + size_t data_len; uint8_t const *data = NULL; uint8_t buffer[32]; fr_pair_t *user_name; fr_pair_t *chap_challenge, *response; - rlm_mschap_t const *inst = mod_inst; + rlm_mschap_t const *inst; + void *instance; + fr_value_box_t *arg = fr_dlist_head(in); + fr_value_box_t *vb; + bool tainted = false; + + memcpy(&instance, xlat_inst, sizeof(instance)); + inst = talloc_get_type_abort(instance, rlm_mschap_t); response = NULL; @@ -311,12 +329,13 @@ static ssize_t mschap_xlat(UNUSED TALLOC_CTX *ctx, char **out, size_t outlen, * Challenge means MS-CHAPv1 challenge, or * hash of MS-CHAPv2 challenge, and peer challenge. */ - if (strncasecmp(fmt, "Challenge", 9) == 0) { + if (strncasecmp(arg->vb_strvalue, "Challenge", 9) == 0) { chap_challenge = fr_pair_find_by_da(&request->request_pairs, attr_ms_chap_challenge, 0); if (!chap_challenge) { REDEBUG("No MS-CHAP-Challenge in the request"); - return -1; + return XLAT_ACTION_FAIL; } + tainted = chap_challenge->vp_tainted; /* * MS-CHAP-Challenges are 8 octets, @@ -340,7 +359,7 @@ static ssize_t mschap_xlat(UNUSED TALLOC_CTX *ctx, char **out, size_t outlen, response = fr_pair_find_by_da(&request->request_pairs, attr_ms_chap2_response, 0); if (!response) { REDEBUG("Vendor-Specific.Microsoft.CHAP2-Response is required to calculate MS-CHAPv1 challenge"); - return -1; + return XLAT_ACTION_FAIL; } /* @@ -354,11 +373,11 @@ static ssize_t mschap_xlat(UNUSED TALLOC_CTX *ctx, char **out, size_t outlen, */ if (response->vp_length < 50) { REDEBUG("Vendor-Specific.Microsoft.CHAP-Response has the wrong format"); - return -1; + return XLAT_ACTION_FAIL; } user_name = mschap_identity_find(request); - if (!user_name) return -1; + if (!user_name) return XLAT_ACTION_FAIL; /* * Check for MS-CHAP-User-Name and if found, use it @@ -370,11 +389,7 @@ static ssize_t mschap_xlat(UNUSED TALLOC_CTX *ctx, char **out, size_t outlen, * packet. */ response_name = fr_pair_find_by_da(&request->request_pairs, attr_ms_chap_user_name, 0); - if (response_name) { - name_vp = response_name; - } else { - name_vp = user_name; - } + name_vp = response_name ? response_name : user_name; /* * with_ntdomain_hack moved here, too. @@ -411,20 +426,21 @@ static ssize_t mschap_xlat(UNUSED TALLOC_CTX *ctx, char **out, size_t outlen, data_len = 8; } else { REDEBUG("Invalid MS-CHAP challenge length"); - return -1; + return XLAT_ACTION_FAIL; } /* * Get the MS-CHAPv1 response, or the MS-CHAPv2 * response. */ - } else if (strncasecmp(fmt, "NT-Response", 11) == 0) { + } else if (strncasecmp(arg->vb_strvalue, "NT-Response", 11) == 0) { response = fr_pair_find_by_da(&request->request_pairs, attr_ms_chap_response, 0); if (!response) response = fr_pair_find_by_da(&request->request_pairs, attr_ms_chap2_response, 0); if (!response) { REDEBUG("No MS-CHAP-Response or MS-CHAP2-Response was found in the request"); - return -1; + return XLAT_ACTION_FAIL; } + tainted = response->vp_tainted; /* * For MS-CHAPv1, the NT-Response exists only @@ -432,7 +448,12 @@ static ssize_t mschap_xlat(UNUSED TALLOC_CTX *ctx, char **out, size_t outlen, */ if ((response->da == attr_ms_chap_response) && ((response->vp_octets[1] & 0x01) == 0)) { REDEBUG("No NT-Response in MS-CHAP-Response"); - return -1; + return XLAT_ACTION_FAIL; + } + + if (response->vp_length < 50) { + REDEBUG("Vendor-Specific.Microsoft.CHAP-Response has the wrong format"); + return XLAT_ACTION_FAIL; } /* @@ -447,20 +468,25 @@ static ssize_t mschap_xlat(UNUSED TALLOC_CTX *ctx, char **out, size_t outlen, * LM-Response is deprecated, and exists only * in MS-CHAPv1, and not often there. */ - } else if (strncasecmp(fmt, "LM-Response", 11) == 0) { + } else if (strncasecmp(arg->vb_strvalue, "LM-Response", 11) == 0) { response = fr_pair_find_by_da(&request->request_pairs, attr_ms_chap_response, 0); if (!response) { REDEBUG("No MS-CHAP-Response was found in the request"); - return -1; + return XLAT_ACTION_FAIL; } + tainted = response->vp_tainted; + if (response->vp_length < 50) { + REDEBUG("Vendor-Specific.Microsoft.CHAP-Response has the wrong format"); + return XLAT_ACTION_FAIL; + } /* * For MS-CHAPv1, the LM-Response exists only * if the second octet says so. */ if ((response->vp_octets[1] & 0x01) != 0) { REDEBUG("No LM-Response in MS-CHAP-Response"); - return -1; + return XLAT_ACTION_FAIL; } data = response->vp_octets + 2; data_len = 24; @@ -468,11 +494,13 @@ static ssize_t mschap_xlat(UNUSED TALLOC_CTX *ctx, char **out, size_t outlen, /* * Pull the NT-Domain out of the User-Name, if it exists. */ - } else if (strncasecmp(fmt, "NT-Domain", 9) == 0) { + } else if (strncasecmp(arg->vb_strvalue, "NT-Domain", 9) == 0) { char *p, *q; + vb = fr_value_box_alloc_null(ctx); + user_name = mschap_identity_find(request); - if (!user_name) return -1; + if (!user_name) return XLAT_ACTION_FAIL; /* * First check to see if this is a host/ style User-Name @@ -488,7 +516,7 @@ static ssize_t mschap_xlat(UNUSED TALLOC_CTX *ctx, char **out, size_t outlen, p = strchr(user_name->vp_strvalue, '.'); if (!p) { RDEBUG2("setting NT-Domain to same as machine name"); - strlcpy(*out, user_name->vp_strvalue + 5, outlen); + fr_value_box_strdup(ctx, vb, NULL, user_name->vp_strvalue + 5, user_name->vp_tainted); } else { p++; /* skip the period */ q = strchr(p, '.'); @@ -497,34 +525,38 @@ static ssize_t mschap_xlat(UNUSED TALLOC_CTX *ctx, char **out, size_t outlen, * only if another period was found */ if (q) *q = '\0'; - strlcpy(*out, p, outlen); + fr_value_box_strdup(ctx, vb, NULL, p, user_name->vp_tainted); if (q) *q = '.'; } } else { p = strchr(user_name->vp_strvalue, '\\'); if (!p) { REDEBUG("No NT-Domain was found in the User-Name"); - return -1; + talloc_free(vb); + return XLAT_ACTION_FAIL; } /* * Hack. This is simpler than the alternatives. */ *p = '\0'; - strlcpy(*out, user_name->vp_strvalue, outlen); + fr_value_box_strdup(ctx, vb, NULL, user_name->vp_strvalue, user_name->vp_tainted); *p = '\\'; } - return strlen(*out); + fr_dcursor_append(out, vb); + return XLAT_ACTION_DONE; /* * Pull the User-Name out of the User-Name... */ - } else if (strncasecmp(fmt, "User-Name", 9) == 0) { + } else if (strncasecmp(arg->vb_strvalue, "User-Name", 9) == 0) { char const *p, *q; user_name = mschap_identity_find(request); - if (!user_name) return -1; + if (!user_name) return XLAT_ACTION_FAIL; + + vb = fr_value_box_alloc_null(ctx); /* * First check to see if this is a host/ style User-Name @@ -549,9 +581,9 @@ static ssize_t mschap_xlat(UNUSED TALLOC_CTX *ctx, char **out, size_t outlen, * only if a period was found */ if (q) { - snprintf(*out, outlen, "%.*s$", (int) (q - p), p); + fr_value_box_asprintf(ctx, vb, NULL, true, "%.*s$", (int) (q - p), p); } else { - snprintf(*out, outlen, "%s$", p); + fr_value_box_asprintf(ctx, vb, NULL, true, "%s$", p); } } else { p = strchr(user_name->vp_strvalue, '\\'); @@ -560,82 +592,65 @@ static ssize_t mschap_xlat(UNUSED TALLOC_CTX *ctx, char **out, size_t outlen, } else { p = user_name->vp_strvalue; /* use the whole User-Name */ } - strlcpy(*out, p, outlen); + fr_value_box_strdup(ctx, vb, NULL, p, user_name->vp_tainted); } - return strlen(*out); + fr_dcursor_append(out, vb); + return XLAT_ACTION_DONE; /* * Return the NT-Hash of the passed string */ - } else if (strncasecmp(fmt, "NT-Hash ", 8) == 0) { - char const *p; - - p = fmt + 8; /* 7 is the length of 'NT-Hash' */ - if ((*p == '\0') || (outlen <= 32)) - return 0; - - fr_skip_whitespace(p); + } else if (strncasecmp(arg->vb_strvalue, "NT-Hash", 7) == 0) { + arg = fr_dlist_next(in, arg); + if ((!arg) || (arg->length == 0)) + return XLAT_ACTION_FAIL; - if (mschap_nt_password_hash(buffer, p) < 0) { + if (mschap_nt_password_hash(buffer, arg->vb_strvalue) < 0) { REDEBUG("Failed generating NT-Password"); *buffer = '\0'; - return -1; + return XLAT_ACTION_FAIL; } - fr_bin2hex(&FR_SBUFF_OUT(*out, (NT_DIGEST_LENGTH * 2) + 1), &FR_DBUFF_TMP(buffer, NT_DIGEST_LENGTH), SIZE_MAX); - (*out)[32] = '\0'; - RDEBUG2("NT-Hash of \"known-good\" password: %s", *out); - return 32; + vb = fr_value_box_alloc_null(ctx); + fr_value_box_memdup(ctx, vb, NULL, buffer, NT_DIGEST_LENGTH, false); + RDEBUG2("NT-Hash of \"known-good\" password: %pV", vb); + fr_dcursor_append(out, vb); + return XLAT_ACTION_DONE; /* * Return the LM-Hash of the passed string */ - } else if (strncasecmp(fmt, "LM-Hash ", 8) == 0) { - char const *p; - - p = fmt + 8; /* 7 is the length of 'LM-Hash' */ - if ((*p == '\0') || (outlen <= 32)) - return 0; - - fr_skip_whitespace(p); - - smbdes_lmpwdhash(p, buffer); - fr_bin2hex(&FR_SBUFF_OUT(*out, (LM_DIGEST_LENGTH * 2) + 1), &FR_DBUFF_TMP(buffer, LM_DIGEST_LENGTH), SIZE_MAX); - (*out)[32] = '\0'; - RDEBUG2("LM-Hash of %s = %s", p, *out); - return 32; + } else if (strncasecmp(arg->vb_strvalue, "LM-Hash", 7) == 0) { + arg = fr_dlist_next(in, arg); + if ((!arg) || (arg->length == 0)) + return XLAT_ACTION_FAIL; + + smbdes_lmpwdhash(arg->vb_strvalue, buffer); + + vb = fr_value_box_alloc_null(ctx); + fr_value_box_memdup(ctx, vb, NULL, buffer, LM_DIGEST_LENGTH, false); + RDEBUG2("LM-Hash of %s = %pV", arg->vb_strvalue, vb); + fr_dcursor_append(out, vb); + return XLAT_ACTION_DONE; } else { - REDEBUG("Unknown expansion string '%s'", fmt); - return -1; + REDEBUG("Unknown expansion string '%pV'", arg); + return XLAT_ACTION_FAIL; } - if (outlen == 0) return 0; /* nowhere to go, don't do anything */ - /* * Didn't set anything: this is bad. */ if (!data) { RWDEBUG2("Failed to do anything intelligent"); - return 0; - } - - /* - * Check the output length. - */ - if (outlen < ((data_len * 2) + 1)) { - data_len = (outlen - 1) / 2; + return XLAT_ACTION_FAIL; } - /* - * - */ - for (i = 0; i < data_len; i++) { - sprintf((*out) + (2 * i), "%02x", data[i]); - } - (*out)[data_len * 2] = '\0'; + vb = fr_value_box_alloc_null(ctx); + fr_value_box_memdup(ctx, vb, NULL, data, data_len, tainted); - return data_len * 2; + fr_dcursor_append(out, vb); + return XLAT_ACTION_DONE; } @@ -721,8 +736,8 @@ static int CC_HINT(nonnull (1, 2, 4, 5)) do_mschap_cpw(rlm_mschap_t const *inst, * we're expecting to use the ntlm-change-password-1 protocol * which needs the following on stdin: * - * username: %{mschap:User-Name} - * nt-domain: %{mschap:NT-Domain} + * username: %(mschap:User-Name) + * nt-domain: %(mschap:NT-Domain) * new-nt-password-blob: bin2hex(new_nt_password) - 1032 bytes encoded * old-nt-hash-blob: bin2hex(old_nt_hash) - 32 bytes encoded * new-lm-password-blob: 00000...0000 - 1032 bytes null @@ -896,7 +911,7 @@ ntlm_auth_err: * * ...or... * - * %{exec:/path/to %{mschap:User-Name} %{MS-CHAP-New-Password}}" + * %{exec:/path/to %(mschap:User-Name) %{MS-CHAP-New-Password}}" * */ fr_pair_t *new_pass, *new_hash; @@ -2198,6 +2213,7 @@ static int mod_bootstrap(void *instance, CONF_SECTION *conf) { char const *name; rlm_mschap_t *inst = instance; + xlat_t *xlat; /* * Create the dynamic translation. @@ -2206,7 +2222,9 @@ static int mod_bootstrap(void *instance, CONF_SECTION *conf) if (!name) name = cf_section_name1(conf); inst->name = name; - xlat_register_legacy(inst, inst->name, mschap_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN); + xlat = xlat_register(inst, inst->name, mschap_xlat, false); + xlat_func_args(xlat, mschap_xlat_args); + xlat_async_instantiate_set(xlat, mod_xlat_instantiate, rlm_mschap_t *, NULL, inst); return 0; } diff --git a/src/modules/rlm_pap/rlm_pap.c b/src/modules/rlm_pap/rlm_pap.c index d6fa65e6683..838cbca516a 100644 --- a/src/modules/rlm_pap/rlm_pap.c +++ b/src/modules/rlm_pap/rlm_pap.c @@ -735,7 +735,7 @@ static unlang_action_t CC_HINT(nonnull) pap_auth_lm(rlm_rcode_t *p_result, RETURN_MODULE_INVALID; } - len = xlat_eval(charbuf, sizeof(charbuf), request, "%{mschap:LM-Hash %{User-Password}}", NULL, NULL); + len = xlat_eval(charbuf, sizeof(charbuf), request, "%(mschap:LM-Hash %{User-Password})", NULL, NULL); if (len < 0) RETURN_MODULE_FAIL; if ((fr_hex2bin(NULL, &FR_DBUFF_TMP(digest, sizeof(digest)), &FR_SBUFF_IN(charbuf, len), false) != diff --git a/src/tests/keywords/mschap b/src/tests/keywords/mschap new file mode 100644 index 00000000000..bcceaf6d58f --- /dev/null +++ b/src/tests/keywords/mschap @@ -0,0 +1,98 @@ +# +# PRE: update +# + +# MS CHAPv1 +update request { + &User-Name := 'EXAMPLE\bob' + &Vendor-Specific.Microsoft.CHAP-Challenge := 0xe96e4fff2955c4f1 + &Vendor-Specific.Microsoft.CHAP-Response := 0x00010000000000000000000000000000000000000000000000008860bbaac0cd3960b4ce5dc6f0f7a462b897ef530484e80f +} + +update request { + &Tmp-Octets-0 := "%(mschap:Challenge)" + &Tmp-Octets-1 := "%(mschap:NT-Response)" + &Tmp-String-0 := "%(mschap:NT-Domain)" + &Tmp-String-1 := "%(mschap:User-Name)" +} + +if (&Tmp-Octets-0 != 0xe96e4fff2955c4f1) { + test_fail +} + +if (&Tmp-Octets-1 != 0x8860bbaac0cd3960b4ce5dc6f0f7a462b897ef530484e80f) { + test_fail +} + +if (&Tmp-String-0 != 'EXAMPLE') { + test_fail +} + +if (&Tmp-String-1 != 'bob') { + test_fail +} + +update request { + &Vendor-Specific.Microsoft.CHAP-Response := 0x00006937d7935bb28a4c1dafe6a193bdea7a853a74d8bcf6db158860bbaac0cd3960b4ce5dc6f0f7a462b897ef530484e80f +} + +update request { + &Tmp-Octets-0 := "%(mschap:LM-Response)" +} + +if (&Tmp-Octets-0 != 0x6937d7935bb28a4c1dafe6a193bdea7a853a74d8bcf6db15) { + test_fail +} + +# Hashing +update request { + &Tmp-Octets-0 := "%(mschap:NT-Hash testing_123)" + &Tmp-Octets-1 := "%(mschap:LM-Hash testing_123)" +} + +if (&Tmp-Octets-0 != 0xfa782604f85eb3564f555648341b53e4) { + test_fail +} + +if (&Tmp-Octets-1 != 0x2d5545077d7b7d2ae4343f96ab15c596) { + test_fail +} + +# MS CHAPv2 +update request { + &Vendor-Specific.Microsoft.CHAP-Response !* ANY + &Vendor-Specific.Microsoft.CHAP-Challenge := 0x04408dc2a98dae1ce351dfc53f57d08e + &Vendor-Specific.Microsoft.CHAP2-Response := 0x00010e93cfbfcef8d5b6af42d2b2ca5b43180000000000000000bc068d1e8c54de5e9db78e6736d686eb88a999dd7fa239b200 +} + +update request { + &Tmp-Octets-0 := "%(mschap:Challenge)" + &Tmp-Octets-1 := "%(mschap:NT-Response)" +} + +if (&Tmp-Octets-0 != 0xad18b6b8e1478b4c) { + test_fail +} + +if (&Tmp-Octets-1 != 0xbc068d1e8c54de5e9db78e6736d686eb88a999dd7fa239b2) { + test_fail +} + +# Invalid +update request { + &Vendor-Specific.Microsoft.CHAP-Challenge := 0xf0eac4151d5346662ba8c5e428 +} + +update request { + &Tmp-String-0 := "%(mschap:Challenge)" +} + +if (&Tmp-String-0 != "") { + test_fail +} + +if (&Module-Failure-Message != "Invalid MS-CHAP challenge length") { + test_fail +} + +success \ No newline at end of file diff --git a/src/tests/keywords/radius.conf b/src/tests/keywords/radius.conf index bbdb5579f6b..336d3753d79 100644 --- a/src/tests/keywords/radius.conf +++ b/src/tests/keywords/radius.conf @@ -51,12 +51,17 @@ modules { date sqldate { format = "%Y-%m-%d %H:%M:%S" utc = yes - } + } idn { allow_unassigned = no use_std3_ascii_rules = yes } + + mschap { + + } + } policy {