r3660: This simulates the logon sequence of a XP login session I'm currently tuning
authorVolker Lendecke <vlendec@samba.org>
Wed, 10 Nov 2004 16:50:15 +0000 (16:50 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:05:42 +0000 (13:05 -0500)
Samba3/OpenLDAP for. For a concrete situation you have to adapt the domain,
pdcname and usernames/passwords. Sorry, not parametrized yet, but this should
be doable if necessary.

Volker
(This used to be commit 02f52058722fc1aea02d4fe237c97404d8e4f491)

source4/librpc/rpc/dcerpc_schannel.c
source4/torture/config.mk
source4/torture/rpc/xplogin.c [new file with mode: 0644]
source4/torture/torture.c

index 3472e1cbe2343b8ce096eabdb8126f1ce033e6f8..c0db63e8b86b04a14846831a29863fb66654b5c3 100644 (file)
@@ -425,39 +425,23 @@ static NTSTATUS dcerpc_schannel_key(struct dcerpc_pipe *p,
   do a schannel style bind on a dcerpc pipe. The username is usually
   of the form HOSTNAME$ and the password is the domain trust password
 */
-NTSTATUS dcerpc_bind_auth_schannel(struct dcerpc_pipe *p,
-                                  const char *uuid, uint_t version,
-                                  const char *domain,
-                                  const char *username,
-                                  const char *password)
+NTSTATUS dcerpc_bind_auth_schannel_withkey(struct dcerpc_pipe *p,
+                                          const char *uuid, uint_t version,
+                                          const char *domain,
+                                          const char *username,
+                                          const char *password,
+                                          uint8_t session_key[16])
 {
        NTSTATUS status;
-       int chan_type = 0;
 
        status = gensec_client_start(p, &p->security_state.generic_state);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       if (p->flags & DCERPC_SCHANNEL_BDC) {
-               chan_type = SEC_CHAN_BDC;
-       } else if (p->flags & DCERPC_SCHANNEL_WORKSTATION) {
-               chan_type = SEC_CHAN_WKSTA;
-       } else if (p->flags & DCERPC_SCHANNEL_DOMAIN) {
-               chan_type = SEC_CHAN_DOMAIN;
-       }
+       memcpy(p->security_state.generic_state->user.schan_session_key,
+              session_key, 16);
 
-       status = dcerpc_schannel_key(p, domain, 
-                                    username,
-                                    password, 
-                                    chan_type, 
-                                    p->security_state.generic_state->user.schan_session_key);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("Failed to fetch schannel session key: %s\n", nt_errstr(status)));
-               gensec_end(&p->security_state.generic_state);
-               return status;
-       }
-       
        status = gensec_set_username(p->security_state.generic_state, username);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1, ("Failed to set schannel username to %s: %s\n", username, nt_errstr(status)));
@@ -492,6 +476,40 @@ NTSTATUS dcerpc_bind_auth_schannel(struct dcerpc_pipe *p,
        return NT_STATUS_OK;
 }
 
+NTSTATUS dcerpc_bind_auth_schannel(struct dcerpc_pipe *p,
+                                  const char *uuid, uint_t version,
+                                  const char *domain,
+                                  const char *username,
+                                  const char *password)
+{
+       NTSTATUS status;
+       int chan_type = 0;
+       uint8_t new_session_key[16];
+
+       if (p->flags & DCERPC_SCHANNEL_BDC) {
+               chan_type = SEC_CHAN_BDC;
+       } else if (p->flags & DCERPC_SCHANNEL_WORKSTATION) {
+               chan_type = SEC_CHAN_WKSTA;
+       } else if (p->flags & DCERPC_SCHANNEL_DOMAIN) {
+               chan_type = SEC_CHAN_DOMAIN;
+       }
+
+       status = dcerpc_schannel_key(p, domain, 
+                                    username,
+                                    password, 
+                                    chan_type,
+                                    new_session_key);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("Failed to fetch schannel session key: %s\n",
+                         nt_errstr(status)));
+               return status;
+       }
+
+       return dcerpc_bind_auth_schannel_withkey(p, uuid, version, domain,
+                                                username, password,
+                                                new_session_key);
+}
 
 static const struct gensec_security_ops gensec_dcerpc_schannel_security_ops = {
        .name           = "dcerpc_schannel",
index b2b301babde8894bc016f8317dec9246a9d063f4..70a3e540f74ad5f28803158c1bc1f381c2be3299 100644 (file)
@@ -86,6 +86,7 @@ ADD_OBJ_FILES = \
                torture/rpc/autoidl.o \
                torture/rpc/countcalls.o \
                torture/rpc/testjoin.o \
+               torture/rpc/xplogin.o \
                torture/rpc/schannel.o \
                torture/rpc/netlogon.o \
                torture/rpc/bind.o
diff --git a/source4/torture/rpc/xplogin.c b/source4/torture/rpc/xplogin.c
new file mode 100644 (file)
index 0000000..a3cca70
--- /dev/null
@@ -0,0 +1,1160 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   Test code to simulate an XP logon.
+
+   Copyright (C) Volker Lendecke 2004
+   
+   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
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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.
+*/
+
+#include "includes.h"
+#include "libcli/auth/credentials.h"
+#include "libcli/raw/libcliraw.h"
+#include "librpc/gen_ndr/ndr_samr.h"
+#include "librpc/gen_ndr/ndr_netlogon.h"
+#include "librpc/gen_ndr/ndr_srvsvc.h"
+
+static int destroy_transport(void *ptr)
+{
+       struct smbcli_transport *trans = ptr;
+       talloc_free(trans->socket);
+       return 0;
+}
+
+static NTSTATUS after_negprot(struct smbcli_transport **dst_transport,
+                             const char *dest_host, uint16_t port,
+                             const char *my_name)
+{
+       struct smbcli_socket *sock;
+       struct smbcli_transport *transport;
+       NTSTATUS status;
+
+       sock = smbcli_sock_init(NULL);
+       if (sock == NULL)
+               return NT_STATUS_NO_MEMORY;
+
+       if (!smbcli_sock_connect_byname(sock, dest_host, port)) {
+               talloc_free(sock);
+               DEBUG(2,("Failed to establish socket connection - %s\n",
+                        strerror(errno)));
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       transport = smbcli_transport_init(sock);
+       talloc_free(sock);
+       if (transport == NULL)
+               return NT_STATUS_NO_MEMORY;
+
+       talloc_set_destructor(transport, destroy_transport);
+
+       {
+               struct nmb_name calling;
+               struct nmb_name called;
+
+               /* send a NBT session request, if applicable */
+               make_nmb_name(&calling, my_name, 0x0);
+               choose_called_name(&called, dest_host, 0x20);
+
+               if (!smbcli_transport_connect(transport, &calling, &called)) {
+                       talloc_free(transport);
+                       return NT_STATUS_NO_MEMORY;
+               }
+       }
+
+       /* negotiate protocol options with the server */
+       status = smb_raw_negotiate(transport);
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(transport);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       *dst_transport = transport;
+
+       return NT_STATUS_OK;
+}
+
+static int destroy_session(void *ptr)
+{
+       struct smbcli_session *session = ptr;
+       smb_raw_ulogoff(session);
+       return 0;
+}
+
+static int destroy_tree_and_session(void *ptr)
+{
+       struct smbcli_tree *tree = ptr;
+       smb_tree_disconnect(tree);
+       talloc_free(tree->session);
+       return 0;
+}
+
+static NTSTATUS anon_ipc(struct smbcli_transport *transport,
+                        struct smbcli_tree **dst_tree)
+{
+       struct smbcli_tree *tree;
+       struct smbcli_session *session;
+       union smb_sesssetup setup;
+       union smb_tcon tcon;
+       TALLOC_CTX *mem_ctx;
+       NTSTATUS status;
+
+       session = smbcli_session_init(transport);
+       if (session == NULL)
+               return NT_STATUS_NO_MEMORY;
+
+       mem_ctx = talloc_init("session_init");
+       if (mem_ctx == NULL) {
+               talloc_free(session);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       /* prepare a session setup to establish a security context */
+       setup.generic.level = RAW_SESSSETUP_GENERIC;
+       setup.generic.in.sesskey = transport->negotiate.sesskey;
+       setup.generic.in.capabilities = transport->negotiate.capabilities;
+       setup.generic.in.password = NULL;
+       setup.generic.in.user = "";
+       setup.generic.in.domain = "";
+       setup.generic.in.capabilities &= ~CAP_EXTENDED_SECURITY;
+
+       status = smb_raw_session_setup(session, mem_ctx, &setup);
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(session);
+               talloc_free(mem_ctx);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       session->vuid = setup.generic.out.vuid;
+
+       talloc_set_destructor(session, destroy_session);
+
+       tree = smbcli_tree_init(session);
+       talloc_free(session);
+       if (tree == NULL) {
+               talloc_free(mem_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       tcon.generic.level = RAW_TCON_TCONX;
+       tcon.tconx.in.flags = 0;
+       tcon.tconx.in.password = data_blob(NULL, 0);
+       tcon.tconx.in.path = talloc_asprintf(mem_ctx, "\\\\%s\\IPC$",
+                                           transport->called.name);
+       tcon.tconx.in.device = "IPC";
+
+       status = smb_tree_connect(tree, mem_ctx, &tcon);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(tree);
+               talloc_free(mem_ctx);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       tree->tid = tcon.tconx.out.cnum;
+
+       if (tcon.tconx.out.dev_type != NULL)
+               tree->device = talloc_strdup(tree, tcon.tconx.out.dev_type);
+
+       if (tcon.tconx.out.fs_type != NULL)
+               tree->fs_type = talloc_strdup(tree, tcon.tconx.out.fs_type);
+
+       talloc_set_destructor(tree, destroy_tree_and_session);
+
+       talloc_free(mem_ctx);
+
+       *dst_tree = tree;
+
+       return NT_STATUS_OK;
+}
+
+static int close_pipe(void *ptr)
+{
+       struct dcerpc_pipe *p = ptr;
+       dcerpc_pipe_close(p);
+       return 0;
+}
+
+static NTSTATUS connect_to_pipe(struct dcerpc_pipe **p,
+                               struct smbcli_transport *transport,
+                               const char *pipe_name,
+                               const char *pipe_uuid,
+                               uint32_t pipe_version)
+{
+       const char *binding = lp_parm_string(-1, "torture", "binding");
+       struct dcerpc_binding b;
+       NTSTATUS status;
+       TALLOC_CTX *mem_ctx;
+       struct smbcli_tree *tree;
+
+       if (!NT_STATUS_IS_OK(status = anon_ipc(transport, &tree)))
+               return status;
+
+       if (binding == NULL)
+               return NT_STATUS_INVALID_PARAMETER;
+
+       mem_ctx = talloc_init("dcerpc_pipe_connect");
+       if (!mem_ctx) return NT_STATUS_NO_MEMORY;
+
+       status = dcerpc_parse_binding(mem_ctx, binding, &b);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0,("Failed to parse dcerpc binding '%s'\n", binding));
+               talloc_destroy(mem_ctx);
+               return status;
+       }
+
+       DEBUG(3,("Using binding %s\n", dcerpc_binding_string(mem_ctx, &b)));
+
+       if (b.endpoint == NULL) {
+               const struct dcerpc_interface_table *table =
+                       idl_iface_by_uuid(pipe_uuid);
+               struct dcerpc_binding default_binding;
+               int i;
+
+               if (!table) {
+                       DEBUG(0,("Unknown interface endpoint '%s'\n",
+                                pipe_uuid));
+                       talloc_destroy(mem_ctx);
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+
+               /* Find one of the default pipes for this interface */
+               for (i = 0; i < table->endpoints->count; i++) {
+                       const char * const *names = table->endpoints->names;
+                       status = dcerpc_parse_binding(mem_ctx, names[i],
+                                                     &default_binding);
+
+                       if (NT_STATUS_IS_OK(status) &&
+                           default_binding.transport == NCACN_NP) {
+                               pipe_name = default_binding.endpoint;   
+                               break;
+                       }
+               }
+       } else {
+               pipe_name = b.endpoint;
+       }
+
+       if (!strncasecmp(pipe_name, "/pipe/", 6) || 
+               !strncasecmp(pipe_name, "\\pipe\\", 6)) {
+               pipe_name+=6;
+       }
+
+       if (pipe_name[0] != '\\') {
+               pipe_name = talloc_asprintf(mem_ctx, "\\%s", pipe_name);
+       }
+       
+       status = dcerpc_pipe_open_smb(p, tree, pipe_name);
+
+       if (!NT_STATUS_IS_OK(status))
+               return status;
+
+       talloc_destroy(mem_ctx);
+       
+       talloc_set_destructor(*p, close_pipe);
+       talloc_steal(*p, tree);
+
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS test_enumtrusts(struct smbcli_transport *transport)
+{
+       struct policy_handle handle;
+       struct lsa_EnumTrustDom r2;
+       uint32_t resume_handle = 0;
+       struct lsa_ObjectAttribute attr;
+       struct lsa_OpenPolicy2 r1;
+       struct lsa_DomainList domains;
+       TALLOC_CTX *mem_ctx;
+       NTSTATUS status;
+        struct dcerpc_pipe *p;
+
+       mem_ctx = talloc_init("test_enumtrusts");
+       if (mem_ctx == NULL)
+               return NT_STATUS_NO_MEMORY;
+
+       status = connect_to_pipe(&p, transport, DCERPC_LSARPC_NAME,
+                                DCERPC_LSARPC_UUID, 
+                                DCERPC_LSARPC_VERSION);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_destroy(mem_ctx);
+               return status;
+       }
+
+       status = dcerpc_bind_auth_none(p, DCERPC_LSARPC_UUID,
+                                      DCERPC_LSARPC_VERSION);
+
+       if (!NT_STATUS_IS_OK(status))
+               return status;
+
+       printf("\ntesting OpenPolicy2\n");
+
+       attr.len = 0;
+       attr.root_dir = NULL;
+       attr.object_name = NULL;
+       attr.attributes = 0;
+       attr.sec_desc = NULL;
+       attr.sec_qos = NULL;
+
+       r1.in.system_name = talloc_asprintf(mem_ctx,
+                                           "\\\\%s", dcerpc_server_name(p));
+       r1.in.attr = &attr;
+       r1.in.access_mask = 1;
+       r1.out.handle = &handle;
+
+       status = dcerpc_lsa_OpenPolicy2(p, mem_ctx, &r1);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("OpenPolicy2 failed - %s\n", nt_errstr(status));
+               return status;
+       }
+
+       printf("\nTesting EnumTrustDom\n");
+
+       r2.in.handle = &handle;
+       r2.in.resume_handle = &resume_handle;
+       r2.in.num_entries = 1000;
+       r2.out.domains = &domains;
+       r2.out.resume_handle = &resume_handle;
+
+       status = dcerpc_lsa_EnumTrustDom(p, mem_ctx, &r2);
+
+       if (!NT_STATUS_IS_OK(status) &&
+           !NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES))
+               return status;
+
+       talloc_free(p);
+
+       talloc_destroy(mem_ctx);
+
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS test_lookupnames(struct smbcli_transport *transport,
+                                const char *name)
+{
+       struct policy_handle handle;
+       struct lsa_ObjectAttribute attr;
+       struct lsa_OpenPolicy2 r1;
+       TALLOC_CTX *mem_ctx;
+       NTSTATUS status;
+        struct dcerpc_pipe *p;
+
+       mem_ctx = talloc_init("test_lookupnames");
+       if (mem_ctx == NULL)
+               return NT_STATUS_NO_MEMORY;
+
+       status = connect_to_pipe(&p, transport, DCERPC_LSARPC_NAME,
+                                DCERPC_LSARPC_UUID, 
+                                DCERPC_LSARPC_VERSION);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_destroy(mem_ctx);
+               return status;
+       }
+
+       status = dcerpc_bind_auth_none(p, DCERPC_LSARPC_UUID,
+                                      DCERPC_LSARPC_VERSION);
+
+       if (!NT_STATUS_IS_OK(status))
+               return status;
+
+       attr.len = 0;
+       attr.root_dir = NULL;
+       attr.object_name = NULL;
+       attr.attributes = 0;
+       attr.sec_desc = NULL;
+       attr.sec_qos = NULL;
+
+       r1.in.system_name = talloc_asprintf(mem_ctx,
+                                           "\\\\%s", dcerpc_server_name(p));
+       r1.in.attr = &attr;
+       r1.in.access_mask = 0x801;
+       r1.out.handle = &handle;
+
+       status = dcerpc_lsa_OpenPolicy2(p, mem_ctx, &r1);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("OpenPolicy2 failed - %s\n", nt_errstr(status));
+               return status;
+       }
+
+       {
+               struct lsa_LookupNames l;
+               struct lsa_TransSidArray sids;
+               struct lsa_Name lsaname;
+               uint32_t count = 0;
+
+               sids.count = 0;
+               sids.sids = NULL;
+
+               lsaname.name = name;
+
+               l.in.handle = &handle;
+               l.in.num_names = 1;
+               l.in.names = &lsaname;
+               l.in.sids = &sids;
+               l.in.level = 2;
+               l.in.count = &count;
+               l.out.count = &count;
+               l.out.sids = &sids;
+
+               status = dcerpc_lsa_LookupNames(p, mem_ctx, &l);
+               if (!NT_STATUS_IS_OK(status) &&
+                   !NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
+                       printf("LookupNames failed - %s\n", nt_errstr(status));
+                       talloc_free(p);
+                       talloc_destroy(mem_ctx);
+                       return NT_STATUS_OK;
+               }
+       }
+
+       {
+               struct lsa_Close c;
+               struct policy_handle handle2;
+
+               c.in.handle = &handle;
+               c.out.handle = &handle2;
+
+               status = dcerpc_lsa_Close(p, mem_ctx, &c);
+               if (!NT_STATUS_IS_OK(status)) {
+                       printf("Close failed - %s\n", nt_errstr(status));
+                       return status;
+               }
+       }
+
+       talloc_free(p);
+
+       talloc_destroy(mem_ctx);
+
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS setup_netlogon_creds(struct smbcli_transport *transport,
+                                    struct dcerpc_pipe **p,
+                                    const char *machine_name,
+                                    const char *domain,
+                                    const char *machine_pwd,
+                                    struct creds_CredentialState *creds)
+{
+        NTSTATUS status;
+       TALLOC_CTX *mem_ctx;
+       struct netr_ServerReqChallenge r;
+       struct netr_ServerAuthenticate2 a;
+       struct netr_Credential credentials1, credentials2, credentials3;
+       const char *plain_pass;
+       struct samr_Password mach_password;
+       uint32_t negotiate_flags = NETLOGON_NEG_AUTH2_FLAGS;
+
+       
+       mem_ctx = talloc_init("torture_rpc_login");
+
+       if (mem_ctx == NULL)
+               return NT_STATUS_NO_MEMORY;
+
+       status = connect_to_pipe(p, transport, DCERPC_NETLOGON_NAME,
+                                DCERPC_NETLOGON_UUID,
+                                DCERPC_NETLOGON_VERSION);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_destroy(mem_ctx);
+               return status;
+       }
+
+       status = dcerpc_bind_auth_none(*p, DCERPC_NETLOGON_UUID,
+                                      DCERPC_NETLOGON_VERSION);
+
+       if (!NT_STATUS_IS_OK(status))
+               return status;
+
+       printf("Testing ServerReqChallenge\n");
+
+       r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s",
+                                          dcerpc_server_name(*p));
+       r.in.computer_name = machine_name;
+       r.in.credentials = &credentials1;
+       r.out.credentials = &credentials2;
+
+       generate_random_buffer(credentials1.data, sizeof(credentials1.data));
+
+       status = dcerpc_netr_ServerReqChallenge(*p, mem_ctx, &r);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("ServerReqChallenge - %s\n", nt_errstr(status));
+               return status;
+       }
+
+       plain_pass = machine_pwd;
+       if (!plain_pass) {
+               printf("Unable to fetch machine password!\n");
+               return status;
+       }
+
+       E_md4hash(plain_pass, mach_password.hash);
+
+       a.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s",
+                                          dcerpc_server_name(*p));
+       a.in.account_name = talloc_asprintf(mem_ctx, "%s$", machine_name);
+       a.in.secure_channel_type = SEC_CHAN_WKSTA;
+       a.in.computer_name = machine_name;
+       a.in.negotiate_flags = &negotiate_flags;
+       a.out.negotiate_flags = &negotiate_flags;
+       a.in.credentials = &credentials3;
+       a.out.credentials = &credentials3;
+
+       creds_client_init(creds, &credentials1, &credentials2,
+                         &mach_password, &credentials3, 
+                         negotiate_flags);
+
+       printf("Testing ServerAuthenticate2\n");
+
+       status = dcerpc_netr_ServerAuthenticate2(*p, mem_ctx, &a);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("ServerAuthenticate2 - %s\n", nt_errstr(status));
+               return status;
+       }
+
+       if (!creds_client_check(creds, &credentials3)) {
+               printf("Credential chaining failed\n");
+               return status;
+       }
+
+       printf("negotiate_flags=0x%08x\n", negotiate_flags);
+
+       talloc_free(mem_ctx);
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS torture_samlogon(struct dcerpc_pipe *p,
+                                struct creds_CredentialState *netlogon_creds,
+                                const char *workstation,
+                                const char *domain,
+                                const char *username,
+                                const char *password)
+{
+       TALLOC_CTX *mem_ctx;
+       struct netr_LogonSamLogon log;
+       struct netr_NetworkInfo ninfo;
+       struct netr_Authenticator auth, auth2;
+       uint8_t user_session_key[16];
+       DATA_BLOB ntlmv2_response = data_blob(NULL, 0);
+       DATA_BLOB lmv2_response = data_blob(NULL, 0);
+       DATA_BLOB names_blob;
+       DATA_BLOB chall;
+       NTSTATUS status;
+
+       mem_ctx = talloc_init("torture_samlogon");
+
+       ZERO_STRUCT(user_session_key);
+
+       printf("testing netr_LogonSamLogon\n");
+
+       log.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s",
+                                            dcerpc_server_name(p));
+       log.in.workstation = workstation;
+       log.in.credential = &auth;
+       log.in.return_authenticator = &auth2;
+       log.in.validation_level = 3;
+       log.in.logon_level = 2;
+       log.in.logon.network = &ninfo;
+
+       chall = data_blob_talloc(mem_ctx, NULL, 8);
+       generate_random_buffer(chall.data, 8);  
+
+       names_blob = NTLMv2_generate_names_blob(mem_ctx, workstation,
+                                               lp_workgroup());
+       ZERO_STRUCT(user_session_key);
+
+       if (!SMBNTLMv2encrypt(username, domain, password,
+                             &chall, &names_blob,
+                             &lmv2_response, &ntlmv2_response, 
+                             NULL, NULL)) {
+               data_blob_free(&names_blob);
+               talloc_destroy(mem_ctx);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+       data_blob_free(&names_blob);
+
+       ninfo.identity_info.domain_name.string = domain;
+       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 = workstation;
+       memcpy(ninfo.challenge, chall.data, 8);
+       ninfo.nt.data = ntlmv2_response.data;
+       ninfo.nt.length = ntlmv2_response.length;
+       ninfo.lm.data = NULL;
+       ninfo.lm.length = 0;
+
+       ZERO_STRUCT(auth2);
+       creds_client_authenticator(netlogon_creds, &auth);
+
+       log.out.return_authenticator = NULL;
+       status = dcerpc_netr_LogonSamLogon(p, mem_ctx, &log);
+       talloc_destroy(mem_ctx);
+       data_blob_free(&lmv2_response);
+       data_blob_free(&ntlmv2_response);
+       return status;
+}
+
+static NTSTATUS test_getgroups(struct smbcli_transport *transport,
+                              const char *name)
+{
+       TALLOC_CTX *mem_ctx;
+       NTSTATUS status;
+        struct dcerpc_pipe *p;
+
+       struct samr_Connect4 r4;
+       struct policy_handle connect_handle, domain_handle, user_handle;
+
+       mem_ctx = talloc_init("test_lookupnames");
+       if (mem_ctx == NULL)
+               return NT_STATUS_NO_MEMORY;
+
+       status = connect_to_pipe(&p, transport, DCERPC_SAMR_NAME,
+                                DCERPC_SAMR_UUID, 
+                                DCERPC_SAMR_VERSION);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_destroy(mem_ctx);
+               return status;
+       }
+
+       status = dcerpc_bind_auth_none(p, DCERPC_SAMR_UUID,
+                                      DCERPC_SAMR_VERSION);
+
+       if (!NT_STATUS_IS_OK(status))
+               return status;
+
+       r4.in.system_name = talloc_asprintf(mem_ctx, "\\\\%s",
+                                           dcerpc_server_name(p));
+       r4.in.unknown = 0;
+       r4.in.access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED;
+       r4.out.connect_handle = &connect_handle;
+
+       status = dcerpc_samr_Connect4(p, mem_ctx, &r4);
+       if (!NT_STATUS_IS_OK(status))
+               return status;
+
+       {
+               struct samr_EnumDomains e;
+               uint32_t resume_handle = 0;
+               int i;
+
+               e.in.connect_handle = &connect_handle;
+               e.in.resume_handle = &resume_handle;
+               e.in.buf_size = (uint32_t)-1;
+               e.out.resume_handle = &resume_handle;
+               status = dcerpc_samr_EnumDomains(p, mem_ctx, &e);
+               if (!NT_STATUS_IS_OK(status))
+                       return status;
+
+               for (i=0; i<e.out.sam->count; i++) {
+
+                       struct samr_LookupDomain l;
+                       struct samr_OpenDomain o;
+
+                       if (strcmp(e.out.sam->entries[i].name.name,
+                                  "Builtin") == 0)
+                               continue;
+
+                       l.in.connect_handle = &connect_handle;
+                       l.in.domain = &e.out.sam->entries[i].name;
+
+                       status = dcerpc_samr_LookupDomain(p, mem_ctx, &l);
+
+                       if (!NT_STATUS_IS_OK(status))
+                               return status;
+
+                       o.in.connect_handle = &connect_handle;
+                       o.in.access_mask = 0x200;
+                       o.in.sid = l.out.sid;
+                       o.out.domain_handle = &domain_handle;
+
+                       status = dcerpc_samr_OpenDomain(p, mem_ctx, &o);
+
+                       if (!NT_STATUS_IS_OK(status))
+                               return status;
+
+                       break;
+               }
+       }
+
+       {
+               struct samr_LookupNames l;
+               struct samr_Name samr_name;
+               struct samr_OpenUser o;
+
+               samr_name.name = name;
+
+               l.in.domain_handle = &domain_handle;
+               l.in.num_names = 1;
+               l.in.names = &samr_name;
+
+               status = dcerpc_samr_LookupNames(p, mem_ctx, &l);
+
+               if (!NT_STATUS_IS_OK(status))
+                       return status;
+
+               o.in.domain_handle = &domain_handle;
+               o.in.rid = l.out.rids.ids[0];
+               o.in.access_mask = 0x100;
+               o.out.user_handle = &user_handle;
+
+               status = dcerpc_samr_OpenUser(p, mem_ctx, &o);
+               
+               if (!NT_STATUS_IS_OK(status))
+                       return status;
+       }
+
+       {
+               struct samr_GetGroupsForUser g;
+               struct samr_LookupRids l;
+               int i;
+
+               g.in.user_handle = &user_handle;
+
+               status = dcerpc_samr_GetGroupsForUser(p, mem_ctx, &g);
+               if (!NT_STATUS_IS_OK(status))
+                       return status;
+
+               l.in.domain_handle = &domain_handle;
+               l.in.num_rids = g.out.rids->count;
+               l.in.rids = talloc(mem_ctx,
+                                  g.out.rids->count * sizeof(uint32_t));
+
+               for (i=0; i<g.out.rids->count; i++)
+                       l.in.rids[i] = g.out.rids->rid[i].rid;
+
+               status = dcerpc_samr_LookupRids(p, mem_ctx, &l);
+               if (!NT_STATUS_IS_OK(status)) {
+                       talloc_destroy(mem_ctx);
+                       return status;
+               }
+       }
+
+       {
+               struct samr_Close c;
+
+               c.in.handle = &user_handle;
+               c.out.handle = &user_handle;
+               dcerpc_samr_Close(p, mem_ctx, &c);
+
+               c.in.handle = &domain_handle;
+               c.out.handle = &domain_handle;
+               dcerpc_samr_Close(p, mem_ctx, &c);
+
+               c.in.handle = &connect_handle;
+               c.out.handle = &connect_handle;
+               dcerpc_samr_Close(p, mem_ctx, &c);
+       }
+
+       talloc_free(p);
+       talloc_destroy(mem_ctx);
+
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS test_getallsids(struct smbcli_transport *transport,
+                               const char *name, BOOL includeDomain)
+{
+       TALLOC_CTX *mem_ctx;
+       NTSTATUS status;
+        struct dcerpc_pipe *p;
+
+       struct samr_Connect4 r4;
+       struct policy_handle connect_handle, user_handle;
+       struct policy_handle builtin_handle, domain_handle;
+       struct dom_sid *domain_sid;
+
+       struct dom_sid *user_sid;
+       struct dom_sid *primary_group_sid;
+       struct samr_GetGroupsForUser g;
+
+
+       mem_ctx = talloc_init("test_getallsids");
+       if (mem_ctx == NULL)
+               return NT_STATUS_NO_MEMORY;
+
+       status = connect_to_pipe(&p, transport, DCERPC_SAMR_NAME,
+                                DCERPC_SAMR_UUID, 
+                                DCERPC_SAMR_VERSION);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_destroy(mem_ctx);
+               return status;
+       }
+
+       status = dcerpc_bind_auth_none(p, DCERPC_SAMR_UUID,
+                                      DCERPC_SAMR_VERSION);
+
+       if (!NT_STATUS_IS_OK(status))
+               return status;
+
+       r4.in.system_name = talloc_asprintf(mem_ctx, "\\\\%s",
+                                           dcerpc_server_name(p));
+       r4.in.unknown = 0;
+       r4.in.access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED;
+       r4.out.connect_handle = &connect_handle;
+
+       status = dcerpc_samr_Connect4(p, mem_ctx, &r4);
+       if (!NT_STATUS_IS_OK(status))
+               return status;
+
+       {
+               struct samr_EnumDomains e;
+               struct samr_OpenDomain o;
+               uint32_t resume_handle = 0;
+               int i;
+
+               e.in.connect_handle = &connect_handle;
+               e.in.resume_handle = &resume_handle;
+               e.in.buf_size = (uint32_t)-1;
+               e.out.resume_handle = &resume_handle;
+               status = dcerpc_samr_EnumDomains(p, mem_ctx, &e);
+               if (!NT_STATUS_IS_OK(status))
+                       return status;
+
+               for (i=0; i<e.out.sam->count; i++) {
+
+                       struct samr_LookupDomain l;
+
+                       if (strcmp(e.out.sam->entries[i].name.name,
+                                  "Builtin") == 0)
+                               continue;
+
+                       l.in.connect_handle = &connect_handle;
+                       l.in.domain = &e.out.sam->entries[i].name;
+
+                       status = dcerpc_samr_LookupDomain(p, mem_ctx, &l);
+
+                       if (!NT_STATUS_IS_OK(status))
+                               return status;
+
+                       o.in.connect_handle = &connect_handle;
+                       o.in.access_mask = 0x200;
+                       domain_sid = l.out.sid;
+                       o.in.sid = l.out.sid;
+                       o.out.domain_handle = &domain_handle;
+
+                       status = dcerpc_samr_OpenDomain(p, mem_ctx, &o);
+
+                       if (!NT_STATUS_IS_OK(status))
+                               return status;
+                       break;
+               }
+               o.in.connect_handle = &connect_handle;
+               o.in.access_mask = 0x200;
+               o.in.sid = dom_sid_parse_talloc(mem_ctx, "S-1-5-32");
+               o.out.domain_handle = &builtin_handle;
+
+               status = dcerpc_samr_OpenDomain(p, mem_ctx, &o);
+
+               if (!NT_STATUS_IS_OK(status))
+                       return status;
+       }
+
+       {
+               struct samr_LookupNames l;
+               struct samr_Name samr_name;
+               struct samr_OpenUser o;
+
+               samr_name.name = name;
+
+               l.in.domain_handle = &domain_handle;
+               l.in.num_names = 1;
+               l.in.names = &samr_name;
+
+               status = dcerpc_samr_LookupNames(p, mem_ctx, &l);
+
+               if (!NT_STATUS_IS_OK(status))
+                       return status;
+
+               o.in.domain_handle = &domain_handle;
+               o.in.rid = l.out.rids.ids[0];
+               o.in.access_mask = 0x100;
+               o.out.user_handle = &user_handle;
+
+               status = dcerpc_samr_OpenUser(p, mem_ctx, &o);
+               
+               if (!NT_STATUS_IS_OK(status))
+                       return status;
+       }
+
+       {
+               struct samr_QueryUserInfo q;
+
+               q.in.user_handle = &user_handle;
+               q.in.level = 21;
+
+               status = dcerpc_samr_QueryUserInfo(p, mem_ctx, &q);
+
+               if (!NT_STATUS_IS_OK(status))
+                       return status;
+
+               user_sid = dom_sid_add_rid(mem_ctx, domain_sid,
+                                          q.out.info->info21.rid);
+               primary_group_sid = dom_sid_add_rid(mem_ctx, domain_sid,
+                                                   q.out.info->info21.primary_gid);
+       }
+
+       g.in.user_handle = &user_handle;
+
+       status = dcerpc_samr_GetGroupsForUser(p, mem_ctx, &g);
+       if (!NT_STATUS_IS_OK(status))
+               return status;
+
+       {
+               struct lsa_SidArray sids;
+               struct samr_Ids rids;
+               struct samr_GetAliasMembership ga;
+               int i;
+
+               ga.in.alias_handle = &builtin_handle;
+
+               sids.num_sids = g.out.rids->count+2;
+               sids.sids = talloc_array_p(mem_ctx, struct lsa_SidPtr,
+                                          g.out.rids->count+2);
+               sids.sids[0].sid = user_sid;
+               sids.sids[1].sid = primary_group_sid;
+               for (i=0; i<g.out.rids->count; i++) {
+                       sids.sids[i+2].sid = dom_sid_add_rid(mem_ctx,
+                                                            domain_sid,
+                                                            g.out.rids->rid[i].rid);
+               }
+               ga.in.sids = &sids;
+               ga.out.rids = &rids;
+
+               status = dcerpc_samr_GetAliasMembership(p, mem_ctx, &ga);
+               if (!NT_STATUS_IS_OK(status))
+                       return status;
+
+               if (includeDomain) {
+                       ga.in.alias_handle = &domain_handle;
+                       status = dcerpc_samr_GetAliasMembership(p, mem_ctx,
+                                                               &ga);
+                       if (!NT_STATUS_IS_OK(status))
+                               return status;
+               }
+       }
+
+       {
+               struct samr_Close c;
+
+               c.in.handle = &user_handle;
+               c.out.handle = &user_handle;
+               dcerpc_samr_Close(p, mem_ctx, &c);
+
+               c.in.handle = &domain_handle;
+               c.out.handle = &domain_handle;
+               dcerpc_samr_Close(p, mem_ctx, &c);
+
+               c.in.handle = &builtin_handle;
+               c.out.handle = &builtin_handle;
+               dcerpc_samr_Close(p, mem_ctx, &c);
+
+               c.in.handle = &connect_handle;
+               c.out.handle = &connect_handle;
+               dcerpc_samr_Close(p, mem_ctx, &c);
+       }
+
+       talloc_free(p);
+       talloc_destroy(mem_ctx);
+
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS test_remoteTOD(struct smbcli_transport *transport)
+{
+       TALLOC_CTX *mem_ctx;
+       NTSTATUS status;
+        struct dcerpc_pipe *p;
+       struct srvsvc_NetRemoteTOD r;
+
+       mem_ctx = talloc_init("test_lookupnames");
+       if (mem_ctx == NULL)
+               return NT_STATUS_NO_MEMORY;
+
+       status = connect_to_pipe(&p, transport, DCERPC_SRVSVC_NAME,
+                                DCERPC_SRVSVC_UUID,
+                                DCERPC_SRVSVC_VERSION);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_destroy(mem_ctx);
+               return status;
+       }
+
+       status = dcerpc_bind_auth_none(p, DCERPC_SRVSVC_UUID,
+                                      DCERPC_SRVSVC_VERSION);
+
+       if (!NT_STATUS_IS_OK(status))
+               return status;
+
+       r.in.server_unc = talloc_asprintf(mem_ctx,"\\\\%s",dcerpc_server_name(p));
+
+       ZERO_STRUCT(r.out);
+       status = dcerpc_srvsvc_NetRemoteTOD(p, mem_ctx, &r);
+       talloc_destroy(mem_ctx);
+       talloc_free(p);
+       return status;
+}
+
+static BOOL xp_login(const char *dcname, const char *wksname,
+                    const char *domain, const char *wkspwd,
+                    const char *user1name, const char *user1pw,
+                    const char *user2name, const char *user2pw)
+{
+        NTSTATUS status;
+       TALLOC_CTX *mem_ctx;
+       char *user1dom;
+
+       struct smbcli_transport *transport;
+
+        struct dcerpc_pipe *netlogon_pipe;
+       struct creds_CredentialState netlogon_creds;
+
+       struct dcerpc_pipe *netlogon_schannel_pipe;
+
+       talloc_enable_leak_report();
+
+       mem_ctx = talloc_init("rpc_login");
+
+       if (mem_ctx == NULL)
+               return False;
+
+       if (!NT_STATUS_IS_OK(after_negprot(&transport, dcname, 139,
+                                          wksname)))
+               return False;
+
+       if (!NT_STATUS_IS_OK(setup_netlogon_creds(transport, &netlogon_pipe,
+                                                 wksname, domain, wkspwd,
+                                                 &netlogon_creds)))
+               return False;
+
+       if (!NT_STATUS_IS_OK(test_enumtrusts(transport)))
+               return False;
+
+       user1dom = talloc_asprintf(mem_ctx, "%s\\%s", domain, user1name);
+
+       if (!NT_STATUS_IS_OK(test_lookupnames(transport, user1dom)))
+               return False;
+
+       status = connect_to_pipe(&netlogon_schannel_pipe,
+                                transport, DCERPC_NETLOGON_NAME,
+                                DCERPC_NETLOGON_UUID,
+                                DCERPC_NETLOGON_VERSION);
+
+       if (!NT_STATUS_IS_OK(status))
+               return False;
+
+       netlogon_schannel_pipe->flags |= DCERPC_SEAL;
+
+       status = dcerpc_bind_auth_schannel_withkey(netlogon_schannel_pipe,
+                                                  DCERPC_NETLOGON_UUID,
+                                                  DCERPC_NETLOGON_VERSION,
+                                                  "", "", "",
+                                                  netlogon_creds.session_key);
+
+       if (!NT_STATUS_IS_OK(status))
+                return False;
+
+       status = torture_samlogon(netlogon_schannel_pipe,
+                                 &netlogon_creds, wksname, domain,
+                                 user1name, user1pw);
+
+       if (!NT_STATUS_IS_OK(status))
+                return False;
+
+       talloc_free(netlogon_pipe);
+
+       status = torture_samlogon(netlogon_schannel_pipe,
+                                 &netlogon_creds, wksname, domain,
+                                 user2name, user2pw);
+
+       if (!NT_STATUS_IS_OK(status))
+                return False;
+
+       status = test_getgroups(transport, user2name);
+       
+       if (!NT_STATUS_IS_OK(status))
+                return False;
+
+       status = test_remoteTOD(transport);
+       
+       if (!NT_STATUS_IS_OK(status))
+                return False;
+
+       status = test_remoteTOD(transport);
+       
+       if (!NT_STATUS_IS_OK(status))
+                return False;
+
+       status = test_getallsids(transport, user2name, False);
+       
+       if (!NT_STATUS_IS_OK(status))
+                return False;
+
+       status = test_getgroups(transport, user2name);
+       
+       if (!NT_STATUS_IS_OK(status))
+                return False;
+
+       status = test_getallsids(transport, user2name, True);
+       
+       if (!NT_STATUS_IS_OK(status))
+                return False;
+
+       talloc_free(netlogon_schannel_pipe);
+
+       talloc_free(transport);
+
+       talloc_destroy(mem_ctx);
+
+       return True;
+}
+
+struct user_pw {
+       const char *username;
+       const char *password;
+};
+
+static const struct user_pw users[] = {
+       { "username1", "password1" },
+       { "username2", "password2" }
+};
+
+static const struct user_pw machines[] = {
+       { "machine1", "mpw1" },
+       { "machine2", "mpw2" }
+};
+
+BOOL torture_rpc_login(int dummy)
+{
+       const char *pdcname = "pdcname";
+       const char *domainname = "domain";
+
+       int useridx1 = rand() % ARRAY_SIZE(users);
+       int useridx2 = rand() % ARRAY_SIZE(users);
+       int machidx = rand() % ARRAY_SIZE(machines);
+       printf("machine: %s user1: %s user2: %s\n",
+              machines[machidx].username,
+              users[useridx1].username,
+              users[useridx2].username);
+
+       return xp_login(pdcname, machines[machidx].username,
+                       domainname, machines[machidx].password,
+                       users[useridx1].username,
+                       users[useridx1].password,
+                       users[useridx2].username,
+                       users[useridx2].password);
+}
index ce8b79943d3a52004ae08a0af629a1e88cf242bb..878325d448f04f0f3a1613b5c581b90d04f1a763 100644 (file)
@@ -2454,6 +2454,7 @@ static struct {
         {"RPC-COUNTCALLS", torture_rpc_countcalls, 0},
        {"RPC-MULTIBIND", torture_multi_bind, 0},
        {"RPC-DRSUAPI", torture_rpc_drsuapi, 0},
+       {"RPC-LOGIN", torture_rpc_login, 0},
 
        /* Distributed COM testers */
        {"DCOM-SIMPLE", torture_dcom_simple, 0},