s3:smb2_server: call change_to_root_user() or smbd_smb2_request_check_tcon()
[metze/samba/wip.git] / source3 / smbd / smb2_server.c
index d2baed7cb4d55e3fd939a6a0c72141298705e5fa..90f476720311f7f3ff29efb58210cb13cd524e73 100644 (file)
 */
 
 #include "includes.h"
+#include "smbd/smbd.h"
 #include "smbd/globals.h"
 #include "../libcli/smb/smb_common.h"
 #include "../lib/tsocket/tsocket.h"
+#include "../lib/util/tevent_ntstatus.h"
+#include "smbprofile.h"
 
 #define OUTVEC_ALLOC_SIZE (SMB2_HDR_BODY + 9)
 
@@ -92,7 +95,7 @@ static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn)
 
        TALLOC_FREE(sconn->smb1.fde);
 
-       sconn->smb2.event_ctx = smbd_event_context();
+       sconn->smb2.event_ctx = server_event_context();
 
        sconn->smb2.recv_queue = tevent_queue_create(sconn, "smb2 recv queue");
        if (sconn->smb2.recv_queue == NULL) {
@@ -111,9 +114,10 @@ static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn)
        sconn->smb2.sessions.limit = 0x0000FFFE;
        sconn->smb2.sessions.list = NULL;
        sconn->smb2.seqnum_low = 0;
-       sconn->smb2.credits_granted = 1;
+       sconn->smb2.credits_granted = 0;
        sconn->smb2.max_credits = lp_smb2_max_credits();
-       sconn->smb2.credits_bitmap = bitmap_talloc(sconn, 2*sconn->smb2.max_credits);
+       sconn->smb2.credits_bitmap = bitmap_talloc(sconn,
+                       DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR*sconn->smb2.max_credits);
        if (sconn->smb2.credits_bitmap == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -265,15 +269,15 @@ static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
        memcpy(req->in.nbt_hdr, inbuf, 4);
 
        ofs = 0;
-       req->in.vector[0].iov_base      = (void *)req->in.nbt_hdr;
+       req->in.vector[0].iov_base      = discard_const_p(void, req->in.nbt_hdr);
        req->in.vector[0].iov_len       = 4;
        ofs += req->in.vector[0].iov_len;
 
-       req->in.vector[1].iov_base      = (void *)(inbuf + ofs);
+       req->in.vector[1].iov_base      = discard_const_p(void, (inbuf + ofs));
        req->in.vector[1].iov_len       = SMB2_HDR_BODY;
        ofs += req->in.vector[1].iov_len;
 
-       req->in.vector[2].iov_base      = (void *)(inbuf + ofs);
+       req->in.vector[2].iov_base      = discard_const_p(void, (inbuf + ofs));
        req->in.vector[2].iov_len       = SVAL(inbuf, ofs) & 0xFFFE;
        ofs += req->in.vector[2].iov_len;
 
@@ -281,7 +285,7 @@ static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       req->in.vector[3].iov_base      = (void *)(inbuf + ofs);
+       req->in.vector[3].iov_base      = discard_const_p(void, (inbuf + ofs));
        req->in.vector[3].iov_len       = size - ofs;
        ofs += req->in.vector[3].iov_len;
 
@@ -306,12 +310,12 @@ static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
 
        if (message_id < sconn->smb2.seqnum_low ||
                        message_id > (sconn->smb2.seqnum_low +
-                       (2*sconn->smb2.credits_granted))) {
+                       (sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR))) {
                DEBUG(0,("smb2_validate_message_id: bad message_id "
-                       "%llu (low = %llu, granted = %lu)\n",
+                       "%llu (low = %llu, max = %lu)\n",
                        (unsigned long long)message_id,
                        (unsigned long long)sconn->smb2.seqnum_low,
-                       (unsigned long)sconn->smb2.credits_granted ));
+                       (unsigned long)sconn->smb2.max_credits ));
                return false;
        }
 
@@ -321,7 +325,7 @@ static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
 
        /* Mark the message_id as seen in the bitmap. */
        bitmap_offset = (unsigned int)(message_id %
-                       (uint64_t)(sconn->smb2.max_credits * 2));
+                       (uint64_t)(sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR));
        if (bitmap_query(credits_bm, bitmap_offset)) {
                DEBUG(0,("smb2_validate_message_id: duplicate message_id "
                        "%llu (bm offset %u)\n",
@@ -342,7 +346,7 @@ static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
                        bitmap_clear(credits_bm, bitmap_offset);
                        sconn->smb2.seqnum_low += 1;
                        bitmap_offset = (bitmap_offset + 1) %
-                               (sconn->smb2.max_credits * 2);
+                               (sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR);
                }
        }
 
@@ -437,7 +441,7 @@ static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
                        const struct iovec *in_vector,
                        struct iovec *out_vector)
 {
-       uint8_t *outhdr = out_vector->iov_base;
+       uint8_t *outhdr = (uint8_t *)out_vector->iov_base;
        uint16_t credits_requested = 0;
        uint16_t credits_granted = 0;
 
@@ -453,7 +457,8 @@ static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
                sconn->smb2.credits_granted));
 
        if (credits_granted == 0 && sconn->smb2.credits_granted == 0) {
-               /* Ensure the client credits can never drop to zero. */
+               /* First negprot packet, or ensure the client credits can
+                  never drop to zero. */
                credits_granted = 1;
        }
 
@@ -603,7 +608,7 @@ static bool dup_smb2_vec3(TALLOC_CTX *ctx,
                        srcvec[1].iov_base ==
                                ((uint8_t *)srcvec[0].iov_base) +
                                        SMB2_HDR_BODY) {
-               outvec[1].iov_base = ((uint8_t *)outvec[1].iov_base) +
+               outvec[1].iov_base = ((uint8_t *)outvec[0].iov_base) +
                                        SMB2_HDR_BODY;
                outvec[1].iov_len = 8;
        } else {
@@ -660,10 +665,18 @@ static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *re
        }
 
        newreq->sconn = req->sconn;
+       newreq->session = req->session;
        newreq->do_signing = req->do_signing;
        newreq->current_idx = req->current_idx;
        newreq->async = false;
        newreq->cancelled = false;
+       /* Note we are leaving:
+               ->tcon
+               ->smb1req
+               ->compat_chain_fsp
+          uninitialized as NULL here as
+          they're not used in the interim
+          response code. JRA. */
 
        outvec = talloc_zero_array(newreq, struct iovec, count);
        if (!outvec) {
@@ -901,14 +914,16 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
        /* Match W2K8R2... */
        SCVAL(body, 0x08, 0x21);
 
-       /* Ensure we correctly go through crediting. */
+       /* Ensure we correctly go through crediting. Grant
+          the credits now, and zero credits on the final
+          response. */
        smb2_set_operation_credit(req->sconn,
-                       NULL,
+                       &req->in.vector[i],
                        &state->vector[1]);
 
        if (req->do_signing) {
                status = smb2_signing_sign_pdu(req->session->session_key,
-                                       state->vector, 3);
+                                       &state->vector[1], 2);
                if (!NT_STATUS_IS_OK(status)) {
                        return status;
                }
@@ -1124,6 +1139,9 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
 
        switch (opcode) {
        case SMB2_OP_NEGPROT:
+               /* This call needs to be run as root */
+               change_to_root_user();
+
                {
                        START_PROFILE(smb2_negprot);
                        return_value = smbd_smb2_request_process_negprot(req);
@@ -1132,6 +1150,9 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                break;
 
        case SMB2_OP_SESSSETUP:
+               /* This call needs to be run as root */
+               change_to_root_user();
+
                {
                        START_PROFILE(smb2_sesssetup);
                        return_value = smbd_smb2_request_process_sesssetup(req);
@@ -1145,6 +1166,9 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                        break;
                }
 
+               /* This call needs to be run as root */
+               change_to_root_user();
+
                {
                        START_PROFILE(smb2_logoff);
                        return_value = smbd_smb2_request_process_logoff(req);
@@ -1157,11 +1181,9 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                        return_value = smbd_smb2_request_error(req, session_status);
                        break;
                }
-               status = smbd_smb2_request_check_session(req);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return_value = smbd_smb2_request_error(req, status);
-                       break;
-               }
+
+               /* This call needs to be run as root */
+               change_to_root_user();
 
                {
                        START_PROFILE(smb2_tcon);
@@ -1180,6 +1202,9 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                        return_value = smbd_smb2_request_error(req, status);
                        break;
                }
+               /* This call needs to be run as root */
+               change_to_root_user();
+
 
                {
                        START_PROFILE(smb2_tdis);
@@ -1323,6 +1348,9 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                break;
 
        case SMB2_OP_CANCEL:
+               /* This call needs to be run as root */
+               change_to_root_user();
+
                {
                        START_PROFILE(smb2_cancel);
                        return_value = smbd_smb2_request_process_cancel(req);
@@ -1331,9 +1359,14 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                break;
 
        case SMB2_OP_KEEPALIVE:
-               {START_PROFILE(smb2_keepalive);
-               return_value = smbd_smb2_request_process_keepalive(req);
-               END_PROFILE(smb2_keepalive);}
+               /* This call needs to be run as root */
+               change_to_root_user();
+
+               {
+                       START_PROFILE(smb2_keepalive);
+                       return_value = smbd_smb2_request_process_keepalive(req);
+                       END_PROFILE(smb2_keepalive);
+               }
                break;
 
        case SMB2_OP_FIND:
@@ -1440,22 +1473,6 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
 
        req->subreq = NULL;
 
-       smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
-
-       /* Set credit for this operation. */
-       smb2_set_operation_credit(req->sconn,
-                       &req->in.vector[i],
-                       &req->out.vector[i]);
-
-       if (req->do_signing) {
-               NTSTATUS status;
-               status = smb2_signing_sign_pdu(req->session->session_key,
-                                              &req->out.vector[i], 3);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
-       }
-
        req->current_idx += 3;
 
        if (req->current_idx < req->out.vector_count) {
@@ -1478,11 +1495,37 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
                return NT_STATUS_OK;
        }
 
+       smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
+
+       /* Set credit for this operation (zero credits if this
+          is a final reply for an async operation). */
+       smb2_set_operation_credit(req->sconn,
+                       req->async ? NULL : &req->in.vector[i],
+                       &req->out.vector[i]);
+
+       if (req->do_signing) {
+               NTSTATUS status;
+               status = smb2_signing_sign_pdu(req->session->session_key,
+                                              &req->out.vector[i], 3);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+       }
+
        if (DEBUGLEVEL >= 10) {
                dbgtext("smbd_smb2_request_reply: sending...\n");
                print_req_vectors(req);
        }
 
+       /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
+       if (req->out.vector_count == 4 &&
+                       req->out.vector[3].iov_base == NULL &&
+                       req->out.vector[3].iov_len != 0) {
+               /* Dynamic part is NULL. Chop it off,
+                  We're going to send it via sendfile. */
+               req->out.vector_count -= 1;
+       }
+
        subreq = tstream_writev_queue_send(req,
                                           req->sconn->smb2.event_ctx,
                                           req->sconn->smb2.stream,
@@ -2001,9 +2044,11 @@ static int smbd_smb2_request_next_vector(struct tstream_context *stream,
                                invalid = true;
                        }
 
-                       if ((body_size % 2) != 0) {
-                               body_size -= 1;
-                       }
+                       /*
+                        * Mask out the lowest bit, the "dynamic" part
+                        * of body_size.
+                        */
+                       body_size &= ~1;
 
                        if (body_size > (full_size - SMB2_HDR_BODY)) {
                                /*
@@ -2155,14 +2200,6 @@ void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
        struct smbd_smb2_request *req = NULL;
        struct tevent_req *subreq;
 
-       if (lp_security() == SEC_SHARE) {
-               DEBUG(2,("WARNING!!: \"security = share\" is deprecated for "
-                       "SMB2 servers. Mapping to \"security = user\" and "
-                       "\"map to guest = Bad User\"\n" ));
-               lp_do_parameter(-1, "security", "user");
-               lp_do_parameter(-1, "map to guest", "Bad User");
-       }
-
        DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
                 (unsigned int)size));