smbd: Simplify smbd_do_locking()
authorVolker Lendecke <vl@samba.org>
Fri, 31 May 2019 10:19:25 +0000 (12:19 +0200)
committerJeremy Allison <jra@samba.org>
Tue, 18 Jun 2019 12:54:00 +0000 (12:54 +0000)
LOCKING_ANDX_CANCEL_LOCK only is used in SMB1. Move its handling out
of the shared smb1/smb2 code.

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
source3/smbd/reply.c

index 4a654c6ab4098593d3a99c80389cf41cc0ca129c..fca0706c68a1c88fde99d89e381e585ff1bcd3db 100644 (file)
@@ -8104,59 +8104,7 @@ NTSTATUS smbd_do_locking(struct smb_request *req,
                          fsp_str_dbg(fsp),
                          timeout);
 
-               if (type & LOCKING_ANDX_CANCEL_LOCK) {
-                       struct blocking_lock_record *blr = NULL;
-
-                       if (num_locks > 1) {
-                               /*
-                                * MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
-                                * if the lock vector contains one entry. When given multiple cancel
-                                * requests in a single PDU we expect the server to return an
-                                * error. Windows servers seem to accept the request but only
-                                * cancel the first lock.
-                                * JRA - Do what Windows does (tm) :-).
-                                */
-
-#if 0
-                               /* MS-CIFS (2.2.4.32.1) behavior. */
-                               return NT_STATUS_DOS(ERRDOS,
-                                               ERRcancelviolation);
-#else
-                               /* Windows behavior. */
-                               if (i != 0) {
-                                       DEBUG(10,("smbd_do_locking: ignoring subsequent "
-                                               "cancel request\n"));
-                                       continue;
-                               }
-#endif
-                       }
-
-                       if (lp_blocking_locks(SNUM(conn))) {
-
-                               /* Schedule a message to ourselves to
-                                  remove the blocking lock record and
-                                  return the right error. */
-
-                               blr = blocking_lock_cancel_smb1(fsp,
-                                               e->smblctx,
-                                               e->offset,
-                                               e->count,
-                                               WINDOWS_LOCK,
-                                               type,
-                                               NT_STATUS_FILE_LOCK_CONFLICT);
-                               if (blr == NULL) {
-                                       return NT_STATUS_DOS(
-                                                       ERRDOS,
-                                                       ERRcancelviolation);
-                               }
-                       }
-                       /* Remove a matching pending lock. */
-                       status = do_lock_cancel(fsp,
-                                               e->smblctx,
-                                               e->count,
-                                               e->offset,
-                                               WINDOWS_LOCK);
-               } else {
+               {
                        bool blocking_lock = (timeout != 0);
                        bool defer_lock = false;
                        struct byte_range_lock *br_lck;
@@ -8239,10 +8187,6 @@ NTSTATUS smbd_do_locking(struct smb_request *req,
 
        if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
 
-               if (type & LOCKING_ANDX_CANCEL_LOCK) {
-                       i = -1; /* we want to skip the for loop */
-               }
-
                /*
                 * Ensure we don't do a remove on the lock that just failed,
                 * as under POSIX rules, if we have a lock already there, we
@@ -8504,6 +8448,61 @@ void reply_lockingX(struct smb_request *req)
                locks[i].brltype = brltype;
        }
 
+       if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
+               struct smbd_lock_element *e = NULL;
+
+               if (num_locks == 0) {
+                       /* See smbtorture3 lock11 test */
+                       goto done;
+               }
+
+               e = &locks[0];
+
+               /*
+                * MS-CIFS (2.2.4.32.1) states that a cancel is
+                * honored if and only if the lock vector contains one
+                * entry. When given multiple cancel requests in a
+                * single PDU we expect the server to return an
+                * error. Windows servers seem to accept the request
+                * but only cancel the first lock.
+                *
+                * JRA - Do what Windows does (tm) :-).
+                */
+
+               if (lp_blocking_locks(SNUM(conn))) {
+                       struct blocking_lock_record *blr = NULL;
+
+                       /* Schedule a message to ourselves to
+                          remove the blocking lock record and
+                          return the right error. */
+
+                       blr = blocking_lock_cancel_smb1(
+                               fsp,
+                               e->smblctx,
+                               e->offset,
+                               e->count,
+                               WINDOWS_LOCK,
+                               locktype,
+                               NT_STATUS_FILE_LOCK_CONFLICT);
+                       if (blr == NULL) {
+                               reply_force_doserror(
+                                       req, ERRDOS, ERRcancelviolation);
+                               END_PROFILE(SMBlockingX);
+                               return;
+                       }
+               }
+
+               /* Remove a matching pending lock. */
+               status = do_lock_cancel(fsp,
+                                       e->smblctx,
+                                       e->count,
+                                       e->offset,
+                                       WINDOWS_LOCK);
+               END_PROFILE(SMBlockingX);
+               reply_nterror(req, status);
+               return;
+       }
+
        status = smbd_do_locking(req, fsp,
                                 locktype, lock_timeout,
                                 num_locks, locks,
@@ -8519,6 +8518,7 @@ void reply_lockingX(struct smb_request *req)
                return;
        }
 
+done:
        reply_outbuf(req, 2, 0);
        SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
        SSVAL(req->outbuf, smb_vwv1, 0);    /* no andx offset */