diff options
author | Joseph Sutton <josephsutton@catalyst.net.nz> | 2022-05-30 19:17:41 +1200 |
---|---|---|
committer | Jule Anger <janger@samba.org> | 2022-07-24 11:42:01 +0200 |
commit | f6c5a60336de8fd67a2ef371dd2ee4cf75c53904 (patch) | |
tree | 9527616a8fec7cfd7f3a04727caa03239584d26e /source4 | |
parent | 1b38a28bcaebdae0128518605a422a194747a60f (diff) | |
download | samba-f6c5a60336de8fd67a2ef371dd2ee4cf75c53904.tar.gz |
CVE-2022-2031 s4:kpasswd: Add MIT fallback for decoding setpw structure
The target principal and realm fields of the setpw structure are
supposed to be optional, but in MIT Kerberos they are mandatory. For
better compatibility and ease of testing, fall back to parsing the
simpler (containing only the new password) structure if the MIT function
fails to decode it.
Although the target principal and realm fields should be optional, one
is not supposed to specified without the other, so we don't have to deal
with the case where only one is specified.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15047
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15049
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15074
Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
Diffstat (limited to 'source4')
-rw-r--r-- | source4/kdc/kpasswd-service-mit.c | 94 |
1 files changed, 79 insertions, 15 deletions
diff --git a/source4/kdc/kpasswd-service-mit.c b/source4/kdc/kpasswd-service-mit.c index b53c1a4618a..9c4d2801669 100644 --- a/source4/kdc/kpasswd-service-mit.c +++ b/source4/kdc/kpasswd-service-mit.c @@ -28,6 +28,7 @@ #include "kdc/kpasswd_glue.h" #include "kdc/kpasswd-service.h" #include "kdc/kpasswd-helper.h" +#include "../lib/util/asn1.h" #define RFC3244_VERSION 0xff80 @@ -35,6 +36,52 @@ krb5_error_code decode_krb5_setpw_req(const krb5_data *code, krb5_data **password_out, krb5_principal *target_out); +/* + * A fallback for when MIT refuses to parse a setpw structure without the + * (optional) target principal and realm + */ +static bool decode_krb5_setpw_req_simple(TALLOC_CTX *mem_ctx, + const DATA_BLOB *decoded_data, + DATA_BLOB *clear_data) +{ + struct asn1_data *asn1 = NULL; + bool ret; + + asn1 = asn1_init(mem_ctx, 3); + if (asn1 == NULL) { + return false; + } + + ret = asn1_load(asn1, *decoded_data); + if (!ret) { + goto out; + } + + ret = asn1_start_tag(asn1, ASN1_SEQUENCE(0)); + if (!ret) { + goto out; + } + ret = asn1_start_tag(asn1, ASN1_CONTEXT(0)); + if (!ret) { + goto out; + } + ret = asn1_read_OctetString(asn1, mem_ctx, clear_data); + if (!ret) { + goto out; + } + + ret = asn1_end_tag(asn1); + if (!ret) { + goto out; + } + ret = asn1_end_tag(asn1); + +out: + asn1_free(asn1); + + return ret; +} + static krb5_error_code kpasswd_change_password(struct kdc_server *kdc, TALLOC_CTX *mem_ctx, struct auth_session_info *session_info, @@ -93,9 +140,10 @@ static krb5_error_code kpasswd_set_password(struct kdc_server *kdc, const char **error_string) { krb5_context context = kdc->smb_krb5_context->krb5_context; + DATA_BLOB clear_data; krb5_data k_dec_data; - krb5_data *k_clear_data; - krb5_principal target_principal; + krb5_data *k_clear_data = NULL; + krb5_principal target_principal = NULL; krb5_error_code code; DATA_BLOB password; char *target_realm = NULL; @@ -114,29 +162,45 @@ static krb5_error_code kpasswd_set_password(struct kdc_server *kdc, code = decode_krb5_setpw_req(&k_dec_data, &k_clear_data, &target_principal); - if (code != 0) { - DBG_WARNING("decode_krb5_setpw_req failed: %s\n", - error_message(code)); - ok = kpasswd_make_error_reply(mem_ctx, - KRB5_KPASSWD_MALFORMED, - "Failed to decode packet", - kpasswd_reply); + if (code == 0) { + clear_data.data = (uint8_t *)k_clear_data->data; + clear_data.length = k_clear_data->length; + } else { + target_principal = NULL; + + /* + * The MIT decode failed, so fall back to trying the simple + * case, without target_principal. + */ + ok = decode_krb5_setpw_req_simple(mem_ctx, + decoded_data, + &clear_data); if (!ok) { - *error_string = "Failed to create reply"; - return KRB5_KPASSWD_HARDERROR; + DBG_WARNING("decode_krb5_setpw_req failed: %s\n", + error_message(code)); + ok = kpasswd_make_error_reply(mem_ctx, + KRB5_KPASSWD_MALFORMED, + "Failed to decode packet", + kpasswd_reply); + if (!ok) { + *error_string = "Failed to create reply"; + return KRB5_KPASSWD_HARDERROR; + } + return 0; } - return 0; } ok = convert_string_talloc_handle(mem_ctx, lpcfg_iconv_handle(kdc->task->lp_ctx), CH_UTF8, CH_UTF16, - (const char *)k_clear_data->data, - k_clear_data->length, + clear_data.data, + clear_data.length, (void **)&password.data, &password.length); - krb5_free_data(context, k_clear_data); + if (k_clear_data != NULL) { + krb5_free_data(context, k_clear_data); + } if (!ok) { DBG_WARNING("String conversion failed\n"); *error_string = "String conversion failed"; |