summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Sutton <josephsutton@catalyst.net.nz>2022-05-30 19:17:41 +1200
committerJule Anger <janger@samba.org>2022-07-24 11:42:01 +0200
commitf6c5a60336de8fd67a2ef371dd2ee4cf75c53904 (patch)
tree9527616a8fec7cfd7f3a04727caa03239584d26e
parent1b38a28bcaebdae0128518605a422a194747a60f (diff)
downloadsamba-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>
-rw-r--r--source4/kdc/kpasswd-service-mit.c94
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";