s4/schema: Handle Object(OR-Name) syntax in extended_dn_out module
[gd/samba/.git] / source3 / smbd / smb2_server.c
index 43afb1b901e78f0c12b5655da6bd56ca4efbc896..9e5be404eff2c473fe20607ee5f121360aab0820 100644 (file)
@@ -20,7 +20,7 @@
 
 #include "includes.h"
 #include "smbd/globals.h"
-#include "../source4/libcli/smb2/smb2_constants.h"
+#include "../libcli/smb/smb_common.h"
 #include "../lib/tsocket/tsocket.h"
 
 bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size)
@@ -36,34 +36,34 @@ bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size)
        return true;
 }
 
-static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *conn)
+static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn)
 {
        NTSTATUS status;
        int ret;
 
-       TALLOC_FREE(conn->smb1.fde);
+       TALLOC_FREE(sconn->smb1.fde);
 
-       conn->smb2.event_ctx = smbd_event_context();
+       sconn->smb2.event_ctx = smbd_event_context();
 
-       conn->smb2.recv_queue = tevent_queue_create(conn, "smb2 recv queue");
-       if (conn->smb2.recv_queue == NULL) {
+       sconn->smb2.recv_queue = tevent_queue_create(sconn, "smb2 recv queue");
+       if (sconn->smb2.recv_queue == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       conn->smb2.send_queue = tevent_queue_create(conn, "smb2 send queue");
-       if (conn->smb2.send_queue == NULL) {
+       sconn->smb2.send_queue = tevent_queue_create(sconn, "smb2 send queue");
+       if (sconn->smb2.send_queue == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       conn->smb2.sessions.idtree = idr_init(conn);
-       if (conn->smb2.sessions.idtree == NULL) {
+       sconn->smb2.sessions.idtree = idr_init(sconn);
+       if (sconn->smb2.sessions.idtree == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
-       conn->smb2.sessions.limit = 0x0000FFFE;
-       conn->smb2.sessions.list = NULL;
+       sconn->smb2.sessions.limit = 0x0000FFFE;
+       sconn->smb2.sessions.list = NULL;
 
-       ret = tstream_bsd_existing_socket(conn, smbd_server_fd(),
-                                         &conn->smb2.stream);
+       ret = tstream_bsd_existing_socket(sconn, smbd_server_fd(),
+                                         &sconn->smb2.stream);
        if (ret == -1) {
                status = map_nt_error_from_unix(errno);
                return status;
@@ -108,7 +108,7 @@ static int smbd_smb2_request_parent_destructor(struct smbd_smb2_request **req)
 static int smbd_smb2_request_destructor(struct smbd_smb2_request *req)
 {
        if (req->out.vector) {
-               DLIST_REMOVE(req->conn->smb2.requests, req);
+               DLIST_REMOVE(req->sconn->smb2.requests, req);
        }
 
        if (req->parent) {
@@ -151,7 +151,7 @@ static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx)
        return req;
 }
 
-static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *conn,
+static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
                                         const uint8_t *inbuf, size_t size,
                                         struct smbd_smb2_request **_req)
 {
@@ -190,11 +190,11 @@ static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *conn,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       req = smbd_smb2_request_allocate(conn);
+       req = smbd_smb2_request_allocate(sconn);
        if (req == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
-       req->conn = conn;
+       req->sconn = sconn;
 
        talloc_steal(req, inbuf);
 
@@ -398,7 +398,7 @@ 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 *);
+       DLIST_ADD_END(req->sconn->smb2.requests, req, struct smbd_smb2_request *);
 
        return NT_STATUS_OK;
 }
@@ -420,10 +420,10 @@ struct smbd_smb2_request_pending_state {
 
 static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq);
 
-NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req)
+NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
+                                        struct tevent_req *subreq)
 {
        struct smbd_smb2_request_pending_state *state;
-       struct tevent_req *subreq;
        uint8_t *outhdr;
        int i = req->current_idx;
        uint32_t flags;
@@ -432,6 +432,13 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req)
        uint8_t *hdr;
        uint8_t *body;
 
+       if (!tevent_req_is_in_progress(subreq)) {
+               return NT_STATUS_OK;
+       }
+
+       req->subreq = subreq;
+       subreq = NULL;
+
        outhdr = (uint8_t *)req->out.vector[i].iov_base;
 
        flags = IVAL(outhdr, SMB2_HDR_FLAGS);
@@ -442,11 +449,11 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req)
        SBVAL(outhdr, SMB2_HDR_PID,     async_id);
 
        /* TODO: add a paramter to delay this */
-       state = talloc(req->conn, struct smbd_smb2_request_pending_state);
+       state = talloc(req->sconn, struct smbd_smb2_request_pending_state);
        if (state == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
-       state->sconn = req->conn;
+       state->sconn = req->sconn;
 
        state->vector.iov_base = (void *)state->buf;
        state->vector.iov_len = sizeof(state->buf);
@@ -480,9 +487,9 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req)
        SIVAL(body, 0x04, 0);
 
        subreq = tstream_writev_queue_send(state,
-                                          req->conn->smb2.event_ctx,
-                                          req->conn->smb2.stream,
-                                          req->conn->smb2.send_queue,
+                                          req->sconn->smb2.event_ctx,
+                                          req->sconn->smb2.stream,
+                                          req->sconn->smb2.send_queue,
                                           &state->vector, 1);
        if (subreq == NULL) {
                return NT_STATUS_NO_MEMORY;
@@ -516,7 +523,7 @@ static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq)
 
 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
 {
-       struct smbd_server_connection *sconn = req->conn;
+       struct smbd_server_connection *sconn = req->sconn;
        struct smbd_smb2_request *cur;
        const uint8_t *inhdr;
        int i = req->current_idx;
@@ -559,8 +566,8 @@ static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
                }
        }
 
-       if (cur) {
-               /* TODO: try to cancel the request */
+       if (cur && cur->subreq) {
+               tevent_req_cancel(cur->subreq);
        }
 
        return NT_STATUS_OK;
@@ -574,6 +581,7 @@ static NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
        uint32_t flags;
        NTSTATUS status;
        NTSTATUS session_status;
+       uint32_t allowed_flags;
 
        inhdr = (const uint8_t *)req->in.vector[i].iov_base;
 
@@ -583,14 +591,15 @@ static NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
        opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
        DEBUG(10,("smbd_smb2_request_dispatch: opcode[%u]\n", opcode));
 
-#define TMP_SMB2_ALLOWED_FLAGS ( \
-       SMB2_HDR_FLAG_CHAINED | \
-       SMB2_HDR_FLAG_SIGNED | \
-       SMB2_HDR_FLAG_DFS)
-       if ((flags & ~TMP_SMB2_ALLOWED_FLAGS) != 0) {
+       allowed_flags = SMB2_HDR_FLAG_CHAINED |
+                       SMB2_HDR_FLAG_SIGNED |
+                       SMB2_HDR_FLAG_DFS;
+       if (opcode == SMB2_OP_CANCEL) {
+               allowed_flags |= SMB2_HDR_FLAG_ASYNC;
+       }
+       if ((flags & ~allowed_flags) != 0) {
                return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
        }
-#undef TMP_SMB2_ALLOWED_FLAGS
 
        session_status = smbd_smb2_request_check_session(req);
 
@@ -795,6 +804,8 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
 {
        struct tevent_req *subreq;
 
+       req->subreq = NULL;
+
        smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
 
        if (req->do_signing) {
@@ -812,7 +823,7 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
        if (req->current_idx < req->out.vector_count) {
                struct timeval zero = timeval_zero();
                subreq = tevent_wakeup_send(req,
-                                           req->conn->smb2.event_ctx,
+                                           req->sconn->smb2.event_ctx,
                                            zero);
                if (subreq == NULL) {
                        return NT_STATUS_NO_MEMORY;
@@ -825,9 +836,9 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
        }
 
        subreq = tstream_writev_queue_send(req,
-                                          req->conn->smb2.event_ctx,
-                                          req->conn->smb2.stream,
-                                          req->conn->smb2.send_queue,
+                                          req->sconn->smb2.event_ctx,
+                                          req->sconn->smb2.stream,
+                                          req->sconn->smb2.send_queue,
                                           req->out.vector,
                                           req->out.vector_count);
        if (subreq == NULL) {
@@ -842,7 +853,7 @@ static void smbd_smb2_request_dispatch_compound(struct tevent_req *subreq)
 {
        struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
                                        struct smbd_smb2_request);
-       struct smbd_server_connection *conn = req->conn;
+       struct smbd_server_connection *sconn = req->sconn;
        NTSTATUS status;
 
        tevent_wakeup_recv(subreq);
@@ -853,7 +864,7 @@ static void smbd_smb2_request_dispatch_compound(struct tevent_req *subreq)
 
        status = smbd_smb2_request_dispatch(req);
        if (!NT_STATUS_IS_OK(status)) {
-               smbd_server_connection_terminate(conn, nt_errstr(status));
+               smbd_server_connection_terminate(sconn, nt_errstr(status));
                return;
        }
 }
@@ -862,7 +873,7 @@ static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
 {
        struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
                                        struct smbd_smb2_request);
-       struct smbd_server_connection *conn = req->conn;
+       struct smbd_server_connection *sconn = req->sconn;
        int ret;
        int sys_errno;
 
@@ -871,7 +882,7 @@ static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
        TALLOC_FREE(req);
        if (ret == -1) {
                NTSTATUS status = map_nt_error_from_unix(sys_errno);
-               smbd_server_connection_terminate(conn, nt_errstr(status));
+               smbd_server_connection_terminate(sconn, nt_errstr(status));
                return;
        }
 }
@@ -1124,7 +1135,7 @@ static void smbd_smb2_request_read_done(struct tevent_req *subreq);
 
 static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
                                        struct tevent_context *ev,
-                                       struct smbd_server_connection *conn)
+                                       struct smbd_server_connection *sconn)
 {
        struct tevent_req *req;
        struct smbd_smb2_request_read_state *state;
@@ -1142,10 +1153,10 @@ static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
        if (tevent_req_nomem(state->smb2_req, req)) {
                return tevent_req_post(req, ev);
        }
-       state->smb2_req->conn = conn;
+       state->smb2_req->sconn = sconn;
 
-       subreq = tstream_readv_pdu_queue_send(state, ev, conn->smb2.stream,
-                                             conn->smb2.recv_queue,
+       subreq = tstream_readv_pdu_queue_send(state, ev, sconn->smb2.stream,
+                                             sconn->smb2.recv_queue,
                                              smbd_smb2_request_next_vector,
                                              state);
        if (tevent_req_nomem(subreq, req)) {
@@ -1328,7 +1339,13 @@ static int smbd_smb2_request_next_vector(struct tstream_context *stream,
                                 * body and let the caller deal with the error
                                 */
                                invalid = true;
-                       } else if (body_size > (full_size - SMB2_HDR_BODY)) {
+                       }
+
+                       if ((body_size % 2) != 0) {
+                               body_size -= 1;
+                       }
+
+                       if (body_size > (full_size - SMB2_HDR_BODY)) {
                                /*
                                 * this is invalid, just return a zero
                                 * body and let the caller deal with the error
@@ -1339,11 +1356,7 @@ static int smbd_smb2_request_next_vector(struct tstream_context *stream,
 
                if (invalid) {
                        /* the caller should check this */
-                       body_size = 0;
-               }
-
-               if ((body_size % 2) != 0) {
-                       body_size -= 1;
+                       body_size = 2;
                }
 
                dyn_size = full_size - (SMB2_HDR_BODY + body_size);
@@ -1376,7 +1389,7 @@ static int smbd_smb2_request_next_vector(struct tstream_context *stream,
                 */
                memcpy(body, hdr + SMB2_HDR_BODY, 2);
                vector[0].iov_base = body + 2;
-               vector[0].iov_len = req->in.vector[idx].iov_len - 2;
+               vector[0].iov_len = body_size - 2;
 
                vector[1] = req->in.vector[idx+1];
 
@@ -1475,7 +1488,7 @@ static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req,
 
 static void smbd_smb2_request_incoming(struct tevent_req *subreq);
 
-void smbd_smb2_first_negprot(struct smbd_server_connection *conn,
+void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
                             const uint8_t *inbuf, size_t size)
 {
        NTSTATUS status;
@@ -1485,50 +1498,50 @@ void smbd_smb2_first_negprot(struct smbd_server_connection *conn,
        DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
                 (unsigned int)size));
 
-       status = smbd_initialize_smb2(conn);
+       status = smbd_initialize_smb2(sconn);
        if (!NT_STATUS_IS_OK(status)) {
-               smbd_server_connection_terminate(conn, nt_errstr(status));
+               smbd_server_connection_terminate(sconn, nt_errstr(status));
                return;
        }
 
-       status = smbd_smb2_request_create(conn, inbuf, size, &req);
+       status = smbd_smb2_request_create(sconn, inbuf, size, &req);
        if (!NT_STATUS_IS_OK(status)) {
-               smbd_server_connection_terminate(conn, nt_errstr(status));
+               smbd_server_connection_terminate(sconn, nt_errstr(status));
                return;
        }
 
        status = smbd_smb2_request_setup_out(req);
        if (!NT_STATUS_IS_OK(status)) {
-               smbd_server_connection_terminate(conn, nt_errstr(status));
+               smbd_server_connection_terminate(sconn, nt_errstr(status));
                return;
        }
 
        status = smbd_smb2_request_dispatch(req);
        if (!NT_STATUS_IS_OK(status)) {
-               smbd_server_connection_terminate(conn, nt_errstr(status));
+               smbd_server_connection_terminate(sconn, nt_errstr(status));
                return;
        }
 
        /* ask for the next request */
-       subreq = smbd_smb2_request_read_send(conn,conn->smb2.event_ctx, conn);
+       subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn);
        if (subreq == NULL) {
-               smbd_server_connection_terminate(conn, "no memory for reading");
+               smbd_server_connection_terminate(sconn, "no memory for reading");
                return;
        }
-       tevent_req_set_callback(subreq, smbd_smb2_request_incoming, conn);
+       tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
 }
 
 static void smbd_smb2_request_incoming(struct tevent_req *subreq)
 {
-       struct smbd_server_connection *conn = tevent_req_callback_data(subreq,
-                                             struct smbd_server_connection);
+       struct smbd_server_connection *sconn = tevent_req_callback_data(subreq,
+                                              struct smbd_server_connection);
        NTSTATUS status;
-       struct smbd_smb2_request *req;
+       struct smbd_smb2_request *req = NULL;
 
-       status = smbd_smb2_request_read_recv(subreq, conn, &req);
+       status = smbd_smb2_request_read_recv(subreq, sconn, &req);
        TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(status)) {
-               smbd_server_connection_terminate(conn, nt_errstr(status));
+               smbd_server_connection_terminate(sconn, nt_errstr(status));
                return;
        }
 
@@ -1546,28 +1559,28 @@ static void smbd_smb2_request_incoming(struct tevent_req *subreq)
 
        status = smbd_smb2_request_validate(req);
        if (!NT_STATUS_IS_OK(status)) {
-               smbd_server_connection_terminate(conn, nt_errstr(status));
+               smbd_server_connection_terminate(sconn, nt_errstr(status));
                return;
        }
 
        status = smbd_smb2_request_setup_out(req);
        if (!NT_STATUS_IS_OK(status)) {
-               smbd_server_connection_terminate(conn, nt_errstr(status));
+               smbd_server_connection_terminate(sconn, nt_errstr(status));
                return;
        }
 
        status = smbd_smb2_request_dispatch(req);
        if (!NT_STATUS_IS_OK(status)) {
-               smbd_server_connection_terminate(conn, nt_errstr(status));
+               smbd_server_connection_terminate(sconn, nt_errstr(status));
                return;
        }
 
 next:
        /* ask for the next request (this constructs the main loop) */
-       subreq = smbd_smb2_request_read_send(conn,conn->smb2.event_ctx, conn);
+       subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn);
        if (subreq == NULL) {
-               smbd_server_connection_terminate(conn, "no memory for reading");
+               smbd_server_connection_terminate(sconn, "no memory for reading");
                return;
        }
-       tevent_req_set_callback(subreq, smbd_smb2_request_incoming, conn);
+       tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
 }