[SCM] Samba Shared Repository - branch master updated - release-4-0-0alpha8-298-g67c7b7f

Stefan Metzmacher metze at samba.org
Fri Jul 10 10:25:19 GMT 2009


The branch, master has been updated
       via  67c7b7f90bd1bad265e892bb00abf649b22345b6 (commit)
       via  8d534d45a5d21967e2d9bca1ac34a55f1518fe42 (commit)
       via  598a9892bc4d5db2c75b218ba235fb7736b6a6e6 (commit)
       via  be1e5493c5aa323681d2843f37e93a0388e95f6a (commit)
       via  24c8e786bcdf2d10e378b655e1df69c2533f7804 (commit)
       via  12ed9ca36a4f8d2f3798f357a619389c26c9feea (commit)
      from  db1e58256861c50a9baed8efc862ba5b5834e28b (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 67c7b7f90bd1bad265e892bb00abf649b22345b6
Author: Stefan Metzmacher <metze at samba.org>
Date:   Wed Jul 8 13:13:32 2009 +0200

    s3:smbd: add support for SMB2 Lock
    
    metze

commit 8d534d45a5d21967e2d9bca1ac34a55f1518fe42
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Jul 7 18:09:16 2009 +0200

    s3:smbd: make smbd_do_locking() non static
    
    metze

commit 598a9892bc4d5db2c75b218ba235fb7736b6a6e6
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Jul 7 17:24:25 2009 +0200

    s3:smbd: abstract the main locking logic from the LockingAndX parsing
    
    This prepares SMB2 Lock support.
    
    metze

commit be1e5493c5aa323681d2843f37e93a0388e95f6a
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Jul 9 11:34:14 2009 +0200

    s3:smbd: pass down the client pid to smbd_smb2_lock_send()
    
    metze

commit 24c8e786bcdf2d10e378b655e1df69c2533f7804
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Jul 9 11:33:58 2009 +0200

    s3:smbd: fix parsing of SMB2 Lock requests with lock_count > 1
    
    We should not reuse the variable 'i'.
    
    metze

commit 12ed9ca36a4f8d2f3798f357a619389c26c9feea
Author: Stefan Metzmacher <metze at samba.org>
Date:   Wed Jul 8 17:02:00 2009 +0200

    s3:smbd: fix parsing of invalid SMB2 requests.
    
    Because of 0 - 2 => 0xFFFFFFFE, we got EMSGSIZE
    from the tstream layer. And terminate the transport
    connection. Instead we should let the caller deal with
    the invalid parameter, when checking the body size.
    So the caller always gets at least a 2 byte body.
    
    metze

-----------------------------------------------------------------------

Summary of changes:
 source3/smbd/globals.h     |   17 ++
 source3/smbd/reply.c       |  425 +++++++++++++++++++++++++------------------
 source3/smbd/smb2_lock.c   |  181 ++++++++++++++++++--
 source3/smbd/smb2_server.c |    4 +-
 4 files changed, 436 insertions(+), 191 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 3d195c8..8163213 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -168,6 +168,23 @@ NTSTATUS smb2_signing_check_pdu(DATA_BLOB session_key,
 				const struct iovec *vector,
 				int count);
 
+struct smbd_lock_element {
+	uint32_t smbpid;
+	enum brl_type brltype;
+	uint64_t offset;
+	uint64_t count;
+};
+
+NTSTATUS smbd_do_locking(struct smb_request *req,
+			 files_struct *fsp,
+			 uint8_t type,
+			 int32_t timeout,
+			 uint16_t num_ulocks,
+			 struct smbd_lock_element *ulocks,
+			 uint16_t num_locks,
+			 struct smbd_lock_element *locks,
+			 bool *async);
+
 void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn,
 					 const char *reason,
 					 const char *location);
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 1fd4e50..98ee83e 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -7223,6 +7223,205 @@ uint64_t get_lock_offset(const uint8_t *data, int data_offset,
 	return offset;
 }
 
+NTSTATUS smbd_do_locking(struct smb_request *req,
+			 files_struct *fsp,
+			 uint8_t type,
+			 int32_t timeout,
+			 uint16_t num_ulocks,
+			 struct smbd_lock_element *ulocks,
+			 uint16_t num_locks,
+			 struct smbd_lock_element *locks,
+			 bool *async)
+{
+	connection_struct *conn = req->conn;
+	int i;
+	NTSTATUS status = NT_STATUS_OK;
+
+	*async = false;
+
+	/* Data now points at the beginning of the list
+	   of smb_unlkrng structs */
+	for(i = 0; i < (int)num_ulocks; i++) {
+		struct smbd_lock_element *e = &ulocks[i];
+
+		DEBUG(10,("smbd_do_locking: unlock start=%.0f, len=%.0f for "
+			  "pid %u, file %s\n",
+			  (double)e->offset,
+			  (double)e->count,
+			  (unsigned int)e->smbpid,
+			  fsp->fsp_name));
+
+		if (e->brltype != UNLOCK_LOCK) {
+			/* this can only happen with SMB2 */
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+
+		status = do_unlock(smbd_messaging_context(),
+				fsp,
+				e->smbpid,
+				e->count,
+				e->offset,
+				WINDOWS_LOCK);
+
+		DEBUG(10, ("smbd_do_locking: unlock returned %s\n",
+		    nt_errstr(status)));
+
+		if (!NT_STATUS_IS_OK(status)) {
+			return status;
+		}
+	}
+
+	/* Setup the timeout in seconds. */
+
+	if (!lp_blocking_locks(SNUM(conn))) {
+		timeout = 0;
+	}
+
+	/* Data now points at the beginning of the list
+	   of smb_lkrng structs */
+
+	for(i = 0; i < (int)num_locks; i++) {
+		struct smbd_lock_element *e = &locks[i];
+
+		DEBUG(10,("smbd_do_locking: lock start=%.0f, len=%.0f for pid "
+			  "%u, file %s timeout = %d\n",
+			  (double)e->offset,
+			  (double)e->count,
+			  (unsigned int)e->smbpid,
+			  fsp->fsp_name,
+			  (int)timeout));
+
+		if (type & LOCKING_ANDX_CANCEL_LOCK) {
+			struct blocking_lock_record *blr = NULL;
+
+			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(fsp,
+						e->smbpid,
+						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->smbpid,
+						e->count,
+						e->offset,
+						WINDOWS_LOCK,
+						blr);
+		} else {
+			bool blocking_lock = timeout ? true : false;
+			bool defer_lock = false;
+			struct byte_range_lock *br_lck;
+			uint32_t block_smbpid;
+
+			br_lck = do_lock(smbd_messaging_context(),
+					fsp,
+					e->smbpid,
+					e->count,
+					e->offset, 
+					e->brltype,
+					WINDOWS_LOCK,
+					blocking_lock,
+					&status,
+					&block_smbpid,
+					NULL);
+
+			if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
+				/* Windows internal resolution for blocking locks seems
+				   to be about 200ms... Don't wait for less than that. JRA. */
+				if (timeout != -1 && timeout < lp_lock_spin_time()) {
+					timeout = lp_lock_spin_time();
+				}
+				defer_lock = true;
+			}
+
+			/* This heuristic seems to match W2K3 very well. If a
+			   lock sent with timeout of zero would fail with NT_STATUS_FILE_LOCK_CONFLICT
+			   it pretends we asked for a timeout of between 150 - 300 milliseconds as
+			   far as I can tell. Replacement for do_lock_spin(). JRA. */
+
+			if (br_lck && lp_blocking_locks(SNUM(conn)) && !blocking_lock &&
+					NT_STATUS_EQUAL((status), NT_STATUS_FILE_LOCK_CONFLICT)) {
+				defer_lock = true;
+				timeout = lp_lock_spin_time();
+			}
+
+			if (br_lck && defer_lock) {
+				/*
+				 * A blocking lock was requested. Package up
+				 * this smb into a queued request and push it
+				 * onto the blocking lock queue.
+				 */
+				if(push_blocking_lock_request(br_lck,
+							req,
+							fsp,
+							timeout,
+							i,
+							e->smbpid,
+							e->brltype,
+							WINDOWS_LOCK,
+							e->offset,
+							e->count,
+							block_smbpid)) {
+					TALLOC_FREE(br_lck);
+					*async = true;
+					return NT_STATUS_OK;
+				}
+			}
+
+			TALLOC_FREE(br_lck);
+		}
+
+		if (!NT_STATUS_IS_OK(status)) {
+			break;
+		}
+	}
+
+	/* If any of the above locks failed, then we must unlock
+	   all of the previous locks (X/Open spec). */
+
+	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
+		 * will delete it (and we shouldn't) .....
+		 */
+		for(i--; i >= 0; i--) {
+			struct smbd_lock_element *e = &locks[i];
+
+			do_unlock(smbd_messaging_context(),
+				fsp,
+				e->smbpid,
+				e->count,
+				e->offset,
+				WINDOWS_LOCK);
+		}
+		return status;
+	}
+
+	DEBUG(3, ("smbd_do_locking: fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
+		  fsp->fnum, (unsigned int)type, num_locks, num_ulocks));
+
+	return NT_STATUS_OK;
+}
+
 /****************************************************************************
  Reply to a lockingX request.
 ****************************************************************************/
@@ -7235,14 +7434,15 @@ void reply_lockingX(struct smb_request *req)
 	unsigned char oplocklevel;
 	uint16 num_ulocks;
 	uint16 num_locks;
-	uint64_t count = 0, offset = 0;
-	uint32 lock_pid;
 	int32 lock_timeout;
 	int i;
 	const uint8_t *data;
 	bool large_file_format;
 	bool err;
 	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+	struct smbd_lock_element *ulocks;
+	struct smbd_lock_element *locks;
+	bool async = false;
 
 	START_PROFILE(SMBlockingX);
 
@@ -7355,12 +7555,27 @@ void reply_lockingX(struct smb_request *req)
 		return;
 	}
 
+	ulocks = talloc_array(req, struct smbd_lock_element, num_ulocks);
+	if (ulocks == NULL) {
+		reply_nterror(req, NT_STATUS_NO_MEMORY);
+		END_PROFILE(SMBlockingX);
+		return;
+	}
+
+	locks = talloc_array(req, struct smbd_lock_element, num_locks);
+	if (locks == NULL) {
+		reply_nterror(req, NT_STATUS_NO_MEMORY);
+		END_PROFILE(SMBlockingX);
+		return;
+	}
+
 	/* Data now points at the beginning of the list
 	   of smb_unlkrng structs */
 	for(i = 0; i < (int)num_ulocks; i++) {
-		lock_pid = get_lock_pid( data, i, large_file_format);
-		count = get_lock_count( data, i, large_file_format);
-		offset = get_lock_offset( data, i, large_file_format, &err);
+		ulocks[i].smbpid = get_lock_pid(data, i, large_file_format);
+		ulocks[i].count = get_lock_count(data, i, large_file_format);
+		ulocks[i].offset = get_lock_offset(data, i, large_file_format, &err);
+		ulocks[i].brltype = UNLOCK_LOCK;
 
 		/*
 		 * There is no error code marked "stupid client bug".... :-).
@@ -7370,32 +7585,6 @@ void reply_lockingX(struct smb_request *req)
 			reply_doserror(req, ERRDOS, ERRnoaccess);
 			return;
 		}
-
-		DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for "
-			  "pid %u, file %s\n", (double)offset, (double)count,
-			  (unsigned int)lock_pid, fsp->fsp_name ));
-
-		status = do_unlock(smbd_messaging_context(),
-				fsp,
-				lock_pid,
-				count,
-				offset,
-				WINDOWS_LOCK);
-
-		DEBUG(10, ("reply_lockingX: unlock returned %s\n",
-		    nt_errstr(status)));
-
-		if (NT_STATUS_V(status)) {
-			END_PROFILE(SMBlockingX);
-			reply_nterror(req, status);
-			return;
-		}
-	}
-
-	/* Setup the timeout in seconds. */
-
-	if (!lp_blocking_locks(SNUM(conn))) {
-		lock_timeout = 0;
 	}
 
 	/* Now do any requested locks */
@@ -7405,11 +7594,23 @@ void reply_lockingX(struct smb_request *req)
 	   of smb_lkrng structs */
 
 	for(i = 0; i < (int)num_locks; i++) {
-		enum brl_type lock_type = ((locktype & LOCKING_ANDX_SHARED_LOCK) ?
-				READ_LOCK:WRITE_LOCK);
-		lock_pid = get_lock_pid( data, i, large_file_format);
-		count = get_lock_count( data, i, large_file_format);
-		offset = get_lock_offset( data, i, large_file_format, &err);
+		locks[i].smbpid = get_lock_pid(data, i, large_file_format);
+		locks[i].count = get_lock_count(data, i, large_file_format);
+		locks[i].offset = get_lock_offset(data, i, large_file_format, &err);
+
+		if (locktype & LOCKING_ANDX_SHARED_LOCK) {
+			if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
+				locks[i].brltype = PENDING_READ_LOCK;
+			} else {
+				locks[i].brltype = READ_LOCK;
+			}
+		} else {
+			if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
+				locks[i].brltype = PENDING_WRITE_LOCK;
+			} else {
+				locks[i].brltype = WRITE_LOCK;
+			}
+		}
 
 		/*
 		 * There is no error code marked "stupid client bug".... :-).
@@ -7419,154 +7620,22 @@ void reply_lockingX(struct smb_request *req)
 			reply_doserror(req, ERRDOS, ERRnoaccess);
 			return;
 		}
-
-		DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid "
-			  "%u, file %s timeout = %d\n", (double)offset,
-			  (double)count, (unsigned int)lock_pid,
-			  fsp->fsp_name, (int)lock_timeout ));
-
-		if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
-			struct blocking_lock_record *blr = NULL;
-
-			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(fsp,
-						lock_pid,
-						offset,
-						count,
-						WINDOWS_LOCK,
-						locktype,
-						NT_STATUS_FILE_LOCK_CONFLICT);
-				if (blr == NULL) {
-					END_PROFILE(SMBlockingX);
-					reply_nterror(
-						req,
-						NT_STATUS_DOS(
-							ERRDOS,
-							ERRcancelviolation));
-					return;
-				}
-			}
-			/* Remove a matching pending lock. */
-			status = do_lock_cancel(fsp,
-						lock_pid,
-						count,
-						offset,
-						WINDOWS_LOCK,
-						blr);
-		} else {
-			bool blocking_lock = lock_timeout ? True : False;
-			bool defer_lock = False;
-			struct byte_range_lock *br_lck;
-			uint32 block_smbpid;
-
-			br_lck = do_lock(smbd_messaging_context(),
-					fsp,
-					lock_pid,
-					count,
-					offset, 
-					lock_type,
-					WINDOWS_LOCK,
-					blocking_lock,
-					&status,
-					&block_smbpid,
-					NULL);
-
-			if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
-				/* Windows internal resolution for blocking locks seems
-				   to be about 200ms... Don't wait for less than that. JRA. */
-				if (lock_timeout != -1 && lock_timeout < lp_lock_spin_time()) {
-					lock_timeout = lp_lock_spin_time();
-				}
-				defer_lock = True;
-			}
-
-			/* This heuristic seems to match W2K3 very well. If a
-			   lock sent with timeout of zero would fail with NT_STATUS_FILE_LOCK_CONFLICT
-			   it pretends we asked for a timeout of between 150 - 300 milliseconds as
-			   far as I can tell. Replacement for do_lock_spin(). JRA. */
-
-			if (br_lck && lp_blocking_locks(SNUM(conn)) && !blocking_lock &&
-					NT_STATUS_EQUAL((status), NT_STATUS_FILE_LOCK_CONFLICT)) {
-				defer_lock = True;
-				lock_timeout = lp_lock_spin_time();
-			}
-
-			if (br_lck && defer_lock) {
-				/*
-				 * A blocking lock was requested. Package up
-				 * this smb into a queued request and push it
-				 * onto the blocking lock queue.
-				 */
-				if(push_blocking_lock_request(br_lck,
-							req,
-							fsp,
-							lock_timeout,
-							i,
-							lock_pid,
-							lock_type,
-							WINDOWS_LOCK,
-							offset,
-							count,
-							block_smbpid)) {
-					TALLOC_FREE(br_lck);
-					END_PROFILE(SMBlockingX);
-					return;
-				}
-			}
-
-			TALLOC_FREE(br_lck);
-		}
-
-		if (NT_STATUS_V(status)) {
-			break;
-		}
 	}
 
-	/* If any of the above locks failed, then we must unlock
-	   all of the previous locks (X/Open spec). */
-	if (num_locks != 0 && !NT_STATUS_IS_OK(status)) {
-
-		if (locktype & 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
-		 * will delete it (and we shouldn't) .....
-		 */
-		for(i--; i >= 0; i--) {
-			lock_pid = get_lock_pid( data, i, large_file_format);
-			count = get_lock_count( data, i, large_file_format);
-			offset = get_lock_offset( data, i, large_file_format,
-						  &err);
-
-			/*
-			 * There is no error code marked "stupid client
-			 * bug".... :-).
-			 */
-			if(err) {
-				END_PROFILE(SMBlockingX);
-				reply_doserror(req, ERRDOS, ERRnoaccess);
-				return;
-			}
-
-			do_unlock(smbd_messaging_context(),
-				fsp,
-				lock_pid,
-				count,
-				offset,
-				WINDOWS_LOCK);
-		}
+	status = smbd_do_locking(req, fsp,
+				 locktype, lock_timeout,
+				 num_ulocks, ulocks,


-- 
Samba Shared Repository


More information about the samba-cvs mailing list