CVE-2022-32744 s4:kpasswd: Ensure we pass the kpasswd server principal into krb5_rd_r...
authorJoseph Sutton <josephsutton@catalyst.net.nz>
Mon, 30 May 2022 07:16:02 +0000 (19:16 +1200)
committerJule Anger <janger@samba.org>
Sun, 24 Jul 2022 09:42:02 +0000 (11:42 +0200)
To ensure that, when decrypting the kpasswd ticket, we look up the
correct principal and don't trust the sname from the ticket, we should
pass the principal name of the kpasswd service into krb5_rd_req_ctx().
However, gensec_krb5_update_internal() will pass in NULL unless the
principal in our credentials is CRED_SPECIFIED.

At present, our principal will be considered obtained as CRED_SMB_CONF
(from the cli_credentials_set_conf() a few lines up), so we explicitly
set the realm again, but this time as CRED_SPECIFIED. Now the value of
server_in_keytab that we provide to smb_krb5_rd_req_decoded() will not
be NULL.

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>
[jsutton@samba.org Removed knownfail as KDC no longer panics]

selftest/knownfail_heimdal_kdc
selftest/knownfail_mit_kdc
source4/kdc/kpasswd-service.c

index 0d93253f9991f0d722895ba890c10d0ffb44c659..424a8b81c38b00f11668a431624ce785328c8980 100644 (file)
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_service_ticket
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_existing
 ^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_nonexisting
-#
-# Kpasswd tests
-#
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_from_rodc.ad_dc
index c2a31b4a140ce28feee4f93d885a97f2cbad2b25..0d2f5bab6d2e531f65207e505c5a0e9186ae75b8 100644 (file)
@@ -581,5 +581,3 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize_realm_case.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_canonicalize_realm_case.ad_dc
 ^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_requester_sid_tgs.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_server.ad_dc
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_wrong_key_service.ad_dc
index 0d2acd8d9e8d288e3c9cac1abcc329c653349a1f..b6400be0c497b2b0c8f4aa3584c2851eba888396 100644 (file)
@@ -29,6 +29,7 @@
 #include "kdc/kdc-server.h"
 #include "kdc/kpasswd-service.h"
 #include "kdc/kpasswd-helper.h"
+#include "param/param.h"
 
 #define HEADER_LEN 6
 #ifndef RFC3244_VERSION
@@ -158,6 +159,20 @@ kdc_code kpasswd_process(struct kdc_server *kdc,
 
        cli_credentials_set_conf(server_credentials, kdc->task->lp_ctx);
 
+       /*
+        * After calling cli_credentials_set_conf(), explicitly set the realm
+        * with CRED_SPECIFIED. We need to do this so the result of
+        * principal_from_credentials() called from the gensec layer is
+        * CRED_SPECIFIED rather than CRED_SMB_CONF, avoiding a fallback to
+        * match-by-key (very undesirable in this case).
+        */
+       ok = cli_credentials_set_realm(server_credentials,
+                                      lpcfg_realm(kdc->task->lp_ctx),
+                                      CRED_SPECIFIED);
+       if (!ok) {
+               goto done;
+       }
+
        ok = cli_credentials_set_username(server_credentials,
                                          "kadmin/changepw",
                                          CRED_SPECIFIED);
@@ -165,6 +180,21 @@ kdc_code kpasswd_process(struct kdc_server *kdc,
                goto done;
        }
 
+       /* Check that the server principal is indeed CRED_SPECIFIED. */
+       {
+               char *principal = NULL;
+               enum credentials_obtained obtained;
+
+               principal = cli_credentials_get_principal_and_obtained(server_credentials,
+                                                                      tmp_ctx,
+                                                                      &obtained);
+               if (obtained < CRED_SPECIFIED) {
+                       goto done;
+               }
+
+               TALLOC_FREE(principal);
+       }
+
        rv = cli_credentials_set_keytab_name(server_credentials,
                                             kdc->task->lp_ctx,
                                             kdc->kpasswd_keytab_name,