From f3e349bebc443133fdbe4e14b148ca8db8237060 Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy Date: Fri, 16 Feb 2018 18:15:28 +0200 Subject: [PATCH] krb5-samba: interdomain trust uses different salt principal Salt principal for the interdomain trust is krbtgt/DOMAIN@REALM where DOMAIN is the sAMAccountName without the dollar sign ($) The salt principal for the BLA$ user object was generated wrong. dn: CN=bla.base,CN=System,DC=w4edom-l4,DC=base securityIdentifier: S-1-5-21-4053568372-2049667917-3384589010 trustDirection: 3 trustPartner: bla.base trustPosixOffset: -2147483648 trustType: 2 trustAttributes: 8 flatName: BLA dn: CN=BLA$,CN=Users,DC=w4edom-l4,DC=base userAccountControl: 2080 primaryGroupID: 513 objectSid: S-1-5-21-278041429-3399921908-1452754838-1597 accountExpires: 9223372036854775807 sAMAccountName: BLA$ sAMAccountType: 805306370 pwdLastSet: 131485652467995000 The salt stored by Windows in the package_PrimaryKerberosBlob (within supplementalCredentials) seems to be 'W4EDOM-L4.BASEkrbtgtBLA' for the above trust and Samba stores 'W4EDOM-L4.BASEBLA$'. While the salt used when building the keys from trustAuthOutgoing/trustAuthIncoming is 'W4EDOM-L4.BASEkrbtgtBLA.BASE', which we handle correct. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13539 Pair-Programmed-With: Stefan Metzmacher Signed-off-by: Alexander Bokovoy Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Wed Sep 5 03:57:22 CEST 2018 on sn-devel-144 --- auth/credentials/credentials_krb5.c | 16 +++-- lib/krb5_wrap/krb5_samba.c | 61 ++++++++++++++----- lib/krb5_wrap/krb5_samba.h | 2 +- selftest/knownfail.d/trust_user_account | 1 - source3/passdb/machine_account_secrets.c | 3 +- .../dsdb/samdb/ldb_modules/password_hash.c | 6 +- 6 files changed, 63 insertions(+), 26 deletions(-) delete mode 100644 selftest/knownfail.d/trust_user_account diff --git a/auth/credentials/credentials_krb5.c b/auth/credentials/credentials_krb5.c index 9da1aa09250..d36797bf0f3 100644 --- a/auth/credentials/credentials_krb5.c +++ b/auth/credentials/credentials_krb5.c @@ -34,6 +34,7 @@ #include "auth/kerberos/kerberos_util.h" #include "auth/kerberos/pac_utils.h" #include "param/param.h" +#include "../libds/common/flags.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_AUTH @@ -974,7 +975,7 @@ _PUBLIC_ int cli_credentials_get_keytab(struct cli_credentials *cred, const char *upn = NULL; const char *realm = cli_credentials_get_realm(cred); char *salt_principal = NULL; - bool is_computer = false; + uint32_t uac_flags = 0; if (cred->keytab_obtained >= (MAX(cred->principal_obtained, cred->username_obtained))) { @@ -999,9 +1000,15 @@ _PUBLIC_ int cli_credentials_get_keytab(struct cli_credentials *cred, switch (cred->secure_channel_type) { case SEC_CHAN_WKSTA: - case SEC_CHAN_BDC: case SEC_CHAN_RODC: - is_computer = true; + uac_flags = UF_WORKSTATION_TRUST_ACCOUNT; + break; + case SEC_CHAN_BDC: + uac_flags = UF_SERVER_TRUST_ACCOUNT; + break; + case SEC_CHAN_DOMAIN: + case SEC_CHAN_DNS_DOMAIN: + uac_flags = UF_INTERDOMAIN_TRUST_ACCOUNT; break; default: upn = cli_credentials_get_principal(cred, mem_ctx); @@ -1009,13 +1016,14 @@ _PUBLIC_ int cli_credentials_get_keytab(struct cli_credentials *cred, TALLOC_FREE(mem_ctx); return ENOMEM; } + uac_flags = UF_NORMAL_ACCOUNT; break; } ret = smb_krb5_salt_principal(realm, username, /* sAMAccountName */ upn, /* userPrincipalName */ - is_computer, + uac_flags, mem_ctx, &salt_principal); if (ret) { diff --git a/lib/krb5_wrap/krb5_samba.c b/lib/krb5_wrap/krb5_samba.c index 7e90913beb0..a6ff97640ca 100644 --- a/lib/krb5_wrap/krb5_samba.c +++ b/lib/krb5_wrap/krb5_samba.c @@ -24,6 +24,7 @@ #include "system/filesys.h" #include "krb5_samba.h" #include "lib/crypto/crypto.h" +#include "../libds/common/flags.h" #ifdef HAVE_COM_ERR_H #include @@ -445,8 +446,7 @@ int smb_krb5_get_pw_salt(krb5_context context, * @param[in] userPrincipalName The userPrincipalName attribute of the object * or NULL is not available. * - * @param[in] is_computer The indication of the object includes - * objectClass=computer. + * @param[in] uac_flags UF_ACCOUNT_TYPE_MASKed userAccountControl field * * @param[in] mem_ctx The TALLOC_CTX to allocate _salt_principal. * @@ -459,7 +459,7 @@ int smb_krb5_get_pw_salt(krb5_context context, int smb_krb5_salt_principal(const char *realm, const char *sAMAccountName, const char *userPrincipalName, - bool is_computer, + uint32_t uac_flags, TALLOC_CTX *mem_ctx, char **_salt_principal) { @@ -480,6 +480,23 @@ int smb_krb5_salt_principal(const char *realm, return EINVAL; } + if (uac_flags & ~UF_ACCOUNT_TYPE_MASK) { + /* + * catch callers which still + * pass 'true'. + */ + TALLOC_FREE(frame); + return EINVAL; + } + if (uac_flags == 0) { + /* + * catch callers which still + * pass 'false'. + */ + TALLOC_FREE(frame); + return EINVAL; + } + upper_realm = strupper_talloc(frame, realm); if (upper_realm == NULL) { TALLOC_FREE(frame); @@ -493,7 +510,7 @@ int smb_krb5_salt_principal(const char *realm, /* * Determine a salting principal */ - if (is_computer) { + if (uac_flags & UF_TRUST_ACCOUNT_MASK) { int computer_len = 0; char *tmp = NULL; @@ -502,20 +519,32 @@ int smb_krb5_salt_principal(const char *realm, computer_len -= 1; } - tmp = talloc_asprintf(frame, "host/%*.*s.%s", - computer_len, computer_len, - sAMAccountName, realm); - if (tmp == NULL) { - TALLOC_FREE(frame); - return ENOMEM; - } + if (uac_flags & UF_INTERDOMAIN_TRUST_ACCOUNT) { + principal = talloc_asprintf(frame, "krbtgt/%*.*s", + computer_len, computer_len, + sAMAccountName); + if (principal == NULL) { + TALLOC_FREE(frame); + return ENOMEM; + } + } else { - principal = strlower_talloc(frame, tmp); - TALLOC_FREE(tmp); - if (principal == NULL) { - TALLOC_FREE(frame); - return ENOMEM; + tmp = talloc_asprintf(frame, "host/%*.*s.%s", + computer_len, computer_len, + sAMAccountName, realm); + if (tmp == NULL) { + TALLOC_FREE(frame); + return ENOMEM; + } + + principal = strlower_talloc(frame, tmp); + TALLOC_FREE(tmp); + if (principal == NULL) { + TALLOC_FREE(frame); + return ENOMEM; + } } + principal_len = strlen(principal); } else if (userPrincipalName != NULL) { diff --git a/lib/krb5_wrap/krb5_samba.h b/lib/krb5_wrap/krb5_samba.h index 315d3c3492e..8305c1f77af 100644 --- a/lib/krb5_wrap/krb5_samba.h +++ b/lib/krb5_wrap/krb5_samba.h @@ -353,7 +353,7 @@ int smb_krb5_get_pw_salt(krb5_context context, int smb_krb5_salt_principal(const char *realm, const char *sAMAccountName, const char *userPrincipalName, - bool is_computer, + uint32_t uac_flags, TALLOC_CTX *mem_ctx, char **_salt_principal); int smb_krb5_salt_principal2data(krb5_context context, diff --git a/selftest/knownfail.d/trust_user_account b/selftest/knownfail.d/trust_user_account deleted file mode 100644 index 1de5052b11d..00000000000 --- a/selftest/knownfail.d/trust_user_account +++ /dev/null @@ -1 +0,0 @@ -^samba4.blackbox.trust_user_account.get.virtualKerberosSalt.for.TDA diff --git a/source3/passdb/machine_account_secrets.c b/source3/passdb/machine_account_secrets.c index 94a7e21c809..a96bf1c0b6a 100644 --- a/source3/passdb/machine_account_secrets.c +++ b/source3/passdb/machine_account_secrets.c @@ -36,6 +36,7 @@ #include "lib/crypto/crypto.h" #include "lib/krb5_wrap/krb5_samba.h" #include "lib/util/time_basic.h" +#include "../libds/common/flags.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_PASSDB @@ -1601,7 +1602,7 @@ NTSTATUS secrets_store_JoinCtx(const struct libnet_JoinCtx *r) ret = smb_krb5_salt_principal(info->domain_info.dns_domain.string, info->account_name, NULL /* userPrincipalName */, - true /* is_computer */, + UF_WORKSTATION_TRUST_ACCOUNT, info, &p); if (ret != 0) { status = krb5_to_nt_status(ret); diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c index 58ae64537eb..5f571033004 100644 --- a/source4/dsdb/samdb/ldb_modules/password_hash.c +++ b/source4/dsdb/samdb/ldb_modules/password_hash.c @@ -130,7 +130,6 @@ struct setup_password_fields_io { NTTIME pwdLastSet; const char *sAMAccountName; const char *user_principal_name; - bool is_computer; bool is_krbtgt; uint32_t restrictions; struct dom_sid *account_sid; @@ -678,15 +677,17 @@ static int setup_kerberos_keys(struct setup_password_fields_io *io) krb5_data salt; krb5_keyblock key; krb5_data cleartext_data; + uint32_t uac_flags = 0; ldb = ldb_module_get_ctx(io->ac->module); cleartext_data.data = (char *)io->n.cleartext_utf8->data; cleartext_data.length = io->n.cleartext_utf8->length; + uac_flags = io->u.userAccountControl & UF_ACCOUNT_TYPE_MASK; krb5_ret = smb_krb5_salt_principal(io->ac->status->domain_data.realm, io->u.sAMAccountName, io->u.user_principal_name, - io->u.is_computer, + uac_flags, io->ac, &salt_principal); if (krb5_ret) { @@ -3190,7 +3191,6 @@ static int setup_io(struct ph_context *ac, "sAMAccountName", NULL); io->u.user_principal_name = ldb_msg_find_attr_as_string(info_msg, "userPrincipalName", NULL); - io->u.is_computer = ldb_msg_check_string_attribute(info_msg, "objectClass", "computer"); /* Ensure it has an objectSID too */ io->u.account_sid = samdb_result_dom_sid(ac, info_msg, "objectSid"); -- 2.34.1