From 7387678ff518a394d9f837561987af0e90464d6c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 16 Dec 2014 15:06:56 +0000 Subject: [PATCH] s3:pdb_samba_dsdb: add pdb_samba_dsdb_get_trusteddom_creds We have the password as raw UTF16 blob, which might not be valid utf16, so we need to use cli_credentials_set_utf16_password(). Bug: https://bugzilla.samba.org/show_bug.cgi?id=11016 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett --- source3/passdb/pdb_samba_dsdb.c | 226 +++++++++++++++++++++++++++++++- 1 file changed, 225 insertions(+), 1 deletion(-) diff --git a/source3/passdb/pdb_samba_dsdb.c b/source3/passdb/pdb_samba_dsdb.c index 5fa2c2fbbf0..638a4a290f1 100644 --- a/source3/passdb/pdb_samba_dsdb.c +++ b/source3/passdb/pdb_samba_dsdb.c @@ -38,6 +38,7 @@ #include "source4/dsdb/common/util.h" #include "source3/include/secrets.h" #include "source4/auth/auth_sam.h" +#include "auth/credentials/credentials.h" struct pdb_samba_dsdb_state { struct tevent_context *ev; @@ -2131,6 +2132,7 @@ static bool pdb_samba_dsdb_get_trusteddom_pw(struct pdb_methods *m, TALLOC_CTX *tmp_ctx = talloc_stackframe(); const char * const attrs[] = { "securityIdentifier", + "flatName", "trustPartner", "trustAuthOutgoing", "whenCreated", @@ -2152,6 +2154,7 @@ static bool pdb_samba_dsdb_get_trusteddom_pw(struct pdb_methods *m, size_t password_len; enum ndr_err_code ndr_err; NTSTATUS status; + const char *netbios_domain = NULL; status = sam_get_results_trust(state->ldb, tmp_ctx, domain, NULL, attrs, &msg); @@ -2166,6 +2169,14 @@ static bool pdb_samba_dsdb_get_trusteddom_pw(struct pdb_methods *m, return false; } + netbios_domain = ldb_msg_find_attr_as_string(msg, "flatName", NULL); + if (netbios_domain == NULL) { + DEBUG(2, ("Trusted domain %s has to flatName defined.\n", + domain)); + TALLOC_FREE(tmp_ctx); + return false; + } + trust_direction_flags = ldb_msg_find_attr_as_int(msg, "trustDirection", 0); if (!(trust_direction_flags & LSA_TRUST_DIRECTION_OUTBOUND)) { DEBUG(2, ("Trusted domain %s is is not an outbound trust.\n", @@ -2230,7 +2241,7 @@ static bool pdb_samba_dsdb_get_trusteddom_pw(struct pdb_methods *m, * utf8. */ if (!convert_string_talloc(tmp_ctx, - CH_UTF16, CH_UTF8, + CH_UTF16MUNGED, CH_UTF8, password_utf16.data, password_utf16.length, (void *)&password_talloc, &password_len)) { @@ -2249,6 +2260,218 @@ static bool pdb_samba_dsdb_get_trusteddom_pw(struct pdb_methods *m, return true; } +static NTSTATUS pdb_samba_dsdb_get_trusteddom_creds(struct pdb_methods *m, + const char *domain, + TALLOC_CTX *mem_ctx, + struct cli_credentials **_creds) +{ + struct pdb_samba_dsdb_state *state = talloc_get_type_abort( + m->private_data, struct pdb_samba_dsdb_state); + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + const char * const attrs[] = { + "securityIdentifier", + "flatName", + "trustPartner", + "trustAuthOutgoing", + "whenCreated", + "msDS-SupportedEncryptionTypes", + "trustAttributes", + "trustDirection", + "trustType", + NULL + }; + struct ldb_message *msg; + const struct ldb_val *password_val; + int trust_direction_flags; + int trust_type; + int i; + DATA_BLOB password_utf16 = {}; + DATA_BLOB password_nt = {}; + struct trustAuthInOutBlob password_blob; + struct AuthenticationInformationArray *auth_array = NULL; + enum ndr_err_code ndr_err; + NTSTATUS status; + time_t last_set_time = 0; + struct cli_credentials *creds = NULL; + bool ok; + const char *my_netbios_name = NULL; + const char *my_netbios_domain = NULL; + const char *netbios_domain = NULL; + char *account_name = NULL; + const char *dns_domain = NULL; + + status = sam_get_results_trust(state->ldb, tmp_ctx, domain, + NULL, attrs, &msg); + if (!NT_STATUS_IS_OK(status)) { + /* + * This can be called to work out of a domain is + * trusted, rather than just to get the password + */ + DEBUG(2, ("Failed to get trusted domain password for %s. " + "It may not be a trusted domain.\n", domain)); + TALLOC_FREE(tmp_ctx); + return status; + } + + netbios_domain = ldb_msg_find_attr_as_string(msg, "flatName", NULL); + if (netbios_domain == NULL) { + DEBUG(2, ("Trusted domain %s has to flatName defined.\n", + domain)); + TALLOC_FREE(tmp_ctx); + return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + } + + dns_domain = ldb_msg_find_attr_as_string(msg, "trustPartner", NULL); + + trust_direction_flags = ldb_msg_find_attr_as_int(msg, "trustDirection", 0); + if (!(trust_direction_flags & LSA_TRUST_DIRECTION_OUTBOUND)) { + DEBUG(2, ("Trusted domain %s is is not an outbound trust.\n", + domain)); + TALLOC_FREE(tmp_ctx); + return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + } + + trust_type = ldb_msg_find_attr_as_int(msg, "trustType", 0); + if (trust_type == LSA_TRUST_TYPE_MIT) { + DEBUG(1, ("Trusted domain %s is is not an AD trust " + "(trustType == LSA_TRUST_TYPE_MIT).\n", + domain)); + TALLOC_FREE(tmp_ctx); + return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + } + + password_val = ldb_msg_find_ldb_val(msg, "trustAuthOutgoing"); + if (password_val == NULL) { + DEBUG(2, ("Failed to get trusted domain password for %s, " + "attribute trustAuthOutgoing not returned.\n", domain)); + TALLOC_FREE(tmp_ctx); + return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + } + + ndr_err = ndr_pull_struct_blob(password_val, tmp_ctx, &password_blob, + (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(0, ("Failed to get trusted domain password for %s, " + "attribute trustAuthOutgoing coult not be parsed %s.\n", + domain, + ndr_map_error2string(ndr_err))); + TALLOC_FREE(tmp_ctx); + return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + } + + auth_array = &password_blob.current; + + for (i=0; i < auth_array->count; i++) { + if (auth_array->array[i].AuthType == TRUST_AUTH_TYPE_CLEAR) { + last_set_time = nt_time_to_unix(auth_array->array[i].LastUpdateTime); + + password_utf16 = data_blob_const(auth_array->array[i].AuthInfo.clear.password, + auth_array->array[i].AuthInfo.clear.size); + password_nt = data_blob_null; + break; + } + + if (auth_array->array[i].AuthType == TRUST_AUTH_TYPE_NT4OWF) { + last_set_time = nt_time_to_unix(auth_array->array[i].LastUpdateTime); + + password_nt = data_blob_const(auth_array->array[i].AuthInfo.clear.password, + auth_array->array[i].AuthInfo.clear.size); + } + } + + if (password_utf16.length == 0 && password_nt.length == 0) { + DEBUG(0, ("Trusted domain %s does not have a " + "clear-text nor nt password stored\n", + domain)); + TALLOC_FREE(tmp_ctx); + return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + } + + my_netbios_name = lpcfg_netbios_name(state->lp_ctx); + my_netbios_domain = lpcfg_workgroup(state->lp_ctx); + + creds = cli_credentials_init(tmp_ctx); + if (creds == NULL) { + TALLOC_FREE(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + + ok = cli_credentials_set_workstation(creds, my_netbios_name, CRED_SPECIFIED); + if (!ok) { + TALLOC_FREE(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + + ok = cli_credentials_set_domain(creds, netbios_domain, CRED_SPECIFIED); + if (!ok) { + TALLOC_FREE(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + ok = cli_credentials_set_realm(creds, dns_domain, CRED_SPECIFIED); + if (!ok) { + TALLOC_FREE(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + + cli_credentials_set_secure_channel_type(creds, SEC_CHAN_DOMAIN); + + account_name = talloc_asprintf(tmp_ctx, "%s$", my_netbios_domain); + if (account_name == NULL) { + TALLOC_FREE(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + + ok = cli_credentials_set_username(creds, account_name, CRED_SPECIFIED); + if (!ok) { + TALLOC_FREE(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + + if (password_nt.length == 16) { + struct samr_Password nt_hash; + + memcpy(nt_hash.hash, password_nt.data, 16); + + ok = cli_credentials_set_nt_hash(creds, &nt_hash, + CRED_SPECIFIED); + ZERO_STRUCT(nt_hash); + if (!ok) { + TALLOC_FREE(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + } + + if (password_utf16.length > 0) { + ok = cli_credentials_set_utf16_password(creds, + &password_utf16, + CRED_SPECIFIED); + if (!ok) { + TALLOC_FREE(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + } + + cli_credentials_set_password_last_changed_time(creds, last_set_time); + + if (password_utf16.length > 0 && dns_domain != NULL) { + /* + * Force kerberos if this is an active directory domain + */ + cli_credentials_set_kerberos_state(creds, + CRED_MUST_USE_KERBEROS); + } else { + /* + * TODO: we should allow krb5 with the raw nt hash. + */ + cli_credentials_set_kerberos_state(creds, + CRED_DONT_USE_KERBEROS); + } + + *_creds = talloc_move(mem_ctx, &creds); + TALLOC_FREE(tmp_ctx); + return NT_STATUS_OK; +} + static bool pdb_samba_dsdb_set_trusteddom_pw(struct pdb_methods *m, const char* domain, const char* pwd, const struct dom_sid *sid) @@ -2329,6 +2552,7 @@ static void pdb_samba_dsdb_init_methods(struct pdb_methods *m) m->capabilities = pdb_samba_dsdb_capabilities; m->new_rid = pdb_samba_dsdb_new_rid; m->get_trusteddom_pw = pdb_samba_dsdb_get_trusteddom_pw; + m->get_trusteddom_creds = pdb_samba_dsdb_get_trusteddom_creds; m->set_trusteddom_pw = pdb_samba_dsdb_set_trusteddom_pw; m->del_trusteddom_pw = pdb_samba_dsdb_del_trusteddom_pw; m->enum_trusteddoms = pdb_samba_dsdb_enum_trusteddoms; -- 2.34.1