1.1 --- a/OpenSecurity/bin/vmmanager.pyw Fri Feb 21 11:04:04 2014 +0100
1.2 +++ b/OpenSecurity/bin/vmmanager.pyw Wed Feb 26 17:27:07 2014 +0100
1.3 @@ -6,7 +6,6 @@
1.4 import os
1.5 import os.path
1.6 from subprocess import Popen, PIPE, call, STARTUPINFO, _subprocess
1.7 -import subprocess
1.8 import sys
1.9 import re
1.10
1.11 @@ -20,7 +19,8 @@
1.12 import stat
1.13 import tempfile
1.14 from opensecurity_util import logger, setupLogger, OpenSecurityException
1.15 -
1.16 +import ctypes
1.17 +import itertools
1.18 DEBUG = True
1.19
1.20 class VMManagerException(Exception):
1.21 @@ -55,15 +55,14 @@
1.22 startNotifications = list()
1.23 _instance = None
1.24 machineFolder = ''
1.25 - attachedRSDs = None
1.26 - connectedRSDs = None
1.27 + rsdHandler = None
1.28
1.29 def __init__(self):
1.30 self.systemProperties = self.getSystemProperties()
1.31 self.machineFolder = self.systemProperties["Default machine folder"]
1.32 self.cleanup()
1.33 - self.attachedRSDs = self.getAttachedRSDs()
1.34 - self.connectedRSDs = self.getConnectedRSDS()
1.35 + self.rsdHandler = DeviceHandler(self)
1.36 + self.rsdHandler.start()
1.37 return
1.38
1.39 @staticmethod
1.40 @@ -73,8 +72,12 @@
1.41 return VMManager._instance
1.42
1.43 def cleanup(self):
1.44 - self.unmapNetworkDrive('G:')
1.45 - self.unmapNetworkDrive('H:')
1.46 + if self.rsdHandler != None:
1.47 + self.rsdHandler.stop()
1.48 + self.rsdHandler.join()
1.49 + drives = self.getNetworkDrives()
1.50 + for drive in drives.keys():
1.51 + self.unmapNetworkDrive(drive)
1.52 for vm in self.listSDVM():
1.53 self.poweroffVM(vm)
1.54 self.removeVM(vm)
1.55 @@ -83,7 +86,7 @@
1.56 self.startNotifications.append(ip)
1.57
1.58 def isSDVMStarted(self, ip):
1.59 - return self.startNotifications.contains(ip)
1.60 + return ip in self.startNotifications
1.61
1.62 # return hosty system properties
1.63 def getSystemProperties(self):
1.64 @@ -97,14 +100,6 @@
1.65 # return the folder containing the guest VMs
1.66 def getMachineFolder(self):
1.67 return self.machineFolder
1.68 -
1.69 - #list the hostonly IFs exposed by the VBox host
1.70 - def getHostOnlyIFs(self):
1.71 - result = Cygwin.vboxExecute('list hostonlyifs')[1]
1.72 - if result=='':
1.73 - return None
1.74 - props = dict((k.strip(),v.strip().strip('"')) for k,v in (line.split(':', 1) for line in result.strip().splitlines()))
1.75 - return props
1.76
1.77 # list all existing VMs registered with VBox
1.78 def listVM(self):
1.79 @@ -258,13 +253,14 @@
1.80 self.waitStartup('SecurityDVM')
1.81 Cygwin.sshExecute('"sudo apt-get -y update"', VMManager.getHostOnlyIP('SecurityDVM'), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + 'SecurityDVM' + '/dvm_key' )
1.82 Cygwin.sshExecute('"sudo apt-get -y upgrade"', VMManager.getHostOnlyIP('SecurityDVM'), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + 'SecurityDVM' + '/dvm_key' )
1.83 - self.stopVM('SecurityDVM')
1.84 - #self.hibernateVM('SecurityDVM')
1.85 + #self.stopVM('SecurityDVM')
1.86 + self.hibernateVM('SecurityDVM')
1.87 self.waitShutdown('SecurityDVM')
1.88 self.storageDetach('SecurityDVM')
1.89 self.changeStorageType(template_storage,'immutable')
1.90 self.storageAttach('SecurityDVM')
1.91 - self.handleDeviceChange()
1.92 + self.rsdHandler = DeviceHandler(self)
1.93 + self.rsdHandler.start()
1.94
1.95 #remove VM from the system. should be used on VMs returned by listSDVMs
1.96 def removeVM(self, vm_name):
1.97 @@ -295,7 +291,7 @@
1.98 # stop VM
1.99 def hibernateVM(self, vm_name):
1.100 logger.info('Sending shutdown signal to ' + vm_name)
1.101 - Cygwin.sshExecute( '"sudo hibernate-disk"', VMManager.getHostOnlyIP(vm_name), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + vm_name + '/dvm_key' )
1.102 + Cygwin.sshExecute( '"sudo hibernate-disk&"', VMManager.getHostOnlyIP(vm_name), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + vm_name + '/dvm_key', wait_return=False )
1.103
1.104 # poweroff VM
1.105 def poweroffVM(self, vm_name):
1.106 @@ -304,18 +300,31 @@
1.107 logger.info('Powering off ' + vm_name)
1.108 return Cygwin.vboxExecute('controlvm ' + vm_name + ' poweroff')
1.109
1.110 - # return the hostOnly IP for a running guest
1.111 + #list the hostonly IFs exposed by the VBox host
1.112 + @staticmethod
1.113 + def getHostOnlyIFs():
1.114 + result = Cygwin.vboxExecute('list hostonlyifs')[1]
1.115 + if result=='':
1.116 + return None
1.117 + props = dict((k.strip(),v.strip().strip('"')) for k,v in (line.split(':', 1) for line in result.strip().splitlines()))
1.118 + return props
1.119 +
1.120 + # return the hostOnly IP for a running guest or the host
1.121 @staticmethod
1.122 def getHostOnlyIP(vm_name):
1.123 - logger.info('Gettting hostOnly IP address ' + vm_name)
1.124 - result = Cygwin.vboxExecute('guestproperty get ' + vm_name + ' /VirtualBox/GuestInfo/Net/0/V4/IP')
1.125 - if result=='':
1.126 - return None
1.127 - result = result[1]
1.128 - if result.startswith('No value set!'):
1.129 - return None
1.130 - return result[result.index(':')+1:].strip()
1.131 -
1.132 + if vm_name == None:
1.133 + logger.info('Gettting hostOnly IP address for Host')
1.134 + return VMManager.getHostOnlyIFs()['IPAddress']
1.135 + else:
1.136 + logger.info('Gettting hostOnly IP address ' + vm_name)
1.137 + result = Cygwin.vboxExecute('guestproperty get ' + vm_name + ' /VirtualBox/GuestInfo/Net/0/V4/IP')
1.138 + if result=='':
1.139 + return None
1.140 + result = result[1]
1.141 + if result.startswith('No value set!'):
1.142 + return None
1.143 + return result[result.index(':')+1:].strip()
1.144 +
1.145 # attach removable storage device to VM by provision of filter
1.146 def attachRSD(self, vm_name, rsd_filter):
1.147 return Cygwin.vboxExecute('usbfilter add 0 --target ' + vm_name + ' --name OpenSecurityRSD --vendorid ' + rsd_filter.vendorid + ' --productid ' + rsd_filter.productid + ' --revision ' + rsd_filter.revision)
1.148 @@ -370,72 +379,18 @@
1.149 result = Cygwin.vboxExecute('storageattach ' + vm_name + ' --storagectl SATA --port 1 --device 0 --type dvddrive --mtype readonly --medium \"' + self.machineFolder + '\\' + vm_name + '\\'+ vm_name + '.iso\"')
1.150 return result
1.151
1.152 -
1.153 - handleDeviceChangeLock = threading.Lock()
1.154 - trigger = False
1.155 - # handles device change events
1.156 - def handleDeviceChange(self):
1.157 - if VMManager.handleDeviceChangeLock.acquire(True):
1.158 - #logger.debug("triggered")
1.159 - #VMManager.handleDeviceChangeLock.release()
1.160 - #return
1.161 - #destroy unused vms
1.162 - #diff = DictDiffer(self.connectedRSDs, tmp_conn)
1.163 - retry = 0
1.164 - while retry < 30:
1.165 - if self.getConnectedRSDS().keys() == self.connectedRSDs.keys():
1.166 - logger.info("Nothing's changed. Waiting for VBox USB sub-system to update...")
1.167 - else:
1.168 - self.connectedRSDs = self.getConnectedRSDS()
1.169 - break
1.170 - time.sleep(1)
1.171 - retry+=1
1.172 -
1.173 - if retry == 30:
1.174 - VMManager.handleDeviceChangeLock.release()
1.175 - return None
1.176 -
1.177 - logger.info("Something's changed")
1.178 -
1.179 - self.attachedRSDs = self.getAttachedRSDs()
1.180 -
1.181 - for vm_name in self.attachedRSDs.keys():
1.182 - if self.attachedRSDs[vm_name] not in self.connectedRSDs.values():
1.183 - self.unmapNetworkDrive('h:')
1.184 - #self.stopVM(vm_name)
1.185 - self.detachRSD(vm_name)
1.186 - self.poweroffVM(vm_name)
1.187 - self.removeVM(vm_name)
1.188 - #create new vm for attached device if any
1.189 - self.attachedRSDs = self.getAttachedRSDs()
1.190 - self.connectedRSDs = self.getConnectedRSDS()
1.191 -
1.192 - new_ip = None
1.193 - for connected_device in self.connectedRSDs.values():
1.194 - if (self.attachedRSDs and False) or (connected_device not in self.attachedRSDs.values()):
1.195 - new_sdvm = self.generateSDVMName()
1.196 - self.createVM(new_sdvm)
1.197 - self.storageAttach(new_sdvm)
1.198 - self.attachRSD(new_sdvm, connected_device)
1.199 - self.startVM(new_sdvm)
1.200 - new_ip = self.waitStartup(new_sdvm)
1.201 -
1.202 - if new_ip != None:
1.203 - self.mapNetworkDrive('h:', '\\\\' + new_ip + '\\USB', None, None)
1.204 - #TODO: cleanup notifications somwhere else (eg. machine shutdown)
1.205 - self.startNotifications.remove(new_ip)
1.206 - VMManager.handleDeviceChangeLock.release()
1.207 - return new_ip
1.208 -
1.209 # wait for machine to come up
1.210 - def waitStartup(self, vm_name):
1.211 - new_ip = None
1.212 - while new_ip == None:
1.213 - time.sleep(1)
1.214 - new_ip = VMManager.getHostOnlyIP(vm_name)
1.215 - while new_ip not in self.startNotifications:
1.216 - time.sleep(1)
1.217 - return new_ip
1.218 + def waitStartup(self, vm_name, timeout_ms = 30000):
1.219 + #result = Cygwin.vboxExecute('guestproperty wait ' + vm_name + ' /VirtualBox/GuestInfo/Net/0/V4/IP --timeout ' + str(timeout_ms) + ' --fail-on-timeout')
1.220 +
1.221 + result = Cygwin.vboxExecute('guestproperty wait ' + vm_name + ' SDVMStarted --timeout ' + str(timeout_ms) + ' --fail-on-timeout')
1.222 + #new_ip = VMManager.getHostOnlyIP(vm_name)
1.223 + #while new_ip == None:
1.224 + # time.sleep(1)
1.225 + # new_ip = VMManager.getHostOnlyIP(vm_name)
1.226 + #while not self.isSDVMStarted(new_ip):
1.227 + # time.sleep(1)
1.228 + return VMManager.getHostOnlyIP(vm_name)
1.229
1.230 # wait for machine to shutdown
1.231 def waitShutdown(self, vm_name):
1.232 @@ -483,7 +438,7 @@
1.233 logger.info("Path not accessible: " + networkPath + " retrying")
1.234 #return -1
1.235
1.236 - command = 'USE ' + drive + ' ' + networkPath
1.237 + command = 'USE ' + drive + ' ' + networkPath + ' /PERSISTENT:NO'
1.238 if user != None:
1.239 command += ' ' + password + ' /User' + user
1.240
1.241 @@ -495,35 +450,119 @@
1.242 return 1
1.243
1.244 def unmapNetworkDrive(self, drive):
1.245 - if not os.path.exists(drive):
1.246 - return -1
1.247 + drives = self.getNetworkDrives()
1.248 + if drive not in drives.keys():
1.249 + return 1
1.250 result = Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE ' + drive + ' /DELETE /YES')
1.251 - if string.find(str(result), 'successfully',) == -1:
1.252 + if string.find(str(result[1]), 'successfully',) == -1:
1.253 logger.error(result[2])
1.254 return -1
1.255 return 1
1.256 +
1.257 + def getNetworkDrives(self):
1.258 + ip = VMManager.getHostOnlyIP(None)
1.259 + ip = ip[:ip.rindex('.')]
1.260 + drives = dict()
1.261 + result = Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE')
1.262 + for line in result[1].splitlines():
1.263 + if ip in line:
1.264 + parts = line.split()
1.265 + drives[parts[1]] = parts[2]
1.266 + return drives
1.267 +
1.268 + def genNetworkDrive(self):
1.269 + network_drives = self.getNetworkDrives()
1.270 + logical_drives = self.getLogicalDrives()
1.271 + drives = list(map(chr, range(68, 91)))
1.272 + for drive in drives:
1.273 + if drive+':' not in network_drives and drive not in logical_drives:
1.274 + return drive+':'
1.275
1.276 + def getNetworkDrive(self, vm_name):
1.277 + ip = self.getHostOnlyIP(vm_name)
1.278 + result = Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE')
1.279 + for line in result[1].splitlines():
1.280 + if ip in line:
1.281 + parts = line.split()
1.282 + return parts[0]
1.283 +
1.284 + def getLogicalDrives(self):
1.285 + drive_bitmask = ctypes.cdll.kernel32.GetLogicalDrives()
1.286 + return list(itertools.compress(string.ascii_uppercase, map(lambda x:ord(x) - ord('0'), bin(drive_bitmask)[:1:-1])))
1.287 +
1.288 + #vms = self.listSDVM()
1.289 + #for vm in vms:
1.290 + # ip = self.getHostOnlyIP(vm)
1.291 +
1.292 class DeviceHandler(threading.Thread):
1.293 vmm = None
1.294 - triggered = False
1.295 - def __init__(self, zahl):
1.296 - threading.Thread.__init__(self)
1.297 - self.vmm = None
1.298 + #handleDeviceChangeLock = threading.Lock()
1.299 + attachedRSDs = None
1.300 + connectedRSDs = None
1.301 + running = True
1.302 + def __init__(self, vmmanger):
1.303 + threading.Thread.__init__(self)
1.304 + self.vmm = vmmanger
1.305
1.306 + def stop(self):
1.307 + self.running = False
1.308 +
1.309 def run(self):
1.310 - while True:
1.311 - if self.triggered:
1.312 - logger.debug("triggered")
1.313 - triggered = False
1.314 - else:
1.315 - time.sleep(1)
1.316 + self.connectedRSDs = dict()#self.vmm.getConnectedRSDS()
1.317 + self.attachedRSDs = self.vmm.getAttachedRSDs()
1.318 + while self.running:
1.319 + tmp_rsds = self.vmm.getConnectedRSDS()
1.320 + if tmp_rsds.keys() == self.connectedRSDs.keys():
1.321 + logger.debug("Nothing's changed. sleep(3)")
1.322 + time.sleep(3)
1.323 + continue
1.324 +
1.325 + logger.info("Something's changed")
1.326 +
1.327 + self.connectedRSDs = tmp_rsds
1.328 + self.attachedRSDs = self.vmm.getAttachedRSDs()
1.329 +
1.330 +
1.331 + for vm_name in self.attachedRSDs.keys():
1.332 + if self.attachedRSDs[vm_name] not in self.connectedRSDs.values():
1.333 + drive = self.vmm.getNetworkDrive(vm_name)
1.334 + self.vmm.unmapNetworkDrive(drive)
1.335 + #self.stopVM(vm_name)
1.336 + self.vmm.detachRSD(vm_name)
1.337 + self.vmm.poweroffVM(vm_name)
1.338 + self.vmm.removeVM(vm_name)
1.339 + #create new vm for attached device if any
1.340 + self.attachedRSDs = self.vmm.getAttachedRSDs()
1.341 + self.connectedRSDs = self.vmm.getConnectedRSDS()
1.342 +
1.343 + new_ip = None
1.344 + for connected_device in self.connectedRSDs.values():
1.345 + if (self.attachedRSDs and False) or (connected_device not in self.attachedRSDs.values()):
1.346 + new_sdvm = self.vmm.generateSDVMName()
1.347 + self.vmm.createVM(new_sdvm)
1.348 + self.vmm.storageAttach(new_sdvm)
1.349 + self.vmm.attachRSD(new_sdvm, connected_device)
1.350 + self.vmm.startVM(new_sdvm)
1.351 + new_ip = self.vmm.waitStartup(new_sdvm)
1.352 + drive = self.vmm.genNetworkDrive()
1.353 + if new_ip != None:
1.354 + self.vmm.mapNetworkDrive(drive, '\\\\' + new_ip + '\\USB', None, None)
1.355 + #TODO: cleanup notifications somwhere else (eg. machine shutdown)
1.356 + self.vmm.startNotifications.remove(new_ip)
1.357 + #self.handleDeviceChangeLock.release()
1.358
1.359
1.360 if __name__ == '__main__':
1.361 - man = VMManager.getInstance()
1.362 + #man = VMManager.getInstance()
1.363 #man.listVM()
1.364 - print man.getConnectedRSDs()
1.365 + #print man.getConnectedRSDs()
1.366 + #print man.getNetworkDrives()
1.367 + #man.genNetworkDrive()
1.368 + drive_bitmask = ctypes.cdll.kernel32.GetLogicalDrives()
1.369 + print list(itertools.compress(string.ascii_uppercase, map(lambda x:ord(x) - ord('0'), bin(drive_bitmask)[:1:-1])))
1.370 + #print list(map(chr, range(68, 91)))
1.371
1.372 + #time.sleep(-1)
1.373 #man.listVM()
1.374 #man.listVM()
1.375 #man.listVM()
1.376 @@ -531,7 +570,7 @@
1.377 #man.genCertificateISO('SecurityDVM0')
1.378 #man.guestExecute('SecurityDVM0', '/bin/ls -la')
1.379 #logger = setupLogger('VMManager')
1.380 - c = Cygwin()
1.381 + #c = Cygwin()
1.382
1.383 #man.sshExecute('/bin/ls -la', 'SecurityDVM0')
1.384 #man.sshExecuteX11('/usr/bin/iceweasel', 'SecurityDVM0')