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 = {};
	struct samr_Password *password_nt = NULL;
	uint32_t password_version = 0;
	DATA_BLOB old_password_utf16 = {};
	struct samr_Password *old_password_nt = NULL;
	struct trustAuthInOutBlob password_blob;
	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 *my_dns_domain = NULL;
	const char *netbios_domain = NULL;
	char *account_name = NULL;
	char *principal_name = NULL;
	const char *dns_domain = NULL;

	status = dsdb_trust_search_tdo(state->ldb, domain, NULL,
				       attrs, tmp_ctx, &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 - %s "
			  "It may not be a trusted domain.\n", domain,
			  nt_errstr(status)));
		TALLOC_FREE(tmp_ctx);
		return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
	}

	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)) {
		DBG_WARNING("Trusted domain %s 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) {
		DBG_WARNING("Trusted domain %s 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 could not be parsed %s.\n",
			  domain,
			  ndr_map_error2string(ndr_err)));
		TALLOC_FREE(tmp_ctx);
		return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
	}

	for (i=0; i < password_blob.current.count; i++) {
		struct AuthenticationInformation *a =
			&password_blob.current.array[i];

		switch (a->AuthType) {
		case TRUST_AUTH_TYPE_NONE:
			break;

		case TRUST_AUTH_TYPE_VERSION:
			password_version = a->AuthInfo.version.version;
			break;

		case TRUST_AUTH_TYPE_CLEAR:
			last_set_time = nt_time_to_unix(a->LastUpdateTime);

			password_utf16 = data_blob_const(a->AuthInfo.clear.password,
							 a->AuthInfo.clear.size);
			password_nt = NULL;
			break;

		case TRUST_AUTH_TYPE_NT4OWF:
			if (password_utf16.length != 0) {
				break;
			}

			last_set_time = nt_time_to_unix(a->LastUpdateTime);

			password_nt = &a->AuthInfo.nt4owf.password;
			break;
		}
	}

	for (i=0; i < password_blob.previous.count; i++) {
		struct AuthenticationInformation *a = &password_blob.previous.array[i];

		switch (a->AuthType) {
		case TRUST_AUTH_TYPE_NONE:
			break;

		case TRUST_AUTH_TYPE_VERSION:
			break;

		case TRUST_AUTH_TYPE_CLEAR:
			old_password_utf16 = data_blob_const(a->AuthInfo.clear.password,
							 a->AuthInfo.clear.size);
			old_password_nt = NULL;
			break;

		case TRUST_AUTH_TYPE_NT4OWF:
			if (old_password_utf16.length != 0) {
				break;
			}

			old_password_nt = &a->AuthInfo.nt4owf.password;
			break;
		}
	}

	if (password_utf16.length == 0 && password_nt == NULL) {
		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);
	my_dns_domain = lpcfg_dnsdomain(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;
	}

	if (my_dns_domain != NULL && dns_domain != NULL) {
		cli_credentials_set_secure_channel_type(creds, SEC_CHAN_DNS_DOMAIN);
		account_name = talloc_asprintf(tmp_ctx, "%s.", my_dns_domain);
		if (account_name == NULL) {
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_NO_MEMORY;
		}
		principal_name = talloc_asprintf(tmp_ctx, "%s$@%s", my_netbios_domain,
						 cli_credentials_get_realm(creds));
		if (principal_name == NULL) {
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_NO_MEMORY;
		}
	} else {
		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;
		}
		principal_name = NULL;
	}

	ok = cli_credentials_set_username(creds, account_name, CRED_SPECIFIED);
	if (!ok) {
		TALLOC_FREE(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	if (principal_name != NULL) {
		ok = cli_credentials_set_principal(creds, principal_name,
						   CRED_SPECIFIED);
		if (!ok) {
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_NO_MEMORY;
		}
	}

	if (old_password_nt != NULL) {
		ok = cli_credentials_set_old_nt_hash(creds, old_password_nt);
		if (!ok) {
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_NO_MEMORY;
		}
	}

	if (old_password_utf16.length > 0) {
		ok = cli_credentials_set_old_utf16_password(creds,
							    &old_password_utf16);
		if (!ok) {
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_NO_MEMORY;
		}
	}

	if (password_nt != NULL) {
		ok = cli_credentials_set_nt_hash(creds, password_nt,
						 CRED_SPECIFIED);
		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);
	cli_credentials_set_kvno(creds, password_version);

	if (password_utf16.length > 0 && dns_domain != NULL) {
		/*
		 * Force kerberos if this is an active directory domain
		 */
		cli_credentials_set_kerberos_state(creds,
						   CRED_USE_KERBEROS_REQUIRED,
						   CRED_SPECIFIED);
	} else  {
		/*
		 * TODO: we should allow krb5 with the raw nt hash.
		 */
		cli_credentials_set_kerberos_state(creds,
						   CRED_USE_KERBEROS_DISABLED,
						   CRED_SPECIFIED);
	}

	*_creds = talloc_move(mem_ctx, &creds);
	TALLOC_FREE(tmp_ctx);
	return NT_STATUS_OK;
}
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 = {};
	struct samr_Password *password_nt = NULL;
	uint32_t password_version = 0;
	DATA_BLOB old_password_utf16 = {};
	struct samr_Password *old_password_nt = NULL;
	struct trustAuthInOutBlob password_blob;
	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 *my_dns_domain = NULL;
	const char *netbios_domain = NULL;
	char *account_name = NULL;
	char *principal_name = NULL;
	const char *dns_domain = NULL;

	status = dsdb_trust_search_tdo(state->ldb, domain, NULL,
				       attrs, tmp_ctx, &msg);
	if (!NT_STATUS_IS_OK(status)) {
		 
		DEBUG(2, ("Failed to get trusted domain password for %s - %s "
			  "It may not be a trusted domain.\n", domain,
			  nt_errstr(status)));
		TALLOC_FREE(tmp_ctx);
		return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
	}

	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)) {
		DBG_WARNING("Trusted domain %s 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) {
		DBG_WARNING("Trusted domain %s 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 could not be parsed %s.\n",
			  domain,
			  ndr_map_error2string(ndr_err)));
		TALLOC_FREE(tmp_ctx);
		return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
	}

	for (i=0; i < password_blob.current.count; i++) {
		struct AuthenticationInformation *a =
			&password_blob.current.array[i];

		switch (a->AuthType) {
		case TRUST_AUTH_TYPE_NONE:
			break;

		case TRUST_AUTH_TYPE_VERSION:
			password_version = a->AuthInfo.version.version;
			break;

		case TRUST_AUTH_TYPE_CLEAR:
			last_set_time = nt_time_to_unix(a->LastUpdateTime);

			password_utf16 = data_blob_const(a->AuthInfo.clear.password,
							 a->AuthInfo.clear.size);
			password_nt = NULL;
			break;

		case TRUST_AUTH_TYPE_NT4OWF:
			if (password_utf16.length != 0) {
				break;
			}

			last_set_time = nt_time_to_unix(a->LastUpdateTime);

			password_nt = &a->AuthInfo.nt4owf.password;
			break;
		}
	}

	for (i=0; i < password_blob.previous.count; i++) {
		struct AuthenticationInformation *a = &password_blob.previous.array[i];

		switch (a->AuthType) {
		case TRUST_AUTH_TYPE_NONE:
			break;

		case TRUST_AUTH_TYPE_VERSION:
			break;

		case TRUST_AUTH_TYPE_CLEAR:
			old_password_utf16 = data_blob_const(a->AuthInfo.clear.password,
							 a->AuthInfo.clear.size);
			old_password_nt = NULL;
			break;

		case TRUST_AUTH_TYPE_NT4OWF:
			if (old_password_utf16.length != 0) {
				break;
			}

			old_password_nt = &a->AuthInfo.nt4owf.password;
			break;
		}
	}

	if (password_utf16.length == 0 && password_nt == NULL) {
		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);
	my_dns_domain = lpcfg_dnsdomain(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;
	}

	if (my_dns_domain != NULL && dns_domain != NULL) {
		cli_credentials_set_secure_channel_type(creds, SEC_CHAN_DNS_DOMAIN);
		account_name = talloc_asprintf(tmp_ctx, "%s.", my_dns_domain);
		if (account_name == NULL) {
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_NO_MEMORY;
		}
		principal_name = talloc_asprintf(tmp_ctx, "%s$@%s", my_netbios_domain,
						 cli_credentials_get_realm(creds));
		if (principal_name == NULL) {
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_NO_MEMORY;
		}
	} else {
		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;
		}
		principal_name = NULL;
	}

	ok = cli_credentials_set_username(creds, account_name, CRED_SPECIFIED);
	if (!ok) {
		TALLOC_FREE(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	if (principal_name != NULL) {
		ok = cli_credentials_set_principal(creds, principal_name,
						   CRED_SPECIFIED);
		if (!ok) {
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_NO_MEMORY;
		}
	}

	if (old_password_nt != NULL) {
		ok = cli_credentials_set_old_nt_hash(creds, old_password_nt);
		if (!ok) {
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_NO_MEMORY;
		}
	}

	if (old_password_utf16.length > 0) {
		ok = cli_credentials_set_old_utf16_password(creds,
							    &old_password_utf16);
		if (!ok) {
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_NO_MEMORY;
		}
	}

	if (password_nt != NULL) {
		ok = cli_credentials_set_nt_hash(creds, password_nt,
						 CRED_SPECIFIED);
		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);
	cli_credentials_set_kvno(creds, password_version);

	if (password_utf16.length > 0 && dns_domain != NULL) {
		 
		cli_credentials_set_kerberos_state(creds,
						   CRED_USE_KERBEROS_REQUIRED,
						   CRED_SPECIFIED);
	} else  {
		 
		cli_credentials_set_kerberos_state(creds,
						   CRED_USE_KERBEROS_DISABLED,
						   CRED_SPECIFIED);
	}

	*_creds = talloc_move(mem_ctx, &creds);
	TALLOC_FREE(tmp_ctx);
	return NT_STATUS_OK;
}