summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2006-02-15 23:15:55 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 11:10:09 -0500
commit3e4cf56fa3f9d465d27dadaa6790bbcdea5d3cd9 (patch)
treea9a118e20c04313e585301e46b27ac8081cafdb5
parent2f2ab29cc110bebce3804f57c32ee55b691e81de (diff)
downloadsamba-3e4cf56fa3f9d465d27dadaa6790bbcdea5d3cd9.tar.gz
samba-3e4cf56fa3f9d465d27dadaa6790bbcdea5d3cd9.tar.bz2
samba-3e4cf56fa3f9d465d27dadaa6790bbcdea5d3cd9.zip
r13519: Fix the credentials chaining across netlogon pipe disconnects.
I mean it this time :-). Jeremy. (This used to be commit 80f4868944d349015d2b64c2414b06466a8194aa)
-rw-r--r--source3/libsmb/credentials.c25
-rw-r--r--source3/passdb/secrets.c14
-rw-r--r--source3/rpc_server/srv_netlog_nt.c169
-rw-r--r--source3/rpc_server/srv_pipe.c23
4 files changed, 163 insertions, 68 deletions
diff --git a/source3/libsmb/credentials.c b/source3/libsmb/credentials.c
index 795c30d12d..5026f513ab 100644
--- a/source3/libsmb/credentials.c
+++ b/source3/libsmb/credentials.c
@@ -183,17 +183,30 @@ static void creds_reseed(struct dcinfo *dc)
BOOL creds_server_step(struct dcinfo *dc, const DOM_CRED *received_cred, DOM_CRED *cred_out)
{
- dc->sequence = received_cred->timestamp.time;
+ BOOL ret;
+ struct dcinfo tmp_dc = *dc;
- creds_step(dc);
+ /* Do all operations on a temporary copy of the dc,
+ which we throw away if the checks fail. */
+
+ tmp_dc.sequence = received_cred->timestamp.time;
+
+ creds_step(&tmp_dc);
/* Create the outgoing credentials */
- cred_out->timestamp.time = dc->sequence + 1;
- cred_out->challenge = dc->srv_chal;
+ cred_out->timestamp.time = tmp_dc.sequence + 1;
+ cred_out->challenge = tmp_dc.srv_chal;
- creds_reseed(dc);
+ creds_reseed(&tmp_dc);
- return creds_server_check(dc, &received_cred->challenge);
+ ret = creds_server_check(&tmp_dc, &received_cred->challenge);
+ if (!ret) {
+ return False;
+ }
+
+ /* creds step succeeded - replace the current creds. */
+ *dc = tmp_dc;
+ return True;
}
/****************************************************************************
diff --git a/source3/passdb/secrets.c b/source3/passdb/secrets.c
index 8f93bec9bc..6e46ea57fe 100644
--- a/source3/passdb/secrets.c
+++ b/source3/passdb/secrets.c
@@ -997,7 +997,7 @@ BOOL secrets_store_schannel_session_info(TALLOC_CTX *mem_ctx, const struct dcinf
BOOL secrets_restore_schannel_session_info(TALLOC_CTX *mem_ctx,
const char *remote_machine,
- struct dcinfo *pdc)
+ struct dcinfo **ppdc)
{
TDB_CONTEXT *tdb_sc = NULL;
TDB_DATA value;
@@ -1008,10 +1008,11 @@ BOOL secrets_restore_schannel_session_info(TALLOC_CTX *mem_ctx,
unsigned char *pmach_pw = NULL;
uint32 l1, l2, l3, l4, l5;
int ret;
+ struct dcinfo *pdc = NULL;
char *keystr = talloc_asprintf(mem_ctx, "%s/%s", SECRETS_SCHANNEL_STATE,
remote_machine);
- ZERO_STRUCTP(pdc);
+ *ppdc = NULL;
if (!keystr) {
return False;
@@ -1035,6 +1036,8 @@ BOOL secrets_restore_schannel_session_info(TALLOC_CTX *mem_ctx,
tdb_close(tdb_sc);
+ pdc = TALLOC_ZERO_P(mem_ctx, struct dcinfo);
+
/* Retrieve the record. */
ret = tdb_unpack(value.dptr, value.dsize, "dBBBBBfff",
&pdc->sequence,
@@ -1049,13 +1052,13 @@ BOOL secrets_restore_schannel_session_info(TALLOC_CTX *mem_ctx,
if (ret == -1 || l1 != 8 || l2 != 8 || l3 != 8 || l4 != 8 || l5 != 16) {
talloc_free(keystr);
+ talloc_free(pdc);
SAFE_FREE(pseed_chal);
SAFE_FREE(pclnt_chal);
SAFE_FREE(psrv_chal);
SAFE_FREE(psess_key);
SAFE_FREE(pmach_pw);
SAFE_FREE(value.dptr);
- ZERO_STRUCTP(pdc);
return False;
}
@@ -1070,7 +1073,7 @@ BOOL secrets_restore_schannel_session_info(TALLOC_CTX *mem_ctx,
pdc->challenge_sent = True;
pdc->authenticated = True;
- DEBUG(3,("secrets_store_schannel_session_info: restored schannel info key %s\n",
+ DEBUG(3,("secrets_restore_schannel_session_info: restored schannel info key %s\n",
keystr ));
SAFE_FREE(pseed_chal);
@@ -1081,5 +1084,8 @@ BOOL secrets_restore_schannel_session_info(TALLOC_CTX *mem_ctx,
talloc_free(keystr);
SAFE_FREE(value.dptr);
+
+ *ppdc = pdc;
+
return True;
}
diff --git a/source3/rpc_server/srv_netlog_nt.c b/source3/rpc_server/srv_netlog_nt.c
index 2b98314722..97e19e6cb7 100644
--- a/source3/rpc_server/srv_netlog_nt.c
+++ b/source3/rpc_server/srv_netlog_nt.c
@@ -281,6 +281,10 @@ NTSTATUS _net_req_chal(pipes_struct *p, NET_Q_REQ_CHAL *q_u, NET_R_REQ_CHAL *r_u
q_u->uni_logon_clnt.buffer,
sizeof(fstring),q_u->uni_logon_clnt.uni_str_len*2,0);
+ /* Remember the workstation name. This is what we'll use to look
+ up the secrets.tdb record later. */
+ fstrcpy(p->wks, p->dc->remote_machine);
+
/* Save the client challenge to the server. */
memcpy(p->dc->clnt_chal.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
@@ -464,10 +468,31 @@ NTSTATUS _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET *
DOM_CRED cred_out;
const uchar *old_pw;
+ DEBUG(5,("_net_srv_pwset: %d\n", __LINE__));
+
+ /* We need the workstation name for the creds lookup. */
+ rpcstr_pull(workstation,q_u->clnt_id.login.uni_comp_name.buffer,
+ sizeof(workstation),q_u->clnt_id.login.uni_comp_name.uni_str_len*2,0);
+
+ if (!p->dc) {
+ /* Restore the saved state of the netlogon creds. */
+ become_root();
+ ret = secrets_restore_schannel_session_info(p->pipe_state_mem_ctx,
+ workstation,
+ &p->dc);
+ unbecome_root();
+ if (!ret) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+ }
+
if (!p->dc || !p->dc->authenticated) {
return NT_STATUS_INVALID_HANDLE;
}
+ DEBUG(3,("_net_srv_pwset: Server Password Set by Wksta:[%s] on account [%s]\n",
+ workstation, p->dc->mach_acct));
+
/* Step the creds chain forward. */
if (!creds_server_step(p->dc, &q_u->clnt_id.cred, &cred_out)) {
DEBUG(2,("_net_srv_pwset: creds_server_step failed. Rejecting auth "
@@ -476,17 +501,10 @@ NTSTATUS _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET *
return NT_STATUS_INVALID_PARAMETER;
}
- DEBUG(5,("_net_srv_pwset: %d\n", __LINE__));
-
- rpcstr_pull(workstation,q_u->clnt_id.login.uni_comp_name.buffer,
- sizeof(workstation),q_u->clnt_id.login.uni_comp_name.uni_str_len*2,0);
-
- DEBUG(3,("_net_srv_pwset: Server Password Set by Wksta:[%s] on account [%s]\n",
- workstation, p->dc->mach_acct));
-
- pdb_init_sam(&sampass);
-
+ /* We must store the creds state after an update. */
become_root();
+ secrets_store_schannel_session_info(p->pipe_state_mem_ctx, p->dc);
+ pdb_init_sam(&sampass);
ret=pdb_getsampwnam(sampass, p->dc->mach_acct);
unbecome_root();
@@ -559,9 +577,28 @@ NTSTATUS _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET *
NTSTATUS _net_sam_logoff(pipes_struct *p, NET_Q_SAM_LOGOFF *q_u, NET_R_SAM_LOGOFF *r_u)
{
+ fstring workstation;
+
if (!get_valid_user_struct(p->vuid))
return NT_STATUS_NO_SUCH_USER;
+ if (!p->dc) {
+ /* Restore the saved state of the netlogon creds. */
+ BOOL ret;
+
+ *workstation = '\0';
+ rpcstr_pull_unistr2_fstring(workstation, &q_u->sam_id.client.login.uni_comp_name);
+
+ become_root();
+ secrets_restore_schannel_session_info(p->pipe_state_mem_ctx,
+ workstation,
+ &p->dc);
+ unbecome_root();
+ if (!ret) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+ }
+
if (!p->dc || !p->dc->authenticated) {
return NT_STATUS_INVALID_HANDLE;
}
@@ -576,6 +613,11 @@ NTSTATUS _net_sam_logoff(pipes_struct *p, NET_Q_SAM_LOGOFF *q_u, NET_R_SAM_LOGOF
return NT_STATUS_INVALID_PARAMETER;
}
+ /* We must store the creds state after an update. */
+ become_root();
+ secrets_store_schannel_session_info(p->pipe_state_mem_ctx, p->dc);
+ unbecome_root();
+
r_u->status = NT_STATUS_OK;
return r_u->status;
}
@@ -651,32 +693,7 @@ static NTSTATUS _net_sam_logon_internal(pipes_struct *p,
if (!get_valid_user_struct(p->vuid))
return NT_STATUS_NO_SUCH_USER;
- if (process_creds) {
- if (!p->dc || !p->dc->authenticated) {
- return NT_STATUS_INVALID_HANDLE;
- }
- }
-
- if ( (lp_server_schannel() == True) && (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) ) {
- /* 'server schannel = yes' should enforce use of
- schannel, the client did offer it in auth2, but
- obviously did not use it. */
- DEBUG(0,("_net_sam_logon: client %s not using schannel for netlogon\n",
- p->dc->remote_machine ));
- return NT_STATUS_ACCESS_DENIED;
- }
-
- if (process_creds) {
- /* checks and updates credentials. creates reply credentials */
- if (!creds_server_step(p->dc, &q_u->sam_id.client.cred, &r_u->srv_creds)) {
- DEBUG(2,("_net_sam_logon: creds_server_step failed. Rejecting auth "
- "request from client %s machine account %s\n",
- p->dc->remote_machine, p->dc->mach_acct ));
- return NT_STATUS_INVALID_PARAMETER;
- }
- }
-
- /* find the username */
+ /* We need the workstation name for the creds lookup. */
switch (q_u->sam_id.logon_level) {
case INTERACTIVE_LOGON_TYPE:
@@ -703,9 +720,52 @@ static NTSTATUS _net_sam_logon_internal(pipes_struct *p,
rpcstr_pull(nt_domain,uni_samlogon_domain->buffer,sizeof(nt_domain),uni_samlogon_domain->uni_str_len*2,0);
rpcstr_pull(nt_workstation,uni_samlogon_workstation->buffer,sizeof(nt_workstation),uni_samlogon_workstation->uni_str_len*2,0);
- DEBUG(3,("User:[%s@%s] Requested Domain:[%s]\n", nt_username,
- nt_workstation, nt_domain));
-
+ DEBUG(3,("User:[%s@%s] Requested Domain:[%s]\n", nt_username, nt_workstation, nt_domain));
+
+ if (process_creds) {
+ if (!p->dc) {
+ /* Restore the saved state of the netlogon creds. */
+ BOOL ret;
+
+ become_root();
+ secrets_restore_schannel_session_info(p->pipe_state_mem_ctx,
+ nt_workstation,
+ &p->dc);
+ unbecome_root();
+ if (!ret) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+ }
+
+ if (!p->dc || !p->dc->authenticated) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+ }
+
+ if ( (lp_server_schannel() == True) && (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) ) {
+ /* 'server schannel = yes' should enforce use of
+ schannel, the client did offer it in auth2, but
+ obviously did not use it. */
+ DEBUG(0,("_net_sam_logon: client %s not using schannel for netlogon\n",
+ p->dc->remote_machine ));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (process_creds) {
+ /* checks and updates credentials. creates reply credentials */
+ if (!creds_server_step(p->dc, &q_u->sam_id.client.cred, &r_u->srv_creds)) {
+ DEBUG(2,("_net_sam_logon: creds_server_step failed. Rejecting auth "
+ "request from client %s machine account %s\n",
+ p->dc->remote_machine, p->dc->mach_acct ));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* We must store the creds state after an update. */
+ become_root();
+ secrets_store_schannel_session_info(p->pipe_state_mem_ctx, p->dc);
+ unbecome_root();
+ }
+
fstrcpy(current_user_info.smb_name, nt_username);
sub_set_smb_name(nt_username);
@@ -822,8 +882,9 @@ static NTSTATUS _net_sam_logon_internal(pipes_struct *p,
pstring my_name;
fstring user_sid_string;
fstring group_sid_string;
- uchar user_session_key[16];
- uchar lm_session_key[16];
+ unsigned char user_session_key[16];
+ unsigned char lm_session_key[16];
+ unsigned char pipe_session_key[16];
sampw = server_info->sam_account;
@@ -870,14 +931,36 @@ static NTSTATUS _net_sam_logon_internal(pipes_struct *p,
server_info->user_session_key.data,
MIN(sizeof(user_session_key),
server_info->user_session_key.length));
- SamOEMhash(user_session_key, p->dc->sess_key, 16);
+ if (process_creds) {
+ /* Get the pipe session key from the creds. */
+ memcpy(pipe_session_key, p->dc->sess_key, 16);
+ } else {
+ /* Get the pipe session key from the schannel. */
+ if (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL || p->auth.a_u.schannel_auth == NULL) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+ memcpy(pipe_session_key, p->auth.a_u.schannel_auth->sess_key, 16);
+ }
+ SamOEMhash(user_session_key, pipe_session_key, 16);
+ memset(pipe_session_key, '\0', 16);
}
if (server_info->lm_session_key.length) {
memcpy(lm_session_key,
server_info->lm_session_key.data,
MIN(sizeof(lm_session_key),
server_info->lm_session_key.length));
- SamOEMhash(lm_session_key, p->dc->sess_key, 16);
+ if (process_creds) {
+ /* Get the pipe session key from the creds. */
+ memcpy(pipe_session_key, p->dc->sess_key, 16);
+ } else {
+ /* Get the pipe session key from the schannel. */
+ if (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL || p->auth.a_u.schannel_auth == NULL) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+ memcpy(pipe_session_key, p->auth.a_u.schannel_auth->sess_key, 16);
+ }
+ SamOEMhash(lm_session_key, pipe_session_key, 16);
+ memset(pipe_session_key, '\0', 16);
}
init_net_user_info3(p->mem_ctx, usr_info,
diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c
index 68b3a2d434..716654103a 100644
--- a/source3/rpc_server/srv_pipe.c
+++ b/source3/rpc_server/srv_pipe.c
@@ -1284,7 +1284,7 @@ static BOOL pipe_schannel_auth_bind(pipes_struct *p, prs_struct *rpc_in_p,
RPC_AUTH_SCHANNEL_NEG neg;
RPC_AUTH_VERIFIER auth_verifier;
BOOL ret;
- struct dcinfo stored_dcinfo;
+ struct dcinfo *pdcinfo;
uint32 flags;
if (!smb_io_rpc_auth_schannel_neg("", &neg, rpc_in_p, 0)) {
@@ -1292,10 +1292,8 @@ static BOOL pipe_schannel_auth_bind(pipes_struct *p, prs_struct *rpc_in_p,
return False;
}
- ZERO_STRUCT(stored_dcinfo);
-
become_root();
- ret = secrets_restore_schannel_session_info(p->mem_ctx, neg.myname, &stored_dcinfo);
+ ret = secrets_restore_schannel_session_info(p->mem_ctx, neg.myname, &pdcinfo);
unbecome_root();
if (!ret) {
@@ -1305,29 +1303,24 @@ static BOOL pipe_schannel_auth_bind(pipes_struct *p, prs_struct *rpc_in_p,
p->auth.a_u.schannel_auth = TALLOC_P(p->pipe_state_mem_ctx, struct schannel_auth_struct);
if (!p->auth.a_u.schannel_auth) {
+ talloc_free(pdcinfo);
return False;
}
memset(p->auth.a_u.schannel_auth->sess_key, 0, sizeof(p->auth.a_u.schannel_auth->sess_key));
- memcpy(p->auth.a_u.schannel_auth->sess_key, stored_dcinfo.sess_key, sizeof(stored_dcinfo.sess_key));
+ memcpy(p->auth.a_u.schannel_auth->sess_key, pdcinfo->sess_key,
+ sizeof(pdcinfo->sess_key));
+
+ talloc_free(pdcinfo);
p->auth.a_u.schannel_auth->seq_num = 0;
/*
* JRA. Should we also copy the schannel session key into the pipe session key p->session_key
- * here ? We do that for NTLMSPP, but the session key is already set up from the vuser
+ * here ? We do that for NTLMSSP, but the session key is already set up from the vuser
* struct of the person who opened the pipe. I need to test this further. JRA.
*/
- /* The client opens a second RPC NETLOGON pipe without
- doing a auth2. The credentials for the schannel are
- re-used from the auth2 the client did before. */
- p->dc = TALLOC_ZERO_P(p->pipe_state_mem_ctx, struct dcinfo);
- if (!p->dc) {
- return False;
- }
- *p->dc = stored_dcinfo;
-
init_rpc_hdr_auth(&auth_info, RPC_SCHANNEL_AUTH_TYPE, pauth_info->auth_level, RPC_HDR_AUTH_LEN, 1);
if(!smb_io_rpc_hdr_auth("", &auth_info, pout_auth, 0)) {
DEBUG(0,("pipe_schannel_auth_bind: marshalling of RPC_HDR_AUTH failed.\n"));