97 lines
3.0 KiB
Python
Executable File
97 lines
3.0 KiB
Python
Executable File
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()
|