summaryrefslogtreecommitdiff
path: root/source3/smbd/smb2_server.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/smbd/smb2_server.c')
-rw-r--r--source3/smbd/smb2_server.c84
1 files changed, 53 insertions, 31 deletions
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index 872e5b9dce..320923a4cf 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -109,6 +109,7 @@ static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn)
}
sconn->smb2.seqnum_low = 0;
+ sconn->smb2.seqnum_range = 1;
sconn->smb2.credits_granted = 1;
sconn->smb2.max_credits = lp_smb2_max_credits();
sconn->smb2.credits_bitmap = bitmap_talloc(sconn,
@@ -301,21 +302,25 @@ static bool smb2_validate_sequence_number(struct smbd_server_connection *sconn,
if (seq_id < sconn->smb2.seqnum_low) {
DEBUG(0,("smb2_validate_sequence_number: bad message_id "
- "%llu (sequence id %llu) (low = %llu, max = %lu)\n",
+ "%llu (sequence id %llu) "
+ "(granted = %u, low = %llu, range = %u)\n",
(unsigned long long)message_id,
(unsigned long long)seq_id,
+ (unsigned int)sconn->smb2.credits_granted,
(unsigned long long)sconn->smb2.seqnum_low,
- (unsigned long)sconn->smb2.max_credits));
+ (unsigned int)sconn->smb2.seqnum_range));
return false;
}
- if (seq_id > (sconn->smb2.seqnum_low + sconn->smb2.max_credits)) {
+ if (seq_id >= sconn->smb2.seqnum_low + sconn->smb2.seqnum_range) {
DEBUG(0,("smb2_validate_sequence_number: bad message_id "
- "%llu (sequence id %llu) (low = %llu, max = %lu)\n",
+ "%llu (sequence id %llu) "
+ "(granted = %u, low = %llu, range = %u)\n",
(unsigned long long)message_id,
(unsigned long long)seq_id,
+ (unsigned int)sconn->smb2.credits_granted,
(unsigned long long)sconn->smb2.seqnum_low,
- (unsigned long)sconn->smb2.max_credits));
+ (unsigned int)sconn->smb2.seqnum_range));
return false;
}
@@ -323,12 +328,14 @@ static bool smb2_validate_sequence_number(struct smbd_server_connection *sconn,
if (bitmap_query(credits_bm, offset)) {
DEBUG(0,("smb2_validate_sequence_number: duplicate message_id "
- "%llu (sequence id %llu) (low = %llu, max = %lu) "
+ "%llu (sequence id %llu) "
+ "(granted = %u, low = %llu, range = %u) "
"(bm offset %u)\n",
(unsigned long long)message_id,
(unsigned long long)seq_id,
+ (unsigned int)sconn->smb2.credits_granted,
(unsigned long long)sconn->smb2.seqnum_low,
- (unsigned long)sconn->smb2.max_credits,
+ (unsigned int)sconn->smb2.seqnum_range,
offset));
return false;
}
@@ -352,6 +359,7 @@ static bool smb2_validate_sequence_number(struct smbd_server_connection *sconn,
bitmap_clear(credits_bm, offset);
sconn->smb2.seqnum_low += 1;
+ sconn->smb2.seqnum_range -= 1;
offset = sconn->smb2.seqnum_low % sconn->smb2.max_credits;
}
@@ -376,23 +384,25 @@ static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
credit_charge = MAX(credit_charge, 1);
}
- DEBUG(11, ("smb2_validate_message_id: mid %llu, credits_granted %llu, "
- "charge %llu, max_credits %llu, seqnum_low: %llu\n",
+ DEBUG(11, ("smb2_validate_message_id: mid %llu (charge %llu), "
+ "credits_granted %llu, "
+ "seqnum low/range: %llu/%llu\n",
(unsigned long long) message_id,
- (unsigned long long) sconn->smb2.credits_granted,
(unsigned long long) credit_charge,
- (unsigned long long) sconn->smb2.max_credits,
- (unsigned long long) sconn->smb2.seqnum_low));
+ (unsigned long long) sconn->smb2.credits_granted,
+ (unsigned long long) sconn->smb2.seqnum_low,
+ (unsigned long long) sconn->smb2.seqnum_range));
if (sconn->smb2.credits_granted < credit_charge) {
DEBUG(0, ("smb2_validate_message_id: client used more "
- "credits than granted, mid %llu, credits_granted %llu, "
- "charge %llu, max_credits %llu, seqnum_low: %llu\n",
+ "credits than granted, mid %llu, charge %llu, "
+ "credits_granted %llu, "
+ "seqnum low/range: %llu/%llu\n",
(unsigned long long) message_id,
- (unsigned long long) sconn->smb2.credits_granted,
(unsigned long long) credit_charge,
- (unsigned long long) sconn->smb2.max_credits,
- (unsigned long long) sconn->smb2.seqnum_low));
+ (unsigned long long) sconn->smb2.credits_granted,
+ (unsigned long long) sconn->smb2.seqnum_low,
+ (unsigned long long) sconn->smb2.seqnum_range));
return false;
}
@@ -517,6 +527,7 @@ static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
uint16_t credits_requested;
uint32_t out_flags;
uint16_t credits_granted = 0;
+ uint64_t credits_possible;
credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
out_flags = IVAL(outhdr, SMB2_HDR_FLAGS);
@@ -529,10 +540,8 @@ static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
* response, we should not grant
* credits on the final response.
*/
- credits_requested = 0;
- }
-
- if (credits_requested) {
+ credits_granted = 0;
+ } else if (credits_requested > 0) {
uint16_t modified_credits_requested;
uint32_t multiplier;
@@ -552,25 +561,38 @@ static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
modified_credits_requested = 1;
}
- /* Remember what we gave out. */
- credits_granted = MIN(modified_credits_requested,
- (sconn->smb2.max_credits - sconn->smb2.credits_granted));
- }
-
- if (credits_granted == 0 && sconn->smb2.credits_granted == 0) {
- /* First negprot packet, or ensure the client credits can
- never drop to zero. */
+ credits_granted = modified_credits_requested;
+ } else if (sconn->smb2.credits_granted == 0) {
+ /*
+ * Make sure the client has always at least one credit
+ */
credits_granted = 1;
}
+ /*
+ * remove the range we'll already granted to the client
+ * this makes sure the client consumes the lowest sequence
+ * number, before we can grant additional credits.
+ */
+ credits_possible = sconn->smb2.max_credits;
+ credits_possible -= sconn->smb2.seqnum_range;
+
+ credits_granted = MIN(credits_granted, credits_possible);
+
SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
sconn->smb2.credits_granted += credits_granted;
+ sconn->smb2.seqnum_range += credits_granted;
DEBUG(10,("smb2_set_operation_credit: requested %u, "
- "granted %u, total granted %u\n",
+ "granted %u, current possible %u, "
+ "total granted/max/low/range %u/%u/%llu/%u\n",
(unsigned int)credits_requested,
(unsigned int)credits_granted,
- (unsigned int)sconn->smb2.credits_granted ));
+ (unsigned int)credits_possible,
+ (unsigned int)sconn->smb2.credits_granted,
+ (unsigned int)sconn->smb2.max_credits,
+ (unsigned long long)sconn->smb2.seqnum_low,
+ (unsigned int)sconn->smb2.seqnum_range));
}
static void smb2_calculate_credits(const struct smbd_smb2_request *inreq,