krb5-samba: interdomain trust uses different salt principal
authorAlexander Bokovoy <ab@samba.org>
Fri, 16 Feb 2018 16:15:28 +0000 (18:15 +0200)
committerAndrew Bartlett <abartlet@samba.org>
Wed, 5 Sep 2018 01:57:22 +0000 (03:57 +0200)
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 <metze@samba.org>

Signed-off-by: Alexander Bokovoy <ab@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Autobuild-User(master): Andrew Bartlett <abartlet@samba.org>
Autobuild-Date(master): Wed Sep  5 03:57:22 CEST 2018 on sn-devel-144

auth/credentials/credentials_krb5.c
lib/krb5_wrap/krb5_samba.c
lib/krb5_wrap/krb5_samba.h
selftest/knownfail.d/trust_user_account [deleted file]
source3/passdb/machine_account_secrets.c
source4/dsdb/samdb/ldb_modules/password_hash.c

index 9da1aa0..d36797b 100644 (file)
@@ -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) {
index 7e90913..a6ff976 100644 (file)
@@ -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 <com_err.h>
@@ -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) {
index 315d3c3..8305c1f 100644 (file)
@@ -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 (file)
index 1de5052..0000000
+++ /dev/null
@@ -1 +0,0 @@
-^samba4.blackbox.trust_user_account.get.virtualKerberosSalt.for.TDA
index 94a7e21..a96bf1c 100644 (file)
@@ -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);
index 58ae645..5f57103 100644 (file)
@@ -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");