docs: fix a typo in history file
[bbaumbach/samba-autobuild/.git] / source3 / passdb / machine_account_secrets.c
index fbc87c5619c21eec4674fed2597d52e04f437ab1..494059b284971173e2ee4ddd8600b003ca5ec478 100644 (file)
@@ -36,6 +36,8 @@
 #include "lib/crypto/crypto.h"
 #include "lib/krb5_wrap/krb5_samba.h"
 #include "lib/util/time_basic.h"
+#include "../libds/common/flags.h"
+#include "lib/util/string_wrappers.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_PASSDB
@@ -97,7 +99,7 @@ bool secrets_clear_domain_protection(const char *domain)
 {
        bool ret;
        void *protection = secrets_fetch(protect_ids_keystr(domain), NULL);
-       
+
        if (protection) {
                SAFE_FREE(protection);
                ret = secrets_delete_entry(protect_ids_keystr(domain));
@@ -113,6 +115,7 @@ bool secrets_store_domain_sid(const char *domain, const struct dom_sid  *sid)
 {
        char *protect_ids;
        bool ret;
+       struct dom_sid clean_sid = { 0 };
 
        protect_ids = secrets_fetch(protect_ids_keystr(domain), NULL);
        if (protect_ids) {
@@ -125,7 +128,15 @@ bool secrets_store_domain_sid(const char *domain, const struct dom_sid  *sid)
        }
        SAFE_FREE(protect_ids);
 
-       ret = secrets_store(domain_sid_keystr(domain), sid, sizeof(struct dom_sid ));
+       /*
+        * use a copy to prevent uninitialized memory from being carried over
+        * to the tdb
+        */
+       sid_copy(&clean_sid, sid);
+
+       ret = secrets_store(domain_sid_keystr(domain),
+                           &clean_sid,
+                           sizeof(struct dom_sid));
 
        /* Force a re-query, in the case where we modified our domain */
        if (ret) {
@@ -187,7 +198,8 @@ bool secrets_fetch_domain_guid(const char *domain, struct GUID *guid)
        dyn_guid = (struct GUID *)secrets_fetch(key, &size);
 
        if (!dyn_guid) {
-               if (lp_server_role() == ROLE_DOMAIN_PDC) {
+               if (lp_server_role() == ROLE_DOMAIN_PDC ||
+                   lp_server_role() == ROLE_IPA_DC) {
                        new_guid = GUID_random();
                        if (!secrets_store_domain_guid(domain, &new_guid))
                                return False;
@@ -303,9 +315,7 @@ static const char *trust_keystr(const char *domain)
 
 enum netr_SchannelType get_default_sec_channel(void)
 {
-       if (lp_server_role() == ROLE_DOMAIN_BDC ||
-           lp_server_role() == ROLE_DOMAIN_PDC ||
-           lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
+       if (IS_DC) {
                return SEC_CHAN_BDC;
        } else {
                return SEC_CHAN_WKSTA;
@@ -335,7 +345,7 @@ bool secrets_fetch_trust_account_password_legacy(const char *domain,
 
        if (size != sizeof(*pass)) {
                DEBUG(0, ("secrets were of incorrect size!\n"));
-               SAFE_FREE(pass);
+               BURN_FREE(pass, size);
                return False;
        }
 
@@ -348,36 +358,10 @@ bool secrets_fetch_trust_account_password_legacy(const char *domain,
                *channel = get_default_sec_channel();
        }
 
-       SAFE_FREE(pass);
+       BURN_FREE(pass, size);
        return True;
 }
 
-/************************************************************************
- Routine to get the trust account password for a domain.
- The user of this function must have locked the trust password file using
- the above secrets_lock_trust_account_password().
-************************************************************************/
-
-bool secrets_fetch_trust_account_password(const char *domain, uint8_t ret_pwd[16],
-                                         time_t *pass_last_set_time,
-                                         enum netr_SchannelType *channel)
-{
-       char *plaintext;
-
-       plaintext = secrets_fetch_machine_password(domain, pass_last_set_time,
-                                                  channel);
-       if (plaintext) {
-               DEBUG(4,("Using cleartext machine password\n"));
-               E_md4hash(plaintext, ret_pwd);
-               SAFE_FREE(plaintext);
-               return True;
-       }
-
-       return secrets_fetch_trust_account_password_legacy(domain, ret_pwd,
-                                                          pass_last_set_time,
-                                                          channel);
-}
-
 /************************************************************************
  Routine to delete all information related to the domain joined machine.
 ************************************************************************/
@@ -452,7 +436,7 @@ bool secrets_delete_domain_sid(const char *domain)
 /************************************************************************
  Set the machine trust account password, the old pw and last change
  time, domain SID and salting principals based on values passed in
- (added to supprt the secrets_tdb_sync module on secrets.ldb)
+ (added to support the secrets_tdb_sync module on secrets.ldb)
 ************************************************************************/
 
 bool secrets_store_machine_pw_sync(const char *pass, const char *oldpass, const char *domain,
@@ -500,7 +484,7 @@ bool secrets_store_machine_pw_sync(const char *pass, const char *oldpass, const
                }
        } else {
                SIVAL(&sec_channel_bytes, 0, secure_channel_type);
-               ret = secrets_store(machine_sec_channel_type_keystr(domain), 
+               ret = secrets_store(machine_sec_channel_type_keystr(domain),
                                    &sec_channel_bytes, sizeof(sec_channel_bytes));
                if (!ret) {
                        TALLOC_FREE(frame);
@@ -701,6 +685,28 @@ char *secrets_fetch_machine_password(const char *domain,
        return ret;
 }
 
+static int password_nt_hash_destructor(struct secrets_domain_info1_password *pw)
+{
+       ZERO_STRUCT(pw->nt_hash);
+
+       return 0;
+}
+
+static int setup_password_zeroing(struct secrets_domain_info1_password *pw)
+{
+       if (pw != NULL) {
+               size_t i;
+
+               talloc_keep_secret(pw->cleartext_blob.data);
+               talloc_set_destructor(pw, password_nt_hash_destructor);
+               for (i = 0; i < pw->num_keys; i++) {
+                       talloc_keep_secret(pw->keys[i].value.data);
+               }
+       }
+
+       return 0;
+}
+
 static char *domain_info_keystr(const char *domain)
 {
        char *keystr;
@@ -735,13 +741,20 @@ static NTSTATUS secrets_fetch_domain_info1_by_key(const char *key,
        /* unpack trusted domain password */
        ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &sdib,
                        (ndr_pull_flags_fn_t)ndr_pull_secrets_domain_infoB);
-       SAFE_FREE(blob.data);
+       BURN_FREE(blob.data, blob.length);
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
                DBG_ERR("ndr_pull_struct_blob failed - %s!\n",
                        ndr_errstr(ndr_err));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
+       if (sdib.info.info1->next_change != NULL) {
+               setup_password_zeroing(sdib.info.info1->next_change->password);
+       }
+       setup_password_zeroing(sdib.info.info1->password);
+       setup_password_zeroing(sdib.info.info1->old_password);
+       setup_password_zeroing(sdib.info.info1->older_password);
+
        if (sdib.version != SECRETS_DOMAIN_INFO_VERSION_1) {
                DBG_ERR("sdib.version = %u\n", (unsigned)sdib.version);
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
@@ -768,8 +781,7 @@ void secrets_debug_domain_info(int lvl, const struct secrets_domain_info1 *info1
 
        sdib.info.info1 = discard_const_p(struct secrets_domain_info1, info1);
 
-       ndr_print_debug((ndr_print_fn_t)ndr_print_secrets_domain_infoB,
-                       name, &sdib);
+       NDR_PRINT_DEBUG_LEVEL(lvl, secrets_domain_infoB, &sdib);
 }
 
 char *secrets_domain_info_string(TALLOC_CTX *mem_ctx, const struct secrets_domain_info1 *info1,
@@ -1020,7 +1032,6 @@ static int secrets_domain_info_kerberos_keys(struct secrets_domain_info1_passwor
        krb5_keyblock key;
        DATA_BLOB aes_256_b = data_blob_null;
        DATA_BLOB aes_128_b = data_blob_null;
-       DATA_BLOB des_md5_b = data_blob_null;
        bool ok;
 #endif /* HAVE_ADS */
        DATA_BLOB arc4_b = data_blob_null;
@@ -1066,15 +1077,17 @@ static int secrets_domain_info_kerberos_keys(struct secrets_domain_info1_passwor
                TALLOC_FREE(keys);
                return ENOMEM;
        }
+       talloc_keep_secret(arc4_b.data);
 
 #ifdef HAVE_ADS
        if (salt_principal == NULL) {
                goto no_kerberos;
        }
 
-       initialize_krb5_error_table();
-       krb5_ret = krb5_init_context(&krb5_ctx);
+       krb5_ret = smb_krb5_init_context_common(&krb5_ctx);
        if (krb5_ret != 0) {
+               DBG_ERR("kerberos init context failed (%s)\n",
+                       error_message(krb5_ret));
                TALLOC_FREE(keys);
                return krb5_ret;
        }
@@ -1090,8 +1103,10 @@ static int secrets_domain_info_kerberos_keys(struct secrets_domain_info1_passwor
                return krb5_ret;
        }
 
-       salt.data = discard_const(salt_data);
-       salt.length = strlen(salt_data);
+       salt = (krb5_data) {
+               .data = discard_const(salt_data),
+               .length = strlen(salt_data),
+       };
 
        ok = convert_string_talloc(keys, CH_UTF16MUNGED, CH_UTF8,
                                   p->cleartext_blob.data,
@@ -1108,6 +1123,7 @@ static int secrets_domain_info_kerberos_keys(struct secrets_domain_info1_passwor
                TALLOC_FREE(keys);
                return krb5_ret;
        }
+       talloc_keep_secret(cleartext_utf8_b.data);
        cleartext_utf8.data = (void *)cleartext_utf8_b.data;
        cleartext_utf8.length = cleartext_utf8_b.length;
 
@@ -1136,6 +1152,7 @@ static int secrets_domain_info_kerberos_keys(struct secrets_domain_info1_passwor
                TALLOC_FREE(salt_data);
                return ENOMEM;
        }
+       talloc_keep_secret(aes_256_b.data);
 
        krb5_ret = smb_krb5_create_key_from_string(krb5_ctx,
                                                   NULL,
@@ -1162,32 +1179,7 @@ static int secrets_domain_info_kerberos_keys(struct secrets_domain_info1_passwor
                TALLOC_FREE(salt_data);
                return ENOMEM;
        }
-
-       krb5_ret = smb_krb5_create_key_from_string(krb5_ctx,
-                                                  NULL,
-                                                  &salt,
-                                                  &cleartext_utf8,
-                                                  ENCTYPE_DES_CBC_MD5,
-                                                  &key);
-       if (krb5_ret != 0) {
-               DBG_ERR("generation of a des-cbc-md5 key failed: %s\n",
-                       smb_get_krb5_error_message(krb5_ctx, krb5_ret, keys));
-               krb5_free_context(krb5_ctx);
-               TALLOC_FREE(keys);
-               TALLOC_FREE(salt_data);
-               return krb5_ret;
-       }
-       des_md5_b = data_blob_talloc(keys,
-                                    KRB5_KEY_DATA(&key),
-                                    KRB5_KEY_LENGTH(&key));
-       krb5_free_keyblock_contents(krb5_ctx, &key);
-       if (des_md5_b.data == NULL) {
-               DBG_ERR("data_blob_talloc failed for des-cbc-md5.\n");
-               krb5_free_context(krb5_ctx);
-               TALLOC_FREE(keys);
-               TALLOC_FREE(salt_data);
-               return ENOMEM;
-       }
+       talloc_keep_secret(aes_128_b.data);
 
        krb5_free_context(krb5_ctx);
 no_kerberos:
@@ -1213,15 +1205,6 @@ no_kerberos:
        keys[idx].value                 = arc4_b;
        idx += 1;
 
-#ifdef HAVE_ADS
-       if (des_md5_b.length != 0) {
-               keys[idx].keytype               = ENCTYPE_DES_CBC_MD5;
-               keys[idx].iteration_count       = 4096;
-               keys[idx].value                 = des_md5_b;
-               idx += 1;
-       }
-#endif /* HAVE_ADS */
-
        p->salt_data = salt_data;
        p->default_iteration_count = 4096;
        p->num_keys = idx;
@@ -1268,10 +1251,12 @@ static NTSTATUS secrets_domain_info_password_create(TALLOC_CTX *mem_ctx,
                TALLOC_FREE(p);
                return status;
        }
+       talloc_keep_secret(p->cleartext_blob.data);
        mdfour(p->nt_hash.hash,
               p->cleartext_blob.data,
               p->cleartext_blob.length);
 
+       talloc_set_destructor(p, password_nt_hash_destructor);
        ret = secrets_domain_info_kerberos_keys(p, salt_principal);
        if (ret != 0) {
                NTSTATUS status = krb5_to_nt_status(ret);
@@ -1315,7 +1300,7 @@ NTSTATUS secrets_fetch_or_upgrade_domain_info(const char *domain,
 
        last_set_time = secrets_fetch_pass_last_set_time(domain);
        if (last_set_time == 0) {
-               return NT_STATUS_OK;
+               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
        }
        unix_to_nt_time(&last_set_nt, last_set_time);
 
@@ -1367,8 +1352,8 @@ NTSTATUS secrets_fetch_or_upgrade_domain_info(const char *domain,
                DBG_ERR("secrets_fetch_domain_sid(%s) failed\n",
                        domain);
                dbwrap_transaction_cancel(db);
-               SAFE_FREE(old_pw);
-               SAFE_FREE(pw);
+               BURN_FREE_STR(old_pw);
+               BURN_FREE_STR(pw);
                TALLOC_FREE(frame);
                return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
        }
@@ -1383,8 +1368,8 @@ NTSTATUS secrets_fetch_or_upgrade_domain_info(const char *domain,
        if (info->account_name == NULL) {
                DBG_ERR("talloc_asprintf(%s$) failed\n", info->computer_name);
                dbwrap_transaction_cancel(db);
-               SAFE_FREE(old_pw);
-               SAFE_FREE(pw);
+               BURN_FREE_STR(old_pw);
+               BURN_FREE_STR(pw);
                TALLOC_FREE(frame);
                return NT_STATUS_NO_MEMORY;
        }
@@ -1422,8 +1407,8 @@ NTSTATUS secrets_fetch_or_upgrade_domain_info(const char *domain,
                        DBG_ERR("talloc_asprintf(%s#%02X) failed\n",
                                domain, NBT_NAME_PDC);
                        dbwrap_transaction_cancel(db);
-                       SAFE_FREE(pw);
-                       SAFE_FREE(old_pw);
+                       BURN_FREE_STR(pw);
+                       BURN_FREE_STR(old_pw);
                        TALLOC_FREE(frame);
                        return NT_STATUS_NO_MEMORY;
                }
@@ -1444,8 +1429,8 @@ NTSTATUS secrets_fetch_or_upgrade_domain_info(const char *domain,
                p = kerberos_secrets_fetch_salt_princ();
                if (p == NULL) {
                        dbwrap_transaction_cancel(db);
-                       SAFE_FREE(old_pw);
-                       SAFE_FREE(pw);
+                       BURN_FREE_STR(old_pw);
+                       BURN_FREE_STR(pw);
                        TALLOC_FREE(frame);
                        return NT_STATUS_INTERNAL_ERROR;
                }
@@ -1453,8 +1438,8 @@ NTSTATUS secrets_fetch_or_upgrade_domain_info(const char *domain,
                SAFE_FREE(p);
                if (info->salt_principal == NULL) {
                        dbwrap_transaction_cancel(db);
-                       SAFE_FREE(pw);
-                       SAFE_FREE(old_pw);
+                       BURN_FREE_STR(pw);
+                       BURN_FREE_STR(old_pw);
                        TALLOC_FREE(frame);
                        return NT_STATUS_NO_MEMORY;
                }
@@ -1469,11 +1454,12 @@ NTSTATUS secrets_fetch_or_upgrade_domain_info(const char *domain,
                                                     info->salt_principal,
                                                     last_set_nt, server,
                                                     &info->password);
-       SAFE_FREE(pw);
+       BURN_FREE_STR(pw);
        if (!NT_STATUS_IS_OK(status)) {
                DBG_ERR("secrets_domain_info_password_create(pw) failed "
                        "for %s - %s\n", domain, nt_errstr(status));
                dbwrap_transaction_cancel(db);
+               BURN_FREE_STR(old_pw);
                TALLOC_FREE(frame);
                return status;
        }
@@ -1487,7 +1473,7 @@ NTSTATUS secrets_fetch_or_upgrade_domain_info(const char *domain,
                                                             info->salt_principal,
                                                             0, server,
                                                             &info->old_password);
-               SAFE_FREE(old_pw);
+               BURN_FREE_STR(old_pw);
                if (!NT_STATUS_IS_OK(status)) {
                        DBG_ERR("secrets_domain_info_password_create(old) failed "
                                "for %s - %s\n", domain, nt_errstr(status));
@@ -1595,11 +1581,11 @@ NTSTATUS secrets_store_JoinCtx(const struct libnet_JoinCtx *r)
        if (info->salt_principal == NULL && r->out.domain_is_ad) {
                char *p = NULL;
 
-               ret = smb_krb5_salt_principal(info->domain_info.dns_domain.string,
-                                             info->account_name,
-                                             NULL /* userPrincipalName */,
-                                             true /* is_computer */,
-                                             info, &p);
+               ret = smb_krb5_salt_principal_str(info->domain_info.dns_domain.string,
+                                                 info->account_name,
+                                                 NULL /* userPrincipalName */,
+                                                 UF_WORKSTATION_TRUST_ACCOUNT,
+                                                 info, &p);
                if (ret != 0) {
                        status = krb5_to_nt_status(ret);
                        DBG_ERR("smb_krb5_salt_principal() failed "
@@ -1800,7 +1786,7 @@ static NTSTATUS secrets_check_password_change(const struct secrets_domain_info1
        struct secrets_domain_info1_change *sn = NULL;
        struct secrets_domain_info1_change *cn = NULL;
        NTSTATUS status;
-       int cmp;
+       bool cmp;
 
        if (cookie->next_change == NULL) {
                DBG_ERR("cookie->next_change == NULL for %s.\n", domain);
@@ -1895,20 +1881,20 @@ static NTSTATUS secrets_check_password_change(const struct secrets_domain_info1
                return NT_STATUS_NETWORK_CREDENTIAL_CONFLICT;
        }
 
-       cmp = memcmp(sn->password->nt_hash.hash,
-                    cn->password->nt_hash.hash,
-                    16);
-       if (cmp != 0) {
+       cmp = mem_equal_const_time(sn->password->nt_hash.hash,
+                                  cn->password->nt_hash.hash,
+                                  16);
+       if (!cmp) {
                DBG_ERR("next password.nt_hash differs for %s.\n",
                        domain);
                TALLOC_FREE(stored);
                return NT_STATUS_NETWORK_CREDENTIAL_CONFLICT;
        }
 
-       cmp = memcmp(stored->password->nt_hash.hash,
-                    cookie->password->nt_hash.hash,
-                    16);
-       if (cmp != 0) {
+       cmp = mem_equal_const_time(stored->password->nt_hash.hash,
+                                  cookie->password->nt_hash.hash,
+                                  16);
+       if (!cmp) {
                DBG_ERR("password.nt_hash differs for %s.\n",
                        domain);
                TALLOC_FREE(stored);