jborean93 / smbprotocol

Python SMBv2 and v3 Client
MIT License
322 stars 73 forks source link

DFS share support in smbprotocol #300

Open akarasik opened 1 week ago

akarasik commented 1 week ago

Hello!

I am trying to connect to a DFS share using the low-level smbprotocol classes and functions, but it seems to be lacking the ability of getting the referral to be able to get a tree from the right hostname and path. I found that getting the referral is tied to the ClientConfig from smbclient, and I couldn't make it work with the smbprotocol functions.

Is there a way in which smbprotocol can support connecting to DFS shares? or even just getting the referral for future tree usage?

Here are some code snippets for example:

This code works for connecting to the DFS share and getting the files list, due to the fact that scandir eventualy uses the get_smb_tree that converts the hostname to the referral host:

hostname = 'some.host'
username = 'myuser'
password = 'mypass'
share_name = 'shares/MYSHARE'
remote_port = '445'
connection_timeout = 10
SMBPROTOCOL_AUTH_PROTOCOL = 'ntlm'
SMBPROTOCOL_REQUIRE_SIGN = True

register_session(server=hostname, username=username, password=password, port=remote_port, connection_timeout=connection_timeout, auth_protocol=SMBPROTOCOL_AUTH_PROTOCOL, require_signing=SMBPROTOCOL_REQUIRE_SIGN)
filelist_iter = scandir(rf"\\{hostname}\{share_name}", search_pattern="*", username=username, password=password)

While when running this code results in an exception of NT_STATUS_BAD_NETWORK_NAME when executing tree.connect:

hostname = 'some.host'
username = 'myuser'
password = 'mypass'
share_name = 'shares/MYSHARE'
remote_port = '445'
connection_timeout = 10
SMBPROTOCOL_AUTH_PROTOCOL = 'ntlm'
SMBPROTOCOL_REQUIRE_SIGN = True

session = register_session(server=hostname, username=username, password=password, port=remote_port, connection_timeout=connection_timeout, auth_protocol=SMBPROTOCOL_AUTH_PROTOCOL, require_signing=SMBPROTOCOL_REQUIRE_SIGN)
tree = TreeConnect(session, rf'\\{hostname}\{share_name}')
tree.connect(require_secure_negotiate=SMBPROTOCOL_REQUIRE_SIGN)

Thank you!

jborean93 commented 1 week ago

Unfortunately the low level API is very much focused on the primitives of SMB and is designed for single connections to a single server. It is certainly possible to use the same primitives (IOCTL requests with the DFS request payloads) from the low level API but it is up to you to handle the logic around how to parse the requests and create the new connections. DFS is a very complex protocol and I can't even say I've implemented it properly in the high level API. You can see the various branches the client needs to take account of in the protocol docs for MS-DFSC.

akarasik commented 1 week ago

Thank you! Is there, by any chance, an example of this implementation using the low level API?

jborean93 commented 1 week ago

There is not sorry, you'll have to look at how the high level API interacts with it.

akarasik commented 1 week ago

Got it, thanks for the information!