+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_CreateTrustedDomain_r(b, tctx, &r),
+ "CreateTrustedDomain failed");
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_OBJECT_NAME_COLLISION)) {
+ test_DeleteTrustedDomain(b, tctx, handle, trustinfo.name);
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_CreateTrustedDomain_r(b, tctx, &r),
+ "CreateTrustedDomain failed");
+ }
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "CreateTrustedDomain failed - %s\n", nt_errstr(r.out.result));
+ ret = false;
+ } else {
+
+ q.in.trustdom_handle = &trustdom_handle[i];
+ q.in.level = LSA_TRUSTED_DOMAIN_INFO_INFO_EX;
+ q.out.info = &info;
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_QueryTrustedDomainInfo_r(b, tctx, &q),
+ "QueryTrustedDomainInfo failed");
+ if (!NT_STATUS_IS_OK(q.out.result)) {
+ torture_comment(tctx, "QueryTrustedDomainInfo level %d failed - %s\n", q.in.level, nt_errstr(q.out.result));
+ ret = false;
+ } else if (!q.out.info) {
+ ret = false;
+ } else {
+ if (strcmp(info->info_ex.netbios_name.string, trustinfo.name.string) != 0) {
+ torture_comment(tctx, "QueryTrustedDomainInfo returned inconsistent short name: %s != %s\n",
+ info->info_ex.netbios_name.string, trustinfo.name.string);
+ ret = false;
+ }
+ if (info->info_ex.trust_type != LSA_TRUST_TYPE_DOWNLEVEL) {
+ torture_comment(tctx, "QueryTrustedDomainInfo of %s returned incorrect trust type %d != %d\n",
+ trust_name, info->info_ex.trust_type, LSA_TRUST_TYPE_DOWNLEVEL);
+ ret = false;
+ }
+ if (info->info_ex.trust_attributes != 0) {
+ torture_comment(tctx, "QueryTrustedDomainInfo of %s returned incorrect trust attributes %d != %d\n",
+ trust_name, info->info_ex.trust_attributes, 0);
+ ret = false;
+ }
+ if (info->info_ex.trust_direction != LSA_TRUST_DIRECTION_OUTBOUND) {
+ torture_comment(tctx, "QueryTrustedDomainInfo of %s returned incorrect trust direction %d != %d\n",
+ trust_name, info->info_ex.trust_direction, LSA_TRUST_DIRECTION_OUTBOUND);
+ ret = false;
+ }
+ }
+ }
+ }
+
+ /* now that we have some domains to look over, we can test the enum calls */
+ if (!test_EnumTrustDom(b, tctx, handle)) {
+ ret = false;
+ }
+
+ if (!test_EnumTrustDomEx(b, tctx, handle)) {
+ ret = false;
+ }
+
+ for (i=0; i<num_trusts; i++) {
+ if (!test_DeleteTrustedDomainBySid(b, tctx, handle, domsid[i])) {
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+static bool gen_authinfo_internal(TALLOC_CTX *mem_ctx, const char *password,
+ DATA_BLOB session_key,
+ struct lsa_TrustDomainInfoAuthInfoInternal **_authinfo_internal)
+{
+ struct lsa_TrustDomainInfoAuthInfoInternal *authinfo_internal;
+ struct trustDomainPasswords auth_struct;
+ struct AuthenticationInformation *auth_info_array;
+ size_t converted_size;
+ DATA_BLOB auth_blob;
+ enum ndr_err_code ndr_err;
+
+ authinfo_internal = talloc_zero(mem_ctx, struct lsa_TrustDomainInfoAuthInfoInternal);
+ if (authinfo_internal == NULL) {
+ return false;
+ }
+
+ auth_info_array = talloc_array(mem_ctx,
+ struct AuthenticationInformation, 1);
+ if (auth_info_array == NULL) {
+ return false;
+ }
+
+ generate_random_buffer(auth_struct.confounder, sizeof(auth_struct.confounder));
+
+ auth_info_array[0].AuthType = TRUST_AUTH_TYPE_CLEAR;
+
+ if (!convert_string_talloc(mem_ctx, CH_UNIX, CH_UTF16, password,
+ strlen(password),
+ &auth_info_array[0].AuthInfo.clear.password,
+ &converted_size)) {
+ return false;
+ }
+
+ auth_info_array[0].AuthInfo.clear.size = converted_size;
+
+ auth_struct.outgoing.count = 1;
+ auth_struct.outgoing.current.count = 1;
+ auth_struct.outgoing.current.array = auth_info_array;
+ auth_struct.outgoing.previous.count = 0;
+ auth_struct.outgoing.previous.array = NULL;
+
+ auth_struct.incoming.count = 1;
+ auth_struct.incoming.current.count = 1;
+ auth_struct.incoming.current.array = auth_info_array;
+ auth_struct.incoming.previous.count = 0;
+ auth_struct.incoming.previous.array = NULL;
+
+
+ ndr_err = ndr_push_struct_blob(&auth_blob, mem_ctx, &auth_struct,
+ (ndr_push_flags_fn_t)ndr_push_trustDomainPasswords);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return false;
+ }
+
+ arcfour_crypt_blob(auth_blob.data, auth_blob.length, &session_key);
+
+ authinfo_internal->auth_blob.size = auth_blob.length;
+ authinfo_internal->auth_blob.data = auth_blob.data;
+
+ *_authinfo_internal = authinfo_internal;
+
+ return true;
+}
+
+static bool gen_authinfo(TALLOC_CTX *mem_ctx, const char *password,
+ struct lsa_TrustDomainInfoAuthInfo **_authinfo)
+{
+ struct lsa_TrustDomainInfoAuthInfo *authinfo;
+ struct lsa_TrustDomainInfoBuffer *info_buffer;
+ size_t converted_size;
+
+ authinfo = talloc_zero(mem_ctx, struct lsa_TrustDomainInfoAuthInfo);
+ if (authinfo == NULL) {
+ return false;
+ }
+
+ info_buffer = talloc_zero(mem_ctx, struct lsa_TrustDomainInfoBuffer);
+ if (info_buffer == NULL) {
+ return false;
+ }
+
+ info_buffer->AuthType = TRUST_AUTH_TYPE_CLEAR;
+
+ if (!convert_string_talloc(mem_ctx, CH_UNIX, CH_UTF16, password,
+ strlen(password),
+ &info_buffer->data.data,
+ &converted_size)) {
+ return false;
+ }
+
+ info_buffer->data.size = converted_size;
+
+ authinfo->incoming_count = 1;
+ authinfo->incoming_current_auth_info = info_buffer;
+ authinfo->incoming_previous_auth_info = NULL;
+ authinfo->outgoing_count = 1;
+ authinfo->outgoing_current_auth_info = info_buffer;
+ authinfo->outgoing_previous_auth_info = NULL;
+
+ *_authinfo = authinfo;
+
+ return true;
+}
+
+static bool check_pw_with_ServerAuthenticate3(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ uint32_t negotiate_flags,
+ struct cli_credentials *machine_credentials,
+ struct netlogon_creds_CredentialState **creds_out)
+{
+ struct netr_ServerReqChallenge r;
+ struct netr_ServerAuthenticate3 a;
+ struct netr_Credential credentials1, credentials2, credentials3;
+ struct netlogon_creds_CredentialState *creds;
+ struct samr_Password mach_password;
+ uint32_t rid;
+ const char *machine_name;
+ const char *plain_pass;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ machine_name = cli_credentials_get_workstation(machine_credentials);
+ plain_pass = cli_credentials_get_password(machine_credentials);
+
+ r.in.server_name = NULL;
+ r.in.computer_name = machine_name;
+ r.in.credentials = &credentials1;
+ r.out.return_credentials = &credentials2;
+
+ generate_random_buffer(credentials1.data, sizeof(credentials1.data));
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
+ "ServerReqChallenge failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed");
+
+ E_md4hash(plain_pass, mach_password.hash);
+
+ a.in.server_name = NULL;
+ a.in.account_name = talloc_asprintf(tctx, "%s$", machine_name);
+ a.in.secure_channel_type = cli_credentials_get_secure_channel_type(machine_credentials);
+ a.in.computer_name = machine_name;
+ a.in.negotiate_flags = &negotiate_flags;
+ a.in.credentials = &credentials3;
+ a.out.return_credentials = &credentials3;
+ a.out.negotiate_flags = &negotiate_flags;
+ a.out.rid = &rid;
+
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ &credentials1, &credentials2,
+ &mach_password, &credentials3,
+ negotiate_flags);
+
+ torture_assert(tctx, creds != NULL, "memory allocation");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b, tctx, &a),
+ "ServerAuthenticate3 failed");
+ if (!NT_STATUS_IS_OK(a.out.result)) {
+ if (!NT_STATUS_EQUAL(a.out.result, NT_STATUS_ACCESS_DENIED)) {
+ torture_assert_ntstatus_ok(tctx, a.out.result,
+ "ServerAuthenticate3 failed");
+ }
+ return false;
+ }
+ torture_assert(tctx, netlogon_creds_client_check(creds, &credentials3), "Credential chaining failed");
+
+ /* Prove that requesting a challenge again won't break it */
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
+ "ServerReqChallenge failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed");
+
+ *creds_out = creds;
+ return true;
+}
+
+static bool check_dom_trust_pw(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ const char *trusted_dom_name,
+ const char *password)
+{
+ struct cli_credentials *credentials;
+ char *dummy;
+ struct netlogon_creds_CredentialState *creds;
+ struct dcerpc_pipe *pipe;
+ NTSTATUS status;
+ bool ok;
+
+ credentials = cli_credentials_init(tctx);
+ if (credentials == NULL) {
+ return false;
+ }
+
+ dummy = talloc_asprintf(tctx, "%s$", trusted_dom_name);
+ if (dummy == NULL) {
+ return false;
+ }
+
+ cli_credentials_set_username(credentials, dummy, CRED_SPECIFIED);
+ cli_credentials_set_password(credentials, password, CRED_SPECIFIED);
+ cli_credentials_set_workstation(credentials,
+ trusted_dom_name, CRED_SPECIFIED);
+ cli_credentials_set_secure_channel_type(credentials, SEC_CHAN_DOMAIN);
+
+ status = dcerpc_pipe_connect_b(tctx, &pipe, p->binding,
+ &ndr_table_netlogon,
+ cli_credentials_init_anon(tctx),
+ tctx->ev, tctx->lp_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "dcerpc_pipe_connect_b failed.\n");
+ return false;
+ }
+
+ ok = check_pw_with_ServerAuthenticate3(pipe, tctx,
+ NETLOGON_NEG_AUTH2_ADS_FLAGS,
+ credentials, &creds);
+ talloc_free(pipe);
+
+ return ok;
+}
+
+static bool test_CreateTrustedDomainEx_common(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ uint32_t num_trusts,
+ bool ex2_call)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct lsa_CreateTrustedDomainEx r;
+ struct lsa_CreateTrustedDomainEx2 r2;
+ struct lsa_TrustDomainInfoInfoEx trustinfo;
+ struct lsa_TrustDomainInfoAuthInfoInternal *authinfo_internal;
+ struct lsa_TrustDomainInfoAuthInfo *authinfo;
+ struct dom_sid **domsid;
+ struct policy_handle *trustdom_handle;
+ struct lsa_QueryTrustedDomainInfo q;
+ union lsa_TrustedDomainInfo *info = NULL;
+ DATA_BLOB session_key;
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (ex2_call) {
+ torture_comment(tctx, "\nTesting CreateTrustedDomainEx2 for %d domains\n", num_trusts);
+ } else {
+ torture_comment(tctx, "\nTesting CreateTrustedDomainEx for %d domains\n", num_trusts);
+ }
+
+ domsid = talloc_array(tctx, struct dom_sid *, num_trusts);
+ trustdom_handle = talloc_array(tctx, struct policy_handle, num_trusts);
+
+ status = dcerpc_fetch_session_key(p, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "dcerpc_fetch_session_key failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ for (i=0; i< num_trusts; i++) {
+ char *trust_name = talloc_asprintf(tctx, "torturedom%02d", i);
+ char *trust_name_dns = talloc_asprintf(tctx, "torturedom%02d.samba.example.com", i);
+ char *trust_sid = talloc_asprintf(tctx, "S-1-5-21-97398-379795-100%02d", i);
+
+ domsid[i] = dom_sid_parse_talloc(tctx, trust_sid);
+
+ trustinfo.sid = domsid[i];
+ trustinfo.netbios_name.string = trust_name;
+ trustinfo.domain_name.string = trust_name_dns;
+
+ /* Create inbound, some outbound, and some
+ * bi-directional trusts in a repeating pattern based
+ * on i */
+
+ /* 1 == inbound, 2 == outbound, 3 == both */
+ trustinfo.trust_direction = (i % 3) + 1;
+
+ /* Try different trust types too */
+
+ /* 1 == downlevel (NT4), 2 == uplevel (ADS), 3 == MIT (kerberos but not AD) */
+ trustinfo.trust_type = (((i / 3) + 1) % 3) + 1;
+
+ trustinfo.trust_attributes = LSA_TRUST_ATTRIBUTE_USES_RC4_ENCRYPTION;
+
+ if (!gen_authinfo_internal(tctx, TRUSTPW, session_key, &authinfo_internal)) {
+ torture_comment(tctx, "gen_authinfo_internal failed");
+ ret = false;
+ }
+
+ if (!gen_authinfo(tctx, TRUSTPW, &authinfo)) {
+ torture_comment(tctx, "gen_authinfonfo failed");
+ ret = false;
+ }
+
+ if (ex2_call) {
+
+ r2.in.policy_handle = handle;
+ r2.in.info = &trustinfo;
+ r2.in.auth_info_internal = authinfo_internal;
+ r2.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r2.out.trustdom_handle = &trustdom_handle[i];
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_CreateTrustedDomainEx2_r(b, tctx, &r2),
+ "CreateTrustedDomainEx2 failed");
+
+ status = r2.out.result;
+ } else {
+
+ r.in.policy_handle = handle;
+ r.in.info = &trustinfo;
+ r.in.auth_info = authinfo;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.trustdom_handle = &trustdom_handle[i];
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_CreateTrustedDomainEx_r(b, tctx, &r),
+ "CreateTrustedDomainEx failed");
+
+ status = r.out.result;
+ }
+