166 lines
4.8 KiB
Diff
166 lines
4.8 KiB
Diff
From f6c5a60336de8fd67a2ef371dd2ee4cf75c53904 Mon Sep 17 00:00:00 2001
|
|
From: Joseph Sutton <josephsutton@catalyst.net.nz>
|
|
Date: Mon, 30 May 2022 19:17:41 +1200
|
|
Subject: [PATCH 58/99] 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>
|
|
---
|
|
source4/kdc/kpasswd-service-mit.c | 94 ++++++++++++++++++++++++++-----
|
|
1 file 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";
|
|
--
|
|
2.25.1
|