From 8eb981c90a6094b15d4b71cc14fee4f23c713cf8 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 3 Jan 2005 06:23:02 +0000 Subject: r4499: Almost make our Samba4 server pass the RPC-SAMLOGON torture test. I just need to fix a couple of NTLMv2 issues before we can fully pass, and put this in test_rpc.sh, as a 'should pass' test. Andrew Bartlett (This used to be commit 4b52409e385366d87724bb79f4fad4803e8ecfec) --- source4/auth/ntlm_check.c | 105 +++++++++++-------- source4/libcli/auth/credentials.c | 11 +- source4/rpc_server/netlogon/dcerpc_netlogon.c | 140 +++++++++++++++----------- source4/rpc_server/netlogon/schannel_state.c | 13 ++- source4/torture/rpc/netlogon.c | 16 +++ source4/torture/rpc/samlogon.c | 11 +- 6 files changed, 191 insertions(+), 105 deletions(-) (limited to 'source4') diff --git a/source4/auth/ntlm_check.c b/source4/auth/ntlm_check.c index e6a8ce681fa..474742bee0b 100644 --- a/source4/auth/ntlm_check.c +++ b/source4/auth/ntlm_check.c @@ -285,48 +285,57 @@ NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx, (unsigned long)nt_response->length, username)); } - if (nt_response->length >= 24 && nt_pw) { - if (nt_response->length > 24) { - /* We have the NT MD4 hash challenge available - see if we can - use it - */ - DEBUG(4,("ntlm_password_check: Checking NTLMv2 password with domain [%s]\n", client_domain)); - if (smb_pwd_check_ntlmv2(mem_ctx, - nt_response, - nt_pw, challenge, - client_username, - client_domain, - False, - user_sess_key)) { - return NT_STATUS_OK; + if (nt_response->length > 24 && nt_pw) { + /* We have the NT MD4 hash challenge available - see if we can + use it + */ + DEBUG(4,("ntlm_password_check: Checking NTLMv2 password with domain [%s]\n", client_domain)); + if (smb_pwd_check_ntlmv2(mem_ctx, + nt_response, + nt_pw, challenge, + client_username, + client_domain, + False, + user_sess_key)) { + if (lm_sess_key) { + *lm_sess_key = *user_sess_key; + lm_sess_key->length = 8; } - - DEBUG(4,("ntlm_password_check: Checking NTLMv2 password with uppercased version of domain [%s]\n", client_domain)); - if (smb_pwd_check_ntlmv2(mem_ctx, - nt_response, - nt_pw, challenge, - client_username, - client_domain, - True, - user_sess_key)) { - return NT_STATUS_OK; + return NT_STATUS_OK; + } + + DEBUG(4,("ntlm_password_check: Checking NTLMv2 password with uppercased version of domain [%s]\n", client_domain)); + if (smb_pwd_check_ntlmv2(mem_ctx, + nt_response, + nt_pw, challenge, + client_username, + client_domain, + True, + user_sess_key)) { + if (lm_sess_key) { + *lm_sess_key = *user_sess_key; + lm_sess_key->length = 8; } - - DEBUG(4,("ntlm_password_check: Checking NTLMv2 password without a domain\n")); - if (smb_pwd_check_ntlmv2(mem_ctx, - nt_response, - nt_pw, challenge, - client_username, - "", - False, - user_sess_key)) { - return NT_STATUS_OK; - } else { - DEBUG(3,("ntlm_password_check: NTLMv2 password check failed\n")); - return NT_STATUS_WRONG_PASSWORD; + return NT_STATUS_OK; + } + + DEBUG(4,("ntlm_password_check: Checking NTLMv2 password without a domain\n")); + if (smb_pwd_check_ntlmv2(mem_ctx, + nt_response, + nt_pw, challenge, + client_username, + "", + False, + user_sess_key)) { + if (lm_sess_key) { + *lm_sess_key = *user_sess_key; + lm_sess_key->length = 8; } + return NT_STATUS_OK; + } else { + DEBUG(3,("ntlm_password_check: NTLMv2 password check failed\n")); } - + } else if (nt_response->length == 24 && nt_pw) { if (lp_ntlm_auth()) { /* We have the NT MD4 hash challenge available - see if we can use it (ie. does it exist in the smbpasswd file). @@ -338,7 +347,7 @@ NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx, user_sess_key)) { /* The LM session key for this response is not very secure, so use it only if we otherwise allow LM authentication */ - + if (lp_lanman_auth() && lm_pw) { *lm_sess_key = data_blob_talloc(mem_ctx, lm_pw, 8); } @@ -409,7 +418,11 @@ NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx, client_username, client_domain, False, - NULL)) { + user_sess_key)) { + if (lm_sess_key) { + *lm_sess_key = *user_sess_key; + lm_sess_key->length = 8; + } return NT_STATUS_OK; } @@ -420,7 +433,11 @@ NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx, client_username, client_domain, True, - NULL)) { + user_sess_key)) { + if (lm_sess_key) { + *lm_sess_key = *user_sess_key; + lm_sess_key->length = 8; + } return NT_STATUS_OK; } @@ -431,7 +448,11 @@ NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx, client_username, "", False, - NULL)) { + user_sess_key)) { + if (lm_sess_key) { + *lm_sess_key = *user_sess_key; + lm_sess_key->length = 8; + } return NT_STATUS_OK; } diff --git a/source4/libcli/auth/credentials.c b/source4/libcli/auth/credentials.c index a61660d7765..8cae71180cd 100644 --- a/source4/libcli/auth/credentials.c +++ b/source4/libcli/auth/credentials.c @@ -273,6 +273,7 @@ void creds_server_init(struct creds_CredentialState *creds, } *initial_credential = creds->server; + creds->negotiate_flags = negotiate_flags; } /* @@ -290,10 +291,14 @@ BOOL creds_server_check(const struct creds_CredentialState *creds, return True; } -BOOL creds_server_step_check(struct creds_CredentialState *creds, +NTSTATUS creds_server_step_check(struct creds_CredentialState *creds, struct netr_Authenticator *received_authenticator, struct netr_Authenticator *return_authenticator) { + if (!received_authenticator || !return_authenticator) { + return NT_STATUS_INVALID_PARAMETER; + } + /* TODO: this may allow the a replay attack on a non-signed connection. Should we check that this is increasing? */ creds->sequence = received_authenticator->timestamp; @@ -301,9 +306,9 @@ BOOL creds_server_step_check(struct creds_CredentialState *creds, if (creds_server_check(creds, &received_authenticator->cred)) { return_authenticator->cred = creds->server; return_authenticator->timestamp = creds->sequence; - return True; + return NT_STATUS_OK; } else { ZERO_STRUCTP(return_authenticator); - return False; + return NT_STATUS_ACCESS_DENIED; } } diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index 422aa626ede..167c4e8ceb5 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -317,12 +317,17 @@ static NTSTATUS netr_ServerAuthenticate2(struct dcesrv_call_state *dce_call, TAL } -static BOOL netr_creds_server_step_check(struct server_pipe_state *pipe_state, - struct netr_Authenticator *received_authenticator, - struct netr_Authenticator *return_authenticator) +static NTSTATUS netr_creds_server_step_check(struct server_pipe_state *pipe_state, + struct netr_Authenticator *received_authenticator, + struct netr_Authenticator *return_authenticator) { + if (!pipe_state) { + DEBUG(1, ("No challenge requested by client, cannot authenticate\n")); + return NT_STATUS_ACCESS_DENIED; + } + if (!pipe_state->authenticated) { - return False; + return NT_STATUS_ACCESS_DENIED; } return creds_server_step_check(pipe_state->creds, received_authenticator, @@ -351,13 +356,9 @@ static NTSTATUS netr_ServerPasswordSet(struct dcesrv_call_state *dce_call, TALLO const char **domain_attrs = attrs; ZERO_STRUCT(mod); - if (!pipe_state) { - DEBUG(1, ("No challenge requested by client, cannot authenticate\n")); - return NT_STATUS_ACCESS_DENIED; - } - - if (!netr_creds_server_step_check(pipe_state, &r->in.credential, &r->out.return_authenticator)) { - return NT_STATUS_ACCESS_DENIED; + nt_status = netr_creds_server_step_check(pipe_state, &r->in.credential, &r->out.return_authenticator); + if (NT_STATUS_IS_OK(nt_status)) { + return nt_status; } sam_ctx = samdb_connect(mem_ctx); @@ -461,9 +462,10 @@ static WERROR netr_LogonUasLogoff(struct dcesrv_call_state *dce_call, TALLOC_CTX /* netr_LogonSamLogonWithFlags + This version of the function allows other wrappers to say 'do not check the credentials' */ -static NTSTATUS netr_LogonSamLogonWithFlags(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct netr_LogonSamLogonWithFlags *r) +static NTSTATUS netr_LogonSamLogonEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct netr_LogonSamLogonEx *r) { struct server_pipe_state *pipe_state = dce_call->conn->private; @@ -478,30 +480,21 @@ static NTSTATUS netr_LogonSamLogonWithFlags(struct dcesrv_call_state *dce_call, struct netr_SamInfo3 *sam3; struct netr_SamInfo6 *sam6; - if (!pipe_state) { - DEBUG(1, ("No challenge requested by client, cannot authenticate\n")); - return NT_STATUS_ACCESS_DENIED; - } - - r->out.return_authenticator = talloc_p(mem_ctx, struct netr_Authenticator); - if (!r->out.return_authenticator) { - return NT_STATUS_NO_MEMORY; - } - - if (!netr_creds_server_step_check(pipe_state, r->in.credential, r->out.return_authenticator)) { - return NT_STATUS_ACCESS_DENIED; - } - switch (r->in.logon_level) { case 1: case 3: case 5: - creds_arcfour_crypt(pipe_state->creds, - r->in.logon.password->lmpassword.hash, - sizeof(r->in.logon.password->lmpassword.hash)); - creds_arcfour_crypt(pipe_state->creds, - r->in.logon.password->ntpassword.hash, - sizeof(r->in.logon.password->ntpassword.hash)); + if (pipe_state->creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) { + creds_arcfour_crypt(pipe_state->creds, + r->in.logon.password->lmpassword.hash, + sizeof(r->in.logon.password->lmpassword.hash)); + creds_arcfour_crypt(pipe_state->creds, + r->in.logon.password->ntpassword.hash, + sizeof(r->in.logon.password->ntpassword.hash)); + } else { + creds_des_decrypt(pipe_state->creds, &r->in.logon.password->lmpassword); + creds_des_decrypt(pipe_state->creds, &r->in.logon.password->ntpassword); + } nt_status = make_auth_context_subsystem(pipe_state, &auth_context); if (!NT_STATUS_IS_OK(nt_status)) { @@ -600,9 +593,13 @@ static NTSTATUS netr_LogonSamLogonWithFlags(struct dcesrv_call_state *dce_call, if ((r->in.validation_level != 6) && memcmp(sam->key.key, zeros, sizeof(sam->key.key)) != 0) { - creds_arcfour_crypt(pipe_state->creds, - sam->key.key, - sizeof(sam->key.key)); + + /* This key is sent unencrypted without the ARCFOUR flag set */ + if (pipe_state->creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) { + creds_arcfour_crypt(pipe_state->creds, + sam->key.key, + sizeof(sam->key.key)); + } } if (server_info->lm_session_key.length == sizeof(sam->LMSessKey.key)) { @@ -617,9 +614,14 @@ static NTSTATUS netr_LogonSamLogonWithFlags(struct dcesrv_call_state *dce_call, if ((r->in.validation_level != 6) && memcmp(sam->LMSessKey.key, zeros, sizeof(sam->LMSessKey.key)) != 0) { - creds_arcfour_crypt(pipe_state->creds, - sam->LMSessKey.key, - sizeof(sam->LMSessKey.key)); + if (pipe_state->creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) { + creds_arcfour_crypt(pipe_state->creds, + sam->LMSessKey.key, + sizeof(sam->LMSessKey.key)); + } else { + creds_des_encrypt_LMKey(pipe_state->creds, + &sam->LMSessKey); + } } switch (r->in.validation_level) { @@ -656,6 +658,45 @@ static NTSTATUS netr_LogonSamLogonWithFlags(struct dcesrv_call_state *dce_call, return NT_STATUS_OK; } +/* + netr_LogonSamLogonWithFlags + +*/ +static NTSTATUS netr_LogonSamLogonWithFlags(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct netr_LogonSamLogonWithFlags *r) +{ + NTSTATUS nt_status; + struct netr_LogonSamLogonEx r2; + + struct server_pipe_state *pipe_state = dce_call->conn->private; + + r->out.return_authenticator = talloc_p(mem_ctx, struct netr_Authenticator); + if (!r->out.return_authenticator) { + return NT_STATUS_NO_MEMORY; + } + + nt_status = netr_creds_server_step_check(pipe_state, r->in.credential, r->out.return_authenticator); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + ZERO_STRUCT(r2); + + r2.in.server_name = r->in.server_name; + r2.in.workstation = r->in.workstation; + r2.in.logon_level = r->in.logon_level; + r2.in.logon = r->in.logon; + r2.in.validation_level = r->in.validation_level; + r2.in.flags = r->in.flags; + + nt_status = netr_LogonSamLogonEx(dce_call, mem_ctx, &r2); + + r->out.validation = r2.out.validation; + r->out.authoritative = r2.out.authoritative; + + return nt_status; +} + /* netr_LogonSamLogon */ @@ -940,13 +981,10 @@ static NTSTATUS netr_LogonGetDomainInfo(struct dcesrv_call_state *dce_call, TALL int ret1, ret2, i; NTSTATUS status; - if (!pipe_state) { - return NT_STATUS_ACCESS_DENIED; - } - - if (!netr_creds_server_step_check(pipe_state, - r->in.credential, r->out.credential)) { - return NT_STATUS_ACCESS_DENIED; + status = netr_creds_server_step_check(pipe_state, + r->in.credential, r->out.credential); + if (!NT_STATUS_IS_OK(status)) { + return status; } sam_ctx = samdb_connect(mem_ctx); @@ -1133,16 +1171,6 @@ static WERROR netr_DSRGETDCSITECOVERAGEW(struct dcesrv_call_state *dce_call, TAL } -/* - netr_LogonSamLogonEx -*/ -static NTSTATUS netr_LogonSamLogonEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct netr_LogonSamLogonEx *r) -{ - DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR); -} - - /* netr_DsrEnumerateDomainTrusts */ diff --git a/source4/rpc_server/netlogon/schannel_state.c b/source4/rpc_server/netlogon/schannel_state.c index 564564e8c21..7dc60a16178 100644 --- a/source4/rpc_server/netlogon/schannel_state.c +++ b/source4/rpc_server/netlogon/schannel_state.c @@ -61,7 +61,8 @@ NTSTATUS schannel_store_session_key(TALLOC_CTX *mem_ctx, struct ldb_wrap *ldb; struct ldb_message *msg; struct ldb_val val, seed; - char *s = NULL; + char *s; + char *f; time_t expiry = time(NULL) + SCHANNEL_CREDENTIALS_EXPIRY; int ret; @@ -77,6 +78,13 @@ NTSTATUS schannel_store_session_key(TALLOC_CTX *mem_ctx, return NT_STATUS_NO_MEMORY; } + f = talloc_asprintf(mem_ctx, "%u", (unsigned int)creds->negotiate_flags); + + if (f == NULL) { + talloc_free(ldb); + return NT_STATUS_NO_MEMORY; + } + msg = ldb_msg_new(mem_ctx); if (msg == NULL) { talloc_free(ldb); @@ -99,6 +107,7 @@ NTSTATUS schannel_store_session_key(TALLOC_CTX *mem_ctx, ldb_msg_add_value(ldb->ldb, msg, "sessionKey", &val); ldb_msg_add_value(ldb->ldb, msg, "seed", &seed); ldb_msg_add_string(ldb->ldb, msg, "expiry", s); + ldb_msg_add_string(ldb->ldb, msg, "negotiateFlags", f); ldb_delete(ldb->ldb, msg->dn); @@ -180,6 +189,8 @@ NTSTATUS schannel_fetch_session_key(TALLOC_CTX *mem_ctx, memcpy((*creds)->seed.data, val->data, 8); + (*creds)->negotiate_flags = ldb_msg_find_int(res[0], "negotiateFlags", 0); + talloc_free(ldb); return NT_STATUS_OK; diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c index a23cdb8b0c5..35f64933a9d 100644 --- a/source4/torture/rpc/netlogon.c +++ b/source4/torture/rpc/netlogon.c @@ -378,6 +378,22 @@ static BOOL test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx) } } + r.in.credential = NULL; + + for (i=2;i<=3;i++) { + + 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_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { + printf("LogonSamLogon expected INVALID_PARAMETER, got: %s\n", nt_errstr(status)); + ret = False; + } + + } + return ret; } diff --git a/source4/torture/rpc/samlogon.c b/source4/torture/rpc/samlogon.c index 821a8235950..29a87f9804e 100644 --- a/source4/torture/rpc/samlogon.c +++ b/source4/torture/rpc/samlogon.c @@ -220,7 +220,11 @@ static NTSTATUS check_samlogon(struct samlogon_state *samlogon_state, /* we cannot check the session key, if the logon failed... */ return status; } - + + if (!base) { + printf("No user info returned from 'successful' SamLogon*() call!\n"); + return NT_STATUS_INVALID_PARAMETER; + } /* find and decyrpt the session keys, return in parameters above */ if (validation_level == 6) { @@ -1043,11 +1047,12 @@ BOOL torture_rpc_samlogon(void) int i; unsigned int credential_flags[] = { - 0, NETLOGON_NEG_AUTH2_FLAGS, NETLOGON_NEG_ARCFOUR, NETLOGON_NEG_ARCFOUR | NETLOGON_NEG_128BIT, - NETLOGON_NEG_AUTH2_ADS_FLAGS}; + NETLOGON_NEG_AUTH2_ADS_FLAGS, + 0 /* yes, this is a valid flag, causes the use of DES */ + }; struct creds_CredentialState *creds; -- cgit