2 Unix SMB/CIFS implementation.
4 test suite for netlogon rpc operations
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004
8 Copyright (C) Tim Potter 2003
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include "lib/events/events.h"
27 #include "librpc/gen_ndr/ndr_netlogon.h"
28 #include "auth/auth.h"
29 #include "lib/cmdline/popt_common.h"
31 static const char *machine_password;
33 #define TEST_MACHINE_NAME "torturetest"
35 static BOOL test_LogonUasLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
38 struct netr_LogonUasLogon r;
40 r.in.server_name = NULL;
41 r.in.account_name = cli_credentials_get_username(cmdline_credentials);
42 r.in.workstation = TEST_MACHINE_NAME;
44 printf("Testing LogonUasLogon\n");
46 status = dcerpc_netr_LogonUasLogon(p, mem_ctx, &r);
47 if (!NT_STATUS_IS_OK(status)) {
48 printf("LogonUasLogon - %s\n", nt_errstr(status));
56 static BOOL test_LogonUasLogoff(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
59 struct netr_LogonUasLogoff r;
61 r.in.server_name = NULL;
62 r.in.account_name = cli_credentials_get_username(cmdline_credentials);
63 r.in.workstation = TEST_MACHINE_NAME;
65 printf("Testing LogonUasLogoff\n");
67 status = dcerpc_netr_LogonUasLogoff(p, mem_ctx, &r);
68 if (!NT_STATUS_IS_OK(status)) {
69 printf("LogonUasLogoff - %s\n", nt_errstr(status));
77 static BOOL test_SetupCredentials(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
78 const char *machine_name,
79 const char *plain_pass,
80 struct creds_CredentialState **creds_out)
83 struct netr_ServerReqChallenge r;
84 struct netr_ServerAuthenticate a;
85 struct netr_Credential credentials1, credentials2, credentials3;
86 struct creds_CredentialState *creds;
87 struct samr_Password mach_password;
89 printf("Testing ServerReqChallenge\n");
91 creds = talloc(mem_ctx, struct creds_CredentialState);
96 r.in.server_name = NULL;
97 r.in.computer_name = machine_name;
98 r.in.credentials = &credentials1;
99 r.out.credentials = &credentials2;
101 generate_random_buffer(credentials1.data, sizeof(credentials1.data));
103 status = dcerpc_netr_ServerReqChallenge(p, mem_ctx, &r);
104 if (!NT_STATUS_IS_OK(status)) {
105 printf("ServerReqChallenge - %s\n", nt_errstr(status));
109 E_md4hash(plain_pass, mach_password.hash);
111 a.in.server_name = NULL;
112 a.in.account_name = talloc_asprintf(mem_ctx, "%s$", machine_name);
113 a.in.secure_channel_type = SEC_CHAN_BDC;
114 a.in.computer_name = machine_name;
115 a.in.credentials = &credentials3;
116 a.out.credentials = &credentials3;
118 creds_client_init(creds, &credentials1, &credentials2,
119 &mach_password, &credentials3,
122 printf("Testing ServerAuthenticate\n");
124 status = dcerpc_netr_ServerAuthenticate(p, mem_ctx, &a);
125 if (!NT_STATUS_IS_OK(status)) {
126 printf("ServerAuthenticate - %s\n", nt_errstr(status));
130 if (!creds_client_check(creds, &credentials3)) {
131 printf("Credential chaining failed\n");
139 static BOOL test_SetupCredentials2(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
140 uint32_t negotiate_flags,
141 const char *machine_name,
142 const char *plain_pass,
144 struct creds_CredentialState **creds_out)
147 struct netr_ServerReqChallenge r;
148 struct netr_ServerAuthenticate2 a;
149 struct netr_Credential credentials1, credentials2, credentials3;
150 struct creds_CredentialState *creds;
151 struct samr_Password mach_password;
153 printf("Testing ServerReqChallenge\n");
155 creds = talloc(mem_ctx, struct creds_CredentialState);
160 r.in.server_name = NULL;
161 r.in.computer_name = machine_name;
162 r.in.credentials = &credentials1;
163 r.out.credentials = &credentials2;
165 generate_random_buffer(credentials1.data, sizeof(credentials1.data));
167 status = dcerpc_netr_ServerReqChallenge(p, mem_ctx, &r);
168 if (!NT_STATUS_IS_OK(status)) {
169 printf("ServerReqChallenge - %s\n", nt_errstr(status));
173 E_md4hash(plain_pass, mach_password.hash);
175 a.in.server_name = NULL;
176 a.in.account_name = talloc_asprintf(mem_ctx, "%s$", machine_name);
177 a.in.secure_channel_type = sec_chan_type;
178 a.in.computer_name = machine_name;
179 a.in.negotiate_flags = &negotiate_flags;
180 a.out.negotiate_flags = &negotiate_flags;
181 a.in.credentials = &credentials3;
182 a.out.credentials = &credentials3;
184 creds_client_init(creds, &credentials1, &credentials2,
185 &mach_password, &credentials3,
188 printf("Testing ServerAuthenticate2\n");
190 status = dcerpc_netr_ServerAuthenticate2(p, mem_ctx, &a);
191 if (!NT_STATUS_IS_OK(status)) {
192 printf("ServerAuthenticate2 - %s\n", nt_errstr(status));
196 if (!creds_client_check(creds, &credentials3)) {
197 printf("Credential chaining failed\n");
201 printf("negotiate_flags=0x%08x\n", negotiate_flags);
208 static BOOL test_SetupCredentials3(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
209 uint32_t negotiate_flags,
210 const char *machine_name,
211 const char *plain_pass,
212 struct creds_CredentialState **creds_out)
215 struct netr_ServerReqChallenge r;
216 struct netr_ServerAuthenticate3 a;
217 struct netr_Credential credentials1, credentials2, credentials3;
218 struct creds_CredentialState *creds;
219 struct samr_Password mach_password;
222 printf("Testing ServerReqChallenge\n");
224 creds = talloc(mem_ctx, struct creds_CredentialState);
229 r.in.server_name = NULL;
230 r.in.computer_name = machine_name;
231 r.in.credentials = &credentials1;
232 r.out.credentials = &credentials2;
234 generate_random_buffer(credentials1.data, sizeof(credentials1.data));
236 status = dcerpc_netr_ServerReqChallenge(p, mem_ctx, &r);
237 if (!NT_STATUS_IS_OK(status)) {
238 printf("ServerReqChallenge - %s\n", nt_errstr(status));
242 E_md4hash(plain_pass, mach_password.hash);
244 a.in.server_name = NULL;
245 a.in.account_name = talloc_asprintf(mem_ctx, "%s$", machine_name);
246 a.in.secure_channel_type = SEC_CHAN_BDC;
247 a.in.computer_name = machine_name;
248 a.in.negotiate_flags = &negotiate_flags;
249 a.in.credentials = &credentials3;
250 a.out.credentials = &credentials3;
251 a.out.negotiate_flags = &negotiate_flags;
254 creds_client_init(creds, &credentials1, &credentials2,
255 &mach_password, &credentials3,
258 printf("Testing ServerAuthenticate3\n");
260 status = dcerpc_netr_ServerAuthenticate3(p, mem_ctx, &a);
261 if (!NT_STATUS_IS_OK(status)) {
262 printf("ServerAuthenticate3 - %s\n", nt_errstr(status));
266 if (!creds_client_check(creds, &credentials3)) {
267 printf("Credential chaining failed\n");
271 printf("negotiate_flags=0x%08x\n", negotiate_flags);
278 try a change password for our machine account
280 static BOOL test_SetPassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
283 struct netr_ServerPasswordSet r;
284 const char *password;
285 struct creds_CredentialState *creds;
287 if (!test_SetupCredentials(p, mem_ctx, TEST_MACHINE_NAME,
288 machine_password, &creds)) {
292 r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
293 r.in.account_name = talloc_asprintf(mem_ctx, "%s$", TEST_MACHINE_NAME);
294 r.in.secure_channel_type = SEC_CHAN_BDC;
295 r.in.computer_name = TEST_MACHINE_NAME;
297 password = generate_random_str(mem_ctx, 8);
298 E_md4hash(password, r.in.new_password.hash);
300 creds_des_encrypt(creds, &r.in.new_password);
302 printf("Testing ServerPasswordSet on machine account\n");
303 printf("Changing machine account password to '%s'\n", password);
305 creds_client_authenticator(creds, &r.in.credential);
307 status = dcerpc_netr_ServerPasswordSet(p, mem_ctx, &r);
308 if (!NT_STATUS_IS_OK(status)) {
309 printf("ServerPasswordSet - %s\n", nt_errstr(status));
313 if (!creds_client_check(creds, &r.out.return_authenticator.cred)) {
314 printf("Credential chaining failed\n");
317 /* by changing the machine password twice we test the
318 credentials chaining fully, and we verify that the server
319 allows the password to be set to the same value twice in a
320 row (match win2k3) */
321 printf("Testing a second ServerPasswordSet on machine account\n");
322 printf("Changing machine account password to '%s' (same as previous run)\n", password);
324 creds_client_authenticator(creds, &r.in.credential);
326 status = dcerpc_netr_ServerPasswordSet(p, mem_ctx, &r);
327 if (!NT_STATUS_IS_OK(status)) {
328 printf("ServerPasswordSet (2) - %s\n", nt_errstr(status));
332 if (!creds_client_check(creds, &r.out.return_authenticator.cred)) {
333 printf("Credential chaining failed\n");
336 machine_password = password;
338 if (!test_SetupCredentials(p, mem_ctx, TEST_MACHINE_NAME, machine_password, &creds)) {
339 printf("ServerPasswordSet failed to actually change the password\n");
347 try a change password for our machine account
349 static BOOL test_SetPassword2(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
352 struct netr_ServerPasswordSet2 r;
353 const char *password;
354 struct creds_CredentialState *creds;
355 struct samr_CryptPassword password_buf;
357 if (!test_SetupCredentials(p, mem_ctx, TEST_MACHINE_NAME,
358 machine_password, &creds)) {
362 r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
363 r.in.account_name = talloc_asprintf(mem_ctx, "%s$", TEST_MACHINE_NAME);
364 r.in.secure_channel_type = SEC_CHAN_BDC;
365 r.in.computer_name = TEST_MACHINE_NAME;
367 password = generate_random_str(mem_ctx, 8);
368 encode_pw_buffer(password_buf.data, password, STR_UNICODE);
369 creds_arcfour_crypt(creds, password_buf.data, 516);
371 memcpy(r.in.new_password.data, password_buf.data, 512);
372 r.in.new_password.length = IVAL(password_buf.data, 512);
374 printf("Testing ServerPasswordSet2 on machine account\n");
375 printf("Changing machine account password to '%s'\n", password);
377 creds_client_authenticator(creds, &r.in.credential);
379 status = dcerpc_netr_ServerPasswordSet2(p, mem_ctx, &r);
380 if (!NT_STATUS_IS_OK(status)) {
381 printf("ServerPasswordSet2 - %s\n", nt_errstr(status));
385 if (!creds_client_check(creds, &r.out.return_authenticator.cred)) {
386 printf("Credential chaining failed\n");
389 machine_password = password;
391 if (!lp_parm_bool(-1, "torture", "dangerous", False)) {
392 printf("Not testing ability to set password to '', enable dangerous tests to perform this test\n");
394 /* by changing the machine password to ""
395 * we check if the server uses password restrictions
396 * for ServerPasswordSet2
397 * (win2k3 accepts "")
400 encode_pw_buffer(password_buf.data, password, STR_UNICODE);
401 creds_arcfour_crypt(creds, password_buf.data, 516);
403 memcpy(r.in.new_password.data, password_buf.data, 512);
404 r.in.new_password.length = IVAL(password_buf.data, 512);
406 printf("Testing ServerPasswordSet2 on machine account\n");
407 printf("Changing machine account password to '%s'\n", password);
409 creds_client_authenticator(creds, &r.in.credential);
411 status = dcerpc_netr_ServerPasswordSet2(p, mem_ctx, &r);
412 if (!NT_STATUS_IS_OK(status)) {
413 printf("ServerPasswordSet2 - %s\n", nt_errstr(status));
417 if (!creds_client_check(creds, &r.out.return_authenticator.cred)) {
418 printf("Credential chaining failed\n");
421 machine_password = password;
424 if (!test_SetupCredentials(p, mem_ctx, TEST_MACHINE_NAME, machine_password, &creds)) {
425 printf("ServerPasswordSet failed to actually change the password\n");
429 /* now try a random password */
430 password = generate_random_str(mem_ctx, 8);
431 encode_pw_buffer(password_buf.data, password, STR_UNICODE);
432 creds_arcfour_crypt(creds, password_buf.data, 516);
434 memcpy(r.in.new_password.data, password_buf.data, 512);
435 r.in.new_password.length = IVAL(password_buf.data, 512);
437 printf("Testing second ServerPasswordSet2 on machine account\n");
438 printf("Changing machine account password to '%s'\n", password);
440 creds_client_authenticator(creds, &r.in.credential);
442 status = dcerpc_netr_ServerPasswordSet2(p, mem_ctx, &r);
443 if (!NT_STATUS_IS_OK(status)) {
444 printf("ServerPasswordSet2 (2) - %s\n", nt_errstr(status));
448 if (!creds_client_check(creds, &r.out.return_authenticator.cred)) {
449 printf("Credential chaining failed\n");
452 /* by changing the machine password twice we test the
453 credentials chaining fully, and we verify that the server
454 allows the password to be set to the same value twice in a
455 row (match win2k3) */
456 printf("Testing a second ServerPasswordSet2 on machine account\n");
457 printf("Changing machine account password to '%s' (same as previous run)\n", password);
459 creds_client_authenticator(creds, &r.in.credential);
461 status = dcerpc_netr_ServerPasswordSet2(p, mem_ctx, &r);
462 if (!NT_STATUS_IS_OK(status)) {
463 printf("ServerPasswordSet (3) - %s\n", nt_errstr(status));
467 if (!creds_client_check(creds, &r.out.return_authenticator.cred)) {
468 printf("Credential chaining failed\n");
471 machine_password = password;
473 if (!test_SetupCredentials(p, mem_ctx, TEST_MACHINE_NAME, machine_password, &creds)) {
474 printf("ServerPasswordSet failed to actually change the password\n");
482 try a netlogon SamLogon
484 BOOL test_netlogon_ops(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
485 struct cli_credentials *credentials,
486 struct creds_CredentialState *creds)
489 struct netr_LogonSamLogon r;
490 struct netr_Authenticator auth, auth2;
491 struct netr_NetworkInfo ninfo;
492 DATA_BLOB names_blob, chal, lm_resp, nt_resp;
495 int flags = CLI_CRED_NTLM_AUTH;
496 if (lp_client_lanman_auth()) {
497 flags |= CLI_CRED_LANMAN_AUTH;
500 if (lp_client_ntlmv2_auth()) {
501 flags |= CLI_CRED_NTLMv2_AUTH;
504 cli_credentials_get_ntlm_username_domain(cmdline_credentials, mem_ctx,
505 &ninfo.identity_info.account_name.string,
506 &ninfo.identity_info.domain_name.string);
508 generate_random_buffer(ninfo.challenge,
509 sizeof(ninfo.challenge));
510 chal = data_blob_const(ninfo.challenge,
511 sizeof(ninfo.challenge));
513 names_blob = NTLMv2_generate_names_blob(mem_ctx, cli_credentials_get_workstation(credentials),
514 cli_credentials_get_domain(credentials));
516 status = cli_credentials_get_ntlm_response(cmdline_credentials, mem_ctx,
522 if (!NT_STATUS_IS_OK(status)) {
523 printf("cli_credentials_get_ntlm_response failed: %s\n",
528 ninfo.lm.data = lm_resp.data;
529 ninfo.lm.length = lm_resp.length;
531 ninfo.nt.data = nt_resp.data;
532 ninfo.nt.length = nt_resp.length;
534 ninfo.identity_info.parameter_control = 0;
535 ninfo.identity_info.logon_id_low = 0;
536 ninfo.identity_info.logon_id_high = 0;
537 ninfo.identity_info.workstation.string = cli_credentials_get_workstation(credentials);
539 r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
540 r.in.workstation = cli_credentials_get_workstation(credentials);
541 r.in.credential = &auth;
542 r.in.return_authenticator = &auth2;
543 r.in.logon_level = 2;
544 r.in.logon.network = &ninfo;
546 printf("Testing LogonSamLogon with name %s\n", ninfo.identity_info.account_name.string);
550 creds_client_authenticator(creds, &auth);
552 r.in.validation_level = i;
554 status = dcerpc_netr_LogonSamLogon(p, mem_ctx, &r);
555 if (!NT_STATUS_IS_OK(status)) {
556 printf("LogonSamLogon failed: %s\n",
561 if (!creds_client_check(creds, &r.out.return_authenticator->cred)) {
562 printf("Credential chaining failed\n");
568 r.in.credential = NULL;
572 r.in.validation_level = i;
574 printf("Testing SamLogon with validation level %d\n", i);
576 status = dcerpc_netr_LogonSamLogon(p, mem_ctx, &r);
577 if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
578 printf("LogonSamLogon expected INVALID_PARAMETER, got: %s\n", nt_errstr(status));
589 try a netlogon SamLogon
591 static BOOL test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
592 struct cli_credentials *credentials)
594 struct creds_CredentialState *creds;
596 if (!test_SetupCredentials(p, mem_ctx, cli_credentials_get_workstation(credentials),
597 cli_credentials_get_password(credentials), &creds)) {
601 return test_netlogon_ops(p, mem_ctx, credentials, creds);
604 /* we remember the sequence numbers so we can easily do a DatabaseDelta */
605 static uint64_t sequence_nums[3];
608 try a netlogon DatabaseSync
610 static BOOL test_DatabaseSync(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
613 struct netr_DatabaseSync r;
614 struct creds_CredentialState *creds;
615 const uint32_t database_ids[] = {SAM_DATABASE_DOMAIN, SAM_DATABASE_BUILTIN, SAM_DATABASE_PRIVS};
619 if (!test_SetupCredentials(p, mem_ctx, TEST_MACHINE_NAME, machine_password, &creds)) {
623 r.in.logon_server = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
624 r.in.computername = TEST_MACHINE_NAME;
625 r.in.preferredmaximumlength = (uint32_t)-1;
626 ZERO_STRUCT(r.in.return_authenticator);
628 for (i=0;i<ARRAY_SIZE(database_ids);i++) {
629 r.in.sync_context = 0;
630 r.in.database_id = database_ids[i];
632 printf("Testing DatabaseSync of id %d\n", r.in.database_id);
635 creds_client_authenticator(creds, &r.in.credential);
637 status = dcerpc_netr_DatabaseSync(p, mem_ctx, &r);
638 if (!NT_STATUS_IS_OK(status) &&
639 !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
640 printf("DatabaseSync - %s\n", nt_errstr(status));
645 if (!creds_client_check(creds, &r.out.return_authenticator.cred)) {
646 printf("Credential chaining failed\n");
649 r.in.sync_context = r.out.sync_context;
651 if (r.out.delta_enum_array &&
652 r.out.delta_enum_array->num_deltas > 0 &&
653 r.out.delta_enum_array->delta_enum[0].delta_type == NETR_DELTA_DOMAIN &&
654 r.out.delta_enum_array->delta_enum[0].delta_union.domain) {
655 sequence_nums[r.in.database_id] =
656 r.out.delta_enum_array->delta_enum[0].delta_union.domain->sequence_num;
657 printf("\tsequence_nums[%d]=%llu\n",
659 (unsigned long long)sequence_nums[r.in.database_id]);
661 } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
669 try a netlogon DatabaseDeltas
671 static BOOL test_DatabaseDeltas(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
674 struct netr_DatabaseDeltas r;
675 struct creds_CredentialState *creds;
676 const uint32_t database_ids[] = {0, 1, 2};
680 if (!test_SetupCredentials(p, mem_ctx, TEST_MACHINE_NAME, machine_password, &creds)) {
684 r.in.logon_server = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
685 r.in.computername = TEST_MACHINE_NAME;
686 r.in.preferredmaximumlength = (uint32_t)-1;
687 ZERO_STRUCT(r.in.return_authenticator);
689 for (i=0;i<ARRAY_SIZE(database_ids);i++) {
690 r.in.database_id = database_ids[i];
691 r.in.sequence_num = sequence_nums[r.in.database_id];
693 if (r.in.sequence_num == 0) continue;
695 r.in.sequence_num -= 1;
698 printf("Testing DatabaseDeltas of id %d at %llu\n",
699 r.in.database_id, (unsigned long long)r.in.sequence_num);
702 creds_client_authenticator(creds, &r.in.credential);
704 status = dcerpc_netr_DatabaseDeltas(p, mem_ctx, &r);
705 if (NT_STATUS_EQUAL(status,
706 NT_STATUS_SYNCHRONIZATION_REQUIRED)) {
707 printf("no considering %s to be an error\n",
711 if (!NT_STATUS_IS_OK(status) &&
712 !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
713 printf("DatabaseDeltas - %s\n", nt_errstr(status));
718 if (!creds_client_check(creds, &r.out.return_authenticator.cred)) {
719 printf("Credential chaining failed\n");
723 } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
731 try a netlogon AccountDeltas
733 static BOOL test_AccountDeltas(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
736 struct netr_AccountDeltas r;
737 struct creds_CredentialState *creds;
740 if (!test_SetupCredentials(p, mem_ctx, TEST_MACHINE_NAME, machine_password, &creds)) {
744 r.in.logon_server = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
745 r.in.computername = TEST_MACHINE_NAME;
746 ZERO_STRUCT(r.in.return_authenticator);
747 creds_client_authenticator(creds, &r.in.credential);
748 ZERO_STRUCT(r.in.uas);
753 printf("Testing AccountDeltas\n");
755 /* w2k3 returns "NOT IMPLEMENTED" for this call */
756 status = dcerpc_netr_AccountDeltas(p, mem_ctx, &r);
757 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
758 printf("AccountDeltas - %s\n", nt_errstr(status));
766 try a netlogon AccountSync
768 static BOOL test_AccountSync(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
771 struct netr_AccountSync r;
772 struct creds_CredentialState *creds;
775 if (!test_SetupCredentials(p, mem_ctx, TEST_MACHINE_NAME, machine_password, &creds)) {
779 r.in.logon_server = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
780 r.in.computername = TEST_MACHINE_NAME;
781 ZERO_STRUCT(r.in.return_authenticator);
782 creds_client_authenticator(creds, &r.in.credential);
783 ZERO_STRUCT(r.in.recordid);
788 printf("Testing AccountSync\n");
790 /* w2k3 returns "NOT IMPLEMENTED" for this call */
791 status = dcerpc_netr_AccountSync(p, mem_ctx, &r);
792 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
793 printf("AccountSync - %s\n", nt_errstr(status));
801 try a netlogon GetDcName
803 static BOOL test_GetDcName(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
806 struct netr_GetDcName r;
808 r.in.logon_server = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
809 r.in.domainname = lp_workgroup();
811 printf("Testing GetDcName\n");
813 status = dcerpc_netr_GetDcName(p, mem_ctx, &r);
814 if (!NT_STATUS_IS_OK(status)) {
815 printf("GetDcName - %s\n", nt_errstr(status));
819 printf("\tDC is at '%s'\n", r.out.dcname);
825 try a netlogon LogonControl
827 static BOOL test_LogonControl(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
830 struct netr_LogonControl r;
834 r.in.logon_server = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
835 r.in.function_code = 1;
840 printf("Testing LogonControl level %d\n", i);
842 status = dcerpc_netr_LogonControl(p, mem_ctx, &r);
843 if (!NT_STATUS_IS_OK(status)) {
844 printf("LogonControl - %s\n", nt_errstr(status));
854 try a netlogon GetAnyDCName
856 static BOOL test_GetAnyDCName(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
859 struct netr_GetAnyDCName r;
861 r.in.logon_server = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
862 r.in.domainname = lp_workgroup();
864 printf("Testing GetAnyDCName\n");
866 status = dcerpc_netr_GetAnyDCName(p, mem_ctx, &r);
867 if (!NT_STATUS_IS_OK(status)) {
868 printf("GetAnyDCName - %s\n", nt_errstr(status));
873 printf("\tDC is at '%s'\n", r.out.dcname);
881 try a netlogon LogonControl2
883 static BOOL test_LogonControl2(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
886 struct netr_LogonControl2 r;
890 r.in.logon_server = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
892 r.in.function_code = NETLOGON_CONTROL_REDISCOVER;
893 r.in.data.domain = lp_workgroup();
898 printf("Testing LogonControl2 level %d function %d\n",
899 i, r.in.function_code);
901 status = dcerpc_netr_LogonControl2(p, mem_ctx, &r);
902 if (!NT_STATUS_IS_OK(status)) {
903 printf("LogonControl - %s\n", nt_errstr(status));
908 r.in.function_code = NETLOGON_CONTROL_TC_QUERY;
909 r.in.data.domain = lp_workgroup();
914 printf("Testing LogonControl2 level %d function %d\n",
915 i, r.in.function_code);
917 status = dcerpc_netr_LogonControl2(p, mem_ctx, &r);
918 if (!NT_STATUS_IS_OK(status)) {
919 printf("LogonControl - %s\n", nt_errstr(status));
924 r.in.function_code = NETLOGON_CONTROL_TRANSPORT_NOTIFY;
925 r.in.data.domain = lp_workgroup();
930 printf("Testing LogonControl2 level %d function %d\n",
931 i, r.in.function_code);
933 status = dcerpc_netr_LogonControl2(p, mem_ctx, &r);
934 if (!NT_STATUS_IS_OK(status)) {
935 printf("LogonControl - %s\n", nt_errstr(status));
940 r.in.function_code = NETLOGON_CONTROL_SET_DBFLAG;
941 r.in.data.debug_level = ~0;
946 printf("Testing LogonControl2 level %d function %d\n",
947 i, r.in.function_code);
949 status = dcerpc_netr_LogonControl2(p, mem_ctx, &r);
950 if (!NT_STATUS_IS_OK(status)) {
951 printf("LogonControl - %s\n", nt_errstr(status));
960 try a netlogon DatabaseSync2
962 static BOOL test_DatabaseSync2(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
965 struct netr_DatabaseSync2 r;
966 struct creds_CredentialState *creds;
967 const uint32_t database_ids[] = {0, 1, 2};
971 if (!test_SetupCredentials2(p, mem_ctx, NETLOGON_NEG_AUTH2_FLAGS,
972 TEST_MACHINE_NAME, machine_password,
973 SEC_CHAN_BDC, &creds)) {
977 r.in.logon_server = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
978 r.in.computername = TEST_MACHINE_NAME;
979 r.in.preferredmaximumlength = (uint32_t)-1;
980 ZERO_STRUCT(r.in.return_authenticator);
982 for (i=0;i<ARRAY_SIZE(database_ids);i++) {
983 r.in.sync_context = 0;
984 r.in.database_id = database_ids[i];
985 r.in.restart_state = 0;
987 printf("Testing DatabaseSync2 of id %d\n", r.in.database_id);
990 creds_client_authenticator(creds, &r.in.credential);
992 status = dcerpc_netr_DatabaseSync2(p, mem_ctx, &r);
993 if (!NT_STATUS_IS_OK(status) &&
994 !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
995 printf("DatabaseSync2 - %s\n", nt_errstr(status));
1000 if (!creds_client_check(creds, &r.out.return_authenticator.cred)) {
1001 printf("Credential chaining failed\n");
1004 r.in.sync_context = r.out.sync_context;
1005 } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
1013 try a netlogon LogonControl2Ex
1015 static BOOL test_LogonControl2Ex(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
1018 struct netr_LogonControl2Ex r;
1022 r.in.logon_server = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
1024 r.in.function_code = NETLOGON_CONTROL_REDISCOVER;
1025 r.in.data.domain = lp_workgroup();
1030 printf("Testing LogonControl2Ex level %d function %d\n",
1031 i, r.in.function_code);
1033 status = dcerpc_netr_LogonControl2Ex(p, mem_ctx, &r);
1034 if (!NT_STATUS_IS_OK(status)) {
1035 printf("LogonControl - %s\n", nt_errstr(status));
1040 r.in.function_code = NETLOGON_CONTROL_TC_QUERY;
1041 r.in.data.domain = lp_workgroup();
1046 printf("Testing LogonControl2Ex level %d function %d\n",
1047 i, r.in.function_code);
1049 status = dcerpc_netr_LogonControl2Ex(p, mem_ctx, &r);
1050 if (!NT_STATUS_IS_OK(status)) {
1051 printf("LogonControl - %s\n", nt_errstr(status));
1056 r.in.function_code = NETLOGON_CONTROL_TRANSPORT_NOTIFY;
1057 r.in.data.domain = lp_workgroup();
1062 printf("Testing LogonControl2Ex level %d function %d\n",
1063 i, r.in.function_code);
1065 status = dcerpc_netr_LogonControl2Ex(p, mem_ctx, &r);
1066 if (!NT_STATUS_IS_OK(status)) {
1067 printf("LogonControl - %s\n", nt_errstr(status));
1072 r.in.function_code = NETLOGON_CONTROL_SET_DBFLAG;
1073 r.in.data.debug_level = ~0;
1078 printf("Testing LogonControl2Ex level %d function %d\n",
1079 i, r.in.function_code);
1081 status = dcerpc_netr_LogonControl2Ex(p, mem_ctx, &r);
1082 if (!NT_STATUS_IS_OK(status)) {
1083 printf("LogonControl - %s\n", nt_errstr(status));
1093 try a netlogon netr_DsrEnumerateDomainTrusts
1095 static BOOL test_DsrEnumerateDomainTrusts(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
1098 struct netr_DsrEnumerateDomainTrusts r;
1100 r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
1101 r.in.trust_flags = 0x3f;
1103 printf("Testing netr_DsrEnumerateDomainTrusts\n");
1105 status = dcerpc_netr_DsrEnumerateDomainTrusts(p, mem_ctx, &r);
1106 if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(r.out.result)) {
1107 printf("netr_DsrEnumerateDomainTrusts - %s/%s\n",
1108 nt_errstr(status), win_errstr(r.out.result));
1115 static BOOL test_netr_DsRGetSiteName(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
1116 const char *computer_name,
1117 const char *expected_site)
1120 struct netr_DsRGetSiteName r;
1123 r.in.computer_name = computer_name;
1124 printf("Testing netr_DsRGetSiteName\n");
1126 status = dcerpc_netr_DsRGetSiteName(p, mem_ctx, &r);
1127 if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(r.out.result)) {
1128 printf("netr_DsRGetSiteName - %s/%s\n",
1129 nt_errstr(status), win_errstr(r.out.result));
1132 if (strcmp(expected_site, r.out.site) != 0) {
1133 printf("netr_DsRGetSiteName - unexpected result: %s, expected %s\n",
1134 r.out.site, expected_site);
1143 try a netlogon netr_DsRGetDCName
1145 static BOOL test_netr_DsRGetDCName(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
1148 struct netr_DsRGetDCName r;
1151 r.in.server_unc = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
1152 r.in.domain_name = talloc_asprintf(mem_ctx, "%s", lp_realm());
1153 r.in.domain_guid = NULL;
1154 r.in.site_guid = NULL;
1155 r.in.flags = 0x40000000;
1157 printf("Testing netr_DsRGetDCName\n");
1159 status = dcerpc_netr_DsRGetDCName(p, mem_ctx, &r);
1160 if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(r.out.result)) {
1161 printf("netr_DsRGetDCName - %s/%s\n",
1162 nt_errstr(status), win_errstr(r.out.result));
1165 ret = test_netr_DsRGetSiteName(p, mem_ctx,
1167 r.out.info->dc_site_name);
1174 try a netlogon netr_DsRGetDCNameEx
1176 static BOOL test_netr_DsRGetDCNameEx(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
1179 struct netr_DsRGetDCNameEx r;
1182 r.in.server_unc = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
1183 r.in.domain_name = talloc_asprintf(mem_ctx, "%s", lp_realm());
1184 r.in.domain_guid = NULL;
1185 r.in.site_name = NULL;
1186 r.in.flags = 0x40000000;
1188 printf("Testing netr_DsRGetDCNameEx\n");
1190 status = dcerpc_netr_DsRGetDCNameEx(p, mem_ctx, &r);
1191 if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(r.out.result)) {
1192 printf("netr_DsRGetDCNameEx - %s/%s\n",
1193 nt_errstr(status), win_errstr(r.out.result));
1196 ret = test_netr_DsRGetSiteName(p, mem_ctx,
1198 r.out.info->dc_site_name);
1205 try a netlogon netr_DsRGetDCNameEx2
1207 static BOOL test_netr_DsRGetDCNameEx2(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
1210 struct netr_DsRGetDCNameEx2 r;
1213 r.in.server_unc = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
1214 r.in.client_account = NULL;
1215 r.in.mask = 0x00000000;
1216 r.in.domain_name = talloc_asprintf(mem_ctx, "%s", lp_realm());
1217 r.in.domain_guid = NULL;
1218 r.in.site_name = NULL;
1219 r.in.flags = 0x40000000;
1221 printf("Testing netr_DsRGetDCNameEx2 without client account\n");
1223 status = dcerpc_netr_DsRGetDCNameEx2(p, mem_ctx, &r);
1224 if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(r.out.result)) {
1225 printf("netr_DsRGetDCNameEx2 - %s/%s\n",
1226 nt_errstr(status), win_errstr(r.out.result));
1230 printf("Testing netr_DsRGetDCNameEx2 with client acount\n");
1231 r.in.client_account = TEST_MACHINE_NAME"$";
1232 r.in.mask = 0x00002000;
1233 r.in.flags = 0x80000000;
1235 status = dcerpc_netr_DsRGetDCNameEx2(p, mem_ctx, &r);
1236 if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(r.out.result)) {
1237 printf("netr_DsRGetDCNameEx2 - %s/%s\n",
1238 nt_errstr(status), win_errstr(r.out.result));
1241 ret = test_netr_DsRGetSiteName(p, mem_ctx,
1243 r.out.info->dc_site_name);
1249 static BOOL test_GetDomainInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
1252 struct netr_LogonGetDomainInfo r;
1253 struct netr_DomainQuery1 q1;
1254 struct netr_Authenticator a;
1255 struct creds_CredentialState *creds;
1257 if (!test_SetupCredentials3(p, mem_ctx, NETLOGON_NEG_AUTH2_ADS_FLAGS,
1258 TEST_MACHINE_NAME, machine_password, &creds)) {
1264 creds_client_authenticator(creds, &a);
1266 r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
1267 r.in.computer_name = TEST_MACHINE_NAME;
1269 r.in.credential = &a;
1270 r.in.return_authenticator = &a;
1271 r.out.return_authenticator = &a;
1273 r.in.query.query1 = &q1;
1276 /* this should really be the fully qualified name */
1277 q1.workstation_domain = TEST_MACHINE_NAME;
1278 q1.workstation_site = "Default-First-Site-Name";
1279 q1.blob2.length = 0;
1281 q1.blob2.data = NULL;
1282 q1.product.string = "product string";
1284 printf("Testing netr_LogonGetDomainInfo\n");
1286 status = dcerpc_netr_LogonGetDomainInfo(p, mem_ctx, &r);
1287 if (!NT_STATUS_IS_OK(status)) {
1288 printf("netr_LogonGetDomainInfo - %s\n", nt_errstr(status));
1292 if (!creds_client_check(creds, &a.cred)) {
1293 printf("Credential chaining failed\n");
1301 static void async_callback(struct rpc_request *req)
1303 int *counter = req->async.private;
1304 if (NT_STATUS_IS_OK(req->status)) {
1309 static BOOL test_GetDomainInfo_async(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
1312 struct netr_LogonGetDomainInfo r;
1313 struct netr_DomainQuery1 q1;
1314 struct netr_Authenticator a;
1315 #define ASYNC_COUNT 100
1316 struct creds_CredentialState *creds;
1317 struct creds_CredentialState *creds_async[ASYNC_COUNT];
1318 struct rpc_request *req[ASYNC_COUNT];
1320 int *async_counter = talloc(mem_ctx, int);
1322 if (!lp_parm_bool(-1, "torture", "dangerous", False)) {
1323 printf("test_GetDomainInfo_async disabled - enable dangerous tests to use\n");
1327 if (!test_SetupCredentials3(p, mem_ctx, NETLOGON_NEG_AUTH2_ADS_FLAGS,
1328 TEST_MACHINE_NAME, machine_password, &creds)) {
1333 r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
1334 r.in.computer_name = TEST_MACHINE_NAME;
1336 r.in.credential = &a;
1337 r.in.return_authenticator = &a;
1338 r.out.return_authenticator = &a;
1340 r.in.query.query1 = &q1;
1343 /* this should really be the fully qualified name */
1344 q1.workstation_domain = TEST_MACHINE_NAME;
1345 q1.workstation_site = "Default-First-Site-Name";
1346 q1.blob2.length = 0;
1348 q1.blob2.data = NULL;
1349 q1.product.string = "product string";
1351 printf("Testing netr_LogonGetDomainInfo - async count %d\n", ASYNC_COUNT);
1355 for (i=0;i<ASYNC_COUNT;i++) {
1356 creds_client_authenticator(creds, &a);
1358 creds_async[i] = talloc_memdup(creds, creds, sizeof(*creds));
1359 req[i] = dcerpc_netr_LogonGetDomainInfo_send(p, mem_ctx, &r);
1361 req[i]->async.callback = async_callback;
1362 req[i]->async.private = async_counter;
1364 /* even with this flush per request a w2k3 server seems to
1365 clag with multiple outstanding requests. bleergh. */
1366 if (event_loop_once(dcerpc_event_context(p)) != 0) {
1371 for (i=0;i<ASYNC_COUNT;i++) {
1372 status = dcerpc_ndr_request_recv(req[i]);
1373 if (!NT_STATUS_IS_OK(status) || !NT_STATUS_IS_OK(r.out.result)) {
1374 printf("netr_LogonGetDomainInfo_async(%d) - %s/%s\n",
1375 i, nt_errstr(status), nt_errstr(r.out.result));
1379 if (!creds_client_check(creds_async[i], &a.cred)) {
1380 printf("Credential chaining failed at async %d\n", i);
1385 printf("Testing netr_LogonGetDomainInfo - async count %d OK\n", *async_counter);
1387 return (*async_counter) == ASYNC_COUNT;
1390 static BOOL test_ManyGetDCName(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
1393 struct dcerpc_binding *b;
1394 struct dcerpc_pipe *p2;
1395 struct lsa_ObjectAttribute attr;
1396 struct lsa_QosInfo qos;
1397 struct lsa_OpenPolicy2 o;
1398 struct policy_handle lsa_handle;
1399 struct lsa_DomainList domains;
1401 struct lsa_EnumTrustDom t;
1402 uint32_t resume_handle = 0;
1403 struct netr_GetAnyDCName d;
1408 if (p->conn->transport.transport != NCACN_NP) {
1412 printf("Torturing GetDCName\n");
1414 status = dcerpc_parse_binding(mem_ctx, p->conn->binding_string, &b);
1415 if (!NT_STATUS_IS_OK(status)) {
1416 printf("Failed to parse dcerpc binding '%s'\n", p->conn->binding_string);
1420 status = dcerpc_secondary_connection(p, &p2, b);
1421 if (!NT_STATUS_IS_OK(status)) {
1422 printf("Failed to create secondary connection\n");
1426 status = dcerpc_bind_auth_none(p2, DCERPC_LSARPC_UUID,
1427 DCERPC_LSARPC_VERSION);
1428 if (!NT_STATUS_IS_OK(status)) {
1429 printf("Failed to create bind on secondary connection\n");
1434 qos.impersonation_level = 2;
1435 qos.context_mode = 1;
1436 qos.effective_only = 0;
1439 attr.root_dir = NULL;
1440 attr.object_name = NULL;
1441 attr.attributes = 0;
1442 attr.sec_desc = NULL;
1443 attr.sec_qos = &qos;
1445 o.in.system_name = "\\";
1447 o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
1448 o.out.handle = &lsa_handle;
1450 status = dcerpc_lsa_OpenPolicy2(p2, mem_ctx, &o);
1451 if (!NT_STATUS_IS_OK(status)) {
1452 printf("OpenPolicy2 failed - %s\n", nt_errstr(status));
1456 t.in.handle = &lsa_handle;
1457 t.in.resume_handle = &resume_handle;
1458 t.in.max_size = 1000;
1459 t.out.domains = &domains;
1460 t.out.resume_handle = &resume_handle;
1462 status = dcerpc_lsa_EnumTrustDom(p2, mem_ctx, &t);
1464 if ((!NT_STATUS_IS_OK(status) &&
1465 (!NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES)))) {
1466 printf("Could not list domains\n");
1472 d.in.logon_server = talloc_asprintf(mem_ctx, "\\\\%s",
1473 dcerpc_server_name(p));
1475 for (i=0; i<domains.count * 4; i++) {
1476 struct lsa_DomainInformation *info =
1477 &domains.domains[rand()%domains.count];
1479 d.in.domainname = info->name.string;
1481 status = dcerpc_netr_GetAnyDCName(p, mem_ctx, &d);
1482 if (!NT_STATUS_IS_OK(status)) {
1483 printf("GetAnyDCName - %s\n", nt_errstr(status));
1487 printf("\tDC for domain %s is %s\n", info->name.string,
1488 d.out.dcname ? d.out.dcname : "unknown");
1495 BOOL torture_rpc_netlogon(void)
1498 struct dcerpc_pipe *p;
1499 TALLOC_CTX *mem_ctx;
1501 struct test_join *join_ctx;
1502 struct cli_credentials *machine_credentials;
1504 mem_ctx = talloc_init("torture_rpc_netlogon");
1506 join_ctx = torture_join_domain(TEST_MACHINE_NAME, ACB_SVRTRUST,
1507 &machine_credentials);
1509 talloc_free(mem_ctx);
1510 printf("Failed to join as BDC\n");
1514 machine_password = cli_credentials_get_password(machine_credentials);
1516 status = torture_rpc_connection(mem_ctx, &p,
1517 DCERPC_NETLOGON_NAME,
1518 DCERPC_NETLOGON_UUID,
1519 DCERPC_NETLOGON_VERSION);
1520 if (!NT_STATUS_IS_OK(status)) {
1521 talloc_free(mem_ctx);
1525 ret &= test_LogonUasLogon(p, mem_ctx);
1526 ret &= test_LogonUasLogoff(p, mem_ctx);
1527 ret &= test_SamLogon(p, mem_ctx, machine_credentials);
1528 ret &= test_SetPassword(p, mem_ctx);
1529 ret &= test_SetPassword2(p, mem_ctx);
1530 ret &= test_GetDomainInfo(p, mem_ctx);
1531 ret &= test_DatabaseSync(p, mem_ctx);
1532 ret &= test_DatabaseDeltas(p, mem_ctx);
1533 ret &= test_AccountDeltas(p, mem_ctx);
1534 ret &= test_AccountSync(p, mem_ctx);
1535 ret &= test_GetDcName(p, mem_ctx);
1536 ret &= test_ManyGetDCName(p, mem_ctx);
1537 ret &= test_LogonControl(p, mem_ctx);
1538 ret &= test_GetAnyDCName(p, mem_ctx);
1539 ret &= test_LogonControl2(p, mem_ctx);
1540 ret &= test_DatabaseSync2(p, mem_ctx);
1541 ret &= test_LogonControl2Ex(p, mem_ctx);
1542 ret &= test_DsrEnumerateDomainTrusts(p, mem_ctx);
1543 ret &= test_GetDomainInfo_async(p, mem_ctx);
1544 ret &= test_netr_DsRGetDCName(p, mem_ctx);
1545 ret &= test_netr_DsRGetDCNameEx(p, mem_ctx);
1546 ret &= test_netr_DsRGetDCNameEx2(p, mem_ctx);
1548 talloc_free(mem_ctx);
1550 torture_leave_domain(join_ctx);