r25026: Move param/param.h out of includes.h
[kai/samba.git] / source4 / torture / rpc / schannel.c
index 1b10e2a4f275160a910a3797e1ec105a70a36906..2494fbeffff96f8051e925bb5e5aff4d3b62b450 100644 (file)
@@ -7,7 +7,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
-#include "librpc/gen_ndr/ndr_samr.h"
-#include "librpc/gen_ndr/ndr_netlogon.h"
+#include "librpc/gen_ndr/ndr_netlogon_c.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "auth/credentials/credentials.h"
+#include "torture/rpc/rpc.h"
+#include "lib/cmdline/popt_common.h"
+#include "auth/gensec/schannel_proto.h"
+#include "libcli/auth/libcli_auth.h"
+#include "libcli/security/security.h"
+#include "system/filesys.h"
+#include "param/param.h"
+
+#define TEST_MACHINE_NAME "schannel"
 
-#define TEST_MACHINE_NAME "schanneltest"
+/*
+  try a netlogon SamLogon
+*/
+bool test_netlogon_ex_ops(struct dcerpc_pipe *p, struct torture_context *tctx, 
+                         struct cli_credentials *credentials, 
+                         struct creds_CredentialState *creds)
+{
+       NTSTATUS status;
+       struct netr_LogonSamLogonEx r;
+       struct netr_NetworkInfo ninfo;
+       DATA_BLOB names_blob, chal, lm_resp, nt_resp;
+       int i;
+       int flags = CLI_CRED_NTLM_AUTH;
+       if (lp_client_lanman_auth()) {
+               flags |= CLI_CRED_LANMAN_AUTH;
+       }
+
+       if (lp_client_ntlmv2_auth()) {
+               flags |= CLI_CRED_NTLMv2_AUTH;
+       }
+
+       cli_credentials_get_ntlm_username_domain(cmdline_credentials, tctx, 
+                                                &ninfo.identity_info.account_name.string,
+                                                &ninfo.identity_info.domain_name.string);
+       
+       generate_random_buffer(ninfo.challenge, 
+                              sizeof(ninfo.challenge));
+       chal = data_blob_const(ninfo.challenge, 
+                              sizeof(ninfo.challenge));
+
+       names_blob = NTLMv2_generate_names_blob(tctx, cli_credentials_get_workstation(credentials), 
+                                               cli_credentials_get_domain(credentials));
+
+       status = cli_credentials_get_ntlm_response(cmdline_credentials, tctx, 
+                                                  &flags, 
+                                                  chal,
+                                                  names_blob,
+                                                  &lm_resp, &nt_resp,
+                                                  NULL, NULL);
+       torture_assert_ntstatus_ok(tctx, status, 
+                                  "cli_credentials_get_ntlm_response failed");
+
+       ninfo.lm.data = lm_resp.data;
+       ninfo.lm.length = lm_resp.length;
+
+       ninfo.nt.data = nt_resp.data;
+       ninfo.nt.length = nt_resp.length;
+
+       ninfo.identity_info.parameter_control = 0;
+       ninfo.identity_info.logon_id_low = 0;
+       ninfo.identity_info.logon_id_high = 0;
+       ninfo.identity_info.workstation.string = cli_credentials_get_workstation(credentials);
+
+       r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+       r.in.computer_name = cli_credentials_get_workstation(credentials);
+       r.in.logon_level = 2;
+       r.in.logon.network = &ninfo;
+       r.in.flags = 0;
+
+       torture_comment(tctx, 
+                       "Testing LogonSamLogonEx with name %s\n", 
+                       ninfo.identity_info.account_name.string);
+       
+       for (i=2;i<3;i++) {
+               r.in.validation_level = i;
+               
+               status = dcerpc_netr_LogonSamLogonEx(p, tctx, &r);
+               torture_assert_ntstatus_ok(tctx, status, "LogonSamLogon failed");
+       }
+
+       return true;
+}
 
 /*
   do some samr ops using the schannel connection
  */
-static BOOL test_samr_ops(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
+static bool test_samr_ops(struct torture_context *tctx,
+                         struct dcerpc_pipe *p)
 {
        NTSTATUS status;
        struct samr_GetDomPwInfo r;
+       struct samr_Connect connect;
+       struct samr_OpenDomain opendom;
        int i;
-       struct samr_String name;
+       struct lsa_String name;
+       struct policy_handle handle;
+       struct policy_handle domain_handle;
 
        name.string = lp_workgroup();
        r.in.domain_name = &name;
 
+       connect.in.system_name = 0;
+       connect.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+       connect.out.connect_handle = &handle;
+       
+       printf("Testing Connect and OpenDomain on BUILTIN\n");
+
+       status = dcerpc_samr_Connect(p, tctx, &connect);
+       if (!NT_STATUS_IS_OK(status)) {
+               if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+                       printf("Connect failed (expected, schannel mapped to anonymous): %s\n",
+                              nt_errstr(status));
+               } else {
+                       printf("Connect failed - %s\n", nt_errstr(status));
+                       return false;
+               }
+       } else {
+               opendom.in.connect_handle = &handle;
+               opendom.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+               opendom.in.sid = dom_sid_parse_talloc(tctx, "S-1-5-32");
+               opendom.out.domain_handle = &domain_handle;
+               
+               status = dcerpc_samr_OpenDomain(p, tctx, &opendom);
+               if (!NT_STATUS_IS_OK(status)) {
+                       printf("OpenDomain failed - %s\n", nt_errstr(status));
+                       return false;
+               }
+       }
+
        printf("Testing GetDomPwInfo with name %s\n", r.in.domain_name->string);
        
        /* do several ops to test credential chaining */
        for (i=0;i<5;i++) {
-               status = dcerpc_samr_GetDomPwInfo(p, mem_ctx, &r);
+               status = dcerpc_samr_GetDomPwInfo(p, tctx, &r);
                if (!NT_STATUS_IS_OK(status)) {
-                       printf("GetDomPwInfo op %d failed - %s\n", i, nt_errstr(status));
-                       return False;
+                       if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+                               printf("GetDomPwInfo op %d failed - %s\n", i, nt_errstr(status));
+                               return False;
+                       }
                }
        }
 
@@ -55,204 +171,310 @@ static BOOL test_samr_ops(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
 
 
 /*
-  try a netlogon SamLogon
-*/
-static BOOL test_netlogon_ops(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
-                                 struct creds_CredentialState *creds)
+  do some lsa ops using the schannel connection
+ */
+static bool test_lsa_ops(struct torture_context *tctx, struct dcerpc_pipe *p)
 {
+       struct lsa_GetUserName r;
        NTSTATUS status;
-       struct netr_LogonSamLogon r;
-       struct netr_Authenticator auth, auth2;
-       struct netr_NetworkInfo ninfo;
-       const char *username = lp_parm_string(-1, "torture", "username");
-       const char *password = lp_parm_string(-1, "torture", "password");
-
-       int i;
        BOOL ret = True;
+       struct lsa_StringPointer authority_name_p;
 
-       ninfo.identity_info.domain_name.string = lp_workgroup();
-       ninfo.identity_info.parameter_control = 0;
-       ninfo.identity_info.logon_id_low = 0;
-       ninfo.identity_info.logon_id_high = 0;
-       ninfo.identity_info.account_name.string = username;
-       ninfo.identity_info.workstation.string = TEST_MACHINE_NAME;
-       generate_random_buffer(ninfo.challenge, 
-                              sizeof(ninfo.challenge));
-       ninfo.nt.length = 24;
-       ninfo.nt.data = talloc_size(mem_ctx, 24);
-       SMBNTencrypt(password, ninfo.challenge, ninfo.nt.data);
-       ninfo.lm.length = 24;
-       ninfo.lm.data = talloc_size(mem_ctx, 24);
-       SMBencrypt(password, ninfo.challenge, ninfo.lm.data);
-
-
-       r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
-       r.in.workstation = TEST_MACHINE_NAME;
-       r.in.credential = &auth;
-       r.in.return_authenticator = &auth2;
-       r.in.logon_level = 2;
-       r.in.logon.network = &ninfo;
+       printf("\nTesting GetUserName\n");
+
+       r.in.system_name = "\\";        
+       r.in.account_name = NULL;       
+       r.in.authority_name = &authority_name_p;
+       authority_name_p.string = NULL;
 
-       printf("Testing LogonSamLogon with name %s\n", username);
+       /* do several ops to test credential chaining and various operations */
+       status = dcerpc_lsa_GetUserName(p, tctx, &r);
        
-       for (i=2;i<3;i++) {
-               ZERO_STRUCT(auth2);
-               creds_client_authenticator(creds, &auth);
-               
-               r.in.validation_level = i;
-               
-               status = dcerpc_netr_LogonSamLogon(p, mem_ctx, &r);
+       if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED)) {
+               printf("not considering %s to be an error\n", nt_errstr(status));
+       } else if (!NT_STATUS_IS_OK(status)) {
+               printf("GetUserName failed - %s\n", nt_errstr(status));
+               return False;
+       } else {
+               if (!r.out.account_name) {
+                       return False;
+               }
                
-               if (!creds_client_check(creds, &r.out.return_authenticator->cred)) {
-                       printf("Credential chaining failed\n");
-                       ret = False;
+               if (strcmp(r.out.account_name->string, "ANONYMOUS LOGON") != 0) {
+                       printf("GetUserName returned wrong user: %s, expected %s\n",
+                              r.out.account_name->string, "ANONYMOUS LOGON");
+                       return False;
+               }
+               if (!r.out.authority_name || !r.out.authority_name->string) {
+                       return False;
                }
                
+               if (strcmp(r.out.authority_name->string->string, "NT AUTHORITY") != 0) {
+                       printf("GetUserName returned wrong user: %s, expected %s\n",
+                              r.out.authority_name->string->string, "NT AUTHORITY");
+                       return False;
+               }
        }
+       if (!test_many_LookupSids(p, tctx, NULL)) {
+               printf("LsaLookupSids3 failed!\n");
+               return False;
+       }
+
        return ret;
 }
 
+
 /*
   test a schannel connection with the given flags
  */
-static BOOL test_schannel(TALLOC_CTX *mem_ctx, 
+static bool test_schannel(struct torture_context *tctx,
                          uint16_t acct_flags, uint32_t dcerpc_flags,
-                         uint32_t schannel_type)
+                         int i)
 {
-       void *join_ctx;
-       const char *machine_password;
+       struct test_join *join_ctx;
        NTSTATUS status;
        const char *binding = lp_parm_string(-1, "torture", "binding");
        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 creds_CredentialState *creds;
-       char *test_machine_account = talloc_asprintf(NULL, "%s$", TEST_MACHINE_NAME);
+       struct cli_credentials *credentials;
 
-       join_ctx = torture_create_testuser(test_machine_account, lp_workgroup(), 
-                                          acct_flags, &machine_password);
-       if (!join_ctx) {
-               printf("Failed to join domain with acct_flags=0x%x\n", acct_flags);
-               return False;
-       }
+       join_ctx = torture_join_domain(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(mem_ctx, binding, &b);
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("Bad binding string %s\n", binding);
-               goto failed;
-       }
+       status = dcerpc_parse_binding(tctx, binding, &b);
+       torture_assert_ntstatus_ok(tctx, status, "Bad binding string");
 
        b->flags &= ~DCERPC_AUTH_OPTIONS;
        b->flags |= dcerpc_flags;
 
-       status = dcerpc_pipe_connect_b(&p, b, 
-                                      DCERPC_SAMR_UUID,
-                                      DCERPC_SAMR_VERSION,
-                                      TEST_MACHINE_NAME,
-                                      lp_workgroup(), 
-                                      test_machine_account,
-                                      machine_password);
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("Failed to connect with schannel: %s\n", nt_errstr(status));
-               goto failed;
-       }
-
-       if (!test_samr_ops(p, mem_ctx)) {
-               printf("Failed to process schannel secured ops\n");
-               goto failed;
-       }
+       status = dcerpc_pipe_connect_b(tctx, &p, b, &ndr_table_samr,
+                                      credentials, NULL);
+       torture_assert_ntstatus_ok(tctx, status, 
+               "Failed to connect with schannel");
 
-       status = dcerpc_schannel_creds(p->conn->security_state.generic_state, mem_ctx, &creds);
-       if (!NT_STATUS_IS_OK(status)) {
-               goto failed;
-       }
+       torture_assert(tctx, test_samr_ops(tctx, p), 
+                      "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(mem_ctx, b, DCERPC_NETLOGON_UUID,
-                                       DCERPC_NETLOGON_VERSION);
-       if (!NT_STATUS_IS_OK(status)) {
-               goto failed;
-       }
+       status = dcerpc_epm_map_binding(tctx, b, &ndr_table_netlogon, NULL);
+       torture_assert_ntstatus_ok(tctx, status, "epm map");
 
        status = dcerpc_secondary_connection(p, &p_netlogon, 
                                             b);
+       torture_assert_ntstatus_ok(tctx, status, "seconday connection");
 
-       if (!NT_STATUS_IS_OK(status)) {
-               goto failed;
-       }
-
-       status = dcerpc_bind_auth_schannel_withkey(p_netlogon, 
-                                                  DCERPC_NETLOGON_UUID,
-                                                  DCERPC_NETLOGON_VERSION, 
-                                                  creds);
+       status = dcerpc_bind_auth(p_netlogon, &ndr_table_netlogon,
+                                 credentials, DCERPC_AUTH_TYPE_SCHANNEL,
+                                 dcerpc_auth_level(p->conn),
+                                 NULL);
 
-       if (!NT_STATUS_IS_OK(status)) {
-               goto failed;
-       }
+       torture_assert_ntstatus_ok(tctx, status, "bind auth");
 
-       status = dcerpc_schannel_creds(p_netlogon->conn->security_state.generic_state, mem_ctx, &creds);
-       if (!NT_STATUS_IS_OK(status)) {
-               goto failed;
-       }
+       status = dcerpc_schannel_creds(p_netlogon->conn->security_state.generic_state, tctx, &creds);
+       torture_assert_ntstatus_ok(tctx, status, "schannel creds");
 
        /* do a couple of logins */
-       if (!test_netlogon_ops(p_netlogon, mem_ctx, creds)) {
-               printf("Failed to process schannel secured ops\n");
-               goto failed;
-       }
+       torture_assert(tctx, test_netlogon_ops(p_netlogon, tctx, credentials, creds),
+               "Failed to process schannel secured NETLOGON ops");
 
-       torture_leave_domain(join_ctx);
-       dcerpc_pipe_close(p_netlogon);
-       dcerpc_pipe_close(p);
-       return True;
+       torture_assert(tctx, test_netlogon_ex_ops(p_netlogon, tctx, credentials, creds),
+               "Failed to process schannel secured NETLOGON EX ops");
+
+       /* Swap the binding details from SAMR to LSARPC */
+       status = dcerpc_epm_map_binding(tctx, b, &ndr_table_lsarpc, NULL);
+       torture_assert_ntstatus_ok(tctx, status, "epm map");
+
+       status = dcerpc_secondary_connection(p, &p_lsa, 
+                                            b);
+
+       torture_assert_ntstatus_ok(tctx, status, "seconday connection");
+
+       status = dcerpc_bind_auth(p_lsa, &ndr_table_lsarpc,
+                                 credentials, DCERPC_AUTH_TYPE_SCHANNEL,
+                                 dcerpc_auth_level(p->conn),
+                                 NULL);
+
+       torture_assert_ntstatus_ok(tctx, status, "bind auth");
+
+       torture_assert(tctx, test_lsa_ops(tctx, p_lsa), 
+               "Failed to process schannel secured LSA ops");
+
+       /* 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");
+
+       b->flags &= ~DCERPC_AUTH_OPTIONS;
+       b->flags |= dcerpc_flags;
+
+       status = dcerpc_pipe_connect_b(tctx, &p_samr2, b, &ndr_table_samr,
+                                      credentials, NULL);
+       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), 
+                       "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, NULL);
+       torture_assert_ntstatus_ok(tctx, status, "epm");
+
+       status = dcerpc_secondary_connection(p_samr2, &p_netlogon2, 
+                                            b);
+       torture_assert_ntstatus_ok(tctx, status, "seconday connection");
+
+       /* and now setup an SCHANNEL bind on netlogon */
+       status = dcerpc_bind_auth(p_netlogon2, &ndr_table_netlogon,
+                                 credentials, DCERPC_AUTH_TYPE_SCHANNEL,
+                                 dcerpc_auth_level(p_samr2->conn),
+                                 NULL);
+
+       torture_assert_ntstatus_ok(tctx, status, "auth failed");
+       
+       /* 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 */
+       b->flags &= ~DCERPC_AUTH_OPTIONS;
+
+       status = dcerpc_pipe_connect_b(tctx, &p_netlogon3, b, &ndr_table_netlogon,
+                                      credentials, NULL);
+       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");
 
-failed:
        torture_leave_domain(join_ctx);
-       dcerpc_pipe_close(p_netlogon);
-       dcerpc_pipe_close(p);
-       return False;   
+       return true;
 }
 
+
+
 /*
   a schannel test suite
  */
-BOOL torture_rpc_schannel(void)
+bool torture_rpc_schannel(struct torture_context *torture)
 {
-       TALLOC_CTX *mem_ctx;
        BOOL ret = True;
        struct {
                uint16_t acct_flags;
                uint32_t dcerpc_flags;
-               uint32_t schannel_type;
        } tests[] = {
-               { ACB_WSTRUST,   DCERPC_SCHANNEL_WORKSTATION | DCERPC_SIGN,                       3 },
-               { ACB_WSTRUST,   DCERPC_SCHANNEL_WORKSTATION | DCERPC_SEAL,                       3 },
-               { ACB_WSTRUST,   DCERPC_SCHANNEL_WORKSTATION | DCERPC_SIGN | DCERPC_SCHANNEL_128, 3 },
-               { ACB_WSTRUST,   DCERPC_SCHANNEL_WORKSTATION | DCERPC_SEAL | DCERPC_SCHANNEL_128, 3 },
-               { ACB_SVRTRUST,  DCERPC_SCHANNEL_BDC | DCERPC_SIGN,                               3 },
-               { ACB_SVRTRUST,  DCERPC_SCHANNEL_BDC | DCERPC_SEAL,                               3 },
-               { ACB_SVRTRUST,  DCERPC_SCHANNEL_BDC | DCERPC_SIGN | DCERPC_SCHANNEL_128,         3 },
-               { ACB_SVRTRUST,  DCERPC_SCHANNEL_BDC | DCERPC_SEAL | DCERPC_SCHANNEL_128,         3 }
+               { ACB_WSTRUST,   DCERPC_SCHANNEL | DCERPC_SIGN},
+               { ACB_WSTRUST,   DCERPC_SCHANNEL | DCERPC_SEAL},
+               { ACB_WSTRUST,   DCERPC_SCHANNEL | DCERPC_SIGN | DCERPC_SCHANNEL_128},
+               { ACB_WSTRUST,   DCERPC_SCHANNEL | DCERPC_SEAL | DCERPC_SCHANNEL_128 },
+               { ACB_SVRTRUST,  DCERPC_SCHANNEL | DCERPC_SIGN },
+               { ACB_SVRTRUST,  DCERPC_SCHANNEL | DCERPC_SEAL },
+               { ACB_SVRTRUST,  DCERPC_SCHANNEL | DCERPC_SIGN | DCERPC_SCHANNEL_128 },
+               { ACB_SVRTRUST,  DCERPC_SCHANNEL | DCERPC_SEAL | DCERPC_SCHANNEL_128 }
        };
        int i;
 
-       mem_ctx = talloc_init("torture_rpc_schannel");
-
        for (i=0;i<ARRAY_SIZE(tests);i++) {
-               if (!test_schannel(mem_ctx
-                                  tests[i].acct_flags, tests[i].dcerpc_flags, tests[i].schannel_type)) {
-                       printf("Failed with acct_flags=0x%x dcerpc_flags=0x%x schannel_type=%d\n",
-                              tests[i].acct_flags, tests[i].dcerpc_flags, tests[i].schannel_type);
-                       ret = False;
-                       break;
+               if (!test_schannel(torture
+                                  tests[i].acct_flags, tests[i].dcerpc_flags,
+                                  i)) {
+                       torture_comment(torture, "Failed with acct_flags=0x%x dcerpc_flags=0x%x \n",
+                              tests[i].acct_flags, tests[i].dcerpc_flags);
+                       ret = false;
                }
        }
 
-       talloc_free(mem_ctx);
-
        return ret;
 }
+
+/*
+  test two schannel connections
+ */
+bool torture_rpc_schannel2(struct torture_context *torture)
+{
+       struct test_join *join_ctx;
+       NTSTATUS status;
+       const char *binding = torture_setting_string(torture, "binding", NULL);
+       struct dcerpc_binding *b;
+       struct dcerpc_pipe *p1 = NULL, *p2 = NULL;
+       struct cli_credentials *credentials1, *credentials2;
+       uint32_t dcerpc_flags = DCERPC_SCHANNEL | DCERPC_SIGN;
+
+       join_ctx = torture_join_domain(talloc_asprintf(torture, "%s2", TEST_MACHINE_NAME), 
+                                      ACB_WSTRUST, &credentials1);
+       torture_assert(torture, join_ctx != NULL, 
+                      "Failed to join domain with acct_flags=ACB_WSTRUST");
+
+       credentials2 = talloc_memdup(torture, credentials1, sizeof(*credentials1));
+       credentials1->netlogon_creds = NULL;
+       credentials2->netlogon_creds = NULL;
+
+       status = dcerpc_parse_binding(torture, binding, &b);
+       torture_assert_ntstatus_ok(torture, status, "Bad binding string");
+
+       b->flags &= ~DCERPC_AUTH_OPTIONS;
+       b->flags |= dcerpc_flags;
+
+       printf("Opening first connection\n");
+       status = dcerpc_pipe_connect_b(torture, &p1, b, &ndr_table_netlogon,
+                                      credentials1, NULL);
+       torture_assert_ntstatus_ok(torture, status, "Failed to connect with schannel");
+
+       torture_comment(torture, "Opening second connection\n");
+       status = dcerpc_pipe_connect_b(torture, &p2, b, &ndr_table_netlogon,
+                                      credentials2, NULL);
+       torture_assert_ntstatus_ok(torture, status, "Failed to connect with schannel");
+
+       credentials1->netlogon_creds = NULL;
+       credentials2->netlogon_creds = NULL;
+
+       torture_comment(torture, "Testing logon on pipe1\n");
+       if (!test_netlogon_ex_ops(p1, torture, credentials1, NULL))
+               return false;
+
+       torture_comment(torture, "Testing logon on pipe2\n");
+       if (!test_netlogon_ex_ops(p2, torture, credentials2, NULL))
+               return false;
+
+       torture_comment(torture, "Again on pipe1\n");
+       if (!test_netlogon_ex_ops(p1, torture, credentials1, NULL))
+               return false;
+
+       torture_comment(torture, "Again on pipe2\n");
+       if (!test_netlogon_ex_ops(p2, torture, credentials2, NULL))
+               return false;
+
+       torture_leave_domain(join_ctx);
+       return true;
+}
+