Skip to content

Commit

Permalink
Fix up session id lookup issues with ksmbd
Browse files Browse the repository at this point in the history
  • Loading branch information
jborean93 committed Jun 25, 2023
1 parent f7eca41 commit ed483f3
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 19 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 1.10.2 - TBD

* Fix up pre authenticated session id lookups that were failing with Linux ksmbd

## 1.10.1 - 2022-11-14

* Raise the original `BadNetworkName` error if the server doesn't indicate it supports DFS or `FSDriverRequired` was raised trying to lookup the DFS information - https://github.com/jborean93/smbprotocol/issues/196
Expand Down
5 changes: 5 additions & 0 deletions build_helpers/run-ci.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
#!/bin/bash -ex

# Set by GHA setup-python
if [[ -n "${pythonLocation}" ]]; then
PATH="${pythonLocation}/bin:${PATH}"
fi

source ./build_helpers/lib.sh

lib::setup::smb_server
Expand Down
13 changes: 6 additions & 7 deletions src/smbprotocol/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -749,10 +749,6 @@ def __init__(self, guid, server_name, port=445, require_signing=True):
# Table of Session entries, the order is important for smbclient.
self.session_table = OrderedDict()

# Table of sessions that have not completed authentication, indexed by
# session_id
self.preauth_session_table = {}

# Table of Requests that have yet to be picked up by the application,
# it MAY contain a response from the server as well
self.outstanding_requests = dict()
Expand Down Expand Up @@ -808,6 +804,9 @@ def __init__(self, guid, server_name, port=445, require_signing=True):
# Preauth integrity hash value computed for the SMB2 NEGOTIATE request
# contains the messages used to compute the hash
self.preauth_integrity_hash_value = []
# Table of raw header bytes for unauthenticated session setup messages,
# indexed by message_id.
self.preauth_integrity_session_hash_value = {}

# The cipher object that was negotiated
self.cipher_id = None
Expand Down Expand Up @@ -1241,7 +1240,7 @@ def _send(
header["command"] = message.COMMAND
header["credit_request"] = credit_request if credit_request else credit_charge
header["message_id"] = current_id
header["session_id"] = session_id if session_id and session_id > 0 else 0
header["session_id"] = session_id
header["data"] = message.pack()
header["next_command"] = next_command

Expand Down Expand Up @@ -1278,7 +1277,7 @@ def _send(
self.preauth_integrity_hash_value.append(b_header)

elif message.COMMAND == Commands.SMB2_SESSION_SETUP:
self.preauth_session_table[session_id].preauth_integrity_hash_value.append(b_header)
self.preauth_integrity_session_hash_value[current_id] = b_header

requests.append(request)

Expand Down Expand Up @@ -1376,7 +1375,7 @@ def _process_message_thread(self):
self.preauth_integrity_hash_value.append(b_header)

elif command == Commands.SMB2_SESSION_SETUP and status == NtStatus.STATUS_MORE_PROCESSING_REQUIRED:
self.preauth_session_table[message_id] = b_header
self.preauth_integrity_session_hash_value[message_id] = b_header

with request.response_event_lock:
if header["flags"].has_flag(Smb2Flags.SMB2_FLAGS_ASYNC_COMMAND):
Expand Down
24 changes: 12 additions & 12 deletions src/smbprotocol/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,7 @@ def __init__(self, connection, username=None, password=None, require_encryption=
"""
log.info("Initialising session with username: %s" % username)
self._connected = False
# This is only used by the client for pre-auth, the server will replace this value by one generated by itself.
self.session_id = random.randint(1, 2147483647) * -1
self.session_id = 0
self.require_encryption = require_encryption

# Table of tree connection, lookup by TreeConnect.tree_connect_id and
Expand Down Expand Up @@ -275,8 +274,6 @@ def connect(self):
except spnego.exceptions.SpnegoError as err:
raise SMBAuthenticationError("Failed to authenticate with server: %s" % str(err.message))

self.connection.preauth_session_table[self.session_id] = self

in_token = self.connection.gss_negotiate_token
if self.auth_protocol != "negotiate":
in_token = None # The GSS Negotiate Token can only be used for Negotiate auth.
Expand All @@ -298,20 +295,23 @@ def connect(self):
log.info("Sending SMB2_SESSION_SETUP request message")
request = self.connection.send(session_setup, sid=self.session_id, credit_request=64)

request_id = request.message["message_id"].get_value()
request_header = self.connection.preauth_integrity_session_hash_value.pop(request_id)
self.preauth_integrity_hash_value.append(request_header)

log.info("Receiving SMB2_SESSION_SETUP response message")
try:
response = self.connection.receive(request)
except MoreProcessingRequired as exc:
mid = request.message["message_id"].get_value()
response = exc.header
else:
mid = response["message_id"].get_value()

# If this is the first time we received the actual session_id, update the preauth table with the server
# assigned id.
# If this is the first time we received the actual session_id,
# record the returned id.
session_id = response["session_id"].get_value()
if self.session_id < 0 and session_id:
del self.connection.preauth_session_table[self.session_id]
self.connection.preauth_session_table[session_id] = self

if self.session_id == 0 and session_id:
self.session_id = session_id

setup_response = SMB2SessionSetupResponse()
Expand All @@ -322,14 +322,14 @@ def connect(self):
status = response["status"].get_value()
if status == NtStatus.STATUS_MORE_PROCESSING_REQUIRED:
log.info("More processing is required for SMB2_SESSION_SETUP")
preauth_value = self.connection.preauth_session_table.pop(response["message_id"].get_value())
preauth_value = self.connection.preauth_integrity_session_hash_value.pop(mid)
self.preauth_integrity_hash_value.append(preauth_value)

log.info("Setting session id to %s" % self.session_id)
self._connected = True

# Move the session from the preauth table to the actual session table.
self.connection.session_table[self.session_id] = self.connection.preauth_session_table.pop(self.session_id)
self.connection.session_table[self.session_id] = self

# session_key is the first 16 bytes, padded 0 if less than 16
self.full_session_key = context.session_key
Expand Down

0 comments on commit ed483f3

Please sign in to comment.