to NT4. Actually, anything other than 1ff would seem to do... */
#define NETLOGON_NEG_AUTH2_FLAGS 0x000701ff
-
-#define NETLOGON_NEG_ARCFOUR 0x00000004
-#define NETLOGON_NEG_128BIT 0x00004000
-
-#define NETLOGON_NEG_SCHANNEL 0x40000000
-
/* these are the flags that ADS clients use */
#define NETLOGON_NEG_AUTH2_ADS_FLAGS (0x200fbffb | NETLOGON_NEG_ARCFOUR | NETLOGON_NEG_128BIT | NETLOGON_NEG_SCHANNEL)
const char *realm;
const char *name;
const char *password;
- char schan_session_key[16];
};
struct gensec_target {
const char *principal;
/* Decode a sam password hash into a password. The password hash is the
same method used to store passwords in the NT registry. The DES key
used is based on the RID of the user. */
-void sam_pwd_hash(uint_t rid, const uint8_t *in, uint8_t *out, int forw)
+void sam_rid_crypt(uint_t rid, const uint8_t *in, uint8_t *out, int forw)
{
uint8_t s[14];
return final_response;
}
-BOOL SMBNTLMv2encrypt(const char *user, const char *domain, const char *password,
- const DATA_BLOB *server_chal,
- const DATA_BLOB *names_blob,
- DATA_BLOB *lm_response, DATA_BLOB *nt_response,
- DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key)
+BOOL SMBNTLMv2encrypt_hash(const char *user, const char *domain, const char nt_hash[16],
+ const DATA_BLOB *server_chal,
+ const DATA_BLOB *names_blob,
+ DATA_BLOB *lm_response, DATA_BLOB *nt_response,
+ DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key)
{
- uint8_t nt_hash[16];
uint8_t ntlm_v2_hash[16];
- E_md4hash(password, nt_hash);
/* We don't use the NT# directly. Instead we use it mashed up with
the username and domain.
return True;
}
+BOOL SMBNTLMv2encrypt(const char *user, const char *domain, const char *password,
+ const DATA_BLOB *server_chal,
+ const DATA_BLOB *names_blob,
+ DATA_BLOB *lm_response, DATA_BLOB *nt_response,
+ DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key)
+{
+ uint8_t nt_hash[16];
+ E_md4hash(password, nt_hash);
+
+ return SMBNTLMv2encrypt_hash(user, domain, nt_hash, server_chal, names_blob,
+ lm_response, nt_response, lm_session_key, user_session_key);
+}
+
/***********************************************************
encode a password buffer with a unicode password. The buffer
is filled with random data to make it harder to attack.
/*****************/
/* Function 0x07 */
+ /* SAM database types */
+ const int SAM_DATABASE_DOMAIN = 0x00; /* Domain users and groups */
+ const int SAM_DATABASE_BUILTIN = 0x01; /* BUILTIN users and groups */
+ const int SAM_DATABASE_PRIVS = 0x02; /* Privileges */
+
typedef struct {
unistr *account_name;
netr_String unknown1;
netr_String logon_script;
netr_String description;
netr_String workstations;
- NTTIME LastLogon;
- NTTIME LastLogoff;
+ NTTIME last_logon;
+ NTTIME last_logoff;
samr_LogonHours logon_hours;
uint16 bad_pw_count;
uint16 logon_count;
- NTTIME PwLastSet;
- NTTIME AccountExpires;
- uint32 AccountControl;
- samr_Password lmpw;
- samr_Password ntpw;
- bool8 NTPwPresent;
- bool8 LMPwPresent;
- bool8 PwExpired;
+ NTTIME last_password_change;
+ NTTIME acct_expiry;
+ uint32 acct_flags;
+ samr_Password lmpassword;
+ samr_Password ntpassword;
+ bool8 ntpassword_present;
+ bool8 lmpassword_present;
+ bool8 password_expired;
netr_String UserComment;
netr_String Parameters;
uint16 CountryCode;
);
+ /* If this flag is not set, then the passwords and LM session keys are
+ * encrypted with DES calls. (And the user session key is
+ * unencrypted) */
+ const int NETLOGON_NEG_ARCFOUR = 0x00000004;
+ const int NETLOGON_NEG_128BIT = 0x00004000;
+ const int NETLOGON_NEG_SCHANNEL = 0x40000000;
+
/*****************/
/* Function 0x0F */
struct dcerpc_schannel_state {
enum schannel_position state;
struct schannel_state *schannel_state;
- struct creds_CredentialState creds;
+ struct creds_CredentialState *creds;
char *account_name;
};
const char *username,
const char *password,
int chan_type,
- uint8_t new_session_key[16]);
+ struct creds_CredentialState *creds);
/*
wrappers for the schannel_*() functions
return NT_STATUS_OK;
}
+ status = schannel_start(&dce_schan_state->schannel_state,
+ dce_schan_state->creds->session_key,
+ True);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to start schannel client\n"));
+ return status;
+ }
+ talloc_steal(dce_schan_state, dce_schan_state->schannel_state);
+
bind_schannel.unknown1 = 0;
#if 0
/* to support this we'd need to have access to the full domain name */
/* start up the schannel server code */
status = schannel_start(&dce_schan_state->schannel_state,
- dce_schan_state->creds.session_key, False);
+ dce_schan_state->creds->session_key, False);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(3, ("Could not initialise schannel state for account %s: %s\n",
account_name, nt_errstr(status)));
{
struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data;
- *creds = talloc_p(mem_ctx, struct creds_CredentialState);
- if (!*creds) {
- return NT_STATUS_NO_MEMORY;
- }
-
- **creds = dce_schan_state->creds;
+ *creds = dce_schan_state->creds;
return NT_STATUS_OK;
}
static NTSTATUS dcerpc_schannel_server_start(struct gensec_security *gensec_security)
{
NTSTATUS status;
- struct dcerpc_schannel_state *dce_schan_state;
status = dcerpc_schannel_start(gensec_security);
-
- dce_schan_state = gensec_security->private_data;
- dce_schan_state->schannel_state = NULL;
-
if (!NT_STATUS_IS_OK(status)) {
return status;
}
+
return NT_STATUS_OK;
}
static NTSTATUS dcerpc_schannel_client_start(struct gensec_security *gensec_security)
{
NTSTATUS status;
- struct dcerpc_schannel_state *dce_schan_state;
status = dcerpc_schannel_start(gensec_security);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- dce_schan_state = gensec_security->private_data;
-
- status = schannel_start(&dce_schan_state->schannel_state,
- gensec_security->user.schan_session_key,
- True);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("Failed to start schannel client\n"));
- return status;
- }
- talloc_steal(dce_schan_state, dce_schan_state->schannel_state);
return NT_STATUS_OK;
}
const char *username,
const char *password,
int chan_type,
- uint8_t new_session_key[16])
+ struct creds_CredentialState *creds)
{
NTSTATUS status;
struct dcerpc_pipe *p2;
struct netr_ServerAuthenticate2 a;
struct netr_Credential credentials1, credentials2, credentials3;
struct samr_Password mach_pwd;
- struct creds_CredentialState creds;
const char *workgroup, *workstation;
uint32_t negotiate_flags;
step 3 - authenticate on the netlogon pipe
*/
E_md4hash(password, mach_pwd.hash);
- creds_client_init(&creds, &credentials1, &credentials2, &mach_pwd, &credentials3,
+ creds_client_init(creds, &credentials1, &credentials2, &mach_pwd, &credentials3,
negotiate_flags);
a.in.server_name = r.in.server_name;
return status;
}
- if (!creds_client_check(&creds, a.out.credentials)) {
+ if (!creds_client_check(creds, a.out.credentials)) {
return NT_STATUS_UNSUCCESSFUL;
}
*/
dcerpc_pipe_close(p2);
- memcpy(new_session_key, creds.session_key, 16);
-
return NT_STATUS_OK;
}
const char *domain,
const char *username,
const char *password,
- uint8_t session_key[16])
+ struct creds_CredentialState *creds)
{
NTSTATUS status;
+ struct dcerpc_schannel_state *dce_schan_state;
status = gensec_client_start(p, &p->security_state.generic_state);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- memcpy(p->security_state.generic_state->user.schan_session_key,
- session_key, 16);
-
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)));
return status;
}
+ dce_schan_state = p->security_state.generic_state->private_data;
+ dce_schan_state->creds = talloc_reference(dce_schan_state, creds);
+
status = dcerpc_bind_auth3(p, DCERPC_AUTH_TYPE_SCHANNEL, dcerpc_auth_level(p),
uuid, version);
{
NTSTATUS status;
int chan_type = 0;
- uint8_t new_session_key[16];
+ struct creds_CredentialState *creds;
+ creds = talloc_p(p, struct creds_CredentialState);
+ if (!creds) {
+ return NT_STATUS_NO_MEMORY;
+ }
if (p->flags & DCERPC_SCHANNEL_BDC) {
chan_type = SEC_CHAN_BDC;
username,
password,
chan_type,
- new_session_key);
+ creds);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("Failed to fetch schannel session key: %s\n",
return dcerpc_bind_auth_schannel_withkey(p, uuid, version, domain,
username, password,
- new_session_key);
+ creds);
}
static const struct gensec_security_ops gensec_dcerpc_schannel_security_ops = {
*/
NTSTATUS schannel_fetch_session_key(TALLOC_CTX *mem_ctx,
const char *computer_name,
- struct creds_CredentialState *creds)
+ struct creds_CredentialState **creds)
{
struct ldb_wrap *ldb;
time_t expiry;
const struct ldb_val *val;
char *expr=NULL;
- ZERO_STRUCTP(creds);
+ *creds = talloc_zero_p(mem_ctx, struct creds_CredentialState);
+ if (!*creds) {
+ return NT_STATUS_NO_MEMORY;
+ }
ldb = schannel_db_connect(mem_ctx);
if (ldb == NULL) {
return NT_STATUS_INVALID_HANDLE;
}
- memcpy(creds->session_key, val->data, 16);
+ memcpy((*creds)->session_key, val->data, 16);
val = ldb_msg_find_ldb_val(res[0], "seed");
if (val == NULL || val->length != 8) {
return NT_STATUS_INVALID_HANDLE;
}
- memcpy(creds->seed.data, val->data, 8);
+ memcpy((*creds)->seed.data, val->data, 8);
talloc_free(ldb);
torture/rpc/schannel.o \
torture/rpc/netlogon.o \
torture/rpc/samlogon.o \
+ torture/rpc/samsync.o \
torture/rpc/bind.o
REQUIRED_SUBSYSTEMS = \
LIBSMB
return True;
}
+/*
+ try a netlogon SamLogon
+*/
+static BOOL test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
+{
+ NTSTATUS status;
+ struct netr_LogonSamLogon r;
+ struct netr_Authenticator auth, auth2;
+ struct netr_NetworkInfo ninfo;
+ const char *username = lp_parm_string(-1, "torture", "username");
+ const char *password = lp_parm_string(-1, "torture", "password");
+ struct creds_CredentialState creds;
+
+ int i;
+ BOOL ret = True;
+
+ if (!test_SetupCredentials(p, mem_ctx, TEST_MACHINE_NAME,
+ machine_password, &creds)) {
+ return False;
+ }
+
+ ninfo.identity_info.domain_name.string = lp_workgroup();
+ ninfo.identity_info.parameter_control = 0;
+ ninfo.identity_info.logon_id_low = 0;
+ ninfo.identity_info.logon_id_high = 0;
+ ninfo.identity_info.account_name.string = username;
+ ninfo.identity_info.workstation.string = TEST_MACHINE_NAME;
+ generate_random_buffer(ninfo.challenge,
+ sizeof(ninfo.challenge));
+ ninfo.nt.length = 24;
+ ninfo.nt.data = talloc(mem_ctx, 24);
+ SMBNTencrypt(password, ninfo.challenge, ninfo.nt.data);
+ ninfo.lm.length = 24;
+ ninfo.lm.data = talloc(mem_ctx, 24);
+ SMBencrypt(password, ninfo.challenge, ninfo.lm.data);
+
+ r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.workstation = TEST_MACHINE_NAME;
+ r.in.credential = &auth;
+ r.in.return_authenticator = &auth2;
+ r.in.logon_level = 2;
+ r.in.logon.network = &ninfo;
+
+ for (i=2;i<=3;i++) {
+ ZERO_STRUCT(auth2);
+ creds_client_authenticator(&creds, &auth);
+
+ r.in.validation_level = i;
+
+ printf("Testing SamLogon with validation level %d\n", i);
+
+ status = dcerpc_netr_LogonSamLogon(p, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("LogonSamLogon - %s\n", nt_errstr(status));
+ ret = False;
+ }
+
+ if (!creds_client_check(&creds, &r.out.return_authenticator->cred)) {
+ printf("Credential chaining failed\n");
+ }
+ }
+
+ return ret;
+}
+
+
/* we remember the sequence numbers so we can easily do a DatabaseDelta */
static uint64_t sequence_nums[3];
NTSTATUS status;
struct netr_DatabaseSync r;
struct creds_CredentialState creds;
- const uint32_t database_ids[] = {0, 1, 2};
+ const uint32_t database_ids[] = {SAM_DATABASE_DOMAIN, SAM_DATABASE_BUILTIN, SAM_DATABASE_PRIVS};
int i;
BOOL ret = True;
if (r.out.delta_enum_array &&
r.out.delta_enum_array->num_deltas > 0 &&
- r.out.delta_enum_array->delta_enum[0].delta_type == 1 &&
+ r.out.delta_enum_array->delta_enum[0].delta_type == NETR_DELTA_DOMAIN &&
r.out.delta_enum_array->delta_enum[0].delta_union.domain) {
sequence_nums[r.in.database_id] =
r.out.delta_enum_array->delta_enum[0].delta_union.domain->sequence_num;
struct dcerpc_pipe *p;
TALLOC_CTX *mem_ctx;
BOOL ret = True;
- void *join_ctx;
+ struct test_join *join_ctx;
mem_ctx = talloc_init("torture_rpc_netlogon");
ret = False;
}
+ if (!test_SamLogon(p, mem_ctx)) {
+ ret = False;
+ }
+
if (!test_SetPassword(p, mem_ctx)) {
ret = False;
}
return True;
}
+
+/*
+ try a netlogon SamLogon
+*/
+static BOOL test_netlogon_ops(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct creds_CredentialState *creds)
+{
+ NTSTATUS status;
+ struct netr_LogonSamLogon r;
+ struct netr_Authenticator auth, auth2;
+ struct netr_NetworkInfo ninfo;
+ const char *username = lp_parm_string(-1, "torture", "username");
+ const char *password = lp_parm_string(-1, "torture", "password");
+
+ int i;
+ BOOL ret = True;
+
+ ninfo.identity_info.domain_name.string = lp_workgroup();
+ ninfo.identity_info.parameter_control = 0;
+ ninfo.identity_info.logon_id_low = 0;
+ ninfo.identity_info.logon_id_high = 0;
+ ninfo.identity_info.account_name.string = username;
+ ninfo.identity_info.workstation.string = TEST_MACHINE_NAME;
+ generate_random_buffer(ninfo.challenge,
+ sizeof(ninfo.challenge));
+ ninfo.nt.length = 24;
+ ninfo.nt.data = talloc(mem_ctx, 24);
+ SMBNTencrypt(password, ninfo.challenge, ninfo.nt.data);
+ ninfo.lm.length = 24;
+ ninfo.lm.data = talloc(mem_ctx, 24);
+ SMBencrypt(password, ninfo.challenge, ninfo.lm.data);
+
+
+ r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.workstation = TEST_MACHINE_NAME;
+ r.in.credential = &auth;
+ r.in.return_authenticator = &auth2;
+ r.in.logon_level = 2;
+ r.in.logon.network = &ninfo;
+
+ for (i=2;i<3;i++) {
+ ZERO_STRUCT(auth2);
+ creds_client_authenticator(creds, &auth);
+
+ r.in.validation_level = i;
+
+ status = dcerpc_netr_LogonSamLogon(p, mem_ctx, &r);
+
+ if (!creds_client_check(creds, &r.out.return_authenticator->cred)) {
+ printf("Credential chaining failed\n");
+ ret = False;
+ }
+
+ }
+ return ret;
+}
+
/*
test a schannel connection with the given flags
*/
const char *binding = lp_parm_string(-1, "torture", "binding");
struct dcerpc_binding b;
struct dcerpc_pipe *p;
+ struct dcerpc_pipe *p_netlogon;
+ struct creds_CredentialState *creds;
join_ctx = torture_join_domain(TEST_MACHINE_NAME, lp_workgroup(), acct_flags,
&machine_password);
goto failed;
}
+
+ status = dcerpc_parse_binding(mem_ctx, binding, &b);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Bad binding string %s\n", binding);
+ goto failed;
+ }
+
+
+ /* Also test that when we connect to the netlogon pipe, that
+ * the credentials we setup on the first pipe are valid for
+ * the second */
+
+ b.flags &= ~DCERPC_AUTH_OPTIONS;
+ b.flags |= dcerpc_flags;
+
+ status = dcerpc_pipe_connect_b(&p_netlogon, &b,
+ DCERPC_NETLOGON_UUID,
+ DCERPC_NETLOGON_VERSION,
+ lp_workgroup(),
+ TEST_MACHINE_NAME,
+ machine_password);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ status = dcerpc_schannel_creds(p_netlogon->security_state.generic_state, mem_ctx, &creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ /* do a couple of logins */
+ if (!test_netlogon_ops(p_netlogon, mem_ctx, creds)) {
+ printf("Failed to process schannel secured ops\n");
+ goto failed;
+ }
+
torture_leave_domain(join_ctx);
+ dcerpc_pipe_close(p_netlogon);
dcerpc_pipe_close(p);
return True;
failed:
torture_leave_domain(join_ctx);
+ dcerpc_pipe_close(p_netlogon);
dcerpc_pipe_close(p);
return False;
}
struct smbcli_transport *transport;
struct dcerpc_pipe *netlogon_pipe;
- struct creds_CredentialState netlogon_creds;
+ struct creds_CredentialState *netlogon_creds;
struct dcerpc_pipe *netlogon_schannel_pipe;
if (mem_ctx == NULL)
return False;
+ netlogon_creds = talloc_p(mem_ctx, struct creds_CredentialState);
+ if (!netlogon_creds) {
+ 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)))
+ netlogon_creds)))
return False;
if (!NT_STATUS_IS_OK(test_enumtrusts(transport)))
DCERPC_NETLOGON_UUID,
DCERPC_NETLOGON_VERSION,
"", "", "",
- netlogon_creds.session_key);
+ netlogon_creds);
if (!NT_STATUS_IS_OK(status))
return False;
status = torture_samlogon(netlogon_schannel_pipe,
- &netlogon_creds, wksname, domain,
+ netlogon_creds, wksname, domain,
user1name, user1pw);
if (!NT_STATUS_IS_OK(status))
talloc_free(netlogon_pipe);
status = torture_samlogon(netlogon_schannel_pipe,
- &netlogon_creds, wksname, domain,
+ netlogon_creds, wksname, domain,
user2name, user2pw);
if (!NT_STATUS_IS_OK(status))
{"RPC-SAMR", torture_rpc_samr, 0},
{"RPC-NETLOGON", torture_rpc_netlogon, 0},
{"RPC-SAMLOGON", torture_rpc_samlogon, 0},
+ {"RPC-SAMSYNC", torture_rpc_samsync, 0},
{"RPC-SCHANNEL", torture_rpc_schannel, 0},
{"RPC-WKSSVC", torture_rpc_wkssvc, 0},
{"RPC-SRVSVC", torture_rpc_srvsvc, 0},