import os, sys, socket, urllib.request, urllib.error, urllib.parse, mimetypes, email, tempfile from urllib.parse import (unwrap, unquote, splittype, splithost, quote, splitport, splittag, splitattr, splituser, splitpasswd, splitvalue) from urllib.response import addinfourl from urllib.request import ftpwrapper from nmb.NetBIOS import NetBIOS from smb.SMBConnection import SMBConnection from io import BytesIO USE_NTLM = True MACHINE_NAME = None class SMBHandler(urllib.request.BaseHandler): def smb_open(self, req): global USE_NTLM, MACHINE_NAME if not req.host: raise urllib.error.URLError('SMB error: no host given') host, port = splitport(req.host) if port is None: port = 139 else: port = int(port) # username/password handling user, host = splituser(host) if user: user, passwd = splitpasswd(user) else: passwd = None host = unquote(host) user = user or '' domain = '' if ';' in user: domain, user = user.split(';', 1) passwd = passwd or '' myname = MACHINE_NAME or self.generateClientMachineName() server_name,host = host.split(',') if ',' in host else [None,host] if server_name is None: n = NetBIOS() names = n.queryIPForName(host) if names: server_name = names[0] else: raise urllib.error.URLError('SMB error: Hostname does not reply back with its machine name') path, attrs = splitattr(req.selector) if path.startswith('/'): path = path[1:] dirs = path.split('/') dirs = list(map(unquote, dirs)) service, path = dirs[0], '/'.join(dirs[1:]) try: conn = SMBConnection(user, passwd, myname, server_name, domain=domain, use_ntlm_v2 = USE_NTLM) conn.connect(host, port) headers = email.message.Message() if req.data: filelen = conn.storeFile(service, path, req.data) headers.add_header('Content-length', '0') fp = BytesIO(b"") else: fp = self.createTempFile() file_attrs, retrlen = conn.retrieveFile(service, path, fp) fp.seek(0) mtype = mimetypes.guess_type(req.get_full_url())[0] if mtype: headers.add_header('Content-type', mtype) if retrlen is not None and retrlen >= 0: headers.add_header('Content-length', '%d' % retrlen) return addinfourl(fp, headers, req.get_full_url()) except Exception as ex: raise urllib.error.URLError('smb error: %s' % ex).with_traceback(sys.exc_info()[2]) def createTempFile(self): return tempfile.TemporaryFile() def generateClientMachineName(self): hostname = socket.gethostname() if hostname: return hostname.split('.')[0] return 'SMB%d' % os.getpid()