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 <[email protected]>
Date:   Tue Jun 9 22:34:14 2009 +0200

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

commit 3b25d868eef517261ff111743affe75d8199040d
Author: Stefan Metzmacher <[email protected]>
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 <[email protected]>
Date:   Tue Jun 9 21:29:40 2009 +0200

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

commit bea384b2776c87c22e6c7e2ae6bca2d2321fd6e1
Author: Stefan Metzmacher <[email protected]>
Date:   Tue Jun 9 20:44:13 2009 +0200

    s3:smbd: add smbd_smb2_send_oplock_break()
    
    metze

commit cf7c41b841d03ecbe09ee531f6dd73be17948ac1
Author: Stefan Metzmacher <[email protected]>
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

Reply via email to