/** * open a rpc connection to a specific transport */ NTSTATUS torture_rpc_connection_transport(struct torture_context *tctx, struct dcerpc_pipe **p, const struct ndr_interface_table *table, enum dcerpc_transport_t transport, uint32_t assoc_group_id, uint32_t extra_flags) { NTSTATUS status; struct dcerpc_binding *binding; *p = NULL; status = torture_rpc_binding(tctx, &binding); if (!NT_STATUS_IS_OK(status)) { return status; } status = dcerpc_binding_set_transport(binding, transport); if (!NT_STATUS_IS_OK(status)) { return status; } status = dcerpc_binding_set_assoc_group_id(binding, assoc_group_id); if (!NT_STATUS_IS_OK(status)) { return status; } status = dcerpc_binding_set_flags(binding, extra_flags, 0); if (!NT_STATUS_IS_OK(status)) { return status; } status = dcerpc_pipe_connect_b(tctx, p, binding, table, popt_get_cmdline_credentials(), tctx->ev, tctx->lp_ctx); if (!NT_STATUS_IS_OK(status)) { *p = NULL; return status; } return NT_STATUS_OK; }
/* test a schannel connection with the given flags */ static bool test_schannel(struct torture_context *tctx, uint16_t acct_flags, uint32_t dcerpc_flags, int i) { struct test_join *join_ctx; NTSTATUS status; const char *binding = torture_setting_string(tctx, "binding", NULL); struct dcerpc_binding *b; struct dcerpc_pipe *p = NULL; struct dcerpc_pipe *p_netlogon = NULL; struct dcerpc_pipe *p_netlogon2 = NULL; struct dcerpc_pipe *p_netlogon3 = NULL; struct dcerpc_pipe *p_samr2 = NULL; struct dcerpc_pipe *p_lsa = NULL; struct netlogon_creds_CredentialState *creds; struct cli_credentials *credentials; enum dcerpc_transport_t transport; join_ctx = torture_join_domain(tctx, talloc_asprintf(tctx, "%s%d", TEST_MACHINE_NAME, i), acct_flags, &credentials); torture_assert(tctx, join_ctx != NULL, "Failed to join domain"); status = dcerpc_parse_binding(tctx, binding, &b); torture_assert_ntstatus_ok(tctx, status, "Bad binding string"); status = dcerpc_binding_set_flags(b, dcerpc_flags, DCERPC_AUTH_OPTIONS); torture_assert_ntstatus_ok(tctx, status, "set flags"); status = dcerpc_pipe_connect_b(tctx, &p, b, &ndr_table_samr, credentials, tctx->ev, tctx->lp_ctx); torture_assert_ntstatus_ok(tctx, status, "Failed to connect to samr with schannel"); torture_assert(tctx, test_samr_ops(tctx, p->binding_handle), "Failed to process schannel secured SAMR ops"); /* Also test that when we connect to the netlogon pipe, that * the credentials we setup on the first pipe are valid for * the second */ /* Swap the binding details from SAMR to NETLOGON */ status = dcerpc_epm_map_binding(tctx, b, &ndr_table_netlogon, tctx->ev, tctx->lp_ctx); torture_assert_ntstatus_ok(tctx, status, "epm map"); status = dcerpc_binding_set_flags(b, dcerpc_flags, DCERPC_AUTH_OPTIONS); torture_assert_ntstatus_ok(tctx, status, "set flags"); status = dcerpc_secondary_auth_connection(p, b, &ndr_table_netlogon, credentials, tctx->lp_ctx, tctx, &p_netlogon); torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection"); creds = cli_credentials_get_netlogon_creds(credentials); torture_assert(tctx, (creds != NULL), "schannel creds"); /* checks the capabilities */ torture_assert(tctx, test_netlogon_capabilities(p_netlogon, tctx, credentials, creds), "Failed to process schannel secured capability ops (on fresh connection)"); /* do a couple of logins */ torture_assert(tctx, test_netlogon_ops(p_netlogon, tctx, credentials, creds), "Failed to process schannel secured NETLOGON ops"); torture_assert(tctx, test_netlogon_ex_ops(p_netlogon, tctx, credentials, creds), "Failed to process schannel secured NETLOGON EX ops"); /* we *MUST* use ncacn_np for openpolicy etc. */ transport = dcerpc_binding_get_transport(b); status = dcerpc_binding_set_transport(b, NCACN_NP); torture_assert_ntstatus_ok(tctx, status, "set transport"); /* Swap the binding details from SAMR to LSARPC */ status = dcerpc_epm_map_binding(tctx, b, &ndr_table_lsarpc, tctx->ev, tctx->lp_ctx); torture_assert_ntstatus_ok(tctx, status, "epm map"); torture_assert_ntstatus_ok(tctx, dcerpc_pipe_connect_b(tctx, &p_lsa, b, &ndr_table_lsarpc, credentials, tctx->ev, tctx->lp_ctx), "failed to connect lsarpc with schannel"); torture_assert(tctx, test_lsa_ops(tctx, p_lsa), "Failed to process schannel secured LSA ops"); talloc_free(p_lsa); p_lsa = NULL; /* we *MUST* use ncacn_ip_tcp for lookupsids3/lookupnames4 */ status = dcerpc_binding_set_transport(b, NCACN_IP_TCP); torture_assert_ntstatus_ok(tctx, status, "set transport"); torture_assert_ntstatus_ok(tctx, dcerpc_epm_map_binding(tctx, b, &ndr_table_lsarpc, tctx->ev, tctx->lp_ctx), "failed to call epm map"); torture_assert_ntstatus_ok(tctx, dcerpc_pipe_connect_b(tctx, &p_lsa, b, &ndr_table_lsarpc, credentials, tctx->ev, tctx->lp_ctx), "failed to connect lsarpc with schannel"); torture_assert(tctx, test_many_LookupSids(p_lsa, tctx, NULL), "LsaLookupSids3 failed!\n"); status = dcerpc_binding_set_transport(b, transport); torture_assert_ntstatus_ok(tctx, status, "set transport"); /* Drop the socket, we want to start from scratch */ talloc_free(p); p = NULL; /* Now see what we are still allowed to do */ status = dcerpc_parse_binding(tctx, binding, &b); torture_assert_ntstatus_ok(tctx, status, "Bad binding string"); status = dcerpc_binding_set_flags(b, dcerpc_flags, DCERPC_AUTH_OPTIONS); torture_assert_ntstatus_ok(tctx, status, "set flags"); status = dcerpc_pipe_connect_b(tctx, &p_samr2, b, &ndr_table_samr, credentials, tctx->ev, tctx->lp_ctx); torture_assert_ntstatus_ok(tctx, status, "Failed to connect with schannel"); /* do a some SAMR operations. We have *not* done a new serverauthenticate */ torture_assert (tctx, test_samr_ops(tctx, p_samr2->binding_handle), "Failed to process schannel secured SAMR ops (on fresh connection)"); /* Swap the binding details from SAMR to NETLOGON */ status = dcerpc_epm_map_binding(tctx, b, &ndr_table_netlogon, tctx->ev, tctx->lp_ctx); torture_assert_ntstatus_ok(tctx, status, "epm"); status = dcerpc_binding_set_flags(b, dcerpc_flags, DCERPC_AUTH_OPTIONS); torture_assert_ntstatus_ok(tctx, status, "set flags"); status = dcerpc_secondary_auth_connection(p_samr2, b, &ndr_table_netlogon, credentials, tctx->lp_ctx, tctx, &p_netlogon2); torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection"); /* checks the capabilities */ torture_assert(tctx, test_netlogon_capabilities(p_netlogon2, tctx, credentials, creds), "Failed to process schannel secured capability ops (on fresh connection)"); /* Try the schannel-only SamLogonEx operation */ torture_assert(tctx, test_netlogon_ex_ops(p_netlogon2, tctx, credentials, creds), "Failed to process schannel secured NETLOGON EX ops (on fresh connection)"); /* And the more traditional style, proving that the * credentials chaining state is fully present */ torture_assert(tctx, test_netlogon_ops(p_netlogon2, tctx, credentials, creds), "Failed to process schannel secured NETLOGON ops (on fresh connection)"); /* Drop the socket, we want to start from scratch (again) */ talloc_free(p_samr2); /* We don't want schannel for this test */ status = dcerpc_binding_set_flags(b, 0, DCERPC_AUTH_OPTIONS); torture_assert_ntstatus_ok(tctx, status, "set flags"); status = dcerpc_pipe_connect_b(tctx, &p_netlogon3, b, &ndr_table_netlogon, credentials, tctx->ev, tctx->lp_ctx); torture_assert_ntstatus_ok(tctx, status, "Failed to connect without schannel"); torture_assert(tctx, !test_netlogon_ex_ops(p_netlogon3, tctx, credentials, creds), "Processed NOT schannel secured NETLOGON EX ops without SCHANNEL (unsafe)"); /* Required because the previous call will mark the current context as having failed */ tctx->last_result = TORTURE_OK; tctx->last_reason = NULL; torture_assert(tctx, test_netlogon_ops(p_netlogon3, tctx, credentials, creds), "Failed to processed NOT schannel secured NETLOGON ops without new ServerAuth"); torture_leave_domain(tctx, join_ctx); return true; }
_PUBLIC_ struct test_join *torture_join_domain(struct torture_context *tctx, const char *machine_name, uint32_t acct_flags, struct cli_credentials **machine_credentials) { NTSTATUS status; struct libnet_context *libnet_ctx; struct libnet_JoinDomain *libnet_r; struct test_join *tj; struct samr_SetUserInfo s; union samr_UserInfo u; const char *binding_str = NULL; struct dcerpc_binding *binding = NULL; enum dcerpc_transport_t transport; tj = talloc_zero(tctx, struct test_join); if (!tj) return NULL; binding_str = torture_setting_string(tctx, "binding", NULL); if (binding_str == NULL) { const char *host = torture_setting_string(tctx, "host", NULL); binding_str = talloc_asprintf(tj, "ncacn_np:%s", host); } status = dcerpc_parse_binding(tj, binding_str, &binding); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("dcerpc_parse_binding(%s) failed - %s\n", binding_str, nt_errstr(status))); talloc_free(tj); return NULL; } transport = dcerpc_binding_get_transport(binding); switch (transport) { case NCALRPC: case NCACN_UNIX_STREAM: break; default: dcerpc_binding_set_transport(binding, NCACN_NP); dcerpc_binding_set_flags(binding, 0, DCERPC_AUTH_OPTIONS); break; } libnet_r = talloc_zero(tj, struct libnet_JoinDomain); if (!libnet_r) { talloc_free(tj); return NULL; } libnet_ctx = libnet_context_init(tctx->ev, tctx->lp_ctx); if (!libnet_ctx) { talloc_free(tj); return NULL; } tj->libnet_r = libnet_r; libnet_ctx->cred = cmdline_credentials; libnet_r->in.binding = dcerpc_binding_string(libnet_r, binding); if (libnet_r->in.binding == NULL) { talloc_free(tj); return NULL; } libnet_r->in.level = LIBNET_JOINDOMAIN_SPECIFIED; libnet_r->in.netbios_name = machine_name; libnet_r->in.account_name = talloc_asprintf(libnet_r, "%s$", machine_name); if (!libnet_r->in.account_name) { talloc_free(tj); return NULL; } libnet_r->in.acct_type = acct_flags; libnet_r->in.recreate_account = true; status = libnet_JoinDomain(libnet_ctx, libnet_r, libnet_r); if (!NT_STATUS_IS_OK(status)) { if (libnet_r->out.error_string) { DEBUG(0, ("Domain join failed - %s\n", libnet_r->out.error_string)); } else { DEBUG(0, ("Domain join failed - %s\n", nt_errstr(status))); } talloc_free(tj); return NULL; } tj->p = libnet_r->out.samr_pipe; tj->user_handle = *libnet_r->out.user_handle; tj->dom_sid = libnet_r->out.domain_sid; talloc_steal(tj, libnet_r->out.domain_sid); tj->dom_netbios_name = libnet_r->out.domain_name; talloc_steal(tj, libnet_r->out.domain_name); tj->dom_dns_name = libnet_r->out.realm; talloc_steal(tj, libnet_r->out.realm); tj->user_guid = libnet_r->out.account_guid; tj->netbios_name = talloc_strdup(tj, machine_name); if (!tj->netbios_name) { talloc_free(tj); return NULL; } ZERO_STRUCT(u); s.in.user_handle = &tj->user_handle; s.in.info = &u; s.in.level = 21; u.info21.fields_present = SAMR_FIELD_DESCRIPTION | SAMR_FIELD_COMMENT | SAMR_FIELD_FULL_NAME; u.info21.comment.string = talloc_asprintf(tj, "Tortured by Samba4: %s", timestring(tj, time(NULL))); u.info21.full_name.string = talloc_asprintf(tj, "Torture account for Samba4: %s", timestring(tj, time(NULL))); u.info21.description.string = talloc_asprintf(tj, "Samba4 torture account created by host %s: %s", lpcfg_netbios_name(tctx->lp_ctx), timestring(tj, time(NULL))); status = dcerpc_samr_SetUserInfo_r(tj->p->binding_handle, tj, &s); if (!NT_STATUS_IS_OK(status)) { printf("SetUserInfo (non-critical) failed - %s\n", nt_errstr(status)); } if (!NT_STATUS_IS_OK(s.out.result)) { printf("SetUserInfo (non-critical) failed - %s\n", nt_errstr(s.out.result)); } *machine_credentials = cli_credentials_init(tj); cli_credentials_set_conf(*machine_credentials, tctx->lp_ctx); cli_credentials_set_workstation(*machine_credentials, machine_name, CRED_SPECIFIED); cli_credentials_set_domain(*machine_credentials, libnet_r->out.domain_name, CRED_SPECIFIED); if (libnet_r->out.realm) { cli_credentials_set_realm(*machine_credentials, libnet_r->out.realm, CRED_SPECIFIED); } cli_credentials_set_username(*machine_credentials, libnet_r->in.account_name, CRED_SPECIFIED); cli_credentials_set_password(*machine_credentials, libnet_r->out.join_password, CRED_SPECIFIED); cli_credentials_set_kvno(*machine_credentials, libnet_r->out.kvno); if (acct_flags & ACB_SVRTRUST) { cli_credentials_set_secure_channel_type(*machine_credentials, SEC_CHAN_BDC); } else if (acct_flags & ACB_WSTRUST) { cli_credentials_set_secure_channel_type(*machine_credentials, SEC_CHAN_WKSTA); } else { DEBUG(0, ("Invalid account type specificed to torture_join_domain\n")); talloc_free(*machine_credentials); return NULL; } return tj; }