无法连接到Windows共享

时间:2013-09-12 11:07:02

标签: python python-3.x smb

我正在使用pysmb library查询SMB / CIFS网络共享上的共享/目录结构。

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]

当连接到运行samba的linux盒子时,我可以连接好,一切正常。当我尝试连接到Win7 / SBS2008 / Server2008共享时,出现错误。

如果is_direct_tcp=True,我会收到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") 

如果is_direct_tcp=False,我会收到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 

我打了一堵砖墙。我怎样才能弄清楚究竟是什么问题并修复它?

进一步诊断......

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

因此,似乎Linux从-W参数获取域,Windows从Username@Domain语法获取它,并且提供两者使得smbclient调用成功到任一服务器。不幸的是,即使我使用@Domain语法

,连接到Windows也无法在pysmb中成功

解决方案

有3个问题......首先,当use_direct_tcp = True时,port需要445。如果是False,则端口应为139。使用Python3中的模块时也存在错误(字节编码错误)。最后,它与服务器通信的方式存在问题(至少在连接到Windows机箱而不是Linux samba服务器时)。

该模块的作者Michael Teo已经开发出一种我们已经测试并运行的修复程序。他计划很快更新这个包。

1 个答案:

答案 0 :(得分:5)

我不确定这对你的情况有帮助,但它对我有用:

  1. SmbConnection的第3个参数应该是(我认为)client_machine_name,所以我从socket.gethostname()传到了那里。

  2. 我没有使用sign_optionsis_direct_tcp我只保留默认值。

  3. 这对我来说同时适用于samba和windows共享(我只需要传递一个不同的端口号)。

    以下是我使用的代码:

    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
    

    并将其用作:

    smb = Smb('domain\\user', 'password', 'server', 'share_name')