[SCM] Samba Shared Repository - branch master updated - release-4-0-0alpha8-54-gb7ea274

Stefan Metzmacher metze at samba.org
Wed Jun 24 19:24:38 GMT 2009


The branch, master has been updated
       via  b7ea2740d5b04ab312c8052ef71429f2a43007aa (commit)
       via  3b25d868eef517261ff111743affe75d8199040d (commit)
       via  754db207f6e77a715dff7f2d606593930776f0d8 (commit)
       via  bea384b2776c87c22e6c7e2ae6bca2d2321fd6e1 (commit)
       via  cf7c41b841d03ecbe09ee531f6dd73be17948ac1 (commit)
      from  17a65541bd27ce852bec77ef404c6f57ae65a50c (commit)

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


- Log -----------------------------------------------------------------
commit b7ea2740d5b04ab312c8052ef71429f2a43007aa
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Jun 9 22:34:14 2009 +0200

    s3:smbd: send SMB2 interim responses for async calls
    
    metze

commit 3b25d868eef517261ff111743affe75d8199040d
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Jun 9 22:33:32 2009 +0200

    s3:smbd: add support for async interim SMB2 responses and prepare SMB2 cancel
    
    metze

commit 754db207f6e77a715dff7f2d606593930776f0d8
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Jun 9 21:29:40 2009 +0200

    s3:smbd: keep a list of outstanding SMB2 requests
    
    metze

commit bea384b2776c87c22e6c7e2ae6bca2d2321fd6e1
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Jun 9 20:44:13 2009 +0200

    s3:smbd: add smbd_smb2_send_oplock_break()
    
    metze

commit cf7c41b841d03ecbe09ee531f6dd73be17948ac1
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Jun 9 20:02:48 2009 +0200

    s3:smbd: the SMB2-COMPOUND test shows that the related vs. unrelated flags isn't checked first
    
    metze

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

Summary of changes:
 source3/smbd/globals.h     |   11 ++
 source3/smbd/smb2_create.c |    5 +
 source3/smbd/smb2_flush.c  |    5 +
 source3/smbd/smb2_ioctl.c  |    5 +
 source3/smbd/smb2_read.c   |    5 +
 source3/smbd/smb2_server.c |  344 ++++++++++++++++++++++++++++++++++++++++----
 source3/smbd/smb2_write.c  |    5 +
 7 files changed, 351 insertions(+), 29 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index f002a6f..5e9da66 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -195,6 +195,13 @@ NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
 #define smbd_smb2_request_done(req, body, dyn) \
 	smbd_smb2_request_done_ex(req, NT_STATUS_OK, body, dyn, __location__)
 
+NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
+				     uint64_t file_id_persistent,
+				     uint64_t file_id_volatile,
+				     uint8_t oplock_level);
+
+NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req);
+
 NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req);
 NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req);
 
@@ -214,7 +221,10 @@ NTSTATUS smbd_smb2_request_process_ioctl(struct smbd_smb2_request *req);
 NTSTATUS smbd_smb2_request_process_keepalive(struct smbd_smb2_request *req);
 
 struct smbd_smb2_request {
+	struct smbd_smb2_request *prev, *next;
+
 	TALLOC_CTX *mem_pool;
+	struct smbd_smb2_request **parent;
 
 	struct smbd_server_connection *conn;
 
@@ -383,6 +393,7 @@ struct smbd_server_connection {
 
 			struct smbd_smb2_session *list;
 		} sessions;
+		struct smbd_smb2_request *requests;
 	} smb2;
 };
 
diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index 0e3cd16..578dfa7 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -123,6 +123,11 @@ NTSTATUS smbd_smb2_request_process_create(struct smbd_smb2_request *req)
 		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
 	}
 	tevent_req_set_callback(subreq, smbd_smb2_request_create_done, req);
+
+	if (tevent_req_is_in_progress(subreq)) {
+		return smbd_smb2_request_pending_queue(req);
+	}
+
 	return NT_STATUS_OK;
 }
 
diff --git a/source3/smbd/smb2_flush.c b/source3/smbd/smb2_flush.c
index ce560a1..8ce6839 100644
--- a/source3/smbd/smb2_flush.c
+++ b/source3/smbd/smb2_flush.c
@@ -69,6 +69,11 @@ NTSTATUS smbd_smb2_request_process_flush(struct smbd_smb2_request *req)
 		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
 	}
 	tevent_req_set_callback(subreq, smbd_smb2_request_flush_done, req);
+
+	if (tevent_req_is_in_progress(subreq)) {
+		return smbd_smb2_request_pending_queue(req);
+	}
+
 	return NT_STATUS_OK;
 }
 
diff --git a/source3/smbd/smb2_ioctl.c b/source3/smbd/smb2_ioctl.c
index a1f2885..85da92e 100644
--- a/source3/smbd/smb2_ioctl.c
+++ b/source3/smbd/smb2_ioctl.c
@@ -104,6 +104,11 @@ NTSTATUS smbd_smb2_request_process_ioctl(struct smbd_smb2_request *req)
 		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
 	}
 	tevent_req_set_callback(subreq, smbd_smb2_request_ioctl_done, req);
+
+	if (tevent_req_is_in_progress(subreq)) {
+		return smbd_smb2_request_pending_queue(req);
+	}
+
 	return NT_STATUS_OK;
 }
 
diff --git a/source3/smbd/smb2_read.c b/source3/smbd/smb2_read.c
index 5890ca6..c9f281f 100644
--- a/source3/smbd/smb2_read.c
+++ b/source3/smbd/smb2_read.c
@@ -100,6 +100,11 @@ NTSTATUS smbd_smb2_request_process_read(struct smbd_smb2_request *req)
 		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
 	}
 	tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
+
+	if (tevent_req_is_in_progress(subreq)) {
+		return smbd_smb2_request_pending_queue(req);
+	}
+
 	return NT_STATUS_OK;
 }
 
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index 101ccc9..6c66098 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -95,11 +95,66 @@ static void smb2_setup_nbt_length(struct iovec *vector, int count)
 	_smb2_setlen(vector[0].iov_base, len);
 }
 
+static int smbd_smb2_request_parent_destructor(struct smbd_smb2_request **req)
+{
+	if (*req) {
+		(*req)->parent = NULL;
+		(*req)->mem_pool = NULL;
+	}
+
+	return 0;
+}
+
+static int smbd_smb2_request_destructor(struct smbd_smb2_request *req)
+{
+	if (req->out.vector) {
+		DLIST_REMOVE(req->conn->smb2.requests, req);
+	}
+
+	if (req->parent) {
+		*req->parent = NULL;
+		talloc_free(req->mem_pool);
+	}
+
+	return 0;
+}
+
+static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx)
+{
+	TALLOC_CTX *mem_pool;
+	struct smbd_smb2_request **parent;
+	struct smbd_smb2_request *req;
+
+	mem_pool = talloc_pool(mem_ctx, 8192);
+	if (mem_pool == NULL) {
+		return NULL;
+	}
+
+	parent = talloc(mem_pool, struct smbd_smb2_request *);
+	if (parent == NULL) {
+		talloc_free(mem_pool);
+		return NULL;
+	}
+
+	req = talloc_zero(parent, struct smbd_smb2_request);
+	if (req == NULL) {
+		talloc_free(mem_pool);
+		return NULL;
+	}
+	*parent		= req;
+	req->mem_pool	= mem_pool;
+	req->parent	= parent;
+
+	talloc_set_destructor(parent, smbd_smb2_request_parent_destructor);
+	talloc_set_destructor(req, smbd_smb2_request_destructor);
+
+	return req;
+}
+
 static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *conn,
 					 const uint8_t *inbuf, size_t size,
 					 struct smbd_smb2_request **_req)
 {
-	TALLOC_CTX *mem_pool;
 	struct smbd_smb2_request *req;
 	uint32_t protocol_version;
 	const uint8_t *inhdr = NULL;
@@ -135,24 +190,17 @@ static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *conn,
 		return NT_STATUS_INVALID_PARAMETER;
 	}
 
-	mem_pool = talloc_pool(conn, 8192);
-	if (mem_pool == NULL) {
-		return NT_STATUS_NO_MEMORY;
-	}
-
-	req = talloc_zero(mem_pool, struct smbd_smb2_request);
+	req = smbd_smb2_request_allocate(conn);
 	if (req == NULL) {
-		talloc_free(mem_pool);
 		return NT_STATUS_NO_MEMORY;
 	}
-	req->mem_pool	= mem_pool;
-	req->conn	= conn;
+	req->conn = conn;
 
 	talloc_steal(req, inbuf);
 
 	req->in.vector = talloc_array(req, struct iovec, 4);
 	if (req->in.vector == NULL) {
-		talloc_free(mem_pool);
+		TALLOC_FREE(req);
 		return NT_STATUS_NO_MEMORY;
 	}
 	req->in.vector_count = 4;
@@ -237,6 +285,12 @@ static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
 				compound_related = true;
 			}
 		} else if (idx > 4) {
+#if 0
+			/*
+			 * It seems the this tests are wrong
+			 * see the SMB2-COMPOUND test
+			 */
+
 			/*
 			 * all other requests should match the 2nd one
 			 */
@@ -253,6 +307,7 @@ static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
 					return NT_STATUS_OK;
 				}
 			}
+#endif
 		}
 	}
 
@@ -343,6 +398,8 @@ static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
 	/* setup the length of the NBT packet */
 	smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
 
+	DLIST_ADD_END(req->conn->smb2.requests, req, struct smbd_smb2_request *);
+
 	return NT_STATUS_OK;
 }
 
@@ -355,6 +412,160 @@ void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn,
 	exit_server_cleanly(reason);
 }
 
+struct smbd_smb2_request_pending_state {
+	struct smbd_server_connection *sconn;
+	uint8_t buf[4 + SMB2_HDR_BODY + 0x08];
+	struct iovec vector;
+};
+
+static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq);
+
+NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req)
+{
+	struct smbd_smb2_request_pending_state *state;
+	struct tevent_req *subreq;
+	uint8_t *outhdr;
+	int i = req->current_idx;
+	uint32_t flags;
+	uint64_t message_id;
+	uint64_t async_id;
+	uint8_t *hdr;
+	uint8_t *body;
+
+	outhdr = (uint8_t *)req->out.vector[i].iov_base;
+
+	flags = IVAL(outhdr, SMB2_HDR_FLAGS);
+	message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
+
+	async_id = message_id; /* keep it simple for now... */
+	SIVAL(outhdr, SMB2_HDR_FLAGS,	flags | SMB2_HDR_FLAG_ASYNC);
+	SBVAL(outhdr, SMB2_HDR_PID,	async_id);
+
+	/* TODO: add a paramter to delay this */
+	state = talloc(req->conn, struct smbd_smb2_request_pending_state);
+	if (state == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	state->sconn = req->conn;
+
+	state->vector.iov_base = (void *)state->buf;
+	state->vector.iov_len = sizeof(state->buf);
+
+	_smb2_setlen(state->buf, sizeof(state->buf) - 4);
+	hdr = state->buf + 4;
+	body = hdr + SMB2_HDR_BODY;
+
+	SIVAL(hdr, SMB2_HDR_PROTOCOL_ID,	SMB2_MAGIC);
+	SSVAL(hdr, SMB2_HDR_LENGTH,		SMB2_HDR_BODY);
+	SSVAL(hdr, SMB2_HDR_EPOCH,		0);
+	SIVAL(hdr, SMB2_HDR_STATUS,		NT_STATUS_V(STATUS_PENDING));
+	SSVAL(hdr, SMB2_HDR_OPCODE,
+	      SVAL(outhdr, SMB2_HDR_OPCODE));
+	SSVAL(hdr, SMB2_HDR_CREDIT,		1);
+	SIVAL(hdr, SMB2_HDR_FLAGS,
+	      IVAL(outhdr, SMB2_HDR_FLAGS));
+	SIVAL(hdr, SMB2_HDR_NEXT_COMMAND,	0);
+	SBVAL(hdr, SMB2_HDR_MESSAGE_ID,
+	      BVAL(outhdr, SMB2_HDR_MESSAGE_ID));
+	SBVAL(hdr, SMB2_HDR_PID,
+	      BVAL(outhdr, SMB2_HDR_PID));
+	SBVAL(hdr, SMB2_HDR_SESSION_ID,
+	      BVAL(outhdr, SMB2_HDR_SESSION_ID));
+	memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
+
+	SSVAL(body, 0x00, 0x08 + 1);
+
+	SCVAL(body, 0x02, 0);
+	SCVAL(body, 0x03, 0);
+	SIVAL(body, 0x04, 0);
+
+	subreq = tstream_writev_queue_send(state,
+					   req->conn->smb2.event_ctx,
+					   req->conn->smb2.stream,
+					   req->conn->smb2.send_queue,
+					   &state->vector, 1);
+	if (subreq == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	tevent_req_set_callback(subreq,
+				smbd_smb2_request_pending_writev_done,
+				state);
+
+	return NT_STATUS_OK;
+}
+
+static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq)
+{
+	struct smbd_smb2_request_pending_state *state =
+		tevent_req_callback_data(subreq,
+		struct smbd_smb2_request_pending_state);
+	struct smbd_server_connection *sconn = state->sconn;
+	int ret;
+	int sys_errno;
+
+	ret = tstream_writev_queue_recv(subreq, &sys_errno);
+	TALLOC_FREE(subreq);
+	if (ret == -1) {
+		NTSTATUS status = map_nt_error_from_unix(sys_errno);
+		smbd_server_connection_terminate(sconn, nt_errstr(status));
+		return;
+	}
+
+	TALLOC_FREE(state);
+}
+
+static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
+{
+	struct smbd_server_connection *sconn = req->conn;
+	struct smbd_smb2_request *cur;
+	const uint8_t *inhdr;
+	int i = req->current_idx;
+	uint32_t flags;
+	uint64_t search_message_id;
+	uint64_t search_async_id;
+
+	inhdr = (const uint8_t *)req->in.vector[i].iov_base;
+
+	flags = IVAL(inhdr, SMB2_HDR_FLAGS);
+	search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
+	search_async_id = BVAL(inhdr, SMB2_HDR_PID);
+
+	/*
+	 * we don't need the request anymore
+	 * cancel requests never have a response
+	 */
+	TALLOC_FREE(req);
+
+	for (cur = sconn->smb2.requests; cur; cur = cur->next) {
+		const uint8_t *outhdr;
+		uint64_t message_id;
+		uint64_t async_id;
+
+		i = cur->current_idx;
+
+		outhdr = (const uint8_t *)cur->out.vector[i].iov_base;
+
+		message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
+		async_id = BVAL(outhdr, SMB2_HDR_PID);
+
+		if (flags & SMB2_HDR_FLAG_ASYNC) {
+			if (search_async_id == async_id) {
+				break;
+			}
+		} else {
+			if (search_message_id == message_id) {
+				break;
+			}
+		}
+	}
+
+	if (cur) {
+		/* TODO: try to cancel the request */
+	}
+
+	return NT_STATUS_OK;
+}
+
 static NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
 {
 	const uint8_t *inhdr;
@@ -518,7 +729,7 @@ static NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
 		return smbd_smb2_request_process_ioctl(req);
 
 	case SMB2_OP_CANCEL:
-		return smbd_smb2_request_error(req, NT_STATUS_NOT_IMPLEMENTED);
+		return smbd_smb2_request_process_cancel(req);
 
 	case SMB2_OP_KEEPALIVE:
 		return smbd_smb2_request_process_keepalive(req);
@@ -654,19 +865,15 @@ static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
 	struct smbd_server_connection *conn = req->conn;
 	int ret;
 	int sys_errno;
-	TALLOC_CTX *mem_pool;
 
 	ret = tstream_writev_queue_recv(subreq, &sys_errno);
 	TALLOC_FREE(subreq);
+	TALLOC_FREE(req);
 	if (ret == -1) {
 		NTSTATUS status = map_nt_error_from_unix(sys_errno);
 		smbd_server_connection_terminate(conn, nt_errstr(status));
 		return;
 	}
-
-	mem_pool = req->mem_pool;
-	req = NULL;
-	talloc_free(mem_pool);
 }
 
 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
@@ -814,6 +1021,94 @@ NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
 	return smbd_smb2_request_reply(req);
 }
 
+struct smbd_smb2_send_oplock_break_state {
+	struct smbd_server_connection *sconn;
+	uint8_t buf[4 + SMB2_HDR_BODY + 0x18];
+	struct iovec vector;
+};
+
+static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq);
+
+NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
+				     uint64_t file_id_persistent,
+				     uint64_t file_id_volatile,
+				     uint8_t oplock_level)
+{
+	struct smbd_smb2_send_oplock_break_state *state;
+	struct tevent_req *subreq;
+	uint8_t *hdr;
+	uint8_t *body;
+
+	state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
+	if (state == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	state->sconn = sconn;
+
+	state->vector.iov_base = (void *)state->buf;
+	state->vector.iov_len = sizeof(state->buf);
+
+	_smb2_setlen(state->buf, sizeof(state->buf) - 4);
+	hdr = state->buf + 4;
+	body = hdr + SMB2_HDR_BODY;
+
+	SIVAL(hdr, 0,				SMB2_MAGIC);
+	SSVAL(hdr, SMB2_HDR_LENGTH,		SMB2_HDR_BODY);
+	SSVAL(hdr, SMB2_HDR_EPOCH,		0);
+	SIVAL(hdr, SMB2_HDR_STATUS,		0);
+	SSVAL(hdr, SMB2_HDR_OPCODE,		SMB2_OP_BREAK);
+	SSVAL(hdr, SMB2_HDR_CREDIT,		0);
+	SIVAL(hdr, SMB2_HDR_FLAGS,		SMB2_HDR_FLAG_REDIRECT);
+	SIVAL(hdr, SMB2_HDR_NEXT_COMMAND,	0);
+	SBVAL(hdr, SMB2_HDR_MESSAGE_ID,		UINT64_MAX);
+	SIVAL(hdr, SMB2_HDR_PID,		0);
+	SIVAL(hdr, SMB2_HDR_TID,		0);
+	SBVAL(hdr, SMB2_HDR_SESSION_ID,		0);
+	memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
+
+	SSVAL(body, 0x00, 0x18);
+
+	SCVAL(body, 0x02, oplock_level);
+	SCVAL(body, 0x03, 0);		/* reserved */
+	SIVAL(body, 0x04, 0);		/* reserved */
+	SBVAL(body, 0x08, file_id_persistent);
+	SBVAL(body, 0x10, file_id_volatile);
+
+	subreq = tstream_writev_queue_send(state,
+					   sconn->smb2.event_ctx,
+					   sconn->smb2.stream,
+					   sconn->smb2.send_queue,
+					   &state->vector, 1);
+	if (subreq == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	tevent_req_set_callback(subreq,
+				smbd_smb2_oplock_break_writev_done,
+				state);
+
+	return NT_STATUS_OK;
+}
+
+static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq)
+{
+	struct smbd_smb2_send_oplock_break_state *state =
+		tevent_req_callback_data(subreq,
+		struct smbd_smb2_send_oplock_break_state);
+	struct smbd_server_connection *sconn = state->sconn;


-- 
Samba Shared Repository


More information about the samba-cvs mailing list