changed the RSD attachment handling
authorBarthaM@N3SIM1218.D03.arc.local
Mon, 02 Jun 2014 17:08:11 +0100
changeset 1723d2812a07881
parent 171 2701e921bf4c
child 173 0659c6521fdc
changed the RSD attachment handling
TODO: device blacklist functionality
OpenSecurity/bin/opensecurityd.pyw
OpenSecurity/bin/vmmanager.pyw
     1.1 --- a/OpenSecurity/bin/opensecurityd.pyw	Fri May 23 15:04:52 2014 +0100
     1.2 +++ b/OpenSecurity/bin/opensecurityd.pyw	Mon Jun 02 17:08:11 2014 +0100
     1.3 @@ -329,7 +329,7 @@
     1.4  class os_setup:
     1.5      """OpenSecurity '/setup' handler
     1.6      
     1.7 -    - GET: Give user some info how to setup the OpenSecurity envvironment
     1.8 +    - GET: Give user some info how to setup the OpenSecurity environment
     1.9      """
    1.10      
    1.11      def GET(self):
     2.1 --- a/OpenSecurity/bin/vmmanager.pyw	Fri May 23 15:04:52 2014 +0100
     2.2 +++ b/OpenSecurity/bin/vmmanager.pyw	Mon Jun 02 17:08:11 2014 +0100
     2.3 @@ -38,24 +38,28 @@
     2.4          return repr(self.value)
     2.5  
     2.6  class USBFilter:
     2.7 +    uuid = ""
     2.8      vendorid = ""
     2.9      productid = ""
    2.10      revision = ""
    2.11 +    serial = ""
    2.12      
    2.13 -    def __init__(self, vendorid, productid, revision):
    2.14 +    def __init__(self, uuid, vendorid, productid, revision, serial):
    2.15 +        self.uuid = uuid
    2.16          self.vendorid = vendorid.lower()
    2.17          self.productid = productid.lower()
    2.18          self.revision = revision.lower()
    2.19 +        self.serial = serial
    2.20          return
    2.21      
    2.22      def __eq__(self, other):
    2.23 -        return self.vendorid == other.vendorid and self.productid == other.productid and self.revision == other.revision
    2.24 +        return self.uuid == other.uuid #self.vendorid == other.vendorid and self.productid == other.productid and self.revision == other.revision
    2.25      
    2.26      def __hash__(self):
    2.27 -        return hash(self.vendorid) ^ hash(self.productid) ^ hash(self.revision)
    2.28 +        return hash(self.uuid) ^ hash(self.vendorid) ^ hash(self.productid) ^ hash(self.revision) ^ hash(self.serial)
    2.29      
    2.30      def __repr__(self):
    2.31 -        return "VendorId = \'" + str(self.vendorid) + "\' ProductId = \'" + str(self.productid) + "\' Revision = \'" + str(self.revision) + "\'"
    2.32 +        return "UUID:" + str(self.uuid) + " VendorId = \'" + str(self.vendorid) + "\' ProductId = \'" + str(self.productid) + "\'" + "\' Revision = \'" + str(self.revision) + "\' SerialNumber = \'" + str(self.serial)
    2.33      
    2.34      #def __getitem__(self, item):
    2.35      #    return self.coords[item]
    2.36 @@ -221,7 +225,7 @@
    2.37      
    2.38      # return the RSDs connected to the host
    2.39      @staticmethod
    2.40 -    def getConnectedRSDS():
    2.41 +    def getExistingRSDs():
    2.42          results = Cygwin.checkResult(Cygwin.vboxExecute('list usbhost'))[1]
    2.43          results = results.split('Host USB Devices:')[1].strip()
    2.44          
    2.45 @@ -229,31 +233,64 @@
    2.46          rsds = dict()   
    2.47          for item in items:
    2.48              props = dict()
    2.49 -            for line in item.splitlines():
    2.50 +            for line in item.splitlines():     
    2.51                  if line != "":         
    2.52                      k,v = line[:line.index(':')].strip(), line[line.index(':')+1:].strip()
    2.53                      props[k] = v
    2.54              
    2.55 -            #if 'Product' in props.keys() and props['Product'] == 'Mass Storage':
    2.56 -            
    2.57 -            usb_filter = USBFilter( re.search(r"\((?P<vid>[0-9A-Fa-f]+)\)", props['VendorId']).groupdict()['vid'], 
    2.58 -                                    re.search(r"\((?P<pid>[0-9A-Fa-f]+)\)", props['ProductId']).groupdict()['pid'],
    2.59 -                                    re.search(r"\((?P<rev>[0-9A-Fa-f]+)\)", props['Revision']).groupdict()['rev'] )
    2.60 +            uuid = re.search(r"(?P<uuid>[0-9A-Fa-f\-]+)", props['UUID']).groupdict()['uuid']
    2.61 +            vid = re.search(r"\((?P<vid>[0-9A-Fa-f]+)\)", props['VendorId']).groupdict()['vid']
    2.62 +            pid = re.search(r"\((?P<pid>[0-9A-Fa-f]+)\)", props['ProductId']).groupdict()['pid']
    2.63 +            rev = re.search(r"\((?P<rev>[0-9A-Fa-f]+)\)", props['Revision']).groupdict()['rev']
    2.64 +            serial = None
    2.65 +            if 'SerialNumber' in props.keys():
    2.66 +                serial = re.search(r"(?P<ser>[0-9A-Fa-f]+)", props['SerialNumber']).groupdict()['ser']
    2.67 +            usb_filter = USBFilter( uuid, vid, pid, rev, serial) 
    2.68              if VMManager.isMassStorageDevice(usb_filter):
    2.69 -                rsds[props['UUID']] = usb_filter;
    2.70 +                rsds[uuid] = usb_filter
    2.71                  logger.debug(usb_filter)
    2.72          return rsds
    2.73      
    2.74 +   
    2.75 +    #def getAttachedRSD(self, vm_name):
    2.76 +    #    props = self.getVMInfo(vm_name)
    2.77 +    #    keys = set(['USBFilterVendorId1', 'USBFilterProductId1', 'USBFilterRevision1', 'USBFilterSerialNumber1'])
    2.78 +    #    keyset = set(props.keys())
    2.79 +    #    usb_filter = None
    2.80 +    #    if keyset.issuperset(keys):
    2.81 +    #        usb_filter = USBFilter(props['USBFilterVendorId1'], props['USBFilterProductId1'], props['USBFilterRevision1'])
    2.82 +    #    return usb_filter
    2.83 +    
    2.84 +    # return the attached USB device as usb descriptor for an existing VM 
    2.85 +    def getAttachedRSD(self, vm_name):
    2.86 +        props = self.getVMInfo(vm_name)
    2.87 +        keys = set(['USBAttachedUUID1', 'USBAttachedVendorId1', 'USBAttachedProductId1', 'USBAttachedRevision1', 'USBAttachedSerialNumber1'])
    2.88 +        keyset = set(props.keys())
    2.89 +        usb_filter = None
    2.90 +        if keyset.issuperset(keys):
    2.91 +            usb_filter = USBFilter(props['USBAttachedUUID1'], props['USBAttachedVendorId1'], props['USBAttachedProductId1'], props['USBAttachedRevision1'], props['USBAttachedSerialNumber1'])
    2.92 +        return usb_filter
    2.93 +        
    2.94      # return the RSDs attached to all existing SDVMs
    2.95      def getAttachedRSDs(self):
    2.96          vms = self.listSDVM()
    2.97          attached_devices = dict()
    2.98          for vm in vms:
    2.99 -            rsd_filter = self.getUSBFilter(vm)
   2.100 +            rsd_filter = self.getAttachedRSD(vm)
   2.101              if rsd_filter != None:
   2.102                  attached_devices[vm] = rsd_filter
   2.103          return attached_devices
   2.104      
   2.105 +    # attach removable storage device to VM by provision of filter
   2.106 +    def attachRSD(self, vm_name, rsd_filter):
   2.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))
   2.108 +        return Cygwin.checkResult(Cygwin.vboxExecute('controlvm ' + vm_name + ' usbattach ' + rsd_filter.uuid ))
   2.109 +    
   2.110 +    # detach removable storage from VM by 
   2.111 +    def detachRSD(self, vm_name, rsd_filter):
   2.112 +        #return Cygwin.checkResult(Cygwin.vboxExecute('usbfilter remove 0 --target ' + vm_name))
   2.113 +        return Cygwin.checkResult(Cygwin.vboxExecute('controlvm ' + vm_name + ' usbdetach ' + rsd_filter.uuid ))
   2.114 +        
   2.115      # configures hostonly networking and DHCP server. requires admin rights
   2.116      def configureHostNetworking(self):
   2.117          #cmd = 'vboxmanage list hostonlyifs'
   2.118 @@ -461,14 +498,6 @@
   2.119              if result.startswith('No value set!'):
   2.120                  return None
   2.121              return result[result.index(':')+1:].strip()
   2.122 -            
   2.123 -    # attach removable storage device to VM by provision of filter
   2.124 -    def attachRSD(self, vm_name, rsd_filter):
   2.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))
   2.126 -    
   2.127 -    # detach removable storage from VM by 
   2.128 -    def detachRSD(self, vm_name):
   2.129 -        return Cygwin.checkResult(Cygwin.vboxExecute('usbfilter remove 0 --target ' + vm_name))
   2.130          
   2.131      # return the description set for an existing VM
   2.132      def getVMInfo(self, vm_name):
   2.133 @@ -476,16 +505,6 @@
   2.134          props = dict((k.strip().strip('"'),v.strip().strip('"')) for k,v in (line.split('=', 1) for line in results.splitlines()))
   2.135          return props
   2.136      
   2.137 -    # return the configured USB filter for an existing VM 
   2.138 -    def getUSBFilter(self, vm_name):
   2.139 -        props = self.getVMInfo(vm_name)
   2.140 -        keys = set(['USBFilterVendorId1', 'USBFilterProductId1', 'USBFilterRevision1'])
   2.141 -        keyset = set(props.keys())
   2.142 -        usb_filter = None
   2.143 -        if keyset.issuperset(keys):
   2.144 -            usb_filter = USBFilter(props['USBFilterVendorId1'], props['USBFilterProductId1'], props['USBFilterRevision1'])
   2.145 -        return usb_filter
   2.146 -    
   2.147      #generates ISO containing authorized_keys for use with guest VM
   2.148      def genCertificateISO(self, vm_name):
   2.149          machineFolder = Cygwin.cygPath(self.machineFolder)
   2.150 @@ -772,8 +791,8 @@
   2.151                  
   2.152  class DeviceHandler(threading.Thread): 
   2.153      vmm = None
   2.154 +    existingRSDs = None
   2.155      attachedRSDs = None  
   2.156 -    connectedRSDs = None
   2.157      running = True
   2.158      def __init__(self, vmmanger): 
   2.159          threading.Thread.__init__(self)
   2.160 @@ -783,51 +802,63 @@
   2.161          self.running = False
   2.162          
   2.163      def run(self):
   2.164 -        self.connectedRSDs = dict()
   2.165 +        self.existingRSDs = self.vmm.getExistingRSDs()
   2.166 +        self.attachedRSDs = self.vmm.getAttachedRSDs()
   2.167          
   2.168          while self.running:
   2.169 -            tmp_rsds = self.vmm.getConnectedRSDS()
   2.170 -            
   2.171 -            self.attachedRSDs = self.vmm.getAttachedRSDs()
   2.172 +            tmp_rsds = self.vmm.getExistingRSDs()
   2.173              for vm_name in self.attachedRSDs.keys():
   2.174                  if self.attachedRSDs[vm_name] not in tmp_rsds.values():
   2.175                      drive = self.vmm.getNetworkDrive(vm_name)
   2.176 -                    if drive == None:
   2.177 -                        logger.error("Error getting SDVM's network drive letter.")
   2.178 -                        continue
   2.179                      try:
   2.180 -                        result = urllib2.urlopen('http://127.0.0.1:8090/netumount?'+'drive_letter='+drive).readline()
   2.181 +                        if drive != None:
   2.182 +                            result = urllib2.urlopen('http://127.0.0.1:8090/netumount?'+'drive_letter='+drive).readline()
   2.183 +                        else:
   2.184 +                            logger.error("Error getting SDVM's network drive letter.")
   2.185                      except urllib2.URLError:
   2.186                          logger.error("Network drive disconnect failed. OpenSecurity Tray client not running.")
   2.187                          continue
   2.188 -                    self.vmm.detachRSD(vm_name)
   2.189 +                    
   2.190 +                    # detach not necessary as already removed from vm description upon disconnect
   2.191 +                    #self.vmm.detachRSD(vm_name, self.attachedRSDs[vm_name])
   2.192 +                    del self.attachedRSDs[vm_name]
   2.193                      self.vmm.poweroffVM(vm_name)
   2.194                      self.vmm.removeVM(vm_name)
   2.195                      break
   2.196                      
   2.197 -                    
   2.198 -            if tmp_rsds.keys() == self.connectedRSDs.keys():
   2.199 +            if tmp_rsds.keys() == self.existingRSDs.keys():
   2.200                  logger.debug("Nothing's changed. sleep(3)")
   2.201                  time.sleep(3)
   2.202                  continue
   2.203              
   2.204              logger.info("Something's changed")          
   2.205 -            self.connectedRSDs = tmp_rsds
   2.206 +            self.existingRSDs = tmp_rsds
   2.207             
   2.208              #create new vm for attached device if any
   2.209 -            self.attachedRSDs = self.vmm.getAttachedRSDs()
   2.210 -            self.connectedRSDs = self.vmm.getConnectedRSDS()
   2.211 +            #self.attachedRSDs = self.vmm.getAttachedRSDs()
   2.212 +            #self.connectedRSDs = self.vmm.getExistingRSDs()
   2.213              
   2.214              new_ip = None
   2.215 -            for connected_device in self.connectedRSDs.values():
   2.216 -                if (self.attachedRSDs and False) or (connected_device not in self.attachedRSDs.values()):
   2.217 +            for new_device in self.existingRSDs.values():
   2.218 +                if (self.attachedRSDs and False) or (new_device not in self.attachedRSDs.values()):
   2.219                      new_sdvm = self.vmm.newSDVM()
   2.220                      self.vmm.storageAttach(new_sdvm)
   2.221 -                    self.vmm.attachRSD(new_sdvm, connected_device)
   2.222                      self.vmm.startVM(new_sdvm)
   2.223                      new_ip = self.vmm.waitStartup(new_sdvm)
   2.224                      if new_ip == None:
   2.225 -                        logger.error("Error getting IP address of SDVM.")
   2.226 +                        logger.error("Error getting IP address of SDVM. Cleaning up.")
   2.227 +                        self.vmm.poweroffVM(new_sdvm)
   2.228 +                        self.vmm.removeVM(new_sdvm)
   2.229 +                        continue
   2.230 +                    else:
   2.231 +                        logger.info("Got IP address for " + new_sdvm + ' ' + new_ip)
   2.232 +                    try:
   2.233 +                        self.vmm.attachRSD(new_sdvm, new_device)
   2.234 +                        self.attachedRSDs[new_sdvm] = new_device
   2.235 +                    except:
   2.236 +                        logger.info("RSD prematurely removed. Cleaning up.")
   2.237 +                        self.vmm.poweroffVM(new_sdvm)
   2.238 +                        self.vmm.removeVM(new_sdvm)
   2.239                          continue
   2.240                      drive = self.vmm.genNetworkDrive()
   2.241                      if drive == None:
   2.242 @@ -837,7 +868,9 @@
   2.243                          net_resource = '\\\\' + new_ip + '\\USB'
   2.244                          result = urllib2.urlopen('http://127.0.0.1:8090/netmount?'+'drive_letter='+drive+'&net_resource='+net_resource).readline()
   2.245                      except urllib2.URLError:
   2.246 -                        logger.error("Network drive connect failed. OpenSecurity Tray client not running.")
   2.247 +                        logger.error("Network drive connect failed (tray client not accessible). Cleaning up.")
   2.248 +                        self.vmm.poweroffVM(new_sdvm)
   2.249 +                        self.vmm.removeVM(new_sdvm)
   2.250                          continue
   2.251                          
   2.252