OpenSecurity/bin/vmmanager.pyw
changeset 172 3d2812a07881
parent 171 2701e921bf4c
child 176 32c895509a2a
     1.1 --- a/OpenSecurity/bin/vmmanager.pyw	Fri May 23 15:04:52 2014 +0100
     1.2 +++ b/OpenSecurity/bin/vmmanager.pyw	Mon Jun 02 17:08:11 2014 +0100
     1.3 @@ -38,24 +38,28 @@
     1.4          return repr(self.value)
     1.5  
     1.6  class USBFilter:
     1.7 +    uuid = ""
     1.8      vendorid = ""
     1.9      productid = ""
    1.10      revision = ""
    1.11 +    serial = ""
    1.12      
    1.13 -    def __init__(self, vendorid, productid, revision):
    1.14 +    def __init__(self, uuid, vendorid, productid, revision, serial):
    1.15 +        self.uuid = uuid
    1.16          self.vendorid = vendorid.lower()
    1.17          self.productid = productid.lower()
    1.18          self.revision = revision.lower()
    1.19 +        self.serial = serial
    1.20          return
    1.21      
    1.22      def __eq__(self, other):
    1.23 -        return self.vendorid == other.vendorid and self.productid == other.productid and self.revision == other.revision
    1.24 +        return self.uuid == other.uuid #self.vendorid == other.vendorid and self.productid == other.productid and self.revision == other.revision
    1.25      
    1.26      def __hash__(self):
    1.27 -        return hash(self.vendorid) ^ hash(self.productid) ^ hash(self.revision)
    1.28 +        return hash(self.uuid) ^ hash(self.vendorid) ^ hash(self.productid) ^ hash(self.revision) ^ hash(self.serial)
    1.29      
    1.30      def __repr__(self):
    1.31 -        return "VendorId = \'" + str(self.vendorid) + "\' ProductId = \'" + str(self.productid) + "\' Revision = \'" + str(self.revision) + "\'"
    1.32 +        return "UUID:" + str(self.uuid) + " VendorId = \'" + str(self.vendorid) + "\' ProductId = \'" + str(self.productid) + "\'" + "\' Revision = \'" + str(self.revision) + "\' SerialNumber = \'" + str(self.serial)
    1.33      
    1.34      #def __getitem__(self, item):
    1.35      #    return self.coords[item]
    1.36 @@ -221,7 +225,7 @@
    1.37      
    1.38      # return the RSDs connected to the host
    1.39      @staticmethod
    1.40 -    def getConnectedRSDS():
    1.41 +    def getExistingRSDs():
    1.42          results = Cygwin.checkResult(Cygwin.vboxExecute('list usbhost'))[1]
    1.43          results = results.split('Host USB Devices:')[1].strip()
    1.44          
    1.45 @@ -229,31 +233,64 @@
    1.46          rsds = dict()   
    1.47          for item in items:
    1.48              props = dict()
    1.49 -            for line in item.splitlines():
    1.50 +            for line in item.splitlines():     
    1.51                  if line != "":         
    1.52                      k,v = line[:line.index(':')].strip(), line[line.index(':')+1:].strip()
    1.53                      props[k] = v
    1.54              
    1.55 -            #if 'Product' in props.keys() and props['Product'] == 'Mass Storage':
    1.56 -            
    1.57 -            usb_filter = USBFilter( re.search(r"\((?P<vid>[0-9A-Fa-f]+)\)", props['VendorId']).groupdict()['vid'], 
    1.58 -                                    re.search(r"\((?P<pid>[0-9A-Fa-f]+)\)", props['ProductId']).groupdict()['pid'],
    1.59 -                                    re.search(r"\((?P<rev>[0-9A-Fa-f]+)\)", props['Revision']).groupdict()['rev'] )
    1.60 +            uuid = re.search(r"(?P<uuid>[0-9A-Fa-f\-]+)", props['UUID']).groupdict()['uuid']
    1.61 +            vid = re.search(r"\((?P<vid>[0-9A-Fa-f]+)\)", props['VendorId']).groupdict()['vid']
    1.62 +            pid = re.search(r"\((?P<pid>[0-9A-Fa-f]+)\)", props['ProductId']).groupdict()['pid']
    1.63 +            rev = re.search(r"\((?P<rev>[0-9A-Fa-f]+)\)", props['Revision']).groupdict()['rev']
    1.64 +            serial = None
    1.65 +            if 'SerialNumber' in props.keys():
    1.66 +                serial = re.search(r"(?P<ser>[0-9A-Fa-f]+)", props['SerialNumber']).groupdict()['ser']
    1.67 +            usb_filter = USBFilter( uuid, vid, pid, rev, serial) 
    1.68              if VMManager.isMassStorageDevice(usb_filter):
    1.69 -                rsds[props['UUID']] = usb_filter;
    1.70 +                rsds[uuid] = usb_filter
    1.71                  logger.debug(usb_filter)
    1.72          return rsds
    1.73      
    1.74 +   
    1.75 +    #def getAttachedRSD(self, vm_name):
    1.76 +    #    props = self.getVMInfo(vm_name)
    1.77 +    #    keys = set(['USBFilterVendorId1', 'USBFilterProductId1', 'USBFilterRevision1', 'USBFilterSerialNumber1'])
    1.78 +    #    keyset = set(props.keys())
    1.79 +    #    usb_filter = None
    1.80 +    #    if keyset.issuperset(keys):
    1.81 +    #        usb_filter = USBFilter(props['USBFilterVendorId1'], props['USBFilterProductId1'], props['USBFilterRevision1'])
    1.82 +    #    return usb_filter
    1.83 +    
    1.84 +    # return the attached USB device as usb descriptor for an existing VM 
    1.85 +    def getAttachedRSD(self, vm_name):
    1.86 +        props = self.getVMInfo(vm_name)
    1.87 +        keys = set(['USBAttachedUUID1', 'USBAttachedVendorId1', 'USBAttachedProductId1', 'USBAttachedRevision1', 'USBAttachedSerialNumber1'])
    1.88 +        keyset = set(props.keys())
    1.89 +        usb_filter = None
    1.90 +        if keyset.issuperset(keys):
    1.91 +            usb_filter = USBFilter(props['USBAttachedUUID1'], props['USBAttachedVendorId1'], props['USBAttachedProductId1'], props['USBAttachedRevision1'], props['USBAttachedSerialNumber1'])
    1.92 +        return usb_filter
    1.93 +        
    1.94      # return the RSDs attached to all existing SDVMs
    1.95      def getAttachedRSDs(self):
    1.96          vms = self.listSDVM()
    1.97          attached_devices = dict()
    1.98          for vm in vms:
    1.99 -            rsd_filter = self.getUSBFilter(vm)
   1.100 +            rsd_filter = self.getAttachedRSD(vm)
   1.101              if rsd_filter != None:
   1.102                  attached_devices[vm] = rsd_filter
   1.103          return attached_devices
   1.104      
   1.105 +    # attach removable storage device to VM by provision of filter
   1.106 +    def attachRSD(self, vm_name, rsd_filter):
   1.107 +        #return Cygwin.checkResult(Cygwin.vboxExecute('usbfilter add 0 --target ' + vm_name + ' --name OpenSecurityRSD --vendorid ' + rsd_filter.vendorid + ' --productid ' + rsd_filter.productid + ' --revision ' + rsd_filter.revision + ' --serialnumber ' + rsd_filter.serial))
   1.108 +        return Cygwin.checkResult(Cygwin.vboxExecute('controlvm ' + vm_name + ' usbattach ' + rsd_filter.uuid ))
   1.109 +    
   1.110 +    # detach removable storage from VM by 
   1.111 +    def detachRSD(self, vm_name, rsd_filter):
   1.112 +        #return Cygwin.checkResult(Cygwin.vboxExecute('usbfilter remove 0 --target ' + vm_name))
   1.113 +        return Cygwin.checkResult(Cygwin.vboxExecute('controlvm ' + vm_name + ' usbdetach ' + rsd_filter.uuid ))
   1.114 +        
   1.115      # configures hostonly networking and DHCP server. requires admin rights
   1.116      def configureHostNetworking(self):
   1.117          #cmd = 'vboxmanage list hostonlyifs'
   1.118 @@ -461,14 +498,6 @@
   1.119              if result.startswith('No value set!'):
   1.120                  return None
   1.121              return result[result.index(':')+1:].strip()
   1.122 -            
   1.123 -    # attach removable storage device to VM by provision of filter
   1.124 -    def attachRSD(self, vm_name, rsd_filter):
   1.125 -        return Cygwin.checkResult(Cygwin.vboxExecute('usbfilter add 0 --target ' + vm_name + ' --name OpenSecurityRSD --vendorid ' + rsd_filter.vendorid + ' --productid ' + rsd_filter.productid + ' --revision ' + rsd_filter.revision))
   1.126 -    
   1.127 -    # detach removable storage from VM by 
   1.128 -    def detachRSD(self, vm_name):
   1.129 -        return Cygwin.checkResult(Cygwin.vboxExecute('usbfilter remove 0 --target ' + vm_name))
   1.130          
   1.131      # return the description set for an existing VM
   1.132      def getVMInfo(self, vm_name):
   1.133 @@ -476,16 +505,6 @@
   1.134          props = dict((k.strip().strip('"'),v.strip().strip('"')) for k,v in (line.split('=', 1) for line in results.splitlines()))
   1.135          return props
   1.136      
   1.137 -    # return the configured USB filter for an existing VM 
   1.138 -    def getUSBFilter(self, vm_name):
   1.139 -        props = self.getVMInfo(vm_name)
   1.140 -        keys = set(['USBFilterVendorId1', 'USBFilterProductId1', 'USBFilterRevision1'])
   1.141 -        keyset = set(props.keys())
   1.142 -        usb_filter = None
   1.143 -        if keyset.issuperset(keys):
   1.144 -            usb_filter = USBFilter(props['USBFilterVendorId1'], props['USBFilterProductId1'], props['USBFilterRevision1'])
   1.145 -        return usb_filter
   1.146 -    
   1.147      #generates ISO containing authorized_keys for use with guest VM
   1.148      def genCertificateISO(self, vm_name):
   1.149          machineFolder = Cygwin.cygPath(self.machineFolder)
   1.150 @@ -772,8 +791,8 @@
   1.151                  
   1.152  class DeviceHandler(threading.Thread): 
   1.153      vmm = None
   1.154 +    existingRSDs = None
   1.155      attachedRSDs = None  
   1.156 -    connectedRSDs = None
   1.157      running = True
   1.158      def __init__(self, vmmanger): 
   1.159          threading.Thread.__init__(self)
   1.160 @@ -783,51 +802,63 @@
   1.161          self.running = False
   1.162          
   1.163      def run(self):
   1.164 -        self.connectedRSDs = dict()
   1.165 +        self.existingRSDs = self.vmm.getExistingRSDs()
   1.166 +        self.attachedRSDs = self.vmm.getAttachedRSDs()
   1.167          
   1.168          while self.running:
   1.169 -            tmp_rsds = self.vmm.getConnectedRSDS()
   1.170 -            
   1.171 -            self.attachedRSDs = self.vmm.getAttachedRSDs()
   1.172 +            tmp_rsds = self.vmm.getExistingRSDs()
   1.173              for vm_name in self.attachedRSDs.keys():
   1.174                  if self.attachedRSDs[vm_name] not in tmp_rsds.values():
   1.175                      drive = self.vmm.getNetworkDrive(vm_name)
   1.176 -                    if drive == None:
   1.177 -                        logger.error("Error getting SDVM's network drive letter.")
   1.178 -                        continue
   1.179                      try:
   1.180 -                        result = urllib2.urlopen('http://127.0.0.1:8090/netumount?'+'drive_letter='+drive).readline()
   1.181 +                        if drive != None:
   1.182 +                            result = urllib2.urlopen('http://127.0.0.1:8090/netumount?'+'drive_letter='+drive).readline()
   1.183 +                        else:
   1.184 +                            logger.error("Error getting SDVM's network drive letter.")
   1.185                      except urllib2.URLError:
   1.186                          logger.error("Network drive disconnect failed. OpenSecurity Tray client not running.")
   1.187                          continue
   1.188 -                    self.vmm.detachRSD(vm_name)
   1.189 +                    
   1.190 +                    # detach not necessary as already removed from vm description upon disconnect
   1.191 +                    #self.vmm.detachRSD(vm_name, self.attachedRSDs[vm_name])
   1.192 +                    del self.attachedRSDs[vm_name]
   1.193                      self.vmm.poweroffVM(vm_name)
   1.194                      self.vmm.removeVM(vm_name)
   1.195                      break
   1.196                      
   1.197 -                    
   1.198 -            if tmp_rsds.keys() == self.connectedRSDs.keys():
   1.199 +            if tmp_rsds.keys() == self.existingRSDs.keys():
   1.200                  logger.debug("Nothing's changed. sleep(3)")
   1.201                  time.sleep(3)
   1.202                  continue
   1.203              
   1.204              logger.info("Something's changed")          
   1.205 -            self.connectedRSDs = tmp_rsds
   1.206 +            self.existingRSDs = tmp_rsds
   1.207             
   1.208              #create new vm for attached device if any
   1.209 -            self.attachedRSDs = self.vmm.getAttachedRSDs()
   1.210 -            self.connectedRSDs = self.vmm.getConnectedRSDS()
   1.211 +            #self.attachedRSDs = self.vmm.getAttachedRSDs()
   1.212 +            #self.connectedRSDs = self.vmm.getExistingRSDs()
   1.213              
   1.214              new_ip = None
   1.215 -            for connected_device in self.connectedRSDs.values():
   1.216 -                if (self.attachedRSDs and False) or (connected_device not in self.attachedRSDs.values()):
   1.217 +            for new_device in self.existingRSDs.values():
   1.218 +                if (self.attachedRSDs and False) or (new_device not in self.attachedRSDs.values()):
   1.219                      new_sdvm = self.vmm.newSDVM()
   1.220                      self.vmm.storageAttach(new_sdvm)
   1.221 -                    self.vmm.attachRSD(new_sdvm, connected_device)
   1.222                      self.vmm.startVM(new_sdvm)
   1.223                      new_ip = self.vmm.waitStartup(new_sdvm)
   1.224                      if new_ip == None:
   1.225 -                        logger.error("Error getting IP address of SDVM.")
   1.226 +                        logger.error("Error getting IP address of SDVM. Cleaning up.")
   1.227 +                        self.vmm.poweroffVM(new_sdvm)
   1.228 +                        self.vmm.removeVM(new_sdvm)
   1.229 +                        continue
   1.230 +                    else:
   1.231 +                        logger.info("Got IP address for " + new_sdvm + ' ' + new_ip)
   1.232 +                    try:
   1.233 +                        self.vmm.attachRSD(new_sdvm, new_device)
   1.234 +                        self.attachedRSDs[new_sdvm] = new_device
   1.235 +                    except:
   1.236 +                        logger.info("RSD prematurely removed. Cleaning up.")
   1.237 +                        self.vmm.poweroffVM(new_sdvm)
   1.238 +                        self.vmm.removeVM(new_sdvm)
   1.239                          continue
   1.240                      drive = self.vmm.genNetworkDrive()
   1.241                      if drive == None:
   1.242 @@ -837,7 +868,9 @@
   1.243                          net_resource = '\\\\' + new_ip + '\\USB'
   1.244                          result = urllib2.urlopen('http://127.0.0.1:8090/netmount?'+'drive_letter='+drive+'&net_resource='+net_resource).readline()
   1.245                      except urllib2.URLError:
   1.246 -                        logger.error("Network drive connect failed. OpenSecurity Tray client not running.")
   1.247 +                        logger.error("Network drive connect failed (tray client not accessible). Cleaning up.")
   1.248 +                        self.vmm.poweroffVM(new_sdvm)
   1.249 +                        self.vmm.removeVM(new_sdvm)
   1.250                          continue
   1.251                          
   1.252