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.
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')