import hashlib, os, threading import xml.parsers.expat as expat import exception, util, truantchild import edfmeta, edfexecution #from plugin import Plugin from edfplugin import EDFPlugin from pytrch import TrchError from redirection import LocalRedirection, RemoteRedirection __all__ = ["DAVEPlugin"] class DAVEPlugin(EDFPlugin): def __init__(self, files, io): # DAVE plugins are *currently* supported only on Win32 (that's a # restriction based on delivery mechanisms, not the DAVE spec itself) import sys if sys.platform != "win32": raise EnvironmentError("DAVEPlugins are supported only on Windows for this version of Fuzzbunch!") try: EDFPlugin.__init__(self, files, io) self.metaconfig = files[2] self.initTouches() self.initConsoleMode() self.initRedirection() except TrchError: # There was an error parsing the plug-in XML raise except IndexError: # We didn't get the right number of files raise self.procs = [] self.package_arches = edfmeta.parse_forward(self.metaconfig) if not self.package_arches: raise EnvironmentError("A DAVEPlugin is missing required 'package' information in its .fb file!") def getMetaHash(self): return "%s %s %s" % (hashlib.sha1(open(self.metaconfig, 'rb').read()).hexdigest(), os.lstat(self.metaconfig).st_size, os.path.basename(self.metaconfig)) def canDeploy(self): return True def killPlugin(self): """Helper function for forceful termination of the plugin executable, primarily used for testing """ for p in self.procs: p.kill() self.procs = [] def write_interpreted_xml_file(self, inConfFile, globalvars={}): """Rewrite the inconfig, substituting variables""" tmpFile = open(inConfFile, "w"); # Note: Truantchild has been used to this point to store parameters, so # the inconfig here represents all of the prompted data configdata = self.getMarshalledInConfig() configlines = configdata.split("\n") newlines = [] for line in configlines: newlines.append(util.variable_replace(line, globalvars)) newconfig = "\n".join(newlines) tmpFile.write(newconfig) tmpFile.close() return inConfFile """ Plugin validation routine """ def validate(self, dirs, globalvars={}): baseDir, logDir = dirs timestamp = util.formattime() exeBaseName = os.path.basename(self.executable) logName = "%s-%s.log" % (exeBaseName, timestamp) logFile = os.path.join(logDir, logName) try: os.remove(logFile) except: pass inConfName = "%s-%s-InConfig.validate.xml" % (exeBaseName, timestamp) inConfFile = os.path.join(logDir, inConfName) self.write_interpreted_xml_file(inConfFile, globalvars=globalvars) if edfexecution.validate_plugin(self.executable, inConfFile, self.io) == 0: return True else: return False def marshal_params(self, logDir, archOs, output_filename=None, globalvars={}): import sys, subprocess, platform # Find/compute various paths and filename components we'll need later storageDir = globalvars['FbStorage'] timestamp = util.formattime() exeBaseName = os.path.basename(self.executable) # Get our own packaging options (for reference) arch_map = self.package_arches # Figure out which piece to use for marshaling host_archOs = "%s-%s" % (platform.machine(), platform.system()) proxy = arch_map[host_archOs][0] core = arch_map[archOs][1] # Non supported! if proxy is None: return (None, None) # Get files/paths set up for marshaling if output_filename is None: output_filename = os.path.join(logDir, "%s-%s-Marshal.bin" % (exeBaseName, timestamp)) output_path = os.path.dirname(output_filename) try: os.makedirs(output_path) except os.error: assert os.path.isdir(output_path), "Output path '%s' could not be found/created!" % output_path xml_config_name = os.path.join(logDir, "%s-%s-InConfig.marshal.xml" % (exeBaseName, timestamp)) self.write_interpreted_xml_file(xml_config_name, globalvars=globalvars) # Fire off the DANE config utility to actually create the package. Note that this is strictly # Win32[/64] for now... # (This stuff should be abtracted away form cross-platformness and to avoid hard-coded paths.) proxy_dll = os.path.join(os.path.dirname(self.executable), proxy) assert os.path.isfile(proxy_dll), "Required file '%s' doesn't exist!" % proxy_dll self.io.print_msg("\tUsing '%s' to handle parameter marshaling" % proxy_dll) self.io.print_msg("\tMarshaling the contents of '%s'" % xml_config_name) config_exe = os.path.join(storageDir, 'dvmarshal.exe') assert os.path.isfile(config_exe), "Required program '%s' doesn't exist!" % config_exe subprocess.check_call([config_exe, proxy_dll, xml_config_name, output_filename]) core_dll = os.path.join(os.path.dirname(self.executable), core) return (core_dll, output_filename) def build_package(self, logDir, archOs, listenPort=None, output_filename=None, globalvars={}): import sys, subprocess, platform # Find/compute various paths and filename components we'll need later storageDir = globalvars['FbStorage'] timestamp = util.formattime() exeBaseName = os.path.basename(self.executable) # Get our own packaging options (for reference) arch_map = self.package_arches # Figure out which architecture/OS to use for each piece host_archOs = "%s-%s" % (platform.machine(), platform.system()) proxy = arch_map[host_archOs][0] core = arch_map[archOs][1] if (proxy is None) or (core is None): # Not supported! return None if output_filename is None: output_filename = os.path.join(logDir, "%s-%s-Package.dll" % (exeBaseName, timestamp)) output_path = os.path.dirname(output_filename) try: os.makedirs(output_path) except os.error: assert os.path.isdir(output_path), "Output path '%s' could not be found/created!" % output_path xml_config_name = os.path.join(logDir, "%s-%s-InConfig.package.xml" % (exeBaseName, timestamp)) self.write_interpreted_xml_file(xml_config_name, globalvars=globalvars) # Fire off the DANE config utility to actually create the package. Note that this is strictly # Win32[/64] for now... # (This stuff should be abtracted away for cross-platformness and to avoid hard-coded paths.) baseArch = archOs.split('-')[0] dane_dll = os.path.join(storageDir, 'dane_%s.dll' % baseArch) assert os.path.isfile(dane_dll), "Required file '%s' doesn't exist!" % dane_dll self.io.print_msg("\tUsing '%s' as the output template" % dane_dll) proxy_dll = os.path.join(os.path.dirname(self.executable), proxy) assert os.path.isfile(proxy_dll), "Required file '%s' doesn't exist!" % proxy_dll self.io.print_msg("\tUsing '%s' to handle parameter marshaling" % proxy_dll) core_dll = os.path.join(os.path.dirname(self.executable), core) assert os.path.isfile(core_dll), "Required file '%s' doesn't exist!" % core_dll self.io.print_msg("\tUsing '%s' as the input payload" % core_dll) config_exe = os.path.join(storageDir, 'danecfg.exe') assert os.path.isfile(config_exe), "Required program '%s' doesn't exist!" % config_exe subprocess.check_call([config_exe, dane_dll, proxy_dll, core_dll, xml_config_name, output_filename]) if listenPort: # Pack in the listen-port as a particular binary resource import ctypes, struct RT_RCDATA = 10 ID_PORTNUM = 101 LANG_ID = 0x0000 BeginUpdateResource = ctypes.windll.kernel32.BeginUpdateResourceA UpdateResource = ctypes.windll.kernel32.UpdateResourceA EndUpdateResource = ctypes.windll.kernel32.EndUpdateResourceA rblob = struct.pack("