import socket, struct, os from twisted.internet import protocol, defer from smbconstants import * import nmb try: from cStringIO import StringIO except ImportError: from StringIO import StringIO try: import crypt except ImportError: crypt = None class SharedDevice: """Contains information about a SMB shared device/service """ def __init__(self, name, type, comment): self.name = name self.type = type self.comment = comment def __repr__(self): return ('' % (self.name, str(self.type), self.comment)) def smbTimeToEpoch(self, t): """Converts the given SMB time to seconds since the UNIX epoch. """ x = t >> 32 y = t & 0xffffffffL geoCalOffset = 11644473600.0 # = 369.0 * 365.25 * 24 * 60 * 60 - (3.0 * 24 * 60 * 60 + 6.0 * 60 * 60) return ((x * 4.0 * (1 << 30) + (y & 0xfff00000L)) * 1.0e-7 - geoCalOffset) def join(server, *path): return '\\\\' + server + '\\' + '\\'.join(path) class SharedFile: """Contains information about the shared file/directory """ def __init__(self, ctime, atime, mtime, filesize, allocsize, attribs, shortname, longname): self.ctime = ctime self.atime = atime self.mtime = mtime self.filesize = filesize self.allocsize = allocsize self.attribs = attribs try: self.shortName = shortname[:string.index(shortname, '\0')] except ValueError: self.shortName = shortname try: self.longName = longname[:string.index(longname, '\0')] except ValueError: self.longName = longname def _checkAttribs(self, flag): return self.attribs & flag def isArchive(self): return self._checkAttribs(ATTR_ARCHIVE) def isCompressed(self): return self._checkAttribs(ATTR_COMPRESSED) def isNormal(self): return self._checkAttribs(ATTR_NORMAL) def isHidden(self): return self._checkAttribs(ATTR_HIDDEN) def isReadOnly(self): return self._checkAttribs(ATTR_READONLY) def isTemporary(self): return self._checkAttribs(ATTR_TEMPORARY) def isDirectory(self): return self._checkAttribs(ATTR_DIRECTORY) def isSystem(self): return self._checkAttribs(ATTR_SYSTEM) def __repr__(self): return '' class SMBMachine: """Contains information about an SMB machine. """ def __init__(self, name, type, comment): self.name = name self.type = type self.comment = comment def __repr__(self): return '' class SMB(nmb.NetBIOSSession): # SMB Command Codes CREATE_DIR = 0x00 DELETE_DIR = 0x01 CLOSE = 0x04 DELETE = 0x06 RENAME = 0x07 CHECK_DIR = 0x10 READ_RAW = 0x1a WRITE_RAW = 0x1d TRANSACTION = 0x25 TRANSACTION2 = 0x32 OPEN_ANDX = 0x2d READ_ANDX = 0x2e WRITE_ANDX = 0x2f TREE_DISCONNECT = 0x71 NEGOTIATE = 0x72 SESSION_SETUP_ANDX = 0x73 LOGOFF = 0x74 TREE_CONNECT_ANDX = 0x75 # Security Share Mode SECURITY_SHARE_MASK = 0x01 SECURITY_SHARE_SHARE = 0x00 SECURITY_SHARE_USER = 0x01 # Security Auth Mode SECURITY_AUTH_MASK = 0x02 SECURITY_AUTH_ENCRYPTED = 0x02 SECURITY_AUTH_PLAINTEXT = 0x00 # Raw Mode Mask (Good for dialect up to and including LANMAN2.1) RAW_READ_MASK = 0x01 RAW_WRITE_MASK = 0x02 # Capabilities Mask (Good for dialect NT LM 0.12) CAP_RAW_MODE = 0x0001 CAP_MPX_MODE = 0x0002 CAP_UNICODE = 0x0004 CAP_LARGE_FILES = 0x0008 CAP_EXTENDED_SECURITY = 0x80000000 # Flags1 Mask FLAGS1_PATHCASELESS = 0x08 # Flags2 Mask FLAGS2_LONG_FILENAME = 0x0001 FLAGS2_UNICODE = 0x8000 def __init__(self, localName, remoteName, remoteType): self.commands = { SMB.CREATE_DIR: self.cmd_createDir, SMB.DELETE_DIR: self.cmd_deleteDir, SMB.CLOSE: self.cmd_close, SMB.DELETE: self.cmd_delete, SMB.RENAME: self.cmd_rename, SMB.CHECK_DIR: self.cmd_checkDir, SMB.READ_RAW: self.cmd_readRaw, SMB.WRITE_RAW: self.cmd_writeRaw, SMB.TRANSACTION: self.cmd_transaction, SMB.TRANSACTION2: self.cmd_transaction2, SMB.OPEN_ANDX: self.cmd_openAndX, SMB.READ_ANDX: self.cmd_readAndX, SMB.WRITE_ANDX: self.cmd_writeAndX, SMB.TREE_DISCONNECT: self.cmd_treeDisconnect, SMB.NEGOTIATE: self.cmd_negotiate, SMB.SESSION_SETUP_ANDX: self.cmd_sessionSetupAndX, SMB.LOGOFF: self.cmd_logoff, SMB.TREE_CONNECT_ANDX: self.cmd_treeConnectAndX } nmb.NetBIOSSession.__init__(self) self.localName = localName self.remoteName = remoteName self.remoteType = remoteType self.transactions = {} self.transactions2 = {} self.userID = 0 def sendPacket(self, cmd, param='', data='', status=0, flags=0, flags2=0, tid=0, mid=0): wordCount = len(param) assert wordCount & 0x1 == 0 nmb.NetBIOSSession.sendPacket(self, struct.pack('<4sBLBH12sHHHHB', '\xffSMB', cmd, status, flags, flags2, '\0' * 12, tid, os.getpid(), self.userID, mid, wordCount / 2) + param + struct.pack(' 0 and len(data) >= keyLength: self._encKey = data[:keyLength] else: self._encKey = '' if self._shareMode == SMB.SECURITY_SHARE_SHARE: self.login('', '') else: self.sessionEstablished() def sessionFailed(self, reason): print 'Session establishment failed' print reason self.transport.loseConnection() def sessionEstablished(self): raise NotImplementedError, "User needs to implement this" def login(self, username, password, domain=''): if self._encKey and crypt: password = crypt.hash(password, self._encKey) params = struct.pack('