1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

r1041: - pulled the domain join code out of the netlogon test and made it a separate utility function, to allow

multiple torture tests to temporarily join a domain

- fixed a session key size problem

- added a schannel test suite

- allow schannel to work with ncacn_ip_tcp
(This used to be commit 36f05e4d57)
This commit is contained in:
Andrew Tridgell 2004-06-06 07:14:10 +00:00 committed by Gerald (Jerry) Carter
parent 7ea6a0b1fc
commit a1318baa55
10 changed files with 515 additions and 237 deletions

View File

@ -286,7 +286,7 @@ void schannel_end(struct schannel_state **state)
create an schannel context state
*/
NTSTATUS schannel_start(struct schannel_state **state,
uint8_t session_key[16],
const uint8_t session_key[16],
BOOL initiator)
{
TALLOC_CTX *mem_ctx;

View File

@ -71,21 +71,28 @@ struct dcerpc_pipe {
};
/* dcerpc pipe flags */
#define DCERPC_DEBUG_PRINT_IN (1<<0)
#define DCERPC_DEBUG_PRINT_OUT (1<<1)
#define DCERPC_DEBUG_PRINT_IN (1<<0)
#define DCERPC_DEBUG_PRINT_OUT (1<<1)
#define DCERPC_DEBUG_PRINT_BOTH (DCERPC_DEBUG_PRINT_IN | DCERPC_DEBUG_PRINT_OUT)
#define DCERPC_DEBUG_VALIDATE_IN 4
#define DCERPC_DEBUG_VALIDATE_OUT 8
#define DCERPC_DEBUG_VALIDATE_IN (1<<2)
#define DCERPC_DEBUG_VALIDATE_OUT (1<<3)
#define DCERPC_DEBUG_VALIDATE_BOTH (DCERPC_DEBUG_VALIDATE_IN | DCERPC_DEBUG_VALIDATE_OUT)
#define DCERPC_SIGN 16
#define DCERPC_SEAL 32
#define DCERPC_SIGN (1<<4)
#define DCERPC_SEAL (1<<5)
#define DCERPC_PUSH_BIGENDIAN 64
#define DCERPC_PULL_BIGENDIAN 128
#define DCERPC_PUSH_BIGENDIAN (1<<6)
#define DCERPC_PULL_BIGENDIAN (1<<7)
#define DCERPC_SCHANNEL 256
#define DCERPC_SCHANNEL_BDC (1<<8)
#define DCERPC_SCHANNEL_WORKSTATION (1<<9)
#define DCERPC_SCHANNEL_DOMAIN (1<<10)
#define DCERPC_SCHANNEL_ANY (DCERPC_SCHANNEL_BDC| \
DCERPC_SCHANNEL_DOMAIN| \
DCERPC_SCHANNEL_WORKSTATION)
#define DCERPC_AUTH_OPTIONS (DCERPC_SEAL|DCERPC_SIGN|DCERPC_SCHANNEL_ANY)
/*
this is used to find pointers to calls

View File

@ -81,7 +81,7 @@ NTSTATUS dcerpc_schannel_key(struct dcerpc_pipe *p,
const char *username,
const char *password,
int chan_type,
uint8_t new_session_key[8])
uint8_t new_session_key[16])
{
NTSTATUS status;
struct dcerpc_pipe *p2;
@ -91,7 +91,7 @@ NTSTATUS dcerpc_schannel_key(struct dcerpc_pipe *p,
struct samr_Password mach_pwd;
struct creds_CredentialState creds;
const char *workgroup, *workstation;
uint32_t negotiate_flags = 0;
uint32_t negotiate_flags = NETLOGON_NEG_AUTH2_FLAGS;
workstation = username;
workgroup = domain;
@ -99,10 +99,10 @@ NTSTATUS dcerpc_schannel_key(struct dcerpc_pipe *p,
/*
step 1 - establish a netlogon connection, with no authentication
*/
status = dcerpc_secondary_smb(p, &p2,
DCERPC_NETLOGON_NAME,
DCERPC_NETLOGON_UUID,
DCERPC_NETLOGON_VERSION);
status = dcerpc_secondary_connection(p, &p2,
DCERPC_NETLOGON_NAME,
DCERPC_NETLOGON_UUID,
DCERPC_NETLOGON_VERSION);
/*
@ -152,7 +152,7 @@ NTSTATUS dcerpc_schannel_key(struct dcerpc_pipe *p,
*/
dcerpc_pipe_close(p2);
memcpy(new_session_key, creds.session_key, 8);
memcpy(new_session_key, creds.session_key, 16);
return NT_STATUS_OK;
}
@ -167,17 +167,13 @@ NTSTATUS dcerpc_bind_auth_schannel_key(struct dcerpc_pipe *p,
const char *uuid, uint_t version,
const char *domain,
const char *username,
const uint8_t session_key[8])
const uint8_t session_key[16])
{
NTSTATUS status;
uint8_t full_session_key[16];
struct schannel_state *schannel_state;
const char *workgroup, *workstation;
struct dcerpc_bind_schannel bind_schannel;
memcpy(full_session_key, session_key, 8);
memset(full_session_key+8, 0, 8);
workstation = username;
workgroup = domain;
@ -234,7 +230,7 @@ NTSTATUS dcerpc_bind_auth_schannel_key(struct dcerpc_pipe *p,
goto done;
}
status = schannel_start(&schannel_state, full_session_key, True);
status = schannel_start(&schannel_state, session_key, True);
if (!NT_STATUS_IS_OK(status)) {
goto done;
}
@ -265,11 +261,19 @@ NTSTATUS dcerpc_bind_auth_schannel(struct dcerpc_pipe *p,
const char *password)
{
NTSTATUS status;
uint8_t session_key[8];
uint8_t session_key[16];
int chan_type = 0;
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,
lp_server_role() == ROLE_DOMAIN_BDC? SEC_CHAN_BDC:SEC_CHAN_WKSTA,
session_key);
chan_type, session_key);
if (!NT_STATUS_IS_OK(status)) {
return status;
}

View File

@ -275,7 +275,6 @@ static const struct {
} ncacn_options[] = {
{"sign", DCERPC_SIGN},
{"seal", DCERPC_SEAL},
{"schannel", DCERPC_SCHANNEL},
{"validate", DCERPC_DEBUG_VALIDATE_BOTH},
{"print", DCERPC_DEBUG_PRINT_BOTH},
{"bigendian", DCERPC_PUSH_BIGENDIAN}
@ -458,11 +457,18 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_np(struct dcerpc_pipe **p,
pipe_name += 6;
}
status = cli_full_connection(&cli, lp_netbios_name(),
binding->host, NULL,
"ipc$", "?????",
username, username[0]?domain:"",
password, 0, &retry);
if ((binding->flags & DCERPC_SCHANNEL_ANY) || !username || !username[0]) {
status = cli_full_connection(&cli, lp_netbios_name(),
binding->host, NULL,
"ipc$", "?????",
"", "", NULL, 0, &retry);
} else {
status = cli_full_connection(&cli, lp_netbios_name(),
binding->host, NULL,
"ipc$", "?????",
username, domain,
password, 0, &retry);
}
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("Failed to connect to %s - %s\n", binding->host, nt_errstr(status)));
return status;
@ -482,23 +488,15 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_np(struct dcerpc_pipe **p,
(*p)->flags = binding->flags;
if (binding->flags & DCERPC_SCHANNEL) {
const char *trust_password = NULL; // samdb_fetch_member_password();
if (!trust_password) {
DEBUG(0,("Unable to fetch machine password\n"));
goto done;
}
if (binding->flags & DCERPC_SCHANNEL_ANY) {
status = dcerpc_bind_auth_schannel(*p, pipe_uuid, pipe_version,
lp_workgroup(),
lp_netbios_name(),
trust_password);
domain, username, password);
} else if (binding->flags & (DCERPC_SIGN | DCERPC_SEAL)) {
status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version, domain, username, password);
} else {
status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version);
}
done:
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("Failed to bind to uuid %s - %s\n", pipe_uuid, nt_errstr(status)));
dcerpc_pipe_close(*p);
@ -552,7 +550,10 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp(struct dcerpc_pipe **p,
(*p)->flags = binding->flags;
if (!(binding->flags & (DCERPC_SIGN|DCERPC_SEAL)) && !username[0]) {
if (binding->flags & DCERPC_SCHANNEL_ANY) {
status = dcerpc_bind_auth_schannel(*p, pipe_uuid, pipe_version,
domain, username, password);
} else if (!(binding->flags & (DCERPC_SIGN|DCERPC_SEAL)) && !username[0]) {
status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version);
} else {
status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version,
@ -560,7 +561,8 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp(struct dcerpc_pipe **p,
}
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("Failed to bind to uuid %s - %s\n", pipe_uuid, nt_errstr(status)));
DEBUG(0,("Failed to bind to uuid %s - %s\n",
pipe_uuid, nt_errstr(status)));
dcerpc_pipe_close(*p);
return status;
}
@ -635,28 +637,46 @@ NTSTATUS dcerpc_pipe_connect(struct dcerpc_pipe **p,
/*
create a secondary dcerpc connection from a primary SMB connection
create a secondary dcerpc connection from a primary connection
the secondary connection will be on the same SMB connection, but use a new fnum
if the primary is a SMB connection then the secondary connection
will be on the same SMB connection, but use a new fnum
*/
NTSTATUS dcerpc_secondary_smb(struct dcerpc_pipe *p, struct dcerpc_pipe **p2,
const char *pipe_name,
const char *pipe_uuid,
uint32_t pipe_version)
NTSTATUS dcerpc_secondary_connection(struct dcerpc_pipe *p, struct dcerpc_pipe **p2,
const char *pipe_name,
const char *pipe_uuid,
uint32_t pipe_version)
{
NTSTATUS status;
struct cli_tree *tree;
NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
struct dcerpc_binding b;
tree = dcerpc_smb_tree(p);
if (!tree) {
return NT_STATUS_INVALID_PARAMETER;
switch (p->transport.transport) {
case NCACN_NP:
tree = dcerpc_smb_tree(p);
if (!tree) {
return NT_STATUS_INVALID_PARAMETER;
}
status = dcerpc_pipe_open_smb(p2, tree, pipe_name);
break;
case NCACN_IP_TCP:
status = dcerpc_parse_binding(p->mem_ctx, p->binding_string, &b);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
b.flags &= ~DCERPC_AUTH_OPTIONS;
status = dcerpc_pipe_connect_ncacn_ip_tcp(p2, &b, pipe_uuid,
pipe_version, NULL,
NULL, NULL);
break;
}
status = dcerpc_pipe_open_smb(p2, tree, pipe_name);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
return status;
}
(*p2)->flags = p->flags;
status = dcerpc_bind_auth_none(*p2, pipe_uuid, pipe_version);

View File

@ -61,6 +61,8 @@ ADD_OBJ_FILES = \
torture/rpc/mgmt.o \
torture/rpc/scanner.o \
torture/rpc/autoidl.o \
torture/rpc/testjoin.o \
torture/rpc/schannel.o \
torture/rpc/netlogon.o
REQUIRED_SUBSYSTEMS = \
LIBSMB

View File

@ -25,173 +25,10 @@
#include "includes.h"
static const char *machine_password;
#define TEST_MACHINE_NAME "torturetest"
static struct {
struct dcerpc_pipe *p;
const char *machine_password;
struct policy_handle acct_handle;
} join;
/*
join the domain as a BDC
*/
static BOOL join_domain_bdc(TALLOC_CTX *mem_ctx)
{
NTSTATUS status;
struct samr_Connect c;
struct samr_CreateUser2 r;
struct samr_OpenDomain o;
struct samr_LookupDomain l;
struct samr_GetUserPwInfo pwp;
struct samr_SetUserInfo s;
union samr_UserInfo u;
struct policy_handle handle;
struct policy_handle domain_handle;
uint32_t access_granted;
uint32_t rid;
BOOL ret = True;
DATA_BLOB session_key;
struct samr_Name name;
int policy_min_pw_len = 0;
printf("Connecting to SAMR\n");
status = torture_rpc_connection(&join.p,
DCERPC_SAMR_NAME,
DCERPC_SAMR_UUID,
DCERPC_SAMR_VERSION);
if (!NT_STATUS_IS_OK(status)) {
return False;
}
c.in.system_name = NULL;
c.in.access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED;
c.out.handle = &handle;
status = dcerpc_samr_Connect(join.p, mem_ctx, &c);
if (!NT_STATUS_IS_OK(status)) {
printf("samr_Connect failed - %s\n", nt_errstr(status));
return False;
}
printf("Opening domain %s\n", lp_workgroup());
name.name = lp_workgroup();
l.in.handle = &handle;
l.in.domain = &name;
status = dcerpc_samr_LookupDomain(join.p, mem_ctx, &l);
if (!NT_STATUS_IS_OK(status)) {
printf("LookupDomain failed - %s\n", nt_errstr(status));
return False;
}
o.in.handle = &handle;
o.in.access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED;
o.in.sid = l.out.sid;
o.out.domain_handle = &domain_handle;
status = dcerpc_samr_OpenDomain(join.p, mem_ctx, &o);
if (!NT_STATUS_IS_OK(status)) {
printf("OpenDomain failed - %s\n", nt_errstr(status));
return False;
}
printf("Creating machine account %s\n", TEST_MACHINE_NAME);
again:
name.name = talloc_asprintf(mem_ctx, "%s$", TEST_MACHINE_NAME);
r.in.handle = &domain_handle;
r.in.account_name = &name;
r.in.acct_flags = ACB_SVRTRUST;
r.in.access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED;
r.out.acct_handle = &join.acct_handle;
r.out.access_granted = &access_granted;
r.out.rid = &rid;
status = dcerpc_samr_CreateUser2(join.p, mem_ctx, &r);
if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS) &&
test_DeleteUser_byname(join.p, mem_ctx, &domain_handle, name.name)) {
goto again;
}
if (!NT_STATUS_IS_OK(status)) {
printf("CreateUser2 failed - %s\n", nt_errstr(status));
return False;
}
pwp.in.handle = &join.acct_handle;
status = dcerpc_samr_GetUserPwInfo(join.p, mem_ctx, &pwp);
if (NT_STATUS_IS_OK(status)) {
policy_min_pw_len = pwp.out.info.min_password_len;
}
join.machine_password = generate_random_str(mem_ctx, MAX(8, policy_min_pw_len));
printf("Setting machine account password '%s'\n", join.machine_password);
s.in.handle = &join.acct_handle;
s.in.info = &u;
s.in.level = 24;
encode_pw_buffer(u.info24.password.data, join.machine_password, STR_UNICODE);
u.info24.pw_len = strlen(join.machine_password);
status = dcerpc_fetch_session_key(join.p, &session_key);
if (!NT_STATUS_IS_OK(status)) {
printf("SetUserInfo level %u - no session key - %s\n",
s.in.level, nt_errstr(status));
return False;
}
arcfour_crypt_blob(u.info24.password.data, 516, &session_key);
status = dcerpc_samr_SetUserInfo(join.p, mem_ctx, &s);
if (!NT_STATUS_IS_OK(status)) {
printf("SetUserInfo failed - %s\n", nt_errstr(status));
return False;
}
s.in.handle = &join.acct_handle;
s.in.info = &u;
s.in.level = 16;
u.info16.acct_flags = ACB_SVRTRUST;
printf("Resetting ACB flags\n");
status = dcerpc_samr_SetUserInfo(join.p, mem_ctx, &s);
if (!NT_STATUS_IS_OK(status)) {
printf("SetUserInfo failed - %s\n", nt_errstr(status));
return False;
}
return ret;
}
/*
leave the domain as a BDC
*/
static BOOL leave_domain_bdc(TALLOC_CTX *mem_ctx)
{
struct samr_DeleteUser d;
NTSTATUS status;
d.in.handle = &join.acct_handle;
d.out.handle = &join.acct_handle;
status = dcerpc_samr_DeleteUser(join.p, mem_ctx, &d);
if (!NT_STATUS_IS_OK(status)) {
printf("Delete of machine account failed\n");
return False;
}
return True;
}
static BOOL test_LogonUasLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
{
NTSTATUS status;
@ -259,7 +96,7 @@ static BOOL test_SetupCredentials(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
return False;
}
plain_pass = join.machine_password;
plain_pass = machine_password;
if (!plain_pass) {
printf("Unable to fetch machine password!\n");
return False;
@ -319,7 +156,7 @@ static BOOL test_SetupCredentials2(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
return False;
}
plain_pass = join.machine_password;
plain_pass = machine_password;
if (!plain_pass) {
printf("Unable to fetch machine password!\n");
return False;
@ -385,7 +222,7 @@ static BOOL test_SetupCredentials3(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
return False;
}
plain_pass = join.machine_password;
plain_pass = machine_password;
if (!plain_pass) {
printf("Unable to fetch machine password!\n");
return False;
@ -1157,7 +994,7 @@ static BOOL test_SetPassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
printf("Credential chaining failed\n");
}
join.machine_password = password;
machine_password = password;
if (!test_SetupCredentials(p, mem_ctx, &creds)) {
printf("ServerPasswordSet failed to actually change the password\n");
@ -1679,10 +1516,13 @@ BOOL torture_rpc_netlogon(int dummy)
struct dcerpc_pipe *p;
TALLOC_CTX *mem_ctx;
BOOL ret = True;
void *join_ctx;
mem_ctx = talloc_init("torture_rpc_netlogon");
if (!join_domain_bdc(mem_ctx)) {
join_ctx = torture_join_domain(TEST_MACHINE_NAME, lp_workgroup(), ACB_SVRTRUST,
&machine_password);
if (!join_ctx) {
printf("Failed to join as BDC\n");
return False;
}
@ -1757,10 +1597,7 @@ BOOL torture_rpc_netlogon(int dummy)
torture_rpc_close(p);
if (!leave_domain_bdc(mem_ctx)) {
printf("Failed to delete BDC machine account\n");
return False;
}
torture_leave_domain(join_ctx);
return ret;
}

View File

@ -0,0 +1,130 @@
/*
Unix SMB/CIFS implementation.
test suite for schannel operations
Copyright (C) Andrew Tridgell 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"
#define TEST_MACHINE_NAME "schanneltest"
static BOOL test_samr_ops(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
{
NTSTATUS status;
struct samr_GetDomPwInfo r;
int i;
struct samr_Name name;
name.name = lp_workgroup();
r.in.name = &name;
printf("Testing GetDomPwInfo with name %s\n", r.in.name->name);
/* do several ops to test credential chaining */
for (i=0;i<5;i++) {
status = dcerpc_samr_GetDomPwInfo(p, mem_ctx, &r);
if (!NT_STATUS_IS_OK(status)) {
printf("GetDomPwInfo op %d failed - %s\n", i, nt_errstr(status));
return False;
}
}
return True;
}
static BOOL test_schannel(TALLOC_CTX *mem_ctx,
uint16 acct_flags, uint32 dcerpc_flags,
uint32 schannel_type)
{
void *join_ctx;
const char *machine_password;
NTSTATUS status;
char *binding = lp_parm_string(-1, "torture", "binding");
struct dcerpc_binding b;
struct dcerpc_pipe *p;
join_ctx = torture_join_domain(TEST_MACHINE_NAME, lp_workgroup(), acct_flags,
&machine_password);
if (!join_ctx) {
printf("Failed to join domain with acct_flags=0x%x\n", acct_flags);
return False;
}
status = dcerpc_parse_binding(mem_ctx, binding, &b);
if (!NT_STATUS_IS_OK(status)) {
printf("Bad binding string %s\n", binding);
goto failed;
}
b.flags &= ~DCERPC_AUTH_OPTIONS;
b.flags |= dcerpc_flags;
status = dcerpc_pipe_connect_b(&p, &b,
DCERPC_SAMR_UUID,
DCERPC_SAMR_VERSION,
lp_workgroup(),
TEST_MACHINE_NAME,
machine_password);
if (!NT_STATUS_IS_OK(status)) {
printf("Failed to connect with schannel\n");
goto failed;
}
test_samr_ops(p, mem_ctx);
torture_leave_domain(join_ctx);
return True;
failed:
torture_leave_domain(join_ctx);
return False;
}
BOOL torture_rpc_schannel(int dummy)
{
TALLOC_CTX *mem_ctx;
BOOL ret = True;
struct {
uint16 acct_flags;
uint32 dcerpc_flags;
uint32 schannel_type;
} tests[] = {
{ ACB_WSTRUST, DCERPC_SCHANNEL_WORKSTATION | DCERPC_SIGN, 3 },
{ ACB_WSTRUST, DCERPC_SCHANNEL_WORKSTATION | DCERPC_SEAL, 3 },
{ ACB_SVRTRUST, DCERPC_SCHANNEL_BDC | DCERPC_SIGN, 3 },
{ ACB_SVRTRUST, DCERPC_SCHANNEL_BDC | DCERPC_SEAL, 3 }
};
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;
}
}
return ret;
}

View File

@ -587,10 +587,10 @@ static BOOL test_SecondaryClosePrinter(struct dcerpc_pipe *p, TALLOC_CTX *mem_ct
printf("testing close on secondary pipe\n");
status = dcerpc_secondary_smb(p, &p2,
DCERPC_SPOOLSS_NAME,
DCERPC_SPOOLSS_UUID,
DCERPC_SPOOLSS_VERSION);
status = dcerpc_secondary_connection(p, &p2,
DCERPC_SPOOLSS_NAME,
DCERPC_SPOOLSS_UUID,
DCERPC_SPOOLSS_VERSION);
if (!NT_STATUS_IS_OK(status)) {
printf("Failed to create secondary connection\n");
return False;

View File

@ -0,0 +1,277 @@
/*
Unix SMB/CIFS implementation.
utility code to join/leave a domain
Copyright (C) Andrew Tridgell 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.
*/
/*
this code is used by other torture modules to join/leave a domain
as either a member, bdc or thru a trust relationship
*/
#include "includes.h"
struct test_join {
TALLOC_CTX *mem_ctx;
struct dcerpc_pipe *p;
const char *machine_password;
struct policy_handle acct_handle;
};
static NTSTATUS DeleteUser_byname(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
struct policy_handle *handle, const char *name)
{
NTSTATUS status;
struct samr_DeleteUser d;
struct policy_handle acct_handle;
uint32_t rid;
struct samr_LookupNames n;
struct samr_Name sname;
struct samr_OpenUser r;
sname.name = name;
n.in.handle = handle;
n.in.num_names = 1;
n.in.names = &sname;
status = dcerpc_samr_LookupNames(p, mem_ctx, &n);
if (NT_STATUS_IS_OK(status)) {
rid = n.out.rids.ids[0];
} else {
return status;
}
r.in.handle = handle;
r.in.access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED;
r.in.rid = rid;
r.out.acct_handle = &acct_handle;
status = dcerpc_samr_OpenUser(p, mem_ctx, &r);
if (!NT_STATUS_IS_OK(status)) {
printf("OpenUser(%s) failed - %s\n", name, nt_errstr(status));
return status;
}
d.in.handle = &acct_handle;
d.out.handle = &acct_handle;
status = dcerpc_samr_DeleteUser(p, mem_ctx, &d);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
return NT_STATUS_OK;
}
/*
join the domain as a test machine
an opaque pointer is returned. Pass it to torture_leave_domain()
when finished
*/
void *torture_join_domain(const char *machine_name,
const char *domain,
uint16 acct_flags,
const char **machine_password)
{
NTSTATUS status;
struct samr_Connect c;
struct samr_CreateUser2 r;
struct samr_OpenDomain o;
struct samr_LookupDomain l;
struct samr_GetUserPwInfo pwp;
struct samr_SetUserInfo s;
union samr_UserInfo u;
struct policy_handle handle;
struct policy_handle domain_handle;
uint32_t access_granted;
uint32_t rid;
DATA_BLOB session_key;
struct samr_Name name;
int policy_min_pw_len = 0;
struct test_join *join;
TALLOC_CTX *mem_ctx;
mem_ctx = talloc_init("torture_join_domain");
if (!mem_ctx) {
return NULL;
}
join = talloc_p(mem_ctx, struct test_join);
if (join == NULL) {
talloc_destroy(mem_ctx);
return NULL;
}
ZERO_STRUCTP(join);
join->mem_ctx = mem_ctx;
printf("Connecting to SAMR\n");
status = torture_rpc_connection(&join->p,
DCERPC_SAMR_NAME,
DCERPC_SAMR_UUID,
DCERPC_SAMR_VERSION);
if (!NT_STATUS_IS_OK(status)) {
goto failed;
}
c.in.system_name = NULL;
c.in.access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED;
c.out.handle = &handle;
status = dcerpc_samr_Connect(join->p, mem_ctx, &c);
if (!NT_STATUS_IS_OK(status)) {
printf("samr_Connect failed - %s\n", nt_errstr(status));
goto failed;
}
printf("Opening domain %s\n", domain);
name.name = domain;
l.in.handle = &handle;
l.in.domain = &name;
status = dcerpc_samr_LookupDomain(join->p, mem_ctx, &l);
if (!NT_STATUS_IS_OK(status)) {
printf("LookupDomain failed - %s\n", nt_errstr(status));
goto failed;
}
o.in.handle = &handle;
o.in.access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED;
o.in.sid = l.out.sid;
o.out.domain_handle = &domain_handle;
status = dcerpc_samr_OpenDomain(join->p, mem_ctx, &o);
if (!NT_STATUS_IS_OK(status)) {
printf("OpenDomain failed - %s\n", nt_errstr(status));
goto failed;
}
printf("Creating machine account %s\n", machine_name);
again:
name.name = talloc_asprintf(mem_ctx, "%s$", machine_name);
r.in.handle = &domain_handle;
r.in.account_name = &name;
r.in.acct_flags = acct_flags;
r.in.access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED;
r.out.acct_handle = &join->acct_handle;
r.out.access_granted = &access_granted;
r.out.rid = &rid;
status = dcerpc_samr_CreateUser2(join->p, mem_ctx, &r);
if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
status = DeleteUser_byname(join->p, mem_ctx, &domain_handle, name.name);
if (NT_STATUS_IS_OK(status)) {
goto again;
}
}
if (!NT_STATUS_IS_OK(status)) {
printf("CreateUser2 failed - %s\n", nt_errstr(status));
goto failed;
}
pwp.in.handle = &join->acct_handle;
status = dcerpc_samr_GetUserPwInfo(join->p, mem_ctx, &pwp);
if (NT_STATUS_IS_OK(status)) {
policy_min_pw_len = pwp.out.info.min_password_len;
}
join->machine_password = generate_random_str(mem_ctx, MAX(8, policy_min_pw_len));
printf("Setting machine account password '%s'\n", join->machine_password);
s.in.handle = &join->acct_handle;
s.in.info = &u;
s.in.level = 24;
encode_pw_buffer(u.info24.password.data, join->machine_password, STR_UNICODE);
u.info24.pw_len = strlen(join->machine_password);
status = dcerpc_fetch_session_key(join->p, &session_key);
if (!NT_STATUS_IS_OK(status)) {
printf("SetUserInfo level %u - no session key - %s\n",
s.in.level, nt_errstr(status));
torture_leave_domain(&join);
goto failed;
}
arcfour_crypt_blob(u.info24.password.data, 516, &session_key);
status = dcerpc_samr_SetUserInfo(join->p, mem_ctx, &s);
if (!NT_STATUS_IS_OK(status)) {
printf("SetUserInfo failed - %s\n", nt_errstr(status));
goto failed;
}
s.in.handle = &join->acct_handle;
s.in.info = &u;
s.in.level = 16;
u.info16.acct_flags = acct_flags;
printf("Resetting ACB flags\n");
status = dcerpc_samr_SetUserInfo(join->p, mem_ctx, &s);
if (!NT_STATUS_IS_OK(status)) {
printf("SetUserInfo failed - %s\n", nt_errstr(status));
goto failed;
}
*machine_password = join->machine_password;
return join;
failed:
torture_leave_domain(join);
return NULL;
}
/*
leave the domain, deleting the machine acct
*/
void torture_leave_domain(void *join_ctx)
{
struct test_join *join = join_ctx;
struct samr_DeleteUser d;
NTSTATUS status;
if (!uuid_all_zero(&join->acct_handle.uuid)) {
d.in.handle = &join->acct_handle;
d.out.handle = &join->acct_handle;
status = dcerpc_samr_DeleteUser(join->p, join->mem_ctx, &d);
if (!NT_STATUS_IS_OK(status)) {
printf("Delete of machine account failed\n");
}
}
if (join->p) {
torture_rpc_close(join->p);
}
talloc_destroy(join->mem_ctx);
}

View File

@ -2795,7 +2795,7 @@ static BOOL run_vuidtest(int dummy)
const char *fname = "\\vuid.tst";
int fnum;
size_t size;
time_t c_time, a_time, m_time, w_time, m_time2;
time_t c_time, a_time, m_time;
BOOL correct = True;
uint16_t orig_vuid;
@ -4131,6 +4131,7 @@ static struct {
{"RPC-SPOOLSS", torture_rpc_spoolss, 0},
{"RPC-SAMR", torture_rpc_samr, 0},
{"RPC-NETLOGON", torture_rpc_netlogon, 0},
{"RPC-SCHANNEL", torture_rpc_schannel, 0},
{"RPC-WKSSVC", torture_rpc_wkssvc, 0},
{"RPC-SRVSVC", torture_rpc_srvsvc, 0},
{"RPC-ATSVC", torture_rpc_atsvc, 0},