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