WORKS BUT NOT NEEDED s3:smbd: allow cancelling deferred SMB1 opens
authorStefan Metzmacher <metze@samba.org>
Wed, 21 Jun 2017 16:03:07 +0000 (18:03 +0200)
committerStefan Metzmacher <metze@samba.org>
Mon, 18 Feb 2019 11:47:34 +0000 (12:47 +0100)
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.

source3/smbd/nttrans.c
source3/smbd/open.c
source3/smbd/process.c
source3/smbd/proto.h

index 7ebd802109fd0557efde396fcf0cd89a6f095ff6..b313a50a60e0c33ccfc9647716569c6e6f09d6dc 100644 (file)
@@ -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));
index bab9286751f5e5dc325f484c02ecca446ab4749f..a8c7b235c715058be04f30da6be9be83f31b05f1 100644 (file)
@@ -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;
                }
        }
index 99693ed1315b98360ca164439b33d061d703b9a2..7a12dc11f6a5dd15c3bc1d55a9efd50c7a3af2b9 100644 (file)
@@ -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.
 ****************************************************************************/
index 3662a925dd6ca1eeab7c0e301362ab16e4fdcc22..de5d320419ce45f975171c8cb9ad9db89c566e3f 100644 (file)
@@ -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,