Ignore:
Timestamp:
Nov 27, 2012, 4:43:17 PM (13 years ago)
Author:
Silvan Scherrer
Message:

Samba Server: updated trunk to 3.6.0

Location:
trunk/server
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/server

  • trunk/server/source3/smbd/smb2_server.c

    r414 r745  
    44
    55   Copyright (C) Stefan Metzmacher 2009
     6   Copyright (C) Jeremy Allison 2010
    67
    78   This program is free software; you can redistribute it and/or modify
     
    2021
    2122#include "includes.h"
     23#include "smbd/smbd.h"
    2224#include "smbd/globals.h"
    2325#include "../libcli/smb/smb_common.h"
    2426#include "../lib/tsocket/tsocket.h"
     27#include "../lib/util/tevent_ntstatus.h"
     28#include "smbprofile.h"
     29
     30#define OUTVEC_ALLOC_SIZE (SMB2_HDR_BODY + 9)
     31
     32static const char *smb2_names[] = {
     33        "SMB2_NEGPROT",
     34        "SMB2_SESSSETUP",
     35        "SMB2_LOGOFF",
     36        "SMB2_TCON",
     37        "SMB2_TDIS",
     38        "SMB2_CREATE",
     39        "SMB2_CLOSE",
     40        "SMB2_FLUSH",
     41        "SMB2_READ",
     42        "SMB2_WRITE",
     43        "SMB2_LOCK",
     44        "SMB2_IOCTL",
     45        "SMB2_CANCEL",
     46        "SMB2_KEEPALIVE",
     47        "SMB2_FIND",
     48        "SMB2_NOTIFY",
     49        "SMB2_GETINFO",
     50        "SMB2_SETINFO",
     51        "SMB2_BREAK"
     52};
     53
     54const char *smb2_opcode_name(uint16_t opcode)
     55{
     56        if (opcode > 0x12) {
     57                return "Bad SMB2 opcode";
     58        }
     59        return smb2_names[opcode];
     60}
     61
     62static void print_req_vectors(struct smbd_smb2_request *req)
     63{
     64        int i;
     65
     66        for (i = 0; i < req->in.vector_count; i++) {
     67                dbgtext("\treq->in.vector[%u].iov_len = %u\n",
     68                        (unsigned int)i,
     69                        (unsigned int)req->in.vector[i].iov_len);
     70        }
     71        for (i = 0; i < req->out.vector_count; i++) {
     72                dbgtext("\treq->out.vector[%u].iov_len = %u\n",
     73                        (unsigned int)i,
     74                        (unsigned int)req->out.vector[i].iov_len);
     75        }
     76}
    2577
    2678bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size)
     
    62114        sconn->smb2.sessions.limit = 0x0000FFFE;
    63115        sconn->smb2.sessions.list = NULL;
    64 
    65         ret = tstream_bsd_existing_socket(sconn, smbd_server_fd(),
     116        sconn->smb2.seqnum_low = 0;
     117        sconn->smb2.credits_granted = 0;
     118        sconn->smb2.max_credits = lp_smb2_max_credits();
     119        sconn->smb2.credits_bitmap = bitmap_talloc(sconn,
     120                        DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR*sconn->smb2.max_credits);
     121        if (sconn->smb2.credits_bitmap == NULL) {
     122                return NT_STATUS_NO_MEMORY;
     123        }
     124
     125        ret = tstream_bsd_existing_socket(sconn, sconn->sock,
    66126                                          &sconn->smb2.stream);
    67127        if (ret == -1) {
     
    71131
    72132        /* Ensure child is set to non-blocking mode */
    73         set_blocking(smbd_server_fd(),false);
     133        set_blocking(sconn->sock, false);
    74134        return NT_STATUS_OK;
    75135}
     
    108168static int smbd_smb2_request_destructor(struct smbd_smb2_request *req)
    109169{
    110         if (req->out.vector) {
    111                 DLIST_REMOVE(req->sconn->smb2.requests, req);
    112         }
    113 
    114170        if (req->parent) {
    115171                *req->parent = NULL;
     
    126182        struct smbd_smb2_request *req;
    127183
     184#if 0
     185        /* Enable this to find subtle valgrind errors. */
     186        mem_pool = talloc_init("smbd_smb2_request_allocate");
     187#else
    128188        mem_pool = talloc_pool(mem_ctx, 8192);
     189#endif
    129190        if (mem_pool == NULL) {
    130191                return NULL;
     
    235296}
    236297
     298static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
     299                                const uint8_t *inhdr)
     300{
     301        uint64_t message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
     302        struct bitmap *credits_bm = sconn->smb2.credits_bitmap;
     303        uint16_t opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
     304        unsigned int bitmap_offset;
     305
     306        if (opcode == SMB2_OP_CANCEL) {
     307                /* SMB2_CANCEL requests by definition resend messageids. */
     308                return true;
     309        }
     310
     311        if (message_id < sconn->smb2.seqnum_low ||
     312                        message_id > (sconn->smb2.seqnum_low +
     313                        (sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR))) {
     314                DEBUG(0,("smb2_validate_message_id: bad message_id "
     315                        "%llu (low = %llu, max = %lu)\n",
     316                        (unsigned long long)message_id,
     317                        (unsigned long long)sconn->smb2.seqnum_low,
     318                        (unsigned long)sconn->smb2.max_credits ));
     319                return false;
     320        }
     321
     322        /* client just used a credit. */
     323        SMB_ASSERT(sconn->smb2.credits_granted > 0);
     324        sconn->smb2.credits_granted -= 1;
     325
     326        /* Mark the message_id as seen in the bitmap. */
     327        bitmap_offset = (unsigned int)(message_id %
     328                        (uint64_t)(sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR));
     329        if (bitmap_query(credits_bm, bitmap_offset)) {
     330                DEBUG(0,("smb2_validate_message_id: duplicate message_id "
     331                        "%llu (bm offset %u)\n",
     332                        (unsigned long long)message_id,
     333                        bitmap_offset));
     334                return false;
     335        }
     336        bitmap_set(credits_bm, bitmap_offset);
     337
     338        if (message_id == sconn->smb2.seqnum_low + 1) {
     339                /* Move the window forward by all the message_id's
     340                   already seen. */
     341                while (bitmap_query(credits_bm, bitmap_offset)) {
     342                        DEBUG(10,("smb2_validate_message_id: clearing "
     343                                "id %llu (position %u) from bitmap\n",
     344                                (unsigned long long)(sconn->smb2.seqnum_low + 1),
     345                                bitmap_offset ));
     346                        bitmap_clear(credits_bm, bitmap_offset);
     347                        sconn->smb2.seqnum_low += 1;
     348                        bitmap_offset = (bitmap_offset + 1) %
     349                                (sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR);
     350                }
     351        }
     352
     353        return true;
     354}
     355
    237356static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
    238357{
     
    262381                inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
    263382
    264                 /* setup the SMB2 header */
     383                /* Check the SMB2 header */
    265384                if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
     385                        return NT_STATUS_INVALID_PARAMETER;
     386                }
     387
     388                if (!smb2_validate_message_id(req->sconn, inhdr)) {
    266389                        return NT_STATUS_INVALID_PARAMETER;
    267390                }
     
    315438}
    316439
     440static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
     441                        const struct iovec *in_vector,
     442                        struct iovec *out_vector)
     443{
     444        const uint8_t *inhdr = (const uint8_t *)in_vector->iov_base;
     445        uint8_t *outhdr = (uint8_t *)out_vector->iov_base;
     446        uint16_t credits_requested;
     447        uint32_t out_flags;
     448        uint16_t credits_granted = 0;
     449
     450        credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
     451        out_flags = IVAL(outhdr, SMB2_HDR_FLAGS);
     452
     453        SMB_ASSERT(sconn->smb2.max_credits >= sconn->smb2.credits_granted);
     454
     455        if (out_flags & SMB2_HDR_FLAG_ASYNC) {
     456                /*
     457                 * In case we already send an async interim
     458                 * response, we should not grant
     459                 * credits on the final response.
     460                 */
     461                credits_requested = 0;
     462        }
     463
     464        if (credits_requested) {
     465                uint16_t modified_credits_requested;
     466                uint32_t multiplier;
     467
     468                /*
     469                 * Split up max_credits into 1/16ths, and then scale
     470                 * the requested credits by how many 16ths have been
     471                 * currently granted. Less than 1/16th == grant all
     472                 * requested (100%), scale down as more have been
     473                 * granted. Never ask for less than 1 as the client
     474                 * asked for at least 1. JRA.
     475                 */
     476
     477                multiplier = 16 - (((sconn->smb2.credits_granted * 16) / sconn->smb2.max_credits) % 16);
     478
     479                modified_credits_requested = (multiplier * credits_requested) / 16;
     480                if (modified_credits_requested == 0) {
     481                        modified_credits_requested = 1;
     482                }
     483
     484                /* Remember what we gave out. */
     485                credits_granted = MIN(modified_credits_requested,
     486                                        (sconn->smb2.max_credits - sconn->smb2.credits_granted));
     487        }
     488
     489        if (credits_granted == 0 && sconn->smb2.credits_granted == 0) {
     490                /* First negprot packet, or ensure the client credits can
     491                   never drop to zero. */
     492                credits_granted = 1;
     493        }
     494
     495        SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
     496        sconn->smb2.credits_granted += credits_granted;
     497
     498        DEBUG(10,("smb2_set_operation_credit: requested %u, "
     499                "granted %u, total granted %u\n",
     500                (unsigned int)credits_requested,
     501                (unsigned int)credits_granted,
     502                (unsigned int)sconn->smb2.credits_granted ));
     503}
     504
     505static void smb2_calculate_credits(const struct smbd_smb2_request *inreq,
     506                                struct smbd_smb2_request *outreq)
     507{
     508        int count, idx;
     509
     510        count = outreq->out.vector_count;
     511
     512        for (idx=1; idx < count; idx += 3) {
     513                smb2_set_operation_credit(outreq->sconn,
     514                        &inreq->in.vector[idx],
     515                        &outreq->out.vector[idx]);
     516        }
     517}
     518
    317519static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
    318520{
     
    322524
    323525        count = req->in.vector_count;
    324         vector = talloc_array(req, struct iovec, count);
     526        vector = talloc_zero_array(req, struct iovec, count);
    325527        if (vector == NULL) {
    326528                return NT_STATUS_NO_MEMORY;
     
    340542
    341543                if ((idx + 3) < count) {
    342                         /* we have a next command */
    343                         next_command_ofs = SMB2_HDR_BODY + 8;
     544                        /* we have a next command -
     545                         * setup for the error case. */
     546                        next_command_ofs = SMB2_HDR_BODY + 9;
    344547                }
    345548
     
    347550                in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
    348551
    349                 outhdr = talloc_array(vector, uint8_t,
    350                                       SMB2_HDR_BODY + 8);
     552                outhdr = talloc_zero_array(vector, uint8_t,
     553                                      OUTVEC_ALLOC_SIZE);
    351554                if (outhdr == NULL) {
    352555                        return NT_STATUS_NO_MEMORY;
     
    372575                SSVAL(outhdr, SMB2_HDR_OPCODE,
    373576                      SVAL(inhdr, SMB2_HDR_OPCODE));
    374                 /* Make up a number for now... JRA. FIXME ! FIXME !*/
    375                 SSVAL(outhdr, SMB2_HDR_CREDIT,          20);
    376577                SIVAL(outhdr, SMB2_HDR_FLAGS,
    377578                      IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
     
    413614}
    414615
     616static bool dup_smb2_vec3(TALLOC_CTX *ctx,
     617                        struct iovec *outvec,
     618                        const struct iovec *srcvec)
     619{
     620        /* vec[0] is always boilerplate and must
     621         * be allocated with size OUTVEC_ALLOC_SIZE. */
     622
     623        outvec[0].iov_base = talloc_memdup(ctx,
     624                                srcvec[0].iov_base,
     625                                OUTVEC_ALLOC_SIZE);
     626        if (!outvec[0].iov_base) {
     627                return false;
     628        }
     629        outvec[0].iov_len = SMB2_HDR_BODY;
     630
     631        /*
     632         * If this is a "standard" vec[1] of length 8,
     633         * pointing to srcvec[0].iov_base + SMB2_HDR_BODY,
     634         * then duplicate this. Else use talloc_memdup().
     635         */
     636
     637        if (srcvec[1].iov_len == 8 &&
     638                        srcvec[1].iov_base ==
     639                                ((uint8_t *)srcvec[0].iov_base) +
     640                                        SMB2_HDR_BODY) {
     641                outvec[1].iov_base = ((uint8_t *)outvec[0].iov_base) +
     642                                        SMB2_HDR_BODY;
     643                outvec[1].iov_len = 8;
     644        } else {
     645                outvec[1].iov_base = talloc_memdup(ctx,
     646                                srcvec[1].iov_base,
     647                                srcvec[1].iov_len);
     648                if (!outvec[1].iov_base) {
     649                        return false;
     650                }
     651                outvec[1].iov_len = srcvec[1].iov_len;
     652        }
     653
     654        /*
     655         * If this is a "standard" vec[2] of length 1,
     656         * pointing to srcvec[0].iov_base + (OUTVEC_ALLOC_SIZE - 1)
     657         * then duplicate this. Else use talloc_memdup().
     658         */
     659
     660        if (srcvec[2].iov_base &&
     661                        srcvec[2].iov_len) {
     662                if (srcvec[2].iov_base ==
     663                                ((uint8_t *)srcvec[0].iov_base) +
     664                                        (OUTVEC_ALLOC_SIZE - 1) &&
     665                                srcvec[2].iov_len == 1) {
     666                        /* Common SMB2 error packet case. */
     667                        outvec[2].iov_base = ((uint8_t *)outvec[0].iov_base) +
     668                                (OUTVEC_ALLOC_SIZE - 1);
     669                } else {
     670                        outvec[2].iov_base = talloc_memdup(ctx,
     671                                        srcvec[2].iov_base,
     672                                        srcvec[2].iov_len);
     673                        if (!outvec[2].iov_base) {
     674                                return false;
     675                        }
     676                }
     677                outvec[2].iov_len = srcvec[2].iov_len;
     678        } else {
     679                outvec[2].iov_base = NULL;
     680                outvec[2].iov_len = 0;
     681        }
     682        return true;
     683}
     684
     685static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *req)
     686{
     687        struct smbd_smb2_request *newreq = NULL;
     688        struct iovec *outvec = NULL;
     689        int count = req->out.vector_count;
     690        int i;
     691
     692        newreq = smbd_smb2_request_allocate(req->sconn);
     693        if (!newreq) {
     694                return NULL;
     695        }
     696
     697        newreq->sconn = req->sconn;
     698        newreq->session = req->session;
     699        newreq->do_signing = req->do_signing;
     700        newreq->current_idx = req->current_idx;
     701        newreq->async = false;
     702        newreq->cancelled = false;
     703        /* Note we are leaving:
     704                ->tcon
     705                ->smb1req
     706                ->compat_chain_fsp
     707           uninitialized as NULL here as
     708           they're not used in the interim
     709           response code. JRA. */
     710
     711        outvec = talloc_zero_array(newreq, struct iovec, count);
     712        if (!outvec) {
     713                TALLOC_FREE(newreq);
     714                return NULL;
     715        }
     716        newreq->out.vector = outvec;
     717        newreq->out.vector_count = count;
     718
     719        /* Setup the outvec's identically to req. */
     720        outvec[0].iov_base = newreq->out.nbt_hdr;
     721        outvec[0].iov_len = 4;
     722        memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4);
     723
     724        /* Setup the vectors identically to the ones in req. */
     725        for (i = 1; i < count; i += 3) {
     726                if (!dup_smb2_vec3(outvec, &outvec[i], &req->out.vector[i])) {
     727                        break;
     728                }
     729        }
     730
     731        if (i < count) {
     732                /* Alloc failed. */
     733                TALLOC_FREE(newreq);
     734                return NULL;
     735        }
     736
     737        smb2_setup_nbt_length(newreq->out.vector,
     738                newreq->out.vector_count);
     739
     740        return newreq;
     741}
     742
     743static void smbd_smb2_request_writev_done(struct tevent_req *subreq);
     744
     745static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request *req)
     746{
     747        int i = 0;
     748        uint8_t *outhdr = NULL;
     749        struct smbd_smb2_request *nreq = NULL;
     750
     751        /* Create a new smb2 request we'll use
     752           for the interim return. */
     753        nreq = dup_smb2_req(req);
     754        if (!nreq) {
     755                return NT_STATUS_NO_MEMORY;
     756        }
     757
     758        /* Lose the last 3 out vectors. They're the
     759           ones we'll be using for the async reply. */
     760        nreq->out.vector_count -= 3;
     761
     762        smb2_setup_nbt_length(nreq->out.vector,
     763                nreq->out.vector_count);
     764
     765        /* Step back to the previous reply. */
     766        i = nreq->current_idx - 3;
     767        outhdr = (uint8_t *)nreq->out.vector[i].iov_base;
     768        /* And end the chain. */
     769        SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0);
     770
     771        /* Calculate outgoing credits */
     772        smb2_calculate_credits(req, nreq);
     773
     774        /* Re-sign if needed. */
     775        if (nreq->do_signing) {
     776                NTSTATUS status;
     777                status = smb2_signing_sign_pdu(nreq->session->session_key,
     778                                        &nreq->out.vector[i], 3);
     779                if (!NT_STATUS_IS_OK(status)) {
     780                        return status;
     781                }
     782        }
     783        if (DEBUGLEVEL >= 10) {
     784                dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n",
     785                        (unsigned int)nreq->current_idx );
     786                dbgtext("smb2_send_async_interim_response: returning %u vectors\n",
     787                        (unsigned int)nreq->out.vector_count );
     788                print_req_vectors(nreq);
     789        }
     790        nreq->subreq = tstream_writev_queue_send(nreq,
     791                                        nreq->sconn->smb2.event_ctx,
     792                                        nreq->sconn->smb2.stream,
     793                                        nreq->sconn->smb2.send_queue,
     794                                        nreq->out.vector,
     795                                        nreq->out.vector_count);
     796
     797        if (nreq->subreq == NULL) {
     798                return NT_STATUS_NO_MEMORY;
     799        }
     800
     801        tevent_req_set_callback(nreq->subreq,
     802                        smbd_smb2_request_writev_done,
     803                        nreq);
     804
     805        return NT_STATUS_OK;
     806}
     807
    415808struct smbd_smb2_request_pending_state {
    416         struct smbd_server_connection *sconn;
    417         uint8_t buf[4 + SMB2_HDR_BODY + 0x08];
    418         struct iovec vector;
     809        struct smbd_server_connection *sconn;
     810        uint8_t buf[4 + SMB2_HDR_BODY + 0x08 + 1];
     811        struct iovec vector[3];
    419812};
    420 
    421 static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq);
    422 
    423 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
    424                                          struct tevent_req *subreq)
    425 {
    426         struct smbd_smb2_request_pending_state *state;
    427         uint8_t *outhdr;
    428         int i = req->current_idx;
    429         uint32_t flags;
    430         uint64_t message_id;
    431         uint64_t async_id;
    432         uint8_t *hdr;
    433         uint8_t *body;
    434 
    435         if (!tevent_req_is_in_progress(subreq)) {
    436                 return NT_STATUS_OK;
    437         }
    438 
    439         req->subreq = subreq;
    440         subreq = NULL;
    441 
    442         outhdr = (uint8_t *)req->out.vector[i].iov_base;
    443 
    444         flags = IVAL(outhdr, SMB2_HDR_FLAGS);
    445         message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
    446 
    447         async_id = message_id; /* keep it simple for now... */
    448         SIVAL(outhdr, SMB2_HDR_FLAGS,   flags | SMB2_HDR_FLAG_ASYNC);
    449         SBVAL(outhdr, SMB2_HDR_PID,     async_id);
    450 
    451         /* TODO: add a paramter to delay this */
    452         state = talloc(req->sconn, struct smbd_smb2_request_pending_state);
    453         if (state == NULL) {
    454                 return NT_STATUS_NO_MEMORY;
    455         }
    456         state->sconn = req->sconn;
    457 
    458         state->vector.iov_base = (void *)state->buf;
    459         state->vector.iov_len = sizeof(state->buf);
    460 
    461         _smb2_setlen(state->buf, sizeof(state->buf) - 4);
    462         hdr = state->buf + 4;
    463         body = hdr + SMB2_HDR_BODY;
    464 
    465         SIVAL(hdr, SMB2_HDR_PROTOCOL_ID,        SMB2_MAGIC);
    466         SSVAL(hdr, SMB2_HDR_LENGTH,             SMB2_HDR_BODY);
    467         SSVAL(hdr, SMB2_HDR_EPOCH,              0);
    468         SIVAL(hdr, SMB2_HDR_STATUS,             NT_STATUS_V(STATUS_PENDING));
    469         SSVAL(hdr, SMB2_HDR_OPCODE,
    470               SVAL(outhdr, SMB2_HDR_OPCODE));
    471         SSVAL(hdr, SMB2_HDR_CREDIT,             1);
    472         SIVAL(hdr, SMB2_HDR_FLAGS,
    473               IVAL(outhdr, SMB2_HDR_FLAGS));
    474         SIVAL(hdr, SMB2_HDR_NEXT_COMMAND,       0);
    475         SBVAL(hdr, SMB2_HDR_MESSAGE_ID,
    476               BVAL(outhdr, SMB2_HDR_MESSAGE_ID));
    477         SBVAL(hdr, SMB2_HDR_PID,
    478               BVAL(outhdr, SMB2_HDR_PID));
    479         SBVAL(hdr, SMB2_HDR_SESSION_ID,
    480               BVAL(outhdr, SMB2_HDR_SESSION_ID));
    481         memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
    482 
    483         SSVAL(body, 0x00, 0x08 + 1);
    484 
    485         SCVAL(body, 0x02, 0);
    486         SCVAL(body, 0x03, 0);
    487         SIVAL(body, 0x04, 0);
    488 
    489         subreq = tstream_writev_queue_send(state,
    490                                            req->sconn->smb2.event_ctx,
    491                                            req->sconn->smb2.stream,
    492                                            req->sconn->smb2.send_queue,
    493                                            &state->vector, 1);
    494         if (subreq == NULL) {
    495                 return NT_STATUS_NO_MEMORY;
    496         }
    497         tevent_req_set_callback(subreq,
    498                                 smbd_smb2_request_pending_writev_done,
    499                                 state);
    500 
    501         return NT_STATUS_OK;
    502 }
    503813
    504814static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq)
     
    506816        struct smbd_smb2_request_pending_state *state =
    507817                tevent_req_callback_data(subreq,
    508                 struct smbd_smb2_request_pending_state);
     818                        struct smbd_smb2_request_pending_state);
    509819        struct smbd_server_connection *sconn = state->sconn;
    510820        int ret;
     
    520830
    521831        TALLOC_FREE(state);
     832}
     833
     834NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
     835                                         struct tevent_req *subreq)
     836{
     837        NTSTATUS status;
     838        struct smbd_smb2_request_pending_state *state = NULL;
     839        int i = req->current_idx;
     840        uint8_t *reqhdr = NULL;
     841        uint8_t *hdr = NULL;
     842        uint8_t *body = NULL;
     843        uint32_t flags = 0;
     844        uint64_t message_id = 0;
     845        uint64_t async_id = 0;
     846        struct iovec *outvec = NULL;
     847
     848        if (!tevent_req_is_in_progress(subreq)) {
     849                return NT_STATUS_OK;
     850        }
     851
     852        req->subreq = subreq;
     853        subreq = NULL;
     854
     855        if (req->async) {
     856                /* We're already async. */
     857                return NT_STATUS_OK;
     858        }
     859
     860        if (req->in.vector_count > i + 3) {
     861                /*
     862                 * We're trying to go async in a compound
     863                 * request chain. This is not allowed.
     864                 * Cancel the outstanding request.
     865                 */
     866                tevent_req_cancel(req->subreq);
     867                return smbd_smb2_request_error(req,
     868                        NT_STATUS_INSUFFICIENT_RESOURCES);
     869        }
     870
     871        if (DEBUGLEVEL >= 10) {
     872                dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
     873                        (unsigned int)req->current_idx );
     874                print_req_vectors(req);
     875        }
     876
     877        if (req->out.vector_count > 4) {
     878                /* This is a compound reply. We
     879                 * must do an interim response
     880                 * followed by the async response
     881                 * to match W2K8R2.
     882                 */
     883                status = smb2_send_async_interim_response(req);
     884                if (!NT_STATUS_IS_OK(status)) {
     885                        return status;
     886                }
     887        }
     888
     889        /* Don't return an intermediate packet on a pipe read/write. */
     890        if (req->tcon && req->tcon->compat_conn && IS_IPC(req->tcon->compat_conn)) {
     891                return NT_STATUS_OK;
     892        }
     893
     894        reqhdr = (uint8_t *)req->out.vector[i].iov_base;
     895        flags = (IVAL(reqhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
     896        message_id = BVAL(reqhdr, SMB2_HDR_MESSAGE_ID);
     897        async_id = message_id; /* keep it simple for now... */
     898
     899        /*
     900         * What we send is identical to a smbd_smb2_request_error
     901         * packet with an error status of STATUS_PENDING. Make use
     902         * of this fact sometime when refactoring. JRA.
     903         */
     904
     905        state = talloc_zero(req->sconn, struct smbd_smb2_request_pending_state);
     906        if (state == NULL) {
     907                return NT_STATUS_NO_MEMORY;
     908        }
     909        state->sconn = req->sconn;
     910
     911        state->vector[0].iov_base = (void *)state->buf;
     912        state->vector[0].iov_len = 4;
     913
     914        state->vector[1].iov_base = state->buf + 4;
     915        state->vector[1].iov_len = SMB2_HDR_BODY;
     916
     917        state->vector[2].iov_base = state->buf + 4 + SMB2_HDR_BODY;
     918        state->vector[2].iov_len = 9;
     919
     920        smb2_setup_nbt_length(state->vector, 3);
     921
     922        hdr = (uint8_t *)state->vector[1].iov_base;
     923        body = (uint8_t *)state->vector[2].iov_base;
     924
     925        SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
     926        SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
     927        SSVAL(hdr, SMB2_HDR_EPOCH, 0);
     928        SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
     929        SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(reqhdr, SMB2_HDR_OPCODE));
     930
     931        SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
     932        SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
     933        SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
     934        SBVAL(hdr, SMB2_HDR_PID, async_id);
     935        SBVAL(hdr, SMB2_HDR_SESSION_ID,
     936                BVAL(reqhdr, SMB2_HDR_SESSION_ID));
     937        memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
     938
     939        SSVAL(body, 0x00, 0x08 + 1);
     940
     941        SCVAL(body, 0x02, 0);
     942        SCVAL(body, 0x03, 0);
     943        SIVAL(body, 0x04, 0);
     944        /* Match W2K8R2... */
     945        SCVAL(body, 0x08, 0x21);
     946
     947        /* Ensure we correctly go through crediting. Grant
     948           the credits now, and zero credits on the final
     949           response. */
     950        smb2_set_operation_credit(req->sconn,
     951                        &req->in.vector[i],
     952                        &state->vector[1]);
     953
     954        if (req->do_signing) {
     955                status = smb2_signing_sign_pdu(req->session->session_key,
     956                                        &state->vector[1], 2);
     957                if (!NT_STATUS_IS_OK(status)) {
     958                        return status;
     959                }
     960        }
     961
     962        subreq = tstream_writev_queue_send(state,
     963                                        req->sconn->smb2.event_ctx,
     964                                        req->sconn->smb2.stream,
     965                                        req->sconn->smb2.send_queue,
     966                                        state->vector,
     967                                        3);
     968
     969        if (subreq == NULL) {
     970                return NT_STATUS_NO_MEMORY;
     971        }
     972
     973        tevent_req_set_callback(subreq,
     974                        smbd_smb2_request_pending_writev_done,
     975                        state);
     976
     977        /* Note we're going async with this request. */
     978        req->async = true;
     979
     980        /*
     981         * Now manipulate req so that the outstanding async request
     982         * is the only one left in the struct smbd_smb2_request.
     983         */
     984
     985        if (req->current_idx == 1) {
     986                /* There was only one. */
     987                goto out;
     988        }
     989
     990        /* Re-arrange the in.vectors. */
     991        req->in.vector[1] = req->in.vector[i];
     992        req->in.vector[2] = req->in.vector[i+1];
     993        req->in.vector[3] = req->in.vector[i+2];
     994        req->in.vector_count = 4;
     995        /* Reset the new in size. */
     996        smb2_setup_nbt_length(req->in.vector, 4);
     997
     998        /* Now recreate the out.vectors. */
     999        outvec = talloc_zero_array(req, struct iovec, 4);
     1000        if (!outvec) {
     1001                return NT_STATUS_NO_MEMORY;
     1002        }
     1003
     1004        /* 0 is always boilerplate and must
     1005         * be of size 4 for the length field. */
     1006
     1007        outvec[0].iov_base = req->out.nbt_hdr;
     1008        outvec[0].iov_len = 4;
     1009        SIVAL(req->out.nbt_hdr, 0, 0);
     1010
     1011        if (!dup_smb2_vec3(outvec, &outvec[1], &req->out.vector[i])) {
     1012                return NT_STATUS_NO_MEMORY;
     1013        }
     1014
     1015        TALLOC_FREE(req->out.vector);
     1016
     1017        req->out.vector = outvec;
     1018
     1019        req->current_idx = 1;
     1020        req->out.vector_count = 4;
     1021
     1022  out:
     1023
     1024        smb2_setup_nbt_length(req->out.vector,
     1025                req->out.vector_count);
     1026
     1027        /* Ensure our final reply matches the interim one. */
     1028        reqhdr = (uint8_t *)req->out.vector[1].iov_base;
     1029        SIVAL(reqhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
     1030        SBVAL(reqhdr, SMB2_HDR_PID, async_id);
     1031
     1032        {
     1033                const uint8_t *inhdr =
     1034                        (const uint8_t *)req->in.vector[1].iov_base;
     1035                DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
     1036                        "going async\n",
     1037                        smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
     1038                        (unsigned long long)async_id ));
     1039        }
     1040        return NT_STATUS_OK;
    5221041}
    5231042
     
    5311050        uint64_t search_message_id;
    5321051        uint64_t search_async_id;
     1052        uint64_t found_id;
    5331053
    5341054        inhdr = (const uint8_t *)req->in.vector[i].iov_base;
     
    5421062         * cancel requests never have a response
    5431063         */
     1064        DLIST_REMOVE(req->sconn->smb2.requests, req);
    5441065        TALLOC_FREE(req);
    5451066
     
    5581079                if (flags & SMB2_HDR_FLAG_ASYNC) {
    5591080                        if (search_async_id == async_id) {
     1081                                found_id = async_id;
    5601082                                break;
    5611083                        }
    5621084                } else {
    5631085                        if (search_message_id == message_id) {
     1086                                found_id = message_id;
    5641087                                break;
    5651088                        }
     
    5681091
    5691092        if (cur && cur->subreq) {
     1093                inhdr = (const uint8_t *)cur->in.vector[i].iov_base;
     1094                DEBUG(10,("smbd_smb2_request_process_cancel: attempting to "
     1095                        "cancel opcode[%s] mid %llu\n",
     1096                        smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
     1097                        (unsigned long long)found_id ));
    5701098                tevent_req_cancel(cur->subreq);
    5711099        }
     
    5741102}
    5751103
    576 static NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
     1104NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
    5771105{
    5781106        const uint8_t *inhdr;
     
    5801108        uint16_t opcode;
    5811109        uint32_t flags;
     1110        uint64_t mid;
    5821111        NTSTATUS status;
    5831112        NTSTATUS session_status;
    5841113        uint32_t allowed_flags;
     1114        NTSTATUS return_value;
    5851115
    5861116        inhdr = (const uint8_t *)req->in.vector[i].iov_base;
     
    5901120        flags = IVAL(inhdr, SMB2_HDR_FLAGS);
    5911121        opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
    592         DEBUG(10,("smbd_smb2_request_dispatch: opcode[%u]\n", opcode));
     1122        mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
     1123        DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
     1124                smb2_opcode_name(opcode),
     1125                (unsigned long long)mid));
    5931126
    5941127        allowed_flags = SMB2_HDR_FLAG_CHAINED |
     
    6021135        }
    6031136
     1137        /*
     1138         * Check if the client provided a valid session id,
     1139         * if so smbd_smb2_request_check_session() calls
     1140         * set_current_user_info().
     1141         *
     1142         * As some command don't require a valid session id
     1143         * we defer the check of the session_status
     1144         */
    6041145        session_status = smbd_smb2_request_check_session(req);
    6051146
     
    6371178        switch (opcode) {
    6381179        case SMB2_OP_NEGPROT:
    639                 return smbd_smb2_request_process_negprot(req);
     1180                /* This call needs to be run as root */
     1181                change_to_root_user();
     1182
     1183                {
     1184                        START_PROFILE(smb2_negprot);
     1185                        return_value = smbd_smb2_request_process_negprot(req);
     1186                        END_PROFILE(smb2_negprot);
     1187                }
     1188                break;
    6401189
    6411190        case SMB2_OP_SESSSETUP:
    642                 return smbd_smb2_request_process_sesssetup(req);
     1191                /* This call needs to be run as root */
     1192                change_to_root_user();
     1193
     1194                {
     1195                        START_PROFILE(smb2_sesssetup);
     1196                        return_value = smbd_smb2_request_process_sesssetup(req);
     1197                        END_PROFILE(smb2_sesssetup);
     1198                }
     1199                break;
    6431200
    6441201        case SMB2_OP_LOGOFF:
    6451202                if (!NT_STATUS_IS_OK(session_status)) {
    646                         return smbd_smb2_request_error(req, session_status);
    647                 }
    648                 return smbd_smb2_request_process_logoff(req);
     1203                        return_value = smbd_smb2_request_error(req, session_status);
     1204                        break;
     1205                }
     1206
     1207                /* This call needs to be run as root */
     1208                change_to_root_user();
     1209
     1210                {
     1211                        START_PROFILE(smb2_logoff);
     1212                        return_value = smbd_smb2_request_process_logoff(req);
     1213                        END_PROFILE(smb2_logoff);
     1214                }
     1215                break;
    6491216
    6501217        case SMB2_OP_TCON:
    6511218                if (!NT_STATUS_IS_OK(session_status)) {
    652                         return smbd_smb2_request_error(req, session_status);
    653                 }
    654                 status = smbd_smb2_request_check_session(req);
    655                 if (!NT_STATUS_IS_OK(status)) {
    656                         return smbd_smb2_request_error(req, status);
    657                 }
    658                 return smbd_smb2_request_process_tcon(req);
     1219                        return_value = smbd_smb2_request_error(req, session_status);
     1220                        break;
     1221                }
     1222
     1223                /*
     1224                 * This call needs to be run as root.
     1225                 *
     1226                 * smbd_smb2_request_process_tcon()
     1227                 * calls make_connection_snum(), which will call
     1228                 * change_to_user(), when needed.
     1229                 */
     1230                change_to_root_user();
     1231
     1232                {
     1233                        START_PROFILE(smb2_tcon);
     1234                        return_value = smbd_smb2_request_process_tcon(req);
     1235                        END_PROFILE(smb2_tcon);
     1236                }
     1237                break;
    6591238
    6601239        case SMB2_OP_TDIS:
    6611240                if (!NT_STATUS_IS_OK(session_status)) {
    662                         return smbd_smb2_request_error(req, session_status);
    663                 }
     1241                        return_value = smbd_smb2_request_error(req, session_status);
     1242                        break;
     1243                }
     1244                /*
     1245                 * This call needs to be run as user.
     1246                 *
     1247                 * smbd_smb2_request_check_tcon()
     1248                 * calls change_to_user() on success.
     1249                 */
    6641250                status = smbd_smb2_request_check_tcon(req);
    6651251                if (!NT_STATUS_IS_OK(status)) {
    666                         return smbd_smb2_request_error(req, status);
    667                 }
    668                 return smbd_smb2_request_process_tdis(req);
     1252                        return_value = smbd_smb2_request_error(req, status);
     1253                        break;
     1254                }
     1255                /* This call needs to be run as root */
     1256                change_to_root_user();
     1257
     1258
     1259                {
     1260                        START_PROFILE(smb2_tdis);
     1261                        return_value = smbd_smb2_request_process_tdis(req);
     1262                        END_PROFILE(smb2_tdis);
     1263                }
     1264                break;
    6691265
    6701266        case SMB2_OP_CREATE:
    6711267                if (!NT_STATUS_IS_OK(session_status)) {
    672                         return smbd_smb2_request_error(req, session_status);
    673                 }
     1268                        return_value = smbd_smb2_request_error(req, session_status);
     1269                        break;
     1270                }
     1271                /*
     1272                 * This call needs to be run as user.
     1273                 *
     1274                 * smbd_smb2_request_check_tcon()
     1275                 * calls change_to_user() on success.
     1276                 */
    6741277                status = smbd_smb2_request_check_tcon(req);
    6751278                if (!NT_STATUS_IS_OK(status)) {
    676                         return smbd_smb2_request_error(req, status);
    677                 }
    678                 return smbd_smb2_request_process_create(req);
     1279                        return_value = smbd_smb2_request_error(req, status);
     1280                        break;
     1281                }
     1282
     1283                {
     1284                        START_PROFILE(smb2_create);
     1285                        return_value = smbd_smb2_request_process_create(req);
     1286                        END_PROFILE(smb2_create);
     1287                }
     1288                break;
    6791289
    6801290        case SMB2_OP_CLOSE:
    6811291                if (!NT_STATUS_IS_OK(session_status)) {
    682                         return smbd_smb2_request_error(req, session_status);
    683                 }
     1292                        return_value = smbd_smb2_request_error(req, session_status);
     1293                        break;
     1294                }
     1295                /*
     1296                 * This call needs to be run as user.
     1297                 *
     1298                 * smbd_smb2_request_check_tcon()
     1299                 * calls change_to_user() on success.
     1300                 */
    6841301                status = smbd_smb2_request_check_tcon(req);
    6851302                if (!NT_STATUS_IS_OK(status)) {
    686                         return smbd_smb2_request_error(req, status);
    687                 }
    688                 return smbd_smb2_request_process_close(req);
     1303                        return_value = smbd_smb2_request_error(req, status);
     1304                        break;
     1305                }
     1306
     1307                {
     1308                        START_PROFILE(smb2_close);
     1309                        return_value = smbd_smb2_request_process_close(req);
     1310                        END_PROFILE(smb2_close);
     1311                }
     1312                break;
    6891313
    6901314        case SMB2_OP_FLUSH:
    6911315                if (!NT_STATUS_IS_OK(session_status)) {
    692                         return smbd_smb2_request_error(req, session_status);
    693                 }
     1316                        return_value = smbd_smb2_request_error(req, session_status);
     1317                        break;
     1318                }
     1319                /*
     1320                 * This call needs to be run as user.
     1321                 *
     1322                 * smbd_smb2_request_check_tcon()
     1323                 * calls change_to_user() on success.
     1324                 */
    6941325                status = smbd_smb2_request_check_tcon(req);
    6951326                if (!NT_STATUS_IS_OK(status)) {
    696                         return smbd_smb2_request_error(req, status);
    697                 }
    698                 return smbd_smb2_request_process_flush(req);
     1327                        return_value = smbd_smb2_request_error(req, status);
     1328                        break;
     1329                }
     1330
     1331                {
     1332                        START_PROFILE(smb2_flush);
     1333                        return_value = smbd_smb2_request_process_flush(req);
     1334                        END_PROFILE(smb2_flush);
     1335                }
     1336                break;
    6991337
    7001338        case SMB2_OP_READ:
    7011339                if (!NT_STATUS_IS_OK(session_status)) {
    702                         return smbd_smb2_request_error(req, session_status);
    703                 }
     1340                        return_value = smbd_smb2_request_error(req, session_status);
     1341                        break;
     1342                }
     1343                /*
     1344                 * This call needs to be run as user.
     1345                 *
     1346                 * smbd_smb2_request_check_tcon()
     1347                 * calls change_to_user() on success.
     1348                 */
    7041349                status = smbd_smb2_request_check_tcon(req);
    7051350                if (!NT_STATUS_IS_OK(status)) {
    706                         return smbd_smb2_request_error(req, status);
    707                 }
    708                 return smbd_smb2_request_process_read(req);
     1351                        return_value = smbd_smb2_request_error(req, status);
     1352                        break;
     1353                }
     1354
     1355                {
     1356                        START_PROFILE(smb2_read);
     1357                        return_value = smbd_smb2_request_process_read(req);
     1358                        END_PROFILE(smb2_read);
     1359                }
     1360                break;
    7091361
    7101362        case SMB2_OP_WRITE:
    7111363                if (!NT_STATUS_IS_OK(session_status)) {
    712                         return smbd_smb2_request_error(req, session_status);
    713                 }
     1364                        return_value = smbd_smb2_request_error(req, session_status);
     1365                        break;
     1366                }
     1367                /*
     1368                 * This call needs to be run as user.
     1369                 *
     1370                 * smbd_smb2_request_check_tcon()
     1371                 * calls change_to_user() on success.
     1372                 */
    7141373                status = smbd_smb2_request_check_tcon(req);
    7151374                if (!NT_STATUS_IS_OK(status)) {
    716                         return smbd_smb2_request_error(req, status);
    717                 }
    718                 return smbd_smb2_request_process_write(req);
     1375                        return_value = smbd_smb2_request_error(req, status);
     1376                        break;
     1377                }
     1378
     1379                {
     1380                        START_PROFILE(smb2_write);
     1381                        return_value = smbd_smb2_request_process_write(req);
     1382                        END_PROFILE(smb2_write);
     1383                }
     1384                break;
    7191385
    7201386        case SMB2_OP_LOCK:
    7211387                if (!NT_STATUS_IS_OK(session_status)) {
    722                         return smbd_smb2_request_error(req, session_status);
    723                 }
     1388                        /* Too ugly to live ? JRA. */
     1389                        if (NT_STATUS_EQUAL(session_status,NT_STATUS_USER_SESSION_DELETED)) {
     1390                                session_status = NT_STATUS_FILE_CLOSED;
     1391                        }
     1392                        return_value = smbd_smb2_request_error(req, session_status);
     1393                        break;
     1394                }
     1395                /*
     1396                 * This call needs to be run as user.
     1397                 *
     1398                 * smbd_smb2_request_check_tcon()
     1399                 * calls change_to_user() on success.
     1400                 */
    7241401                status = smbd_smb2_request_check_tcon(req);
    7251402                if (!NT_STATUS_IS_OK(status)) {
    726                         return smbd_smb2_request_error(req, status);
    727                 }
    728                 return smbd_smb2_request_process_lock(req);
     1403                        /* Too ugly to live ? JRA. */
     1404                        if (NT_STATUS_EQUAL(status,NT_STATUS_NETWORK_NAME_DELETED)) {
     1405                                status = NT_STATUS_FILE_CLOSED;
     1406                        }
     1407                        return_value = smbd_smb2_request_error(req, status);
     1408                        break;
     1409                }
     1410
     1411                {
     1412                        START_PROFILE(smb2_lock);
     1413                        return_value = smbd_smb2_request_process_lock(req);
     1414                        END_PROFILE(smb2_lock);
     1415                }
     1416                break;
    7291417
    7301418        case SMB2_OP_IOCTL:
    7311419                if (!NT_STATUS_IS_OK(session_status)) {
    732                         return smbd_smb2_request_error(req, session_status);
    733                 }
     1420                        return_value = smbd_smb2_request_error(req, session_status);
     1421                        break;
     1422                }
     1423                /*
     1424                 * This call needs to be run as user.
     1425                 *
     1426                 * smbd_smb2_request_check_tcon()
     1427                 * calls change_to_user() on success.
     1428                 */
    7341429                status = smbd_smb2_request_check_tcon(req);
    7351430                if (!NT_STATUS_IS_OK(status)) {
    736                         return smbd_smb2_request_error(req, status);
    737                 }
    738                 return smbd_smb2_request_process_ioctl(req);
     1431                        return_value = smbd_smb2_request_error(req, status);
     1432                        break;
     1433                }
     1434
     1435                {
     1436                        START_PROFILE(smb2_ioctl);
     1437                        return_value = smbd_smb2_request_process_ioctl(req);
     1438                        END_PROFILE(smb2_ioctl);
     1439                }
     1440                break;
    7391441
    7401442        case SMB2_OP_CANCEL:
    741                 return smbd_smb2_request_process_cancel(req);
     1443                /*
     1444                 * This call needs to be run as root
     1445                 *
     1446                 * That is what we also do in the SMB1 case.
     1447                 */
     1448                change_to_root_user();
     1449
     1450                {
     1451                        START_PROFILE(smb2_cancel);
     1452                        return_value = smbd_smb2_request_process_cancel(req);
     1453                        END_PROFILE(smb2_cancel);
     1454                }
     1455                break;
    7421456
    7431457        case SMB2_OP_KEEPALIVE:
    744                 return smbd_smb2_request_process_keepalive(req);
     1458                /* This call needs to be run as root */
     1459                change_to_root_user();
     1460
     1461                {
     1462                        START_PROFILE(smb2_keepalive);
     1463                        return_value = smbd_smb2_request_process_keepalive(req);
     1464                        END_PROFILE(smb2_keepalive);
     1465                }
     1466                break;
    7451467
    7461468        case SMB2_OP_FIND:
    7471469                if (!NT_STATUS_IS_OK(session_status)) {
    748                         return smbd_smb2_request_error(req, session_status);
    749                 }
     1470                        return_value = smbd_smb2_request_error(req, session_status);
     1471                        break;
     1472                }
     1473                /*
     1474                 * This call needs to be run as user.
     1475                 *
     1476                 * smbd_smb2_request_check_tcon()
     1477                 * calls change_to_user() on success.
     1478                 */
    7501479                status = smbd_smb2_request_check_tcon(req);
    7511480                if (!NT_STATUS_IS_OK(status)) {
    752                         return smbd_smb2_request_error(req, status);
    753                 }
    754                 return smbd_smb2_request_process_find(req);
     1481                        return_value = smbd_smb2_request_error(req, status);
     1482                        break;
     1483                }
     1484
     1485                {
     1486                        START_PROFILE(smb2_find);
     1487                        return_value = smbd_smb2_request_process_find(req);
     1488                        END_PROFILE(smb2_find);
     1489                }
     1490                break;
    7551491
    7561492        case SMB2_OP_NOTIFY:
    7571493                if (!NT_STATUS_IS_OK(session_status)) {
    758                         return smbd_smb2_request_error(req, session_status);
    759                 }
     1494                        return_value = smbd_smb2_request_error(req, session_status);
     1495                        break;
     1496                }
     1497                /*
     1498                 * This call needs to be run as user.
     1499                 *
     1500                 * smbd_smb2_request_check_tcon()
     1501                 * calls change_to_user() on success.
     1502                 */
    7601503                status = smbd_smb2_request_check_tcon(req);
    7611504                if (!NT_STATUS_IS_OK(status)) {
    762                         return smbd_smb2_request_error(req, status);
    763                 }
    764                 return smbd_smb2_request_process_notify(req);
     1505                        return_value = smbd_smb2_request_error(req, status);
     1506                        break;
     1507                }
     1508
     1509                {
     1510                        START_PROFILE(smb2_notify);
     1511                        return_value = smbd_smb2_request_process_notify(req);
     1512                        END_PROFILE(smb2_notify);
     1513                }
     1514                break;
    7651515
    7661516        case SMB2_OP_GETINFO:
    7671517                if (!NT_STATUS_IS_OK(session_status)) {
    768                         return smbd_smb2_request_error(req, session_status);
    769                 }
     1518                        return_value = smbd_smb2_request_error(req, session_status);
     1519                        break;
     1520                }
     1521                /*
     1522                 * This call needs to be run as user.
     1523                 *
     1524                 * smbd_smb2_request_check_tcon()
     1525                 * calls change_to_user() on success.
     1526                 */
    7701527                status = smbd_smb2_request_check_tcon(req);
    7711528                if (!NT_STATUS_IS_OK(status)) {
    772                         return smbd_smb2_request_error(req, status);
    773                 }
    774                 return smbd_smb2_request_process_getinfo(req);
     1529                        return_value = smbd_smb2_request_error(req, status);
     1530                        break;
     1531                }
     1532
     1533                {
     1534                        START_PROFILE(smb2_getinfo);
     1535                        return_value = smbd_smb2_request_process_getinfo(req);
     1536                        END_PROFILE(smb2_getinfo);
     1537                }
     1538                break;
    7751539
    7761540        case SMB2_OP_SETINFO:
    7771541                if (!NT_STATUS_IS_OK(session_status)) {
    778                         return smbd_smb2_request_error(req, session_status);
    779                 }
     1542                        return_value = smbd_smb2_request_error(req, session_status);
     1543                        break;
     1544                }
     1545                /*
     1546                 * This call needs to be run as user.
     1547                 *
     1548                 * smbd_smb2_request_check_tcon()
     1549                 * calls change_to_user() on success.
     1550                 */
    7801551                status = smbd_smb2_request_check_tcon(req);
    7811552                if (!NT_STATUS_IS_OK(status)) {
    782                         return smbd_smb2_request_error(req, status);
    783                 }
    784                 return smbd_smb2_request_process_setinfo(req);
     1553                        return_value = smbd_smb2_request_error(req, status);
     1554                        break;
     1555                }
     1556
     1557                {
     1558                        START_PROFILE(smb2_setinfo);
     1559                        return_value = smbd_smb2_request_process_setinfo(req);
     1560                        END_PROFILE(smb2_setinfo);
     1561                }
     1562                break;
    7851563
    7861564        case SMB2_OP_BREAK:
    7871565                if (!NT_STATUS_IS_OK(session_status)) {
    788                         return smbd_smb2_request_error(req, session_status);
    789                 }
     1566                        return_value = smbd_smb2_request_error(req, session_status);
     1567                        break;
     1568                }
     1569                /*
     1570                 * This call needs to be run as user.
     1571                 *
     1572                 * smbd_smb2_request_check_tcon()
     1573                 * calls change_to_user() on success.
     1574                 */
    7901575                status = smbd_smb2_request_check_tcon(req);
    7911576                if (!NT_STATUS_IS_OK(status)) {
    792                         return smbd_smb2_request_error(req, status);
    793                 }
    794                 return smbd_smb2_request_process_break(req);
    795         }
    796 
    797         return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
    798 }
    799 
    800 static void smbd_smb2_request_dispatch_compound(struct tevent_req *subreq);
    801 static void smbd_smb2_request_writev_done(struct tevent_req *subreq);
     1577                        return_value = smbd_smb2_request_error(req, status);
     1578                        break;
     1579                }
     1580
     1581                {
     1582                        START_PROFILE(smb2_break);
     1583                        return_value = smbd_smb2_request_process_break(req);
     1584                        END_PROFILE(smb2_break);
     1585                }
     1586                break;
     1587
     1588        default:
     1589                return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
     1590                break;
     1591        }
     1592        return return_value;
     1593}
    8021594
    8031595static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
    8041596{
    8051597        struct tevent_req *subreq;
     1598        int i = req->current_idx;
    8061599
    8071600        req->subreq = NULL;
    8081601
     1602        req->current_idx += 3;
     1603
     1604        if (req->current_idx < req->out.vector_count) {
     1605                /*
     1606                 * We must process the remaining compound
     1607                 * SMB2 requests before any new incoming SMB2
     1608                 * requests. This is because incoming SMB2
     1609                 * requests may include a cancel for a
     1610                 * compound request we haven't processed
     1611                 * yet.
     1612                 */
     1613                struct tevent_immediate *im = tevent_create_immediate(req);
     1614                if (!im) {
     1615                        return NT_STATUS_NO_MEMORY;
     1616                }
     1617                tevent_schedule_immediate(im,
     1618                                        req->sconn->smb2.event_ctx,
     1619                                        smbd_smb2_request_dispatch_immediate,
     1620                                        req);
     1621                return NT_STATUS_OK;
     1622        }
     1623
    8091624        smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
    8101625
     1626        /* Set credit for this operation (zero credits if this
     1627           is a final reply for an async operation). */
     1628        smb2_set_operation_credit(req->sconn,
     1629                        &req->in.vector[i],
     1630                        &req->out.vector[i]);
     1631
    8111632        if (req->do_signing) {
    812                 int i = req->current_idx;
    8131633                NTSTATUS status;
    8141634                status = smb2_signing_sign_pdu(req->session->session_key,
     
    8191639        }
    8201640
    821         req->current_idx += 3;
    822 
    823         if (req->current_idx < req->out.vector_count) {
    824                 struct timeval zero = timeval_zero();
    825                 subreq = tevent_wakeup_send(req,
    826                                             req->sconn->smb2.event_ctx,
    827                                             zero);
    828                 if (subreq == NULL) {
    829                         return NT_STATUS_NO_MEMORY;
    830                 }
    831                 tevent_req_set_callback(subreq,
    832                                         smbd_smb2_request_dispatch_compound,
    833                                         req);
    834 
    835                 return NT_STATUS_OK;
     1641        if (DEBUGLEVEL >= 10) {
     1642                dbgtext("smbd_smb2_request_reply: sending...\n");
     1643                print_req_vectors(req);
     1644        }
     1645
     1646        /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
     1647        if (req->out.vector_count == 4 &&
     1648                        req->out.vector[3].iov_base == NULL &&
     1649                        req->out.vector[3].iov_len != 0) {
     1650                /* Dynamic part is NULL. Chop it off,
     1651                   We're going to send it via sendfile. */
     1652                req->out.vector_count -= 1;
    8361653        }
    8371654
     
    8461663        }
    8471664        tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req);
     1665        /*
     1666         * We're done with this request -
     1667         * move it off the "being processed" queue.
     1668         */
     1669        DLIST_REMOVE(req->sconn->smb2.requests, req);
    8481670
    8491671        return NT_STATUS_OK;
    8501672}
    8511673
    852 static void smbd_smb2_request_dispatch_compound(struct tevent_req *subreq)
    853 {
    854         struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
     1674void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
     1675                                        struct tevent_immediate *im,
     1676                                        void *private_data)
     1677{
     1678        struct smbd_smb2_request *req = talloc_get_type_abort(private_data,
    8551679                                        struct smbd_smb2_request);
    8561680        struct smbd_server_connection *sconn = req->sconn;
    8571681        NTSTATUS status;
    8581682
    859         tevent_wakeup_recv(subreq);
    860         TALLOC_FREE(subreq);
    861 
    862         DEBUG(10,("smbd_smb2_request_dispatch_compound: idx[%d] of %d vectors\n",
    863                   req->current_idx, req->in.vector_count));
     1683        TALLOC_FREE(im);
     1684
     1685        if (DEBUGLEVEL >= 10) {
     1686                DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
     1687                        req->current_idx, req->in.vector_count));
     1688                print_req_vectors(req);
     1689        }
    8641690
    8651691        status = smbd_smb2_request_dispatch(req);
     
    8831709        if (ret == -1) {
    8841710                NTSTATUS status = map_nt_error_from_unix(sys_errno);
     1711                DEBUG(2,("smbd_smb2_request_writev_done: client write error %s\n",
     1712                        nt_errstr(status)));
    8851713                smbd_server_connection_terminate(sconn, nt_errstr(status));
    8861714                return;
    8871715        }
    888 }
    889 
    890 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
    891                                     NTSTATUS status,
    892                                     DATA_BLOB *info,
    893                                     const char *location)
    894 {
    895         uint8_t *outhdr;
    896         uint8_t *outbody;
    897         int i = req->current_idx;
    898 
    899         DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
    900                   i, nt_errstr(status), info ? " +info" : "",
    901                   location));
    902 
    903         outhdr = (uint8_t *)req->out.vector[i].iov_base;
    904 
    905         SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
    906 
    907         outbody = outhdr + SMB2_HDR_BODY;
    908 
    909         req->out.vector[i+1].iov_base = (void *)outbody;
    910         req->out.vector[i+1].iov_len = 8;
    911 
    912         if (info) {
    913                 SIVAL(outbody, 0x04, info->length);
    914                 req->out.vector[i+2].iov_base   = (void *)info->data;
    915                 req->out.vector[i+2].iov_len    = info->length;
    916         } else {
    917                 req->out.vector[i+2].iov_base = NULL;
    918                 req->out.vector[i+2].iov_len = 0;
    919         }
    920 
    921         /*
    922          * if a request fails, all other remaining
    923          * compounded requests should fail too
    924          */
    925         req->next_status = NT_STATUS_INVALID_PARAMETER;
    926 
    927         return smbd_smb2_request_reply(req);
    9281716}
    9291717
     
    9341722{
    9351723        uint8_t *outhdr;
    936         uint8_t *outdyn;
    9371724        int i = req->current_idx;
    9381725        uint32_t next_command_ofs;
     
    9541741
    9551742        outhdr = (uint8_t *)req->out.vector[i].iov_base;
    956         /* the fallback dynamic buffer */
    957         outdyn = outhdr + SMB2_HDR_BODY + 8;
    9581743
    9591744        next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
     
    10101795
    10111796                        new_size = old_size + pad_size;
    1012                         new_dyn = talloc_array(req->out.vector,
     1797                        new_dyn = talloc_zero_array(req->out.vector,
    10131798                                               uint8_t, new_size);
    10141799                        if (new_dyn == NULL) {
     
    10221807                        req->out.vector[i+2].iov_base = (void *)new_dyn;
    10231808                        req->out.vector[i+2].iov_len = new_size;
    1024 
    1025                         TALLOC_FREE(old_dyn);
    10261809                }
    10271810                next_command_ofs += pad_size;
     
    10321815        return smbd_smb2_request_reply(req);
    10331816}
     1817
     1818NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
     1819                                    NTSTATUS status,
     1820                                    DATA_BLOB *info,
     1821                                    const char *location)
     1822{
     1823        DATA_BLOB body;
     1824        int i = req->current_idx;
     1825        uint8_t *outhdr = (uint8_t *)req->out.vector[i].iov_base;
     1826
     1827        DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
     1828                  i, nt_errstr(status), info ? " +info" : "",
     1829                  location));
     1830
     1831        body.data = outhdr + SMB2_HDR_BODY;
     1832        body.length = 8;
     1833        SSVAL(body.data, 0, 9);
     1834
     1835        if (info) {
     1836                SIVAL(body.data, 0x04, info->length);
     1837        } else {
     1838                /* Allocated size of req->out.vector[i].iov_base
     1839                 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
     1840                 * 1 byte without having to do an alloc.
     1841                 */
     1842                info = talloc_zero_array(req->out.vector,
     1843                                        DATA_BLOB,
     1844                                        1);
     1845                if (!info) {
     1846                        return NT_STATUS_NO_MEMORY;
     1847                }
     1848                info->data = ((uint8_t *)outhdr) +
     1849                        OUTVEC_ALLOC_SIZE - 1;
     1850                info->length = 1;
     1851                SCVAL(info->data, 0, 0);
     1852        }
     1853
     1854        /*
     1855         * if a request fails, all other remaining
     1856         * compounded requests should fail too
     1857         */
     1858        req->next_status = NT_STATUS_INVALID_PARAMETER;
     1859
     1860        return smbd_smb2_request_done_ex(req, status, body, info, __location__);
     1861}
     1862
    10341863
    10351864struct smbd_smb2_send_oplock_break_state {
     
    14932322{
    14942323        NTSTATUS status;
    1495         struct smbd_smb2_request *req;
     2324        struct smbd_smb2_request *req = NULL;
    14962325        struct tevent_req *subreq;
    14972326
     
    15302359        }
    15312360        tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
     2361
     2362        sconn->num_requests++;
    15322363}
    15332364
     
    15422373        TALLOC_FREE(subreq);
    15432374        if (!NT_STATUS_IS_OK(status)) {
     2375                DEBUG(2,("smbd_smb2_request_incoming: client read error %s\n",
     2376                        nt_errstr(status)));
    15442377                smbd_server_connection_terminate(sconn, nt_errstr(status));
    15452378                return;
     
    15842417        }
    15852418        tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
    1586 }
     2419
     2420        sconn->num_requests++;
     2421
     2422        /* The timeout_processing function isn't run nearly
     2423           often enough to implement 'max log size' without
     2424           overrunning the size of the file by many megabytes.
     2425           This is especially true if we are running at debug
     2426           level 10.  Checking every 50 SMB2s is a nice
     2427           tradeoff of performance vs log file size overrun. */
     2428
     2429        if ((sconn->num_requests % 50) == 0 &&
     2430            need_to_check_log_size()) {
     2431                change_to_root_user();
     2432                check_log_size();
     2433        }
     2434}
Note: See TracChangeset for help on using the changeset viewer.