diff options
Diffstat (limited to 'source3/smbd/sesssetup.c')
-rw-r--r-- | source3/smbd/sesssetup.c | 122 |
1 files changed, 79 insertions, 43 deletions
diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index 22ad43ff75..e63511c368 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -249,8 +249,8 @@ static void reply_spnego_kerberos(connection_struct *conn, fstring netbios_domain_name; struct passwd *pw; fstring user; - int sess_vuid; - NTSTATUS ret; + int sess_vuid = SVAL(req->inbuf, smb_uid); + NTSTATUS ret = NT_STATUS_OK; PAC_DATA *pac_data; DATA_BLOB ap_rep, ap_rep_wrapped, response; auth_serversupplied_info *server_info = NULL; @@ -535,18 +535,28 @@ static void reply_spnego_kerberos(connection_struct *conn, } } - /* register_vuid keeps the server info */ - /* register_vuid takes ownership of session_key, no need to free after this. - A better interface would copy it.... */ - sess_vuid = register_vuid(server_info, session_key, nullblob, client); + /* register_existing_vuid keeps the server info */ + /* register_existing_vuid takes ownership of session_key on success, + * no need to free after this on success. A better interface would copy + * it.... */ + + if (!is_partial_auth_vuid(sess_vuid)) { + sess_vuid = register_initial_vuid(); + } + sess_vuid = register_existing_vuid(sess_vuid, + server_info, + session_key, + nullblob, + client); SAFE_FREE(client); reply_outbuf(req, 4, 0); - SSVAL(req->outbuf,smb_uid,vuid); + SSVAL(req->outbuf,smb_uid,sess_vuid); if (sess_vuid == UID_FIELD_INVALID ) { ret = NT_STATUS_LOGON_FAILURE; + data_blob_free(&session_key); } else { /* current_user_info is changed on new vuid */ reload_services( True ); @@ -560,6 +570,8 @@ static void reply_spnego_kerberos(connection_struct *conn, SSVAL(req->outbuf, smb_uid, sess_vuid); sessionsetup_start_signing_engine(server_info, req->inbuf); + /* Successful logon. Keep this vuid. */ + *p_invalidate_vuid = False; } /* wrap that up in a nice GSS-API wrapping */ @@ -611,33 +623,43 @@ static void reply_spnego_ntlmssp(connection_struct *conn, SSVAL(req->outbuf, smb_uid, vuid); if (NT_STATUS_IS_OK(nt_status)) { - int sess_vuid; DATA_BLOB nullblob = data_blob_null; DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length); - /* register_vuid keeps the server info */ - sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user); + if (!is_partial_auth_vuid(vuid)) { + data_blob_free(&session_key); + nt_status = NT_STATUS_LOGON_FAILURE; + goto out; + } + /* register_existing_vuid keeps the server info */ + if (register_existing_vuid(vuid, + server_info, + session_key, nullblob, + (*auth_ntlmssp_state)->ntlmssp_state->user) != + vuid) { + data_blob_free(&session_key); + nt_status = NT_STATUS_LOGON_FAILURE; + goto out; + } + (*auth_ntlmssp_state)->server_info = NULL; - if (sess_vuid == UID_FIELD_INVALID ) { - nt_status = NT_STATUS_LOGON_FAILURE; - } else { - - /* current_user_info is changed on new vuid */ - reload_services( True ); + /* current_user_info is changed on new vuid */ + reload_services( True ); - SSVAL(req->outbuf, smb_vwv3, 0); - - if (server_info->guest) { - SSVAL(req->outbuf,smb_vwv2,1); - } - - SSVAL(req->outbuf,smb_uid,sess_vuid); + SSVAL(req->outbuf, smb_vwv3, 0); - sessionsetup_start_signing_engine(server_info, req->inbuf); + if (server_info->guest) { + SSVAL(req->outbuf,smb_vwv2,1); } + + SSVAL(req->outbuf,smb_uid,vuid); + + sessionsetup_start_signing_engine(server_info, req->inbuf); } + out: + if (wrap) { response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP); } else { @@ -655,8 +677,10 @@ static void reply_spnego_ntlmssp(connection_struct *conn, if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { /* NB. This is *NOT* an error case. JRA */ auth_ntlmssp_end(auth_ntlmssp_state); - /* Kill the intermediate vuid */ - invalidate_vuid(vuid); + if (!NT_STATUS_IS_OK(nt_status)) { + /* Kill the intermediate vuid */ + invalidate_vuid(vuid); + } } } @@ -1111,36 +1135,36 @@ static void reply_sesssetup_and_X_spnego(connection_struct *conn, } } - vuser = get_partial_auth_user_struct(vuid); - if (!vuser) { + /* Did we get a valid vuid ? */ + if (!is_partial_auth_vuid(vuid)) { + /* No, then try and see if this is an intermediate sessionsetup + * for a large SPNEGO packet. */ struct pending_auth_data *pad = get_pending_auth_data(smbpid); if (pad) { DEBUG(10,("reply_sesssetup_and_X_spnego: found pending vuid %u\n", (unsigned int)pad->vuid )); vuid = pad->vuid; - vuser = get_partial_auth_user_struct(vuid); } } - if (!vuser) { - vuid = register_vuid(NULL, data_blob_null, data_blob_null, NULL); - if (vuid == UID_FIELD_INVALID ) { + /* Do we have a valid vuid now ? */ + if (!is_partial_auth_vuid(vuid)) { + /* No, start a new authentication setup. */ + vuid = register_initial_vuid(); + if (vuid == UID_FIELD_INVALID) { data_blob_free(&blob1); reply_nterror(req, nt_status_squash( NT_STATUS_INVALID_PARAMETER)); return; } - - vuser = get_partial_auth_user_struct(vuid); } + vuser = get_partial_auth_user_struct(vuid); + /* This MUST be valid. */ if (!vuser) { - data_blob_free(&blob1); - reply_nterror(req, nt_status_squash( - NT_STATUS_INVALID_PARAMETER)); - return; + smb_panic("reply_sesssetup_and_X_spnego: invalid vuid."); } - + /* Large (greater than 4k) SPNEGO blobs are split into multiple * sessionsetup requests as the Windows limit on the security blob * field is 4k. Bug #4400. JRA. @@ -1617,13 +1641,25 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req) data_blob_free(&session_key); TALLOC_FREE(server_info); } else { - /* register_vuid keeps the server info */ - sess_vuid = register_vuid(server_info, session_key, - nt_resp.data ? nt_resp : lm_resp, - sub_user); + /* Ignore the initial vuid. */ + sess_vuid = register_initial_vuid(); if (sess_vuid == UID_FIELD_INVALID) { data_blob_free(&nt_resp); data_blob_free(&lm_resp); + data_blob_free(&session_key); + reply_nterror(req, nt_status_squash( + NT_STATUS_LOGON_FAILURE)); + } + /* register_existing_vuid keeps the server info */ + sess_vuid = register_existing_vuid(sess_vuid, + server_info, + session_key, + nt_resp.data ? nt_resp : lm_resp, + sub_user); + if (sess_vuid == UID_FIELD_INVALID) { + data_blob_free(&nt_resp); + data_blob_free(&lm_resp); + data_blob_free(&session_key); reply_nterror(req, nt_status_squash( NT_STATUS_LOGON_FAILURE)); return; |