Ignore:
Timestamp:
Nov 29, 2012, 1:59:04 PM (13 years ago)
Author:
Silvan Scherrer
Message:

Samba Server: updated trunk to 3.6.9

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/server/source3/smbd/smb2_server.c

    r745 r751  
    115115        sconn->smb2.sessions.list = NULL;
    116116        sconn->smb2.seqnum_low = 0;
    117         sconn->smb2.credits_granted = 0;
     117        sconn->smb2.seqnum_range = 1;
     118        sconn->smb2.credits_granted = 1;
    118119        sconn->smb2.max_credits = lp_smb2_max_credits();
    119120        sconn->smb2.credits_bitmap = bitmap_talloc(sconn,
    120                         DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR*sconn->smb2.max_credits);
     121                                                   sconn->smb2.max_credits);
    121122        if (sconn->smb2.credits_bitmap == NULL) {
    122123                return NT_STATUS_NO_MEMORY;
     
    207208        req->parent     = parent;
    208209
     210        req->last_session_id = UINT64_MAX;
     211        req->last_tid = UINT32_MAX;
     212
    209213        talloc_set_destructor(parent, smbd_smb2_request_parent_destructor);
    210214        talloc_set_destructor(req, smbd_smb2_request_destructor);
     
    296300}
    297301
     302static bool smb2_validate_sequence_number(struct smbd_server_connection *sconn,
     303                                          uint64_t message_id, uint64_t seq_id)
     304{
     305        struct bitmap *credits_bm = sconn->smb2.credits_bitmap;
     306        unsigned int offset;
     307
     308        if (seq_id < sconn->smb2.seqnum_low) {
     309                DEBUG(0,("smb2_validate_sequence_number: bad message_id "
     310                        "%llu (sequence id %llu) "
     311                        "(granted = %u, low = %llu, range = %u)\n",
     312                        (unsigned long long)message_id,
     313                        (unsigned long long)seq_id,
     314                        (unsigned int)sconn->smb2.credits_granted,
     315                        (unsigned long long)sconn->smb2.seqnum_low,
     316                        (unsigned int)sconn->smb2.seqnum_range));
     317                return false;
     318        }
     319
     320        if (seq_id >= sconn->smb2.seqnum_low + sconn->smb2.seqnum_range) {
     321                DEBUG(0,("smb2_validate_sequence_number: bad message_id "
     322                        "%llu (sequence id %llu) "
     323                        "(granted = %u, low = %llu, range = %u)\n",
     324                        (unsigned long long)message_id,
     325                        (unsigned long long)seq_id,
     326                        (unsigned int)sconn->smb2.credits_granted,
     327                        (unsigned long long)sconn->smb2.seqnum_low,
     328                        (unsigned int)sconn->smb2.seqnum_range));
     329                return false;
     330        }
     331
     332        offset = seq_id % sconn->smb2.max_credits;
     333
     334        if (bitmap_query(credits_bm, offset)) {
     335                DEBUG(0,("smb2_validate_sequence_number: duplicate message_id "
     336                        "%llu (sequence id %llu) "
     337                        "(granted = %u, low = %llu, range = %u) "
     338                        "(bm offset %u)\n",
     339                        (unsigned long long)message_id,
     340                        (unsigned long long)seq_id,
     341                        (unsigned int)sconn->smb2.credits_granted,
     342                        (unsigned long long)sconn->smb2.seqnum_low,
     343                        (unsigned int)sconn->smb2.seqnum_range,
     344                        offset));
     345                return false;
     346        }
     347
     348        /* Mark the message_ids as seen in the bitmap. */
     349        bitmap_set(credits_bm, offset);
     350
     351        if (seq_id != sconn->smb2.seqnum_low) {
     352                return true;
     353        }
     354
     355        /*
     356         * Move the window forward by all the message_id's
     357         * already seen.
     358         */
     359        while (bitmap_query(credits_bm, offset)) {
     360                DEBUG(10,("smb2_validate_sequence_number: clearing "
     361                          "id %llu (position %u) from bitmap\n",
     362                          (unsigned long long)(sconn->smb2.seqnum_low),
     363                          offset));
     364                bitmap_clear(credits_bm, offset);
     365
     366                sconn->smb2.seqnum_low += 1;
     367                sconn->smb2.seqnum_range -= 1;
     368                offset = sconn->smb2.seqnum_low % sconn->smb2.max_credits;
     369        }
     370
     371        return true;
     372}
     373
    298374static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
    299375                                const uint8_t *inhdr)
    300376{
    301377        uint64_t message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
    302         struct bitmap *credits_bm = sconn->smb2.credits_bitmap;
    303378        uint16_t opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
    304         unsigned int bitmap_offset;
     379        bool ok;
    305380
    306381        if (opcode == SMB2_OP_CANCEL) {
     
    309384        }
    310385
    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 ));
     386        DEBUG(11, ("smb2_validate_message_id: mid %llu, credits_granted %llu, "
     387                   "seqnum low/range: %llu/%llu\n",
     388                   (unsigned long long) message_id,
     389                   (unsigned long long) sconn->smb2.credits_granted,
     390                   (unsigned long long) sconn->smb2.seqnum_low,
     391                   (unsigned long long) sconn->smb2.seqnum_range));
     392
     393        if (sconn->smb2.credits_granted < 1) {
     394                DEBUG(0, ("smb2_validate_message_id: client used more "
     395                          "credits than granted, mid %llu, credits_granted %llu, "
     396                          "seqnum low/range: %llu/%llu\n",
     397                          (unsigned long long) message_id,
     398                          (unsigned long long) sconn->smb2.credits_granted,
     399                          (unsigned long long) sconn->smb2.seqnum_low,
     400                          (unsigned long long) sconn->smb2.seqnum_range));
    319401                return false;
    320402        }
    321403
    322         /* client just used a credit. */
    323         SMB_ASSERT(sconn->smb2.credits_granted > 0);
     404        ok = smb2_validate_sequence_number(sconn, message_id, message_id);
     405        if (!ok) {
     406                return false;
     407        }
     408
     409        /* substract used credits */
    324410        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         }
    352411
    353412        return true;
     
    358417        int count;
    359418        int idx;
    360         bool compound_related = false;
    361419
    362420        count = req->in.vector_count;
     
    369427        for (idx=1; idx < count; idx += 3) {
    370428                const uint8_t *inhdr = NULL;
    371                 uint32_t flags;
    372429
    373430                if (req->in.vector[idx].iov_len != SMB2_HDR_BODY) {
     
    388445                if (!smb2_validate_message_id(req->sconn, inhdr)) {
    389446                        return NT_STATUS_INVALID_PARAMETER;
    390                 }
    391 
    392                 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
    393                 if (idx == 1) {
    394                         /*
    395                          * the 1st request should never have the
    396                          * SMB2_HDR_FLAG_CHAINED flag set
    397                          */
    398                         if (flags & SMB2_HDR_FLAG_CHAINED) {
    399                                 req->next_status = NT_STATUS_INVALID_PARAMETER;
    400                                 return NT_STATUS_OK;
    401                         }
    402                 } else if (idx == 4) {
    403                         /*
    404                          * the 2nd request triggers related vs. unrelated
    405                          * compounded requests
    406                          */
    407                         if (flags & SMB2_HDR_FLAG_CHAINED) {
    408                                 compound_related = true;
    409                         }
    410                 } else if (idx > 4) {
    411 #if 0
    412                         /*
    413                          * It seems the this tests are wrong
    414                          * see the SMB2-COMPOUND test
    415                          */
    416 
    417                         /*
    418                          * all other requests should match the 2nd one
    419                          */
    420                         if (flags & SMB2_HDR_FLAG_CHAINED) {
    421                                 if (!compound_related) {
    422                                         req->next_status =
    423                                                 NT_STATUS_INVALID_PARAMETER;
    424                                         return NT_STATUS_OK;
    425                                 }
    426                         } else {
    427                                 if (compound_related) {
    428                                         req->next_status =
    429                                                 NT_STATUS_INVALID_PARAMETER;
    430                                         return NT_STATUS_OK;
    431                                 }
    432                         }
    433 #endif
    434447                }
    435448        }
     
    446459        uint16_t credits_requested;
    447460        uint32_t out_flags;
     461        uint16_t cmd;
     462        NTSTATUS out_status;
    448463        uint16_t credits_granted = 0;
    449 
     464        uint64_t credits_possible;
     465        uint16_t current_max_credits;
     466
     467        /*
     468         * first we grant only 1/16th of the max range.
     469         *
     470         * Windows also starts with the 1/16th and then grants
     471         * more later. I was only able to trigger higher
     472         * values, when using a verify high credit charge.
     473         *
     474         * TODO: scale up depending one load, free memory
     475         *       or other stuff.
     476         *       Maybe also on the relationship between number
     477         *       of requests and the used sequence number.
     478         *       Which means we would grant more credits
     479         *       for client which use multi credit requests.
     480         */
     481        current_max_credits = sconn->smb2.max_credits / 16;
     482        current_max_credits = MAX(current_max_credits, 1);
     483
     484        cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
    450485        credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
    451486        out_flags = IVAL(outhdr, SMB2_HDR_FLAGS);
     487        out_status = NT_STATUS(IVAL(outhdr, SMB2_HDR_STATUS));
    452488
    453489        SMB_ASSERT(sconn->smb2.max_credits >= sconn->smb2.credits_granted);
     
    459495                 * credits on the final response.
    460496                 */
    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. */
     497                credits_granted = 0;
     498        } else if (credits_requested > 0) {
     499                uint16_t additional_max = 0;
     500                uint16_t additional_credits = credits_requested - 1;
     501
     502                switch (cmd) {
     503                case SMB2_OP_NEGPROT:
     504                        break;
     505                case SMB2_OP_SESSSETUP:
     506                        /*
     507                         * Windows 2012 RC1 starts to grant
     508                         * additional credits
     509                         * with a successful session setup
     510                         */
     511                        if (NT_STATUS_IS_OK(out_status)) {
     512                                additional_max = 32;
     513                        }
     514                        break;
     515                default:
     516                        /*
     517                         * We match windows and only grant additional credits
     518                         * in chunks of 32.
     519                         */
     520                        additional_max = 32;
     521                        break;
     522                }
     523
     524                additional_credits = MIN(additional_credits, additional_max);
     525
     526                credits_granted = 1 + additional_credits;
     527        } else if (sconn->smb2.credits_granted == 0) {
     528                /*
     529                 * Make sure the client has always at least one credit
     530                 */
    492531                credits_granted = 1;
    493532        }
     533
     534        /*
     535         * sequence numbers should not wrap
     536         *
     537         * 1. calculate the possible credits until
     538         *    the sequence numbers start to wrap on 64-bit.
     539         *
     540         * 2. UINT64_MAX is used for Break Notifications.
     541         *
     542         * 2. truncate the possible credits to the maximum
     543         *    credits we want to grant to the client in total.
     544         *
     545         * 3. remove the range we'll already granted to the client
     546         *    this makes sure the client consumes the lowest sequence
     547         *    number, before we can grant additional credits.
     548         */
     549        credits_possible = UINT64_MAX - sconn->smb2.seqnum_low;
     550        if (credits_possible > 0) {
     551                /* remove UINT64_MAX */
     552                credits_possible -= 1;
     553        }
     554        credits_possible = MIN(credits_possible, current_max_credits);
     555        credits_possible -= sconn->smb2.seqnum_range;
     556
     557        credits_granted = MIN(credits_granted, credits_possible);
    494558
    495559        SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
    496560        sconn->smb2.credits_granted += credits_granted;
     561        sconn->smb2.seqnum_range += credits_granted;
    497562
    498563        DEBUG(10,("smb2_set_operation_credit: requested %u, "
    499                 "granted %u, total granted %u\n",
     564                "granted %u, current possible/max %u/%u, "
     565                "total granted/max/low/range %u/%u/%llu/%u\n",
    500566                (unsigned int)credits_requested,
    501567                (unsigned int)credits_granted,
    502                 (unsigned int)sconn->smb2.credits_granted ));
     568                (unsigned int)credits_possible,
     569                (unsigned int)current_max_credits,
     570                (unsigned int)sconn->smb2.credits_granted,
     571                (unsigned int)sconn->smb2.max_credits,
     572                (unsigned long long)sconn->smb2.seqnum_low,
     573                (unsigned int)sconn->smb2.seqnum_range));
    503574}
    504575
     
    507578{
    508579        int count, idx;
     580        uint16_t total_credits = 0;
    509581
    510582        count = outreq->out.vector_count;
    511583
    512584        for (idx=1; idx < count; idx += 3) {
     585                uint8_t *outhdr = (uint8_t *)outreq->out.vector[idx].iov_base;
    513586                smb2_set_operation_credit(outreq->sconn,
    514587                        &inreq->in.vector[idx],
    515588                        &outreq->out.vector[idx]);
     589                /* To match Windows, count up what we
     590                   just granted. */
     591                total_credits += SVAL(outhdr, SMB2_HDR_CREDIT);
     592                /* Set to zero in all but the last reply. */
     593                if (idx + 3 < count) {
     594                        SSVAL(outhdr, SMB2_HDR_CREDIT, 0);
     595                } else {
     596                        SSVAL(outhdr, SMB2_HDR_CREDIT, total_credits);
     597                }
    516598        }
    517599}
     
    570652                SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID,     SMB2_MAGIC);
    571653                SSVAL(outhdr, SMB2_HDR_LENGTH,          SMB2_HDR_BODY);
    572                 SSVAL(outhdr, SMB2_HDR_EPOCH,           0);
     654                SSVAL(outhdr, SMB2_HDR_CREDIT_CHARGE,
     655                      SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE));
    573656                SIVAL(outhdr, SMB2_HDR_STATUS,
    574657                      NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
     
    586669                SBVAL(outhdr, SMB2_HDR_SESSION_ID,
    587670                      BVAL(inhdr, SMB2_HDR_SESSION_ID));
    588                 memset(outhdr + SMB2_HDR_SIGNATURE, 0, 16);
     671                memcpy(outhdr + SMB2_HDR_SIGNATURE,
     672                       inhdr + SMB2_HDR_SIGNATURE, 16);
    589673
    590674                /* setup error body header */
     
    864948                 * Cancel the outstanding request.
    865949                 */
    866                 tevent_req_cancel(req->subreq);
     950                bool ok = tevent_req_cancel(req->subreq);
     951                if (ok) {
     952                        return NT_STATUS_OK;
     953                }
     954                TALLOC_FREE(req->subreq);
    867955                return smbd_smb2_request_error(req,
    868                         NT_STATUS_INSUFFICIENT_RESOURCES);
     956                        NT_STATUS_INTERNAL_ERROR);
    869957        }
    870958
     
    885973                        return status;
    886974                }
     975
     976                /*
     977                 * We're splitting off the last SMB2
     978                 * request in a compound set, and the
     979                 * smb2_send_async_interim_response()
     980                 * call above just sent all the replies
     981                 * for the previous SMB2 requests in
     982                 * this compound set. So we're no longer
     983                 * in the "compound_related_in_progress"
     984                 * state, and this is no longer a compound
     985                 * request.
     986                 */
     987                req->compound_related = false;
     988                req->sconn->smb2.compound_related_in_progress = false;
    887989        }
    888990
    889991        /* Don't return an intermediate packet on a pipe read/write. */
    890992        if (req->tcon && req->tcon->compat_conn && IS_IPC(req->tcon->compat_conn)) {
    891                 return NT_STATUS_OK;
     993                goto ipc_out;
    892994        }
    893995
     
    9291031        SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(reqhdr, SMB2_HDR_OPCODE));
    9301032
    931         SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
     1033        SIVAL(hdr, SMB2_HDR_FLAGS, flags);
    9321034        SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
    9331035        SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id);
     
    9521054                        &state->vector[1]);
    9531055
     1056        SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
     1057
    9541058        if (req->do_signing) {
    9551059                status = smb2_signing_sign_pdu(req->session->session_key,
     
    9771081        /* Note we're going async with this request. */
    9781082        req->async = true;
     1083
     1084  ipc_out:
    9791085
    9801086        /*
     
    10251131                req->out.vector_count);
    10261132
    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         }
     1133        if (req->async) {
     1134                /* Ensure our final reply matches the interim one. */
     1135                reqhdr = (uint8_t *)req->out.vector[1].iov_base;
     1136                SIVAL(reqhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
     1137                SBVAL(reqhdr, SMB2_HDR_PID, async_id);
     1138
     1139                {
     1140                        const uint8_t *inhdr =
     1141                                (const uint8_t *)req->in.vector[1].iov_base;
     1142                        DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu "
     1143                                "going async\n",
     1144                                smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)),
     1145                                (unsigned long long)async_id ));
     1146                }
     1147        }
     1148
    10401149        return NT_STATUS_OK;
    10411150}
     
    11021211}
    11031212
     1213NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req,
     1214                                        size_t expected_body_size)
     1215{
     1216        const uint8_t *inhdr;
     1217        uint16_t opcode;
     1218        const uint8_t *inbody;
     1219        int i = req->current_idx;
     1220        size_t body_size;
     1221        size_t min_dyn_size = expected_body_size & 0x00000001;
     1222
     1223        /*
     1224         * The following should be checked already.
     1225         */
     1226        if ((i+2) > req->in.vector_count) {
     1227                return NT_STATUS_INTERNAL_ERROR;
     1228        }
     1229        if (req->in.vector[i+0].iov_len != SMB2_HDR_BODY) {
     1230                return NT_STATUS_INTERNAL_ERROR;
     1231        }
     1232        if (req->in.vector[i+1].iov_len < 2) {
     1233                return NT_STATUS_INTERNAL_ERROR;
     1234        }
     1235
     1236        inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
     1237        opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
     1238
     1239        switch (opcode) {
     1240        case SMB2_OP_IOCTL:
     1241        case SMB2_OP_GETINFO:
     1242                min_dyn_size = 0;
     1243                break;
     1244        }
     1245
     1246        /*
     1247         * Now check the expected body size,
     1248         * where the last byte might be in the
     1249         * dynnamic section..
     1250         */
     1251        if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
     1252                return NT_STATUS_INVALID_PARAMETER;
     1253        }
     1254        if (req->in.vector[i+2].iov_len < min_dyn_size) {
     1255                return NT_STATUS_INVALID_PARAMETER;
     1256        }
     1257
     1258        inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
     1259
     1260        body_size = SVAL(inbody, 0x00);
     1261        if (body_size != expected_body_size) {
     1262                return NT_STATUS_INVALID_PARAMETER;
     1263        }
     1264
     1265        return NT_STATUS_OK;
     1266}
     1267
    11041268NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
    11051269{
     
    11251289                (unsigned long long)mid));
    11261290
     1291        if (get_Protocol() >= PROTOCOL_SMB2) {
     1292                /*
     1293                 * once the protocol is negotiated
     1294                 * SMB2_OP_NEGPROT is not allowed anymore
     1295                 */
     1296                if (opcode == SMB2_OP_NEGPROT) {
     1297                        /* drop the connection */
     1298                        return NT_STATUS_INVALID_PARAMETER;
     1299                }
     1300        } else {
     1301                /*
     1302                 * if the protocol is not negotiated yet
     1303                 * only SMB2_OP_NEGPROT is allowed.
     1304                 */
     1305                if (opcode != SMB2_OP_NEGPROT) {
     1306                        /* drop the connection */
     1307                        return NT_STATUS_INVALID_PARAMETER;
     1308                }
     1309        }
     1310
    11271311        allowed_flags = SMB2_HDR_FLAG_CHAINED |
    11281312                        SMB2_HDR_FLAG_SIGNED |
     
    11451329        session_status = smbd_smb2_request_check_session(req);
    11461330
     1331        if (flags & SMB2_HDR_FLAG_CHAINED) {
     1332                /*
     1333                 * This check is mostly for giving the correct error code
     1334                 * for compounded requests.
     1335                 */
     1336                if (!NT_STATUS_IS_OK(session_status)) {
     1337                        return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
     1338                }
     1339        } else {
     1340                req->compat_chain_fsp = NULL;
     1341        }
     1342
    11471343        req->do_signing = false;
    11481344        if (flags & SMB2_HDR_FLAG_SIGNED) {
     
    11571353                        return smbd_smb2_request_error(req, status);
    11581354                }
     1355        } else if (opcode == SMB2_OP_CANCEL) {
     1356                /* Cancel requests are allowed to skip the signing */
    11591357        } else if (req->session && req->session->do_signing) {
    11601358                return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
     
    11621360
    11631361        if (flags & SMB2_HDR_FLAG_CHAINED) {
    1164                 /*
    1165                  * This check is mostly for giving the correct error code
    1166                  * for compounded requests.
    1167                  *
    1168                  * TODO: we may need to move this after the session
    1169                  *       and tcon checks.
    1170                  */
    1171                 if (!NT_STATUS_IS_OK(req->next_status)) {
    1172                         return smbd_smb2_request_error(req, req->next_status);
    1173                 }
    1174         } else {
    1175                 req->compat_chain_fsp = NULL;
     1362                req->compound_related = true;
     1363                req->sconn->smb2.compound_related_in_progress = true;
    11761364        }
    11771365
     
    16221810        }
    16231811
     1812        if (req->compound_related) {
     1813                req->compound_related = false;
     1814                req->sconn->smb2.compound_related_in_progress = false;
     1815        }
     1816
    16241817        smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
    16251818
    1626         /* Set credit for this operation (zero credits if this
     1819        /* Set credit for these operations (zero credits if this
    16271820           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]);
     1821        smb2_calculate_credits(req, req);
    16311822
    16321823        if (req->do_signing) {
     
    16721863}
    16731864
     1865static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn);
     1866
    16741867void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
    16751868                                        struct tevent_immediate *im,
     
    16901883
    16911884        status = smbd_smb2_request_dispatch(req);
     1885        if (!NT_STATUS_IS_OK(status)) {
     1886                smbd_server_connection_terminate(sconn, nt_errstr(status));
     1887                return;
     1888        }
     1889
     1890        status = smbd_smb2_request_next_incoming(sconn);
    16921891        if (!NT_STATUS_IS_OK(status)) {
    16931892                smbd_server_connection_terminate(sconn, nt_errstr(status));
     
    17031902        int ret;
    17041903        int sys_errno;
     1904        NTSTATUS status;
    17051905
    17061906        ret = tstream_writev_queue_recv(subreq, &sys_errno);
     
    17081908        TALLOC_FREE(req);
    17091909        if (ret == -1) {
    1710                 NTSTATUS status = map_nt_error_from_unix(sys_errno);
     1910                status = map_nt_error_from_unix(sys_errno);
    17111911                DEBUG(2,("smbd_smb2_request_writev_done: client write error %s\n",
    17121912                        nt_errstr(status)));
     1913                smbd_server_connection_terminate(sconn, nt_errstr(status));
     1914                return;
     1915        }
     1916
     1917        status = smbd_smb2_request_next_incoming(sconn);
     1918        if (!NT_STATUS_IS_OK(status)) {
    17131919                smbd_server_connection_terminate(sconn, nt_errstr(status));
    17141920                return;
     
    18532059
    18542060        /*
    1855          * if a request fails, all other remaining
    1856          * compounded requests should fail too
     2061         * Note: Even if there is an error, continue to process the request.
     2062         * per MS-SMB2.
    18572063         */
    1858         req->next_status = NT_STATUS_INVALID_PARAMETER;
    18592064
    18602065        return smbd_smb2_request_done_ex(req, status, body, info, __location__);
     
    23182523static void smbd_smb2_request_incoming(struct tevent_req *subreq);
    23192524
     2525static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn)
     2526{
     2527        size_t max_send_queue_len;
     2528        size_t cur_send_queue_len;
     2529        struct tevent_req *subreq;
     2530
     2531        if (sconn->smb2.compound_related_in_progress) {
     2532                /*
     2533                 * Can't read another until the related
     2534                 * compound is done.
     2535                 */
     2536                return NT_STATUS_OK;
     2537        }
     2538
     2539        if (tevent_queue_length(sconn->smb2.recv_queue) > 0) {
     2540                /*
     2541                 * if there is already a smbd_smb2_request_read
     2542                 * pending, we are done.
     2543                 */
     2544                return NT_STATUS_OK;
     2545        }
     2546
     2547        max_send_queue_len = MAX(1, sconn->smb2.max_credits/16);
     2548        cur_send_queue_len = tevent_queue_length(sconn->smb2.send_queue);
     2549
     2550        if (cur_send_queue_len > max_send_queue_len) {
     2551                /*
     2552                 * if we have a lot of requests to send,
     2553                 * we wait until they are on the wire until we
     2554                 * ask for the next request.
     2555                 */
     2556                return NT_STATUS_OK;
     2557        }
     2558
     2559        /* ask for the next request */
     2560        subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn);
     2561        if (subreq == NULL) {
     2562                return NT_STATUS_NO_MEMORY;
     2563        }
     2564        tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
     2565
     2566        return NT_STATUS_OK;
     2567}
     2568
    23202569void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
    23212570                             const uint8_t *inbuf, size_t size)
     
    23232572        NTSTATUS status;
    23242573        struct smbd_smb2_request *req = NULL;
    2325         struct tevent_req *subreq;
    23262574
    23272575        DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
     
    23402588        }
    23412589
     2590        status = smbd_smb2_request_validate(req);
     2591        if (!NT_STATUS_IS_OK(status)) {
     2592                smbd_server_connection_terminate(sconn, nt_errstr(status));
     2593                return;
     2594        }
     2595
    23422596        status = smbd_smb2_request_setup_out(req);
    23432597        if (!NT_STATUS_IS_OK(status)) {
     
    23522606        }
    23532607
    2354         /* ask for the next request */
    2355         subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn);
    2356         if (subreq == NULL) {
    2357                 smbd_server_connection_terminate(sconn, "no memory for reading");
     2608        status = smbd_smb2_request_next_incoming(sconn);
     2609        if (!NT_STATUS_IS_OK(status)) {
     2610                smbd_server_connection_terminate(sconn, nt_errstr(status));
    23582611                return;
    23592612        }
    2360         tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
    23612613
    23622614        sconn->num_requests++;
     
    24102662
    24112663next:
    2412         /* ask for the next request (this constructs the main loop) */
    2413         subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn);
    2414         if (subreq == NULL) {
    2415                 smbd_server_connection_terminate(sconn, "no memory for reading");
     2664        status = smbd_smb2_request_next_incoming(sconn);
     2665        if (!NT_STATUS_IS_OK(status)) {
     2666                smbd_server_connection_terminate(sconn, nt_errstr(status));
    24162667                return;
    24172668        }
    2418         tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
    24192669
    24202670        sconn->num_requests++;
Note: See TracChangeset for help on using the changeset viewer.