I'm using the pysmb library to query shares/directory structures on SMB/CIFS network shares.
def ListShares(Server, Username=None, Password=None, Domain=None):
Ip = socket.gethostbyname(Server)
conn = SMBConnection(Username,
Password,
'MyApp',
Server,
Domain,
use_ntlm_v2=True,
sign_options=SMBConnection.SIGN_WHEN_SUPPORTED,
is_direct_tcp=True)
assert conn.connect(Ip)
Response = conn.listShares(timeout=30)
return [{'Name': x.name,
'Type': x.type,
'IsTemporary': x.isTemporary,
'Comments': x.comments} for x in Response if not x.isSpecial]
When connecting to a linux box running samba, I can connect okay and everything works. When I try to connect to a Win7/SBS2008/Server2008 share, I get an error.
If is_direct_tcp=True
, I get an Invalid protocol header for Direct TCP session message
File ".../MyApp/Managers/SmbHelper.py", line 38, in ListShares assert conn.connect(Ip)
File "/opt/pyenv/lib/python3.3/site-packages/smb/SMBConnection.py", line 111, in connect self._pollForNetBIOSPacket(timeout)
File "/opt/pyenv/lib/python3.3/site-packages/smb/SMBConnection.py", line 504, in _pollForNetBIOSPacket self.feedData(data)
File "/opt/pyenv/lib/python3.3/site-packages/nmb/base.py", line 49, in feedData length = self.data_nmb.decode(self.data_buf, offset)
File "/opt/pyenv/lib/python3.3/site-packages/nmb/nmb_structs.py", line 60, in decode raise NMBError("Invalid protocol header for Direct TCP session message")
If is_direct_tcp=False
, I get a NotConnectedError
File ".../MyApp/Managers/SmbHelper.py", line 38, in ListShares assert conn.connect(Ip)
File "/opt/pyenv/lib/python3.3/lib/site-packages/smb/SMBConnection.py", line 111, in connect self._pollForNetBIOSPacket(timeout)
File "/opt/pyenv/lib/python3.3/lib/site-packages/smb/SMBConnection.py", line 466, in _pollForNetBIOSPacket raise NotConnectedError
I'm hitting a bit of a brick wall. How can I work out what exactly is wrong and fix it?
Further diagnostics...
smbclient -L linux.domain.local -U MyUsername -W domain //Works
smbclient -L linux.domain.local -U MyUsername@domain //Doesn't work (Auth failed)
smbclient -L windows.domain.local -U MyUsername -W domain //Doesn't work (Auth failed)
smbclient -L windows.domain.local -U MyUsername@domain //Works
smbclient -L [either].domain.local -U MyUsername@domain -W domain //Works, despite redundancy
So it seems Linux gets the domain from the -W
parameter, Windows gets it from the Username@Domain
syntax and providing both makes the smbclient
call succeed to either server. Unfortunately, connecting to Windows doesn't succeed succeed from within pysmb even if I use the @Domain
syntax
There were 3 problems... Firstly, when use_direct_tcp
= True
, port
needs to be 445
. When it's False
, port should be 139
. There was also a bug when using the module from Python3 (bytes were being incorrectly encoded). Finally, there was a problem with the way it was communicating with the server (at least when connecting to Windows boxes rather than a linux samba server).
Michael Teo, author of the module has developed a fix which we've tested and works. He's planning to update the package shortly.
If Network Discovery is disabled on your PC, you may not be able to see or access shared folders in Windows 10. To resolve the issue, turn on Network Discovery and disable password-protected sharing.
I'm not sure if this helps in your case, but it works for me:
The 3rd parameter to the SmbConnection
should be (I think) the client_machine_name
, so I pass there what I get from socket.gethostname()
.
I'm not using the sign_options
and is_direct_tcp
I just leave the default values.
This works for me with both samba and windows shares (I just have to pass a different port number sometimes).
Here is the code I use:
class Smb(object):
def __init__(self, username, password, server, share, port=139):
# split username if it contains a domain (domain\username)
domain, username = username.split('\\') if username.count('\\') == 1 else ('', username)
# setup data
self.domain = str(domain)
self.username = str(username)
self.password = str(password)
self.client = socket.gethostname()
self.server = str(server)
self.server_ip = socket.gethostbyname(server)
self.share = str(share)
self.port = port
self.conn = None
self.connected = False
# SMB.SMBConnection logs too much
smb_logger = logging.getLogger('SMB.SMBConnection')
smb_logger.setLevel(logging.WARNING)
def connect(self):
try:
self.conn = SMBConnection(self.username, self.password,
self.client, self.server,
use_ntlm_v2=True, domain=self.domain)
self.connected = self.conn.connect(self.server_ip, self.port)
logger.info('Connected to %s' % self.server)
return self.connected
except Exception, e:
logger.error('Connect failed. Reason: %s', e)
return False
And use it as:
smb = Smb('domain\\user', 'password', 'server', 'share_name')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With