#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
{
bool ret;
void *protection = secrets_fetch(protect_ids_keystr(domain), NULL);
-
+
if (protection) {
SAFE_FREE(protection);
ret = secrets_delete_entry(protect_ids_keystr(domain));
{
char *protect_ids;
bool ret;
+ struct dom_sid clean_sid = { 0 };
protect_ids = secrets_fetch(protect_ids_keystr(domain), NULL);
if (protect_ids) {
}
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) {
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;
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;
if (size != sizeof(*pass)) {
DEBUG(0, ("secrets were of incorrect size!\n"));
- SAFE_FREE(pass);
+ BURN_FREE(pass, size);
return False;
}
*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.
************************************************************************/
/************************************************************************
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,
}
} 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);
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;
/* 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;
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,
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;
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;
}
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,
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;
TALLOC_FREE(salt_data);
return ENOMEM;
}
+ talloc_keep_secret(aes_256_b.data);
krb5_ret = smb_krb5_create_key_from_string(krb5_ctx,
NULL,
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:
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;
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);
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);
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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));
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 "
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);
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);