summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/librpc/rpc/dcerpc_schannel.c66
-rw-r--r--source4/torture/config.mk1
-rw-r--r--source4/torture/rpc/xplogin.c1160
-rw-r--r--source4/torture/torture.c1
4 files changed, 1204 insertions, 24 deletions
diff --git a/source4/librpc/rpc/dcerpc_schannel.c b/source4/librpc/rpc/dcerpc_schannel.c
index 3472e1cbe2..c0db63e8b8 100644
--- a/source4/librpc/rpc/dcerpc_schannel.c
+++ b/source4/librpc/rpc/dcerpc_schannel.c
@@ -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",
diff --git a/source4/torture/config.mk b/source4/torture/config.mk
index b2b301babd..70a3e540f7 100644
--- a/source4/torture/config.mk
+++ b/source4/torture/config.mk
@@ -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
index 0000000000..a3cca7003c
--- /dev/null
+++ b/source4/torture/rpc/xplogin.c
@@ -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);
+}
diff --git a/source4/torture/torture.c b/source4/torture/torture.c
index ce8b79943d..878325d448 100644
--- a/source4/torture/torture.c
+++ b/source4/torture/torture.c
@@ -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},