Changeset 751 for trunk/server/source3/smbd/smb2_server.c
- Timestamp:
- Nov 29, 2012, 1:59:04 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/server/source3/smbd/smb2_server.c
r745 r751 115 115 sconn->smb2.sessions.list = NULL; 116 116 sconn->smb2.seqnum_low = 0; 117 sconn->smb2.credits_granted = 0; 117 sconn->smb2.seqnum_range = 1; 118 sconn->smb2.credits_granted = 1; 118 119 sconn->smb2.max_credits = lp_smb2_max_credits(); 119 120 sconn->smb2.credits_bitmap = bitmap_talloc(sconn, 120 DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR*sconn->smb2.max_credits);121 sconn->smb2.max_credits); 121 122 if (sconn->smb2.credits_bitmap == NULL) { 122 123 return NT_STATUS_NO_MEMORY; … … 207 208 req->parent = parent; 208 209 210 req->last_session_id = UINT64_MAX; 211 req->last_tid = UINT32_MAX; 212 209 213 talloc_set_destructor(parent, smbd_smb2_request_parent_destructor); 210 214 talloc_set_destructor(req, smbd_smb2_request_destructor); … … 296 300 } 297 301 302 static 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 298 374 static bool smb2_validate_message_id(struct smbd_server_connection *sconn, 299 375 const uint8_t *inhdr) 300 376 { 301 377 uint64_t message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID); 302 struct bitmap *credits_bm = sconn->smb2.credits_bitmap;303 378 uint16_t opcode = IVAL(inhdr, SMB2_HDR_OPCODE); 304 unsigned int bitmap_offset;379 bool ok; 305 380 306 381 if (opcode == SMB2_OP_CANCEL) { … … 309 384 } 310 385 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)); 319 401 return false; 320 402 } 321 403 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 */ 324 410 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's340 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 411 353 412 return true; … … 358 417 int count; 359 418 int idx; 360 bool compound_related = false;361 419 362 420 count = req->in.vector_count; … … 369 427 for (idx=1; idx < count; idx += 3) { 370 428 const uint8_t *inhdr = NULL; 371 uint32_t flags;372 429 373 430 if (req->in.vector[idx].iov_len != SMB2_HDR_BODY) { … … 388 445 if (!smb2_validate_message_id(req->sconn, inhdr)) { 389 446 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 the396 * SMB2_HDR_FLAG_CHAINED flag set397 */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. unrelated405 * compounded requests406 */407 if (flags & SMB2_HDR_FLAG_CHAINED) {408 compound_related = true;409 }410 } else if (idx > 4) {411 #if 0412 /*413 * It seems the this tests are wrong414 * see the SMB2-COMPOUND test415 */416 417 /*418 * all other requests should match the 2nd one419 */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 #endif434 447 } 435 448 } … … 446 459 uint16_t credits_requested; 447 460 uint32_t out_flags; 461 uint16_t cmd; 462 NTSTATUS out_status; 448 463 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); 450 485 credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT); 451 486 out_flags = IVAL(outhdr, SMB2_HDR_FLAGS); 487 out_status = NT_STATUS(IVAL(outhdr, SMB2_HDR_STATUS)); 452 488 453 489 SMB_ASSERT(sconn->smb2.max_credits >= sconn->smb2.credits_granted); … … 459 495 * credits on the final response. 460 496 */ 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 */ 492 531 credits_granted = 1; 493 532 } 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); 494 558 495 559 SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted); 496 560 sconn->smb2.credits_granted += credits_granted; 561 sconn->smb2.seqnum_range += credits_granted; 497 562 498 563 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", 500 566 (unsigned int)credits_requested, 501 567 (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)); 503 574 } 504 575 … … 507 578 { 508 579 int count, idx; 580 uint16_t total_credits = 0; 509 581 510 582 count = outreq->out.vector_count; 511 583 512 584 for (idx=1; idx < count; idx += 3) { 585 uint8_t *outhdr = (uint8_t *)outreq->out.vector[idx].iov_base; 513 586 smb2_set_operation_credit(outreq->sconn, 514 587 &inreq->in.vector[idx], 515 588 &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 } 516 598 } 517 599 } … … 570 652 SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC); 571 653 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)); 573 656 SIVAL(outhdr, SMB2_HDR_STATUS, 574 657 NT_STATUS_V(NT_STATUS_INTERNAL_ERROR)); … … 586 669 SBVAL(outhdr, SMB2_HDR_SESSION_ID, 587 670 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); 589 673 590 674 /* setup error body header */ … … 864 948 * Cancel the outstanding request. 865 949 */ 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); 867 955 return smbd_smb2_request_error(req, 868 NT_STATUS_IN SUFFICIENT_RESOURCES);956 NT_STATUS_INTERNAL_ERROR); 869 957 } 870 958 … … 885 973 return status; 886 974 } 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; 887 989 } 888 990 889 991 /* Don't return an intermediate packet on a pipe read/write. */ 890 992 if (req->tcon && req->tcon->compat_conn && IS_IPC(req->tcon->compat_conn)) { 891 return NT_STATUS_OK;993 goto ipc_out; 892 994 } 893 995 … … 929 1031 SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(reqhdr, SMB2_HDR_OPCODE)); 930 1032 931 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);1033 SIVAL(hdr, SMB2_HDR_FLAGS, flags); 932 1034 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0); 933 1035 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id); … … 952 1054 &state->vector[1]); 953 1055 1056 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC); 1057 954 1058 if (req->do_signing) { 955 1059 status = smb2_signing_sign_pdu(req->session->session_key, … … 977 1081 /* Note we're going async with this request. */ 978 1082 req->async = true; 1083 1084 ipc_out: 979 1085 980 1086 /* … … 1025 1131 req->out.vector_count); 1026 1132 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 1040 1149 return NT_STATUS_OK; 1041 1150 } … … 1102 1211 } 1103 1212 1213 NTSTATUS 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 1104 1268 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req) 1105 1269 { … … 1125 1289 (unsigned long long)mid)); 1126 1290 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 1127 1311 allowed_flags = SMB2_HDR_FLAG_CHAINED | 1128 1312 SMB2_HDR_FLAG_SIGNED | … … 1145 1329 session_status = smbd_smb2_request_check_session(req); 1146 1330 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 1147 1343 req->do_signing = false; 1148 1344 if (flags & SMB2_HDR_FLAG_SIGNED) { … … 1157 1353 return smbd_smb2_request_error(req, status); 1158 1354 } 1355 } else if (opcode == SMB2_OP_CANCEL) { 1356 /* Cancel requests are allowed to skip the signing */ 1159 1357 } else if (req->session && req->session->do_signing) { 1160 1358 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED); … … 1162 1360 1163 1361 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; 1176 1364 } 1177 1365 … … 1622 1810 } 1623 1811 1812 if (req->compound_related) { 1813 req->compound_related = false; 1814 req->sconn->smb2.compound_related_in_progress = false; 1815 } 1816 1624 1817 smb2_setup_nbt_length(req->out.vector, req->out.vector_count); 1625 1818 1626 /* Set credit for th is operation(zero credits if this1819 /* Set credit for these operations (zero credits if this 1627 1820 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); 1631 1822 1632 1823 if (req->do_signing) { … … 1672 1863 } 1673 1864 1865 static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn); 1866 1674 1867 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx, 1675 1868 struct tevent_immediate *im, … … 1690 1883 1691 1884 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); 1692 1891 if (!NT_STATUS_IS_OK(status)) { 1693 1892 smbd_server_connection_terminate(sconn, nt_errstr(status)); … … 1703 1902 int ret; 1704 1903 int sys_errno; 1904 NTSTATUS status; 1705 1905 1706 1906 ret = tstream_writev_queue_recv(subreq, &sys_errno); … … 1708 1908 TALLOC_FREE(req); 1709 1909 if (ret == -1) { 1710 NTSTATUSstatus = map_nt_error_from_unix(sys_errno);1910 status = map_nt_error_from_unix(sys_errno); 1711 1911 DEBUG(2,("smbd_smb2_request_writev_done: client write error %s\n", 1712 1912 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)) { 1713 1919 smbd_server_connection_terminate(sconn, nt_errstr(status)); 1714 1920 return; … … 1853 2059 1854 2060 /* 1855 * if a request fails, all other remaining1856 * compounded requests should fail too2061 * Note: Even if there is an error, continue to process the request. 2062 * per MS-SMB2. 1857 2063 */ 1858 req->next_status = NT_STATUS_INVALID_PARAMETER;1859 2064 1860 2065 return smbd_smb2_request_done_ex(req, status, body, info, __location__); … … 2318 2523 static void smbd_smb2_request_incoming(struct tevent_req *subreq); 2319 2524 2525 static 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 2320 2569 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn, 2321 2570 const uint8_t *inbuf, size_t size) … … 2323 2572 NTSTATUS status; 2324 2573 struct smbd_smb2_request *req = NULL; 2325 struct tevent_req *subreq;2326 2574 2327 2575 DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n", … … 2340 2588 } 2341 2589 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 2342 2596 status = smbd_smb2_request_setup_out(req); 2343 2597 if (!NT_STATUS_IS_OK(status)) { … … 2352 2606 } 2353 2607 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)); 2358 2611 return; 2359 2612 } 2360 tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);2361 2613 2362 2614 sconn->num_requests++; … … 2410 2662 2411 2663 next: 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)); 2416 2667 return; 2417 2668 } 2418 tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);2419 2669 2420 2670 sconn->num_requests++;
Note:
See TracChangeset
for help on using the changeset viewer.