From: Stefan Metzmacher Date: Wed, 21 Jun 2017 16:03:07 +0000 (+0200) Subject: WORKS BUT NOT NEEDED s3:smbd: allow cancelling deferred SMB1 opens X-Git-Url: http://git.samba.org/?p=metze%2Fsamba%2Fwip.git;a=commitdiff_plain;h=637dc1998b244103d3fc4d5137292b86b74020aa WORKS BUT NOT NEEDED s3:smbd: allow cancelling deferred SMB1 opens The Windows 2012R2 behaviour seems to be a NTCREATE response with STATUS_CANCELLED, but the underlying open is not really cancelled and a following open get SHARING_VIOLATION. --- diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 7ebd802109fd..b313a50a60e0 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -1404,6 +1404,7 @@ void reply_ntcancel(struct smb_request *req) srv_cancel_sign_response(xconn); remove_pending_change_notify_requests_by_mid(sconn, req->mid); remove_pending_lock_requests_by_mid_smb1(sconn, req->mid); + cancel_deferred_open_message_smb(xconn, req->mid); DEBUG(3,("reply_ntcancel: cancel called on mid = %llu.\n", (unsigned long long)req->mid)); diff --git a/source3/smbd/open.c b/source3/smbd/open.c index bab9286751f5..a8c7b235c715 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -45,6 +45,7 @@ extern const struct generic_mapping file_generic_mapping; struct deferred_open_record { bool delayed_for_oplocks; bool async_open; + bool cancelled; struct file_id id; /* @@ -2844,6 +2845,21 @@ bool is_deferred_open_async(const struct deferred_open_record *rec) return rec->async_open; } +bool cancel_open_async(struct deferred_open_record *rec) +{ + if (rec->cancelled) { + return false; + } + + if (is_deferred_open_async(rec)) { + /* Can't cancel an async create. */ + return false; + } + + rec->cancelled = true; + return true; +} + static bool clear_ads(uint32_t create_disposition) { bool ret = false; @@ -3069,6 +3085,10 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, /* Ensure we don't reprocess this message. */ remove_deferred_open_message_smb(req->xconn, req->mid); + if (open_rec->cancelled) { + return NT_STATUS_CANCELLED; + } + first_open_attempt = false; } } diff --git a/source3/smbd/process.c b/source3/smbd/process.c index 99693ed1315b..7a12dc11f6a5 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -855,6 +855,76 @@ bool schedule_deferred_open_message_smb(struct smbXsrv_connection *xconn, return false; } +/**************************************************************************** + Function to cancel a sharing violation open message by mid. +****************************************************************************/ + +void cancel_deferred_open_message_smb(struct smbXsrv_connection *xconn, + uint64_t mid) +{ + struct smbd_server_connection *sconn = xconn->client->sconn; + struct pending_message_list *pml; + int i = 0; + + if (sconn->using_smb2) { + return; + } + + for (pml = sconn->deferred_open_queue; pml; pml = pml->next) { + uint64_t msg_mid = (uint64_t)SVAL(pml->buf.data,smb_mid); + struct tevent_timer *te = NULL; + bool ok; + + DBG_DEBUG("[%d] msg_mid = %llu\n", + i++, (unsigned long long)msg_mid); + + if (mid != msg_mid) { + continue; + } + + if (pml->processed) { + /* A processed message should not be + * rescheduled. */ + DBG_WARNING("LOGIC ERROR message mid %llu was " + "already processed\n", + (unsigned long long)msg_mid); + return; + } + + ok = cancel_open_async(pml->open_rec); + if (!ok) { + DBG_DEBUG("Request not cancelable, " + "skipping mid %llu\n", + (unsigned long long)msg_mid); + return; + } + + DBG_DEBUG("canceling deferred open mid %llu\n", + (unsigned long long)mid); + + te = tevent_add_timer(pml->sconn->ev_ctx, + pml, + timeval_zero(), + smbd_deferred_open_timer, + pml); + if (te == NULL) { + DBG_ERR("tevent_add_timer() failed, " + "skipping mid %llu\n", + (unsigned long long)msg_mid); + return; + } + + TALLOC_FREE(pml->te); + pml->te = te; + DLIST_PROMOTE(sconn->deferred_open_queue, pml); + return; + } + + DBG_DEBUG("failed to find message mid %llu\n", + (unsigned long long)mid); + return; +} + /**************************************************************************** Return true if this mid is on the deferred queue and was not yet processed. ****************************************************************************/ diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index 3662a925dd6c..de5d320419ce 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -682,6 +682,7 @@ NTSTATUS send_break_message(struct messaging_context *msg_ctx, uint16_t break_to); struct deferred_open_record; bool is_deferred_open_async(const struct deferred_open_record *rec); +bool cancel_open_async(struct deferred_open_record *rec); NTSTATUS create_directory(connection_struct *conn, struct smb_request *req, struct smb_filename *smb_dname); void msg_file_was_renamed(struct messaging_context *msg, @@ -854,6 +855,8 @@ void remove_deferred_open_message_smb(struct smbXsrv_connection *xconn, uint64_t mid); bool schedule_deferred_open_message_smb(struct smbXsrv_connection *xconn, uint64_t mid); +void cancel_deferred_open_message_smb(struct smbXsrv_connection *xconn, + uint64_t mid); bool open_was_deferred(struct smbXsrv_connection *xconn, uint64_t mid); bool get_deferred_open_message_state(struct smb_request *smbreq, struct timeval *p_request_time,