1.1 --- a/OpenSecurity/bin/vmmanager.pyw Thu Feb 27 11:39:37 2014 +0100
1.2 +++ b/OpenSecurity/bin/vmmanager.pyw Tue Mar 04 16:54:51 2014 +0100
1.3 @@ -1,598 +1,598 @@
1.4 -'''
1.5 -Created on Nov 19, 2013
1.6 -
1.7 -@author: BarthaM
1.8 -'''
1.9 -import os
1.10 -import os.path
1.11 -from subprocess import Popen, PIPE, call, STARTUPINFO, _subprocess
1.12 -import sys
1.13 -import re
1.14 -
1.15 -from cygwin import Cygwin
1.16 -from environment import Environment
1.17 -import threading
1.18 -import time
1.19 -import string
1.20 -
1.21 -import shutil
1.22 -import stat
1.23 -import tempfile
1.24 -from opensecurity_util import logger, setupLogger, OpenSecurityException
1.25 -import ctypes
1.26 -import itertools
1.27 -DEBUG = True
1.28 -
1.29 -class VMManagerException(Exception):
1.30 - def __init__(self, value):
1.31 - self.value = value
1.32 - def __str__(self):
1.33 - return repr(self.value)
1.34 -
1.35 -class USBFilter:
1.36 - vendorid = ""
1.37 - productid = ""
1.38 - revision = ""
1.39 -
1.40 - def __init__(self, vendorid, productid, revision):
1.41 - self.vendorid = vendorid.lower()
1.42 - self.productid = productid.lower()
1.43 - self.revision = revision.lower()
1.44 - return
1.45 -
1.46 - def __eq__(self, other):
1.47 - return self.vendorid == other.vendorid and self.productid == other.productid and self.revision == other.revision
1.48 -
1.49 - def __hash__(self):
1.50 - return hash(self.vendorid) ^ hash(self.productid) ^ hash(self.revision)
1.51 -
1.52 - def __repr__(self):
1.53 - return "VendorId = \'" + str(self.vendorid) + "\' ProductId = \'" + str(self.productid) + "\' Revision = \'" + str(self.revision) + "\'"
1.54 -
1.55 -class VMManager(object):
1.56 - vmRootName = "SecurityDVM"
1.57 - systemProperties = None
1.58 - _instance = None
1.59 - machineFolder = ''
1.60 - rsdHandler = None
1.61 -
1.62 - def __init__(self):
1.63 - self.systemProperties = self.getSystemProperties()
1.64 - self.machineFolder = self.systemProperties["Default machine folder"]
1.65 - self.cleanup()
1.66 - self.rsdHandler = DeviceHandler(self)
1.67 - self.rsdHandler.start()
1.68 - return
1.69 -
1.70 - @staticmethod
1.71 - def getInstance():
1.72 - if VMManager._instance == None:
1.73 - VMManager._instance = VMManager()
1.74 - return VMManager._instance
1.75 -
1.76 - def cleanup(self):
1.77 - if self.rsdHandler != None:
1.78 - self.rsdHandler.stop()
1.79 - self.rsdHandler.join()
1.80 - drives = self.getNetworkDrives()
1.81 - for drive in drives.keys():
1.82 - self.unmapNetworkDrive(drive)
1.83 - for vm in self.listSDVM():
1.84 - self.poweroffVM(vm)
1.85 - self.removeVM(vm)
1.86 -
1.87 - # return hosty system properties
1.88 - def getSystemProperties(self):
1.89 - result = Cygwin.vboxExecute('list systemproperties')
1.90 - if result[1]=='':
1.91 - return None
1.92 - props = dict((k.strip(),v.strip().strip('"')) for k,v in (line.split(':', 1) for line in result[1].strip().splitlines()))
1.93 - #logger.debug(props)
1.94 - return props
1.95 -
1.96 - # return the folder containing the guest VMs
1.97 - def getMachineFolder(self):
1.98 - return self.machineFolder
1.99 -
1.100 - # list all existing VMs registered with VBox
1.101 - def listVM(self):
1.102 - result = Cygwin.vboxExecute('list vms')[1]
1.103 - vms = list(k.strip().strip('"') for k,_ in (line.split(' ') for line in result.splitlines()))
1.104 - return vms
1.105 -
1.106 - # list running VMs
1.107 - def listRunningVMS(self):
1.108 - result = Cygwin.vboxExecute('list runningvms')[1]
1.109 - vms = list(k.strip().strip('"') for k,_ in (line.split(' ') for line in result.splitlines()))
1.110 - return vms
1.111 -
1.112 - # list existing SDVMs
1.113 - def listSDVM(self):
1.114 - vms = self.listVM()
1.115 - svdms = []
1.116 - for vm in vms:
1.117 - if vm.startswith(self.vmRootName) and vm != self.vmRootName:
1.118 - svdms.append(vm)
1.119 - return svdms
1.120 -
1.121 - # generate valid (not already existing SDVM name). necessary for creating a new VM
1.122 - def generateSDVMName(self):
1.123 - vms = self.listVM()
1.124 - for i in range(0,999):
1.125 - if(not self.vmRootName+str(i) in vms):
1.126 - return self.vmRootName+str(i)
1.127 - return ''
1.128 -
1.129 - # return the RSDs connected to the host
1.130 - def getConnectedRSDS(self):
1.131 - results = Cygwin.vboxExecute('list usbhost')[1]
1.132 - results = results.split('Host USB Devices:')[1].strip()
1.133 -
1.134 - items = list( "UUID:"+result for result in results.split('UUID:') if result != '')
1.135 - rsds = dict()
1.136 - for item in items:
1.137 - props = dict()
1.138 - for line in item.splitlines():
1.139 - if line != "":
1.140 - k,v = line[:line.index(':')].strip(), line[line.index(':')+1:].strip()
1.141 - props[k] = v
1.142 -
1.143 - if 'Product' in props.keys() and props['Product'] == 'Mass Storage':
1.144 - usb_filter = USBFilter( re.search(r"\((?P<vid>[0-9A-Fa-f]+)\)", props['VendorId']).groupdict()['vid'],
1.145 - re.search(r"\((?P<pid>[0-9A-Fa-f]+)\)", props['ProductId']).groupdict()['pid'],
1.146 - re.search(r"\((?P<rev>[0-9A-Fa-f]+)\)", props['Revision']).groupdict()['rev'] )
1.147 - rsds[props['UUID']] = usb_filter;
1.148 - logger.debug(usb_filter)
1.149 - return rsds
1.150 -
1.151 - # return the RSDs attached to all existing SDVMs
1.152 - def getAttachedRSDs(self):
1.153 - vms = self.listSDVM()
1.154 - attached_devices = dict()
1.155 - for vm in vms:
1.156 - rsd_filter = self.getUSBFilter(vm)
1.157 - if rsd_filter != None:
1.158 - attached_devices[vm] = rsd_filter
1.159 - return attached_devices
1.160 -
1.161 - # configures hostonly networking and DHCP server. requires admin rights
1.162 - def configureHostNetworking(self):
1.163 - #cmd = 'vboxmanage list hostonlyifs'
1.164 - #Cygwin.vboxExecute(cmd)
1.165 - #cmd = 'vboxmanage hostonlyif remove \"VirtualBox Host-Only Ethernet Adapter\"'
1.166 - #Cygwin.vboxExecute(cmd)
1.167 - #cmd = 'vboxmanage hostonlyif create'
1.168 - #Cygwin.vboxExecute(cmd)
1.169 - Cygwin.vboxExecute('hostonlyif ipconfig \"VirtualBox Host-Only Ethernet Adapter\" --ip 192.168.56.1 --netmask 255.255.255.0')
1.170 - #cmd = 'vboxmanage dhcpserver add'
1.171 - #Cygwin.vboxExecute(cmd)
1.172 - Cygwin.vboxExecute('dhcpserver modify --ifname \"VirtualBox Host-Only Ethernet Adapter\" --ip 192.168.56.100 --netmask 255.255.255.0 --lowerip 192.168.56.101 --upperip 192.168.56.200')
1.173 -
1.174 - #create new virtual machine instance based on template vm named SecurityDVM (\SecurityDVM\SecurityDVM.vmdk)
1.175 - def createVM(self, vm_name):
1.176 - hostonly_if = self.getHostOnlyIFs()
1.177 - Cygwin.vboxExecute('createvm --name ' + vm_name + ' --ostype Debian --register')
1.178 - Cygwin.vboxExecute('modifyvm ' + vm_name + ' --memory 512 --vram 10 --cpus 1 --usb on --usbehci on --nic1 hostonly --hostonlyadapter1 \"' + hostonly_if['Name'] + '\" --nic2 nat')
1.179 - Cygwin.vboxExecute('storagectl ' + vm_name + ' --name SATA --add sata --portcount 2')
1.180 - return
1.181 -
1.182 - # attach storage image to controller
1.183 - def storageAttach(self, vm_name):
1.184 - if self.isStorageAttached(vm_name):
1.185 - self.storageDetach(vm_name)
1.186 - Cygwin.vboxExecute('storageattach ' + vm_name + ' --storagectl SATA --port 0 --device 0 --type hdd --medium \"'+ self.machineFolder + '\SecurityDVM\SecurityDVM.vmdk\"')
1.187 - return
1.188 -
1.189 - # return true if storage is attached
1.190 - def isStorageAttached(self, vm_name):
1.191 - info = self.getVMInfo(vm_name)
1.192 - return (info['SATA-0-0']!='none')
1.193 -
1.194 - # detach storage from controller
1.195 - def storageDetach(self, vm_name):
1.196 - if self.isStorageAttached(vm_name):
1.197 - Cygwin.vboxExecute('storageattach ' + vm_name + ' --storagectl SATA --port 0 --device 0 --type hdd --medium none')
1.198 - return
1.199 -
1.200 - def changeStorageType(self, filename, storage_type):
1.201 - Cygwin.vboxExecute('modifyhd \"' + filename + '\" --type ' + storage_type)
1.202 - return
1.203 -
1.204 - # list storage snaphots for VM
1.205 - def updateTemplate(self):
1.206 - self.cleanup()
1.207 - self.poweroffVM('SecurityDVM')
1.208 - self.waitShutdown('SecurityDVM')
1.209 -
1.210 - # check for updates
1.211 - self.genCertificateISO('SecurityDVM')
1.212 - self.attachCertificateISO('SecurityDVM')
1.213 -
1.214 - self.storageDetach('SecurityDVM')
1.215 - results = Cygwin.vboxExecute('list hdds')[1]
1.216 - results = results.replace('Parent UUID', 'Parent')
1.217 - items = list( "UUID:"+result for result in results.split('UUID:') if result != '')
1.218 -
1.219 - snaps = dict()
1.220 - for item in items:
1.221 - props = dict()
1.222 - for line in item.splitlines():
1.223 - if line != "":
1.224 - k,v = line[:line.index(':')].strip(), line[line.index(':')+1:].strip()
1.225 - props[k] = v;
1.226 - snaps[props['UUID']] = props
1.227 -
1.228 -
1.229 - template_storage = self.machineFolder + '\SecurityDVM\SecurityDVM.vmdk'
1.230 -
1.231 - # find template uuid
1.232 - template_uuid = ''
1.233 - for hdd in snaps.values():
1.234 - if hdd['Location'] == template_storage:
1.235 - template_uuid = hdd['UUID']
1.236 - logger.debug('found parent uuid ' + template_uuid)
1.237 -
1.238 - # remove snapshots
1.239 - for hdd in snaps.values():
1.240 - if hdd['Parent'] == template_uuid:
1.241 - #template_uuid = hdd['UUID']
1.242 - logger.debug('removing snapshot ' + hdd['UUID'])
1.243 - results = Cygwin.vboxExecute('closemedium disk {' + hdd['UUID'] + '} --delete')[1]
1.244 - # parse result 0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
1.245 -
1.246 - self.changeStorageType(template_storage,'normal')
1.247 - self.storageAttach('SecurityDVM')
1.248 - self.startVM('SecurityDVM')
1.249 - self.waitStartup('SecurityDVM')
1.250 - Cygwin.sshExecute('"sudo apt-get -y update"', VMManager.getHostOnlyIP('SecurityDVM'), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + 'SecurityDVM' + '/dvm_key' )
1.251 - Cygwin.sshExecute('"sudo apt-get -y upgrade"', VMManager.getHostOnlyIP('SecurityDVM'), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + 'SecurityDVM' + '/dvm_key' )
1.252 - #self.stopVM('SecurityDVM')
1.253 - self.hibernateVM('SecurityDVM')
1.254 - self.waitShutdown('SecurityDVM')
1.255 - self.storageDetach('SecurityDVM')
1.256 - self.changeStorageType(template_storage,'immutable')
1.257 - self.storageAttach('SecurityDVM')
1.258 - self.rsdHandler = DeviceHandler(self)
1.259 - self.rsdHandler.start()
1.260 -
1.261 - #remove VM from the system. should be used on VMs returned by listSDVMs
1.262 - def removeVM(self, vm_name):
1.263 - logger.info('Removing ' + vm_name)
1.264 - Cygwin.vboxExecute('unregistervm ' + vm_name + ' --delete')
1.265 - machineFolder = Cygwin.cygPath(self.machineFolder)
1.266 - Cygwin.bashExecute('"/usr/bin/rm -rf ' + machineFolder + '/' + vm_name + '"')
1.267 -
1.268 - # start VM
1.269 - def startVM(self, vm_name):
1.270 - logger.info('Starting ' + vm_name)
1.271 - result = Cygwin.vboxExecute('startvm ' + vm_name + ' --type headless' )
1.272 - while not string.find(str(result), 'successfully started',):
1.273 - logger.error("Failed to start SDVM: " + vm_name + " retrying")
1.274 - time.sleep(1)
1.275 - result = Cygwin.vboxExecute('startvm ' + vm_name + ' --type headless')
1.276 - return result[0]
1.277 -
1.278 - # return wether VM is running or not
1.279 - def isVMRunning(self, vm_name):
1.280 - return vm_name in self.listRunningVMS()
1.281 -
1.282 - # stop VM
1.283 - def stopVM(self, vm_name):
1.284 - logger.info('Sending shutdown signal to ' + vm_name)
1.285 - Cygwin.sshExecute( '"sudo shutdown -h now"', VMManager.getHostOnlyIP(vm_name), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + vm_name + '/dvm_key' )
1.286 -
1.287 - # stop VM
1.288 - def hibernateVM(self, vm_name):
1.289 - logger.info('Sending shutdown signal to ' + vm_name)
1.290 - Cygwin.sshExecute( '"sudo hibernate-disk&"', VMManager.getHostOnlyIP(vm_name), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + vm_name + '/dvm_key', wait_return=False )
1.291 -
1.292 - # poweroff VM
1.293 - def poweroffVM(self, vm_name):
1.294 - if not self.isVMRunning(vm_name):
1.295 - return
1.296 - logger.info('Powering off ' + vm_name)
1.297 - return Cygwin.vboxExecute('controlvm ' + vm_name + ' poweroff')
1.298 -
1.299 - #list the hostonly IFs exposed by the VBox host
1.300 - @staticmethod
1.301 - def getHostOnlyIFs():
1.302 - result = Cygwin.vboxExecute('list hostonlyifs')[1]
1.303 - if result=='':
1.304 - return None
1.305 - props = dict((k.strip(),v.strip().strip('"')) for k,v in (line.split(':', 1) for line in result.strip().splitlines()))
1.306 - return props
1.307 -
1.308 - # return the hostOnly IP for a running guest or the host
1.309 - @staticmethod
1.310 - def getHostOnlyIP(vm_name):
1.311 - if vm_name == None:
1.312 - logger.info('Gettting hostOnly IP address for Host')
1.313 - return VMManager.getHostOnlyIFs()['IPAddress']
1.314 - else:
1.315 - logger.info('Gettting hostOnly IP address ' + vm_name)
1.316 - result = Cygwin.vboxExecute('guestproperty get ' + vm_name + ' /VirtualBox/GuestInfo/Net/0/V4/IP')
1.317 - if result=='':
1.318 - return None
1.319 - result = result[1]
1.320 - if result.startswith('No value set!'):
1.321 - return None
1.322 - return result[result.index(':')+1:].strip()
1.323 -
1.324 - # attach removable storage device to VM by provision of filter
1.325 - def attachRSD(self, vm_name, rsd_filter):
1.326 - return Cygwin.vboxExecute('usbfilter add 0 --target ' + vm_name + ' --name OpenSecurityRSD --vendorid ' + rsd_filter.vendorid + ' --productid ' + rsd_filter.productid + ' --revision ' + rsd_filter.revision)
1.327 -
1.328 - # detach removable storage from VM by
1.329 - def detachRSD(self, vm_name):
1.330 - return Cygwin.vboxExecute('usbfilter remove 0 --target ' + vm_name )
1.331 -
1.332 -
1.333 - # return the description set for an existing VM
1.334 - def getVMInfo(self, vm_name):
1.335 - results = Cygwin.vboxExecute('showvminfo ' + vm_name + ' --machinereadable')[1]
1.336 - props = dict((k.strip().strip('"'),v.strip().strip('"')) for k,v in (line.split('=', 1) for line in results.splitlines()))
1.337 - #logger.debug(props)
1.338 - return props
1.339 -
1.340 - # return the configured USB filter for an existing VM
1.341 - def getUSBFilter(self, vm_name):
1.342 - props = self.getVMInfo(vm_name)
1.343 - keys = set(['USBFilterVendorId1', 'USBFilterProductId1', 'USBFilterRevision1'])
1.344 - keyset = set(props.keys())
1.345 - usb_filter = None
1.346 - if keyset.issuperset(keys):
1.347 - usb_filter = USBFilter(props['USBFilterVendorId1'], props['USBFilterProductId1'], props['USBFilterRevision1'])
1.348 - return usb_filter
1.349 -
1.350 - #generates ISO containing authorized_keys for use with guest VM
1.351 - def genCertificateISO(self, vm_name):
1.352 - machineFolder = Cygwin.cygPath(self.machineFolder)
1.353 - # remove .ssh folder if exists
1.354 - cmd = '\"/usr/bin/rm -rf \\\"' + machineFolder + '/' + vm_name + '/.ssh\\\"\"'
1.355 - Cygwin.bashExecute(cmd)
1.356 - # remove .ssh folder if exists
1.357 - Cygwin.bashExecute('\"/usr/bin/rm -rf \\\"' + machineFolder + '/' + vm_name + '/dvm_key\\\"\"')
1.358 - # create .ssh folder in vm_name
1.359 - Cygwin.bashExecute('\"/usr/bin/mkdir -p \\\"' + machineFolder + '/' + vm_name + '/.ssh\\\"\"')
1.360 - # generate dvm_key pair in vm_name / .ssh
1.361 - Cygwin.bashExecute('\"/usr/bin/ssh-keygen -q -t rsa -N \\"\\" -C \\\"' + vm_name + '\\\" -f \\\"' + machineFolder + '/' + vm_name + '/.ssh/dvm_key\\\"\"')
1.362 - # move out private key
1.363 - Cygwin.bashExecute('\"/usr/bin/mv \\\"' + machineFolder + '/' + vm_name + '/.ssh/dvm_key\\\" \\\"' + machineFolder + '/' + vm_name + '\\\"')
1.364 - # set permissions for private key
1.365 - Cygwin.bashExecute('\"/usr/bin/chmod 500 \\\"' + machineFolder + '/' + vm_name + '/dvm_key\\\"\"')
1.366 - # rename public key to authorized_keys
1.367 - Cygwin.bashExecute('\"/usr/bin/mv \\\"' + machineFolder + '/' + vm_name + '/.ssh/dvm_key.pub\\\" \\\"' + machineFolder + '/' + vm_name + '/.ssh/authorized_keys\\\"')
1.368 - # set permissions for authorized_keys
1.369 - Cygwin.bashExecute('\"/usr/bin/chmod 500 \\\"' + machineFolder + '/' + vm_name + '/.ssh/authorized_keys\\\"\"')
1.370 - # generate iso image with .ssh/authorized keys
1.371 - Cygwin.bashExecute('\"/usr/bin/genisoimage -J -R -o \\\"' + machineFolder + '/' + vm_name + '/'+ vm_name + '.iso\\\" \\\"' + machineFolder + '/' + vm_name + '/.ssh\\\"\"')
1.372 -
1.373 - # attaches generated ssh public cert to guest vm
1.374 - def attachCertificateISO(self, vm_name):
1.375 - 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.376 - return result
1.377 -
1.378 - # wait for machine to come up
1.379 - def waitStartup(self, vm_name, timeout_ms = 30000):
1.380 - result = Cygwin.vboxExecute('guestproperty wait ' + vm_name + ' SDVMStarted --timeout ' + str(timeout_ms) + ' --fail-on-timeout')
1.381 - return VMManager.getHostOnlyIP(vm_name)
1.382 -
1.383 - # wait for machine to shutdown
1.384 - def waitShutdown(self, vm_name):
1.385 - while vm_name in self.listRunningVMS():
1.386 - time.sleep(1)
1.387 - return
1.388 -
1.389 - # handles browsing request
1.390 - def handleBrowsingRequest(self):
1.391 - if VMManager.handleDeviceChangeLock.acquire(True):
1.392 - new_sdvm = self.generateSDVMName()
1.393 - self.createVM(new_sdvm)
1.394 - self.storageAttach(new_sdvm)
1.395 - self.genCertificateISO(new_sdvm)
1.396 - self.attachCertificateISO(new_sdvm)
1.397 - self.startVM(new_sdvm)
1.398 - new_ip = self.waitStartup(new_sdvm)
1.399 - if new_ip != None:
1.400 - self.mapNetworkDrive('g:', '\\\\' + new_ip + '\\Download', None, None)
1.401 - #TODO: cleanup notifications somwhere else (eg. machine shutdown)
1.402 - VMManager.handleDeviceChangeLock.release()
1.403 - return new_sdvm
1.404 -
1.405 - #Small function to check the availability of network resource.
1.406 - #def isAvailable(self, path):
1.407 - #return os.path.exists(path)
1.408 - #result = Cygwin.cmdExecute('IF EXIST "' + path + '" echo YES')
1.409 - #return string.find(result[1], 'YES',)
1.410 -
1.411 - #Small function to check if the mention location is a directory
1.412 - def isDirectory(self, path):
1.413 - result = Cygwin.cmdExecute('dir ' + path + ' | FIND ".."')
1.414 - return string.find(result[1], 'DIR',)
1.415 -
1.416 - def mapNetworkDrive(self, drive, networkPath, user, password):
1.417 - self.unmapNetworkDrive(drive)
1.418 - #Check for drive availability
1.419 - if os.path.exists(drive):
1.420 - logger.error("Drive letter is already in use: " + drive)
1.421 - return -1
1.422 - #Check for network resource availability
1.423 - while not os.path.exists(networkPath):
1.424 - time.sleep(1)
1.425 - logger.info("Path not accessible: " + networkPath + " retrying")
1.426 - #return -1
1.427 -
1.428 - command = 'USE ' + drive + ' ' + networkPath + ' /PERSISTENT:NO'
1.429 - if user != None:
1.430 - command += ' ' + password + ' /User' + user
1.431 -
1.432 - #TODO: Execute 'NET USE' command with authentication
1.433 - result = Cygwin.execute('C:\\Windows\\system32\\net.exe', command)
1.434 - if string.find(result[1], 'successfully',) == -1:
1.435 - logger.error("Failed: NET " + command)
1.436 - return -1
1.437 - return 1
1.438 -
1.439 - def unmapNetworkDrive(self, drive):
1.440 - drives = self.getNetworkDrives()
1.441 - if drive not in drives.keys():
1.442 - return 1
1.443 - result = Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE ' + drive + ' /DELETE /YES')
1.444 - if string.find(str(result[1]), 'successfully',) == -1:
1.445 - logger.error(result[2])
1.446 - return -1
1.447 - return 1
1.448 -
1.449 - def getNetworkDrives(self):
1.450 - ip = VMManager.getHostOnlyIP(None)
1.451 - ip = ip[:ip.rindex('.')]
1.452 - drives = dict()
1.453 - result = Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE')
1.454 - for line in result[1].splitlines():
1.455 - if ip in line:
1.456 - parts = line.split()
1.457 - drives[parts[1]] = parts[2]
1.458 - return drives
1.459 -
1.460 - def genNetworkDrive(self):
1.461 - network_drives = self.getNetworkDrives()
1.462 - logical_drives = self.getLogicalDrives()
1.463 - drives = list(map(chr, range(68, 91)))
1.464 - for drive in drives:
1.465 - if drive+':' not in network_drives and drive not in logical_drives:
1.466 - return drive+':'
1.467 -
1.468 - def getNetworkDrive(self, vm_name):
1.469 - ip = self.getHostOnlyIP(vm_name)
1.470 - result = Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE')
1.471 - for line in result[1].splitlines():
1.472 - if ip in line:
1.473 - parts = line.split()
1.474 - return parts[0]
1.475 -
1.476 - def getLogicalDrives(self):
1.477 - drive_bitmask = ctypes.cdll.kernel32.GetLogicalDrives()
1.478 - return list(itertools.compress(string.ascii_uppercase, map(lambda x:ord(x) - ord('0'), bin(drive_bitmask)[:1:-1])))
1.479 -
1.480 - #vms = self.listSDVM()
1.481 - #for vm in vms:
1.482 - # ip = self.getHostOnlyIP(vm)
1.483 -
1.484 -class DeviceHandler(threading.Thread):
1.485 - vmm = None
1.486 - #handleDeviceChangeLock = threading.Lock()
1.487 - attachedRSDs = None
1.488 - connectedRSDs = None
1.489 - running = True
1.490 - def __init__(self, vmmanger):
1.491 - threading.Thread.__init__(self)
1.492 - self.vmm = vmmanger
1.493 -
1.494 - def stop(self):
1.495 - self.running = False
1.496 -
1.497 - def run(self):
1.498 - self.connectedRSDs = dict()#self.vmm.getConnectedRSDS()
1.499 - self.attachedRSDs = self.vmm.getAttachedRSDs()
1.500 - while self.running:
1.501 - tmp_rsds = self.vmm.getConnectedRSDS()
1.502 - if tmp_rsds.keys() == self.connectedRSDs.keys():
1.503 - logger.debug("Nothing's changed. sleep(3)")
1.504 - time.sleep(3)
1.505 - continue
1.506 -
1.507 - logger.info("Something's changed")
1.508 -
1.509 - self.connectedRSDs = tmp_rsds
1.510 - self.attachedRSDs = self.vmm.getAttachedRSDs()
1.511 -
1.512 -
1.513 - for vm_name in self.attachedRSDs.keys():
1.514 - if self.attachedRSDs[vm_name] not in self.connectedRSDs.values():
1.515 - drive = self.vmm.getNetworkDrive(vm_name)
1.516 - self.vmm.unmapNetworkDrive(drive)
1.517 - #self.stopVM(vm_name)
1.518 - self.vmm.detachRSD(vm_name)
1.519 - self.vmm.poweroffVM(vm_name)
1.520 - self.vmm.removeVM(vm_name)
1.521 - #create new vm for attached device if any
1.522 - self.attachedRSDs = self.vmm.getAttachedRSDs()
1.523 - self.connectedRSDs = self.vmm.getConnectedRSDS()
1.524 -
1.525 - new_ip = None
1.526 - for connected_device in self.connectedRSDs.values():
1.527 - if (self.attachedRSDs and False) or (connected_device not in self.attachedRSDs.values()):
1.528 - new_sdvm = self.vmm.generateSDVMName()
1.529 - self.vmm.createVM(new_sdvm)
1.530 - self.vmm.storageAttach(new_sdvm)
1.531 - self.vmm.attachRSD(new_sdvm, connected_device)
1.532 - self.vmm.startVM(new_sdvm)
1.533 - new_ip = self.vmm.waitStartup(new_sdvm)
1.534 - drive = self.vmm.genNetworkDrive()
1.535 - if new_ip != None:
1.536 - self.vmm.mapNetworkDrive(drive, '\\\\' + new_ip + '\\USB', None, None)
1.537 - #TODO: cleanup notifications somwhere else (eg. machine shutdown)
1.538 - #self.handleDeviceChangeLock.release()
1.539 -
1.540 -
1.541 -if __name__ == '__main__':
1.542 - #man = VMManager.getInstance()
1.543 - #man.listVM()
1.544 - #print man.getConnectedRSDs()
1.545 - #print man.getNetworkDrives()
1.546 - #man.genNetworkDrive()
1.547 - drive_bitmask = ctypes.cdll.kernel32.GetLogicalDrives()
1.548 - print list(itertools.compress(string.ascii_uppercase, map(lambda x:ord(x) - ord('0'), bin(drive_bitmask)[:1:-1])))
1.549 - #print list(map(chr, range(68, 91)))
1.550 -
1.551 - #time.sleep(-1)
1.552 - #man.listVM()
1.553 - #man.listVM()
1.554 - #man.listVM()
1.555 - #man.listVM()
1.556 - #man.genCertificateISO('SecurityDVM0')
1.557 - #man.guestExecute('SecurityDVM0', '/bin/ls -la')
1.558 - #logger = setupLogger('VMManager')
1.559 - #c = Cygwin()
1.560 -
1.561 - #man.sshExecute('/bin/ls -la', 'SecurityDVM0')
1.562 - #man.sshExecuteX11('/usr/bin/iceweasel', 'SecurityDVM0')
1.563 - #man.removeVM('SecurityDVM0')
1.564 - #man.netUse('192.168.56.134', 'USB\\')
1.565 - #ip = '192.168.56.139'
1.566 -
1.567 - #man.cygwin_path = 'c:\\cygwin64\\bin\\'
1.568 - #man.handleDeviceChange()
1.569 - #print man.listSDVM()
1.570 - #man.configureHostNetworking()
1.571 - #new_vm = man.generateSDVMName()
1.572 - #man.createVM(new_vm)
1.573 -
1.574 - #print Cygwin.cmd()
1.575 - #man.isAvailable('c:')
1.576 - #ip = man.getHostOnlyIP('SecurityDVM0')
1.577 - #man.mapNetworkDrive('h:', '\\\\' + ip + '\Download', None, None)
1.578 -
1.579 - #man.genCertificateISO(new_vm)
1.580 - #man.attachCertificateISO(new_vm)
1.581 -
1.582 - #man.attachCertificateISO(vm_name)
1.583 - #man.guestExecute(vm_name, "ls")
1.584 - #man.sshGuestX11Execute('SecurityDVM1', '/usr/bin/iceweasel')
1.585 - #time.sleep(60)
1.586 - #print man.cygwinPath("C:\Users\BarthaM\VirtualBox VMs\SecurityDVM\.ssh\*")
1.587 - #man.genCertificateISO('SecurityDVM')
1.588 - #man.attachCertificateISO('SecurityDVM')
1.589 - #man.isStorageAttached('SecurityDVM')
1.590 - #man.guestExecute('SecurityDVM', 'sudo apt-get -y update')
1.591 - #man.guestExecute('SecurityDVM', 'sudo apt-get -y upgrade' )
1.592 -
1.593 - #man.stopVM('SecurityDVM')
1.594 - #man.storageDetach('SecurityDVM')
1.595 - #man.changeStorageType('C:\Users\BarthaM\VirtualBox VMs\SecurityDVM\SecurityDVM.vmdk','immutable')
1.596 - #man.storageAttach('SecurityDVM')
1.597 -
1.598 -
1.599 - #cmd = "c:\\cygwin64\\bin\\bash.exe --login -c \"/bin/ls\""
1.600 - #man.execute(cmd)
1.601 -
1.602 +'''
1.603 +Created on Nov 19, 2013
1.604 +
1.605 +@author: BarthaM
1.606 +'''
1.607 +import os
1.608 +import os.path
1.609 +from subprocess import Popen, PIPE, call, STARTUPINFO, _subprocess
1.610 +import sys
1.611 +import re
1.612 +
1.613 +from cygwin import Cygwin
1.614 +from environment import Environment
1.615 +import threading
1.616 +import time
1.617 +import string
1.618 +
1.619 +import shutil
1.620 +import stat
1.621 +import tempfile
1.622 +from opensecurity_util import logger, setupLogger, OpenSecurityException
1.623 +import ctypes
1.624 +import itertools
1.625 +DEBUG = True
1.626 +
1.627 +class VMManagerException(Exception):
1.628 + def __init__(self, value):
1.629 + self.value = value
1.630 + def __str__(self):
1.631 + return repr(self.value)
1.632 +
1.633 +class USBFilter:
1.634 + vendorid = ""
1.635 + productid = ""
1.636 + revision = ""
1.637 +
1.638 + def __init__(self, vendorid, productid, revision):
1.639 + self.vendorid = vendorid.lower()
1.640 + self.productid = productid.lower()
1.641 + self.revision = revision.lower()
1.642 + return
1.643 +
1.644 + def __eq__(self, other):
1.645 + return self.vendorid == other.vendorid and self.productid == other.productid and self.revision == other.revision
1.646 +
1.647 + def __hash__(self):
1.648 + return hash(self.vendorid) ^ hash(self.productid) ^ hash(self.revision)
1.649 +
1.650 + def __repr__(self):
1.651 + return "VendorId = \'" + str(self.vendorid) + "\' ProductId = \'" + str(self.productid) + "\' Revision = \'" + str(self.revision) + "\'"
1.652 +
1.653 +class VMManager(object):
1.654 + vmRootName = "SecurityDVM"
1.655 + systemProperties = None
1.656 + _instance = None
1.657 + machineFolder = ''
1.658 + rsdHandler = None
1.659 +
1.660 + def __init__(self):
1.661 + self.systemProperties = self.getSystemProperties()
1.662 + self.machineFolder = self.systemProperties["Default machine folder"]
1.663 + self.cleanup()
1.664 + self.rsdHandler = DeviceHandler(self)
1.665 + self.rsdHandler.start()
1.666 + return
1.667 +
1.668 + @staticmethod
1.669 + def getInstance():
1.670 + if VMManager._instance == None:
1.671 + VMManager._instance = VMManager()
1.672 + return VMManager._instance
1.673 +
1.674 + def cleanup(self):
1.675 + if self.rsdHandler != None:
1.676 + self.rsdHandler.stop()
1.677 + self.rsdHandler.join()
1.678 + drives = self.getNetworkDrives()
1.679 + for drive in drives.keys():
1.680 + self.unmapNetworkDrive(drive)
1.681 + for vm in self.listSDVM():
1.682 + self.poweroffVM(vm)
1.683 + self.removeVM(vm)
1.684 +
1.685 + # return hosty system properties
1.686 + def getSystemProperties(self):
1.687 + result = Cygwin.vboxExecute('list systemproperties')
1.688 + if result[1]=='':
1.689 + return None
1.690 + props = dict((k.strip(),v.strip().strip('"')) for k,v in (line.split(':', 1) for line in result[1].strip().splitlines()))
1.691 + #logger.debug(props)
1.692 + return props
1.693 +
1.694 + # return the folder containing the guest VMs
1.695 + def getMachineFolder(self):
1.696 + return self.machineFolder
1.697 +
1.698 + # list all existing VMs registered with VBox
1.699 + def listVM(self):
1.700 + result = Cygwin.vboxExecute('list vms')[1]
1.701 + vms = list(k.strip().strip('"') for k,_ in (line.split(' ') for line in result.splitlines()))
1.702 + return vms
1.703 +
1.704 + # list running VMs
1.705 + def listRunningVMS(self):
1.706 + result = Cygwin.vboxExecute('list runningvms')[1]
1.707 + vms = list(k.strip().strip('"') for k,_ in (line.split(' ') for line in result.splitlines()))
1.708 + return vms
1.709 +
1.710 + # list existing SDVMs
1.711 + def listSDVM(self):
1.712 + vms = self.listVM()
1.713 + svdms = []
1.714 + for vm in vms:
1.715 + if vm.startswith(self.vmRootName) and vm != self.vmRootName:
1.716 + svdms.append(vm)
1.717 + return svdms
1.718 +
1.719 + # generate valid (not already existing SDVM name). necessary for creating a new VM
1.720 + def generateSDVMName(self):
1.721 + vms = self.listVM()
1.722 + for i in range(0,999):
1.723 + if(not self.vmRootName+str(i) in vms):
1.724 + return self.vmRootName+str(i)
1.725 + return ''
1.726 +
1.727 + # return the RSDs connected to the host
1.728 + def getConnectedRSDS(self):
1.729 + results = Cygwin.vboxExecute('list usbhost')[1]
1.730 + results = results.split('Host USB Devices:')[1].strip()
1.731 +
1.732 + items = list( "UUID:"+result for result in results.split('UUID:') if result != '')
1.733 + rsds = dict()
1.734 + for item in items:
1.735 + props = dict()
1.736 + for line in item.splitlines():
1.737 + if line != "":
1.738 + k,v = line[:line.index(':')].strip(), line[line.index(':')+1:].strip()
1.739 + props[k] = v
1.740 +
1.741 + if 'Product' in props.keys() and props['Product'] == 'Mass Storage':
1.742 + usb_filter = USBFilter( re.search(r"\((?P<vid>[0-9A-Fa-f]+)\)", props['VendorId']).groupdict()['vid'],
1.743 + re.search(r"\((?P<pid>[0-9A-Fa-f]+)\)", props['ProductId']).groupdict()['pid'],
1.744 + re.search(r"\((?P<rev>[0-9A-Fa-f]+)\)", props['Revision']).groupdict()['rev'] )
1.745 + rsds[props['UUID']] = usb_filter;
1.746 + logger.debug(usb_filter)
1.747 + return rsds
1.748 +
1.749 + # return the RSDs attached to all existing SDVMs
1.750 + def getAttachedRSDs(self):
1.751 + vms = self.listSDVM()
1.752 + attached_devices = dict()
1.753 + for vm in vms:
1.754 + rsd_filter = self.getUSBFilter(vm)
1.755 + if rsd_filter != None:
1.756 + attached_devices[vm] = rsd_filter
1.757 + return attached_devices
1.758 +
1.759 + # configures hostonly networking and DHCP server. requires admin rights
1.760 + def configureHostNetworking(self):
1.761 + #cmd = 'vboxmanage list hostonlyifs'
1.762 + #Cygwin.vboxExecute(cmd)
1.763 + #cmd = 'vboxmanage hostonlyif remove \"VirtualBox Host-Only Ethernet Adapter\"'
1.764 + #Cygwin.vboxExecute(cmd)
1.765 + #cmd = 'vboxmanage hostonlyif create'
1.766 + #Cygwin.vboxExecute(cmd)
1.767 + Cygwin.vboxExecute('hostonlyif ipconfig \"VirtualBox Host-Only Ethernet Adapter\" --ip 192.168.56.1 --netmask 255.255.255.0')
1.768 + #cmd = 'vboxmanage dhcpserver add'
1.769 + #Cygwin.vboxExecute(cmd)
1.770 + Cygwin.vboxExecute('dhcpserver modify --ifname \"VirtualBox Host-Only Ethernet Adapter\" --ip 192.168.56.100 --netmask 255.255.255.0 --lowerip 192.168.56.101 --upperip 192.168.56.200')
1.771 +
1.772 + #create new virtual machine instance based on template vm named SecurityDVM (\SecurityDVM\SecurityDVM.vmdk)
1.773 + def createVM(self, vm_name):
1.774 + hostonly_if = self.getHostOnlyIFs()
1.775 + Cygwin.vboxExecute('createvm --name ' + vm_name + ' --ostype Debian --register')
1.776 + Cygwin.vboxExecute('modifyvm ' + vm_name + ' --memory 512 --vram 10 --cpus 1 --usb on --usbehci on --nic1 hostonly --hostonlyadapter1 \"' + hostonly_if['Name'] + '\" --nic2 nat')
1.777 + Cygwin.vboxExecute('storagectl ' + vm_name + ' --name SATA --add sata --portcount 2')
1.778 + return
1.779 +
1.780 + # attach storage image to controller
1.781 + def storageAttach(self, vm_name):
1.782 + if self.isStorageAttached(vm_name):
1.783 + self.storageDetach(vm_name)
1.784 + Cygwin.vboxExecute('storageattach ' + vm_name + ' --storagectl SATA --port 0 --device 0 --type hdd --medium \"'+ self.machineFolder + '\SecurityDVM\SecurityDVM.vmdk\"')
1.785 + return
1.786 +
1.787 + # return true if storage is attached
1.788 + def isStorageAttached(self, vm_name):
1.789 + info = self.getVMInfo(vm_name)
1.790 + return (info['SATA-0-0']!='none')
1.791 +
1.792 + # detach storage from controller
1.793 + def storageDetach(self, vm_name):
1.794 + if self.isStorageAttached(vm_name):
1.795 + Cygwin.vboxExecute('storageattach ' + vm_name + ' --storagectl SATA --port 0 --device 0 --type hdd --medium none')
1.796 + return
1.797 +
1.798 + def changeStorageType(self, filename, storage_type):
1.799 + Cygwin.vboxExecute('modifyhd \"' + filename + '\" --type ' + storage_type)
1.800 + return
1.801 +
1.802 + # list storage snaphots for VM
1.803 + def updateTemplate(self):
1.804 + self.cleanup()
1.805 + self.poweroffVM('SecurityDVM')
1.806 + self.waitShutdown('SecurityDVM')
1.807 +
1.808 + # check for updates
1.809 + self.genCertificateISO('SecurityDVM')
1.810 + self.attachCertificateISO('SecurityDVM')
1.811 +
1.812 + self.storageDetach('SecurityDVM')
1.813 + results = Cygwin.vboxExecute('list hdds')[1]
1.814 + results = results.replace('Parent UUID', 'Parent')
1.815 + items = list( "UUID:"+result for result in results.split('UUID:') if result != '')
1.816 +
1.817 + snaps = dict()
1.818 + for item in items:
1.819 + props = dict()
1.820 + for line in item.splitlines():
1.821 + if line != "":
1.822 + k,v = line[:line.index(':')].strip(), line[line.index(':')+1:].strip()
1.823 + props[k] = v;
1.824 + snaps[props['UUID']] = props
1.825 +
1.826 +
1.827 + template_storage = self.machineFolder + '\SecurityDVM\SecurityDVM.vmdk'
1.828 +
1.829 + # find template uuid
1.830 + template_uuid = ''
1.831 + for hdd in snaps.values():
1.832 + if hdd['Location'] == template_storage:
1.833 + template_uuid = hdd['UUID']
1.834 + logger.debug('found parent uuid ' + template_uuid)
1.835 +
1.836 + # remove snapshots
1.837 + for hdd in snaps.values():
1.838 + if hdd['Parent'] == template_uuid:
1.839 + #template_uuid = hdd['UUID']
1.840 + logger.debug('removing snapshot ' + hdd['UUID'])
1.841 + results = Cygwin.vboxExecute('closemedium disk {' + hdd['UUID'] + '} --delete')[1]
1.842 + # parse result 0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
1.843 +
1.844 + self.changeStorageType(template_storage,'normal')
1.845 + self.storageAttach('SecurityDVM')
1.846 + self.startVM('SecurityDVM')
1.847 + self.waitStartup('SecurityDVM')
1.848 + Cygwin.sshExecute('"sudo apt-get -y update"', VMManager.getHostOnlyIP('SecurityDVM'), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + 'SecurityDVM' + '/dvm_key' )
1.849 + Cygwin.sshExecute('"sudo apt-get -y upgrade"', VMManager.getHostOnlyIP('SecurityDVM'), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + 'SecurityDVM' + '/dvm_key' )
1.850 + #self.stopVM('SecurityDVM')
1.851 + self.hibernateVM('SecurityDVM')
1.852 + self.waitShutdown('SecurityDVM')
1.853 + self.storageDetach('SecurityDVM')
1.854 + self.changeStorageType(template_storage,'immutable')
1.855 + self.storageAttach('SecurityDVM')
1.856 + self.rsdHandler = DeviceHandler(self)
1.857 + self.rsdHandler.start()
1.858 +
1.859 + #remove VM from the system. should be used on VMs returned by listSDVMs
1.860 + def removeVM(self, vm_name):
1.861 + logger.info('Removing ' + vm_name)
1.862 + Cygwin.vboxExecute('unregistervm ' + vm_name + ' --delete')
1.863 + machineFolder = Cygwin.cygPath(self.machineFolder)
1.864 + Cygwin.bashExecute('"/usr/bin/rm -rf ' + machineFolder + '/' + vm_name + '"')
1.865 +
1.866 + # start VM
1.867 + def startVM(self, vm_name):
1.868 + logger.info('Starting ' + vm_name)
1.869 + result = Cygwin.vboxExecute('startvm ' + vm_name + ' --type headless' )
1.870 + while not string.find(str(result), 'successfully started',):
1.871 + logger.error("Failed to start SDVM: " + vm_name + " retrying")
1.872 + time.sleep(1)
1.873 + result = Cygwin.vboxExecute('startvm ' + vm_name + ' --type headless')
1.874 + return result[0]
1.875 +
1.876 + # return wether VM is running or not
1.877 + def isVMRunning(self, vm_name):
1.878 + return vm_name in self.listRunningVMS()
1.879 +
1.880 + # stop VM
1.881 + def stopVM(self, vm_name):
1.882 + logger.info('Sending shutdown signal to ' + vm_name)
1.883 + Cygwin.sshExecute( '"sudo shutdown -h now"', VMManager.getHostOnlyIP(vm_name), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + vm_name + '/dvm_key' )
1.884 +
1.885 + # stop VM
1.886 + def hibernateVM(self, vm_name):
1.887 + logger.info('Sending shutdown signal to ' + vm_name)
1.888 + Cygwin.sshExecute( '"sudo hibernate-disk&"', VMManager.getHostOnlyIP(vm_name), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + vm_name + '/dvm_key', wait_return=False )
1.889 +
1.890 + # poweroff VM
1.891 + def poweroffVM(self, vm_name):
1.892 + if not self.isVMRunning(vm_name):
1.893 + return
1.894 + logger.info('Powering off ' + vm_name)
1.895 + return Cygwin.vboxExecute('controlvm ' + vm_name + ' poweroff')
1.896 +
1.897 + #list the hostonly IFs exposed by the VBox host
1.898 + @staticmethod
1.899 + def getHostOnlyIFs():
1.900 + result = Cygwin.vboxExecute('list hostonlyifs')[1]
1.901 + if result=='':
1.902 + return None
1.903 + props = dict((k.strip(),v.strip().strip('"')) for k,v in (line.split(':', 1) for line in result.strip().splitlines()))
1.904 + return props
1.905 +
1.906 + # return the hostOnly IP for a running guest or the host
1.907 + @staticmethod
1.908 + def getHostOnlyIP(vm_name):
1.909 + if vm_name == None:
1.910 + logger.info('Gettting hostOnly IP address for Host')
1.911 + return VMManager.getHostOnlyIFs()['IPAddress']
1.912 + else:
1.913 + logger.info('Gettting hostOnly IP address ' + vm_name)
1.914 + result = Cygwin.vboxExecute('guestproperty get ' + vm_name + ' /VirtualBox/GuestInfo/Net/0/V4/IP')
1.915 + if result=='':
1.916 + return None
1.917 + result = result[1]
1.918 + if result.startswith('No value set!'):
1.919 + return None
1.920 + return result[result.index(':')+1:].strip()
1.921 +
1.922 + # attach removable storage device to VM by provision of filter
1.923 + def attachRSD(self, vm_name, rsd_filter):
1.924 + return Cygwin.vboxExecute('usbfilter add 0 --target ' + vm_name + ' --name OpenSecurityRSD --vendorid ' + rsd_filter.vendorid + ' --productid ' + rsd_filter.productid + ' --revision ' + rsd_filter.revision)
1.925 +
1.926 + # detach removable storage from VM by
1.927 + def detachRSD(self, vm_name):
1.928 + return Cygwin.vboxExecute('usbfilter remove 0 --target ' + vm_name )
1.929 +
1.930 +
1.931 + # return the description set for an existing VM
1.932 + def getVMInfo(self, vm_name):
1.933 + results = Cygwin.vboxExecute('showvminfo ' + vm_name + ' --machinereadable')[1]
1.934 + props = dict((k.strip().strip('"'),v.strip().strip('"')) for k,v in (line.split('=', 1) for line in results.splitlines()))
1.935 + #logger.debug(props)
1.936 + return props
1.937 +
1.938 + # return the configured USB filter for an existing VM
1.939 + def getUSBFilter(self, vm_name):
1.940 + props = self.getVMInfo(vm_name)
1.941 + keys = set(['USBFilterVendorId1', 'USBFilterProductId1', 'USBFilterRevision1'])
1.942 + keyset = set(props.keys())
1.943 + usb_filter = None
1.944 + if keyset.issuperset(keys):
1.945 + usb_filter = USBFilter(props['USBFilterVendorId1'], props['USBFilterProductId1'], props['USBFilterRevision1'])
1.946 + return usb_filter
1.947 +
1.948 + #generates ISO containing authorized_keys for use with guest VM
1.949 + def genCertificateISO(self, vm_name):
1.950 + machineFolder = Cygwin.cygPath(self.machineFolder)
1.951 + # remove .ssh folder if exists
1.952 + cmd = '\"/usr/bin/rm -rf \\\"' + machineFolder + '/' + vm_name + '/.ssh\\\"\"'
1.953 + Cygwin.bashExecute(cmd)
1.954 + # remove .ssh folder if exists
1.955 + Cygwin.bashExecute('\"/usr/bin/rm -rf \\\"' + machineFolder + '/' + vm_name + '/dvm_key\\\"\"')
1.956 + # create .ssh folder in vm_name
1.957 + Cygwin.bashExecute('\"/usr/bin/mkdir -p \\\"' + machineFolder + '/' + vm_name + '/.ssh\\\"\"')
1.958 + # generate dvm_key pair in vm_name / .ssh
1.959 + Cygwin.bashExecute('\"/usr/bin/ssh-keygen -q -t rsa -N \\"\\" -C \\\"' + vm_name + '\\\" -f \\\"' + machineFolder + '/' + vm_name + '/.ssh/dvm_key\\\"\"')
1.960 + # move out private key
1.961 + Cygwin.bashExecute('\"/usr/bin/mv \\\"' + machineFolder + '/' + vm_name + '/.ssh/dvm_key\\\" \\\"' + machineFolder + '/' + vm_name + '\\\"')
1.962 + # set permissions for private key
1.963 + Cygwin.bashExecute('\"/usr/bin/chmod 500 \\\"' + machineFolder + '/' + vm_name + '/dvm_key\\\"\"')
1.964 + # rename public key to authorized_keys
1.965 + Cygwin.bashExecute('\"/usr/bin/mv \\\"' + machineFolder + '/' + vm_name + '/.ssh/dvm_key.pub\\\" \\\"' + machineFolder + '/' + vm_name + '/.ssh/authorized_keys\\\"')
1.966 + # set permissions for authorized_keys
1.967 + Cygwin.bashExecute('\"/usr/bin/chmod 500 \\\"' + machineFolder + '/' + vm_name + '/.ssh/authorized_keys\\\"\"')
1.968 + # generate iso image with .ssh/authorized keys
1.969 + Cygwin.bashExecute('\"/usr/bin/genisoimage -J -R -o \\\"' + machineFolder + '/' + vm_name + '/'+ vm_name + '.iso\\\" \\\"' + machineFolder + '/' + vm_name + '/.ssh\\\"\"')
1.970 +
1.971 + # attaches generated ssh public cert to guest vm
1.972 + def attachCertificateISO(self, vm_name):
1.973 + 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.974 + return result
1.975 +
1.976 + # wait for machine to come up
1.977 + def waitStartup(self, vm_name, timeout_ms = 30000):
1.978 + result = Cygwin.vboxExecute('guestproperty wait ' + vm_name + ' SDVMStarted --timeout ' + str(timeout_ms) + ' --fail-on-timeout')
1.979 + return VMManager.getHostOnlyIP(vm_name)
1.980 +
1.981 + # wait for machine to shutdown
1.982 + def waitShutdown(self, vm_name):
1.983 + while vm_name in self.listRunningVMS():
1.984 + time.sleep(1)
1.985 + return
1.986 +
1.987 + # handles browsing request
1.988 + def handleBrowsingRequest(self):
1.989 + if VMManager.handleDeviceChangeLock.acquire(True):
1.990 + new_sdvm = self.generateSDVMName()
1.991 + self.createVM(new_sdvm)
1.992 + self.storageAttach(new_sdvm)
1.993 + self.genCertificateISO(new_sdvm)
1.994 + self.attachCertificateISO(new_sdvm)
1.995 + self.startVM(new_sdvm)
1.996 + new_ip = self.waitStartup(new_sdvm)
1.997 + if new_ip != None:
1.998 + self.mapNetworkDrive('g:', '\\\\' + new_ip + '\\Download', None, None)
1.999 + #TODO: cleanup notifications somwhere else (eg. machine shutdown)
1.1000 + VMManager.handleDeviceChangeLock.release()
1.1001 + return new_sdvm
1.1002 +
1.1003 + #Small function to check the availability of network resource.
1.1004 + #def isAvailable(self, path):
1.1005 + #return os.path.exists(path)
1.1006 + #result = Cygwin.cmdExecute('IF EXIST "' + path + '" echo YES')
1.1007 + #return string.find(result[1], 'YES',)
1.1008 +
1.1009 + #Small function to check if the mention location is a directory
1.1010 + def isDirectory(self, path):
1.1011 + result = Cygwin.cmdExecute('dir ' + path + ' | FIND ".."')
1.1012 + return string.find(result[1], 'DIR',)
1.1013 +
1.1014 + def mapNetworkDrive(self, drive, networkPath, user, password):
1.1015 + self.unmapNetworkDrive(drive)
1.1016 + #Check for drive availability
1.1017 + if os.path.exists(drive):
1.1018 + logger.error("Drive letter is already in use: " + drive)
1.1019 + return -1
1.1020 + #Check for network resource availability
1.1021 + while not os.path.exists(networkPath):
1.1022 + time.sleep(1)
1.1023 + logger.info("Path not accessible: " + networkPath + " retrying")
1.1024 + #return -1
1.1025 +
1.1026 + command = 'USE ' + drive + ' ' + networkPath + ' /PERSISTENT:NO'
1.1027 + if user != None:
1.1028 + command += ' ' + password + ' /User' + user
1.1029 +
1.1030 + #TODO: Execute 'NET USE' command with authentication
1.1031 + result = Cygwin.execute('C:\\Windows\\system32\\net.exe', command)
1.1032 + if string.find(result[1], 'successfully',) == -1:
1.1033 + logger.error("Failed: NET " + command)
1.1034 + return -1
1.1035 + return 1
1.1036 +
1.1037 + def unmapNetworkDrive(self, drive):
1.1038 + drives = self.getNetworkDrives()
1.1039 + if drive not in drives.keys():
1.1040 + return 1
1.1041 + result = Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE ' + drive + ' /DELETE /YES')
1.1042 + if string.find(str(result[1]), 'successfully',) == -1:
1.1043 + logger.error(result[2])
1.1044 + return -1
1.1045 + return 1
1.1046 +
1.1047 + def getNetworkDrives(self):
1.1048 + ip = VMManager.getHostOnlyIP(None)
1.1049 + ip = ip[:ip.rindex('.')]
1.1050 + drives = dict()
1.1051 + result = Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE')
1.1052 + for line in result[1].splitlines():
1.1053 + if ip in line:
1.1054 + parts = line.split()
1.1055 + drives[parts[1]] = parts[2]
1.1056 + return drives
1.1057 +
1.1058 + def genNetworkDrive(self):
1.1059 + network_drives = self.getNetworkDrives()
1.1060 + logical_drives = self.getLogicalDrives()
1.1061 + drives = list(map(chr, range(68, 91)))
1.1062 + for drive in drives:
1.1063 + if drive+':' not in network_drives and drive not in logical_drives:
1.1064 + return drive+':'
1.1065 +
1.1066 + def getNetworkDrive(self, vm_name):
1.1067 + ip = self.getHostOnlyIP(vm_name)
1.1068 + result = Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE')
1.1069 + for line in result[1].splitlines():
1.1070 + if ip in line:
1.1071 + parts = line.split()
1.1072 + return parts[0]
1.1073 +
1.1074 + def getLogicalDrives(self):
1.1075 + drive_bitmask = ctypes.cdll.kernel32.GetLogicalDrives()
1.1076 + return list(itertools.compress(string.ascii_uppercase, map(lambda x:ord(x) - ord('0'), bin(drive_bitmask)[:1:-1])))
1.1077 +
1.1078 + #vms = self.listSDVM()
1.1079 + #for vm in vms:
1.1080 + # ip = self.getHostOnlyIP(vm)
1.1081 +
1.1082 +class DeviceHandler(threading.Thread):
1.1083 + vmm = None
1.1084 + #handleDeviceChangeLock = threading.Lock()
1.1085 + attachedRSDs = None
1.1086 + connectedRSDs = None
1.1087 + running = True
1.1088 + def __init__(self, vmmanger):
1.1089 + threading.Thread.__init__(self)
1.1090 + self.vmm = vmmanger
1.1091 +
1.1092 + def stop(self):
1.1093 + self.running = False
1.1094 +
1.1095 + def run(self):
1.1096 + self.connectedRSDs = dict()#self.vmm.getConnectedRSDS()
1.1097 + self.attachedRSDs = self.vmm.getAttachedRSDs()
1.1098 + while self.running:
1.1099 + tmp_rsds = self.vmm.getConnectedRSDS()
1.1100 + if tmp_rsds.keys() == self.connectedRSDs.keys():
1.1101 + logger.debug("Nothing's changed. sleep(3)")
1.1102 + time.sleep(3)
1.1103 + continue
1.1104 +
1.1105 + logger.info("Something's changed")
1.1106 +
1.1107 + self.connectedRSDs = tmp_rsds
1.1108 + self.attachedRSDs = self.vmm.getAttachedRSDs()
1.1109 +
1.1110 +
1.1111 + for vm_name in self.attachedRSDs.keys():
1.1112 + if self.attachedRSDs[vm_name] not in self.connectedRSDs.values():
1.1113 + drive = self.vmm.getNetworkDrive(vm_name)
1.1114 + self.vmm.unmapNetworkDrive(drive)
1.1115 + #self.stopVM(vm_name)
1.1116 + self.vmm.detachRSD(vm_name)
1.1117 + self.vmm.poweroffVM(vm_name)
1.1118 + self.vmm.removeVM(vm_name)
1.1119 + #create new vm for attached device if any
1.1120 + self.attachedRSDs = self.vmm.getAttachedRSDs()
1.1121 + self.connectedRSDs = self.vmm.getConnectedRSDS()
1.1122 +
1.1123 + new_ip = None
1.1124 + for connected_device in self.connectedRSDs.values():
1.1125 + if (self.attachedRSDs and False) or (connected_device not in self.attachedRSDs.values()):
1.1126 + new_sdvm = self.vmm.generateSDVMName()
1.1127 + self.vmm.createVM(new_sdvm)
1.1128 + self.vmm.storageAttach(new_sdvm)
1.1129 + self.vmm.attachRSD(new_sdvm, connected_device)
1.1130 + self.vmm.startVM(new_sdvm)
1.1131 + new_ip = self.vmm.waitStartup(new_sdvm)
1.1132 + drive = self.vmm.genNetworkDrive()
1.1133 + if new_ip != None:
1.1134 + self.vmm.mapNetworkDrive(drive, '\\\\' + new_ip + '\\USB', None, None)
1.1135 + #TODO: cleanup notifications somwhere else (eg. machine shutdown)
1.1136 + #self.handleDeviceChangeLock.release()
1.1137 +
1.1138 +
1.1139 +if __name__ == '__main__':
1.1140 + #man = VMManager.getInstance()
1.1141 + #man.listVM()
1.1142 + #print man.getConnectedRSDs()
1.1143 + #print man.getNetworkDrives()
1.1144 + #man.genNetworkDrive()
1.1145 + drive_bitmask = ctypes.cdll.kernel32.GetLogicalDrives()
1.1146 + print list(itertools.compress(string.ascii_uppercase, map(lambda x:ord(x) - ord('0'), bin(drive_bitmask)[:1:-1])))
1.1147 + #print list(map(chr, range(68, 91)))
1.1148 +
1.1149 + #time.sleep(-1)
1.1150 + #man.listVM()
1.1151 + #man.listVM()
1.1152 + #man.listVM()
1.1153 + #man.listVM()
1.1154 + #man.genCertificateISO('SecurityDVM0')
1.1155 + #man.guestExecute('SecurityDVM0', '/bin/ls -la')
1.1156 + #logger = setupLogger('VMManager')
1.1157 + #c = Cygwin()
1.1158 +
1.1159 + #man.sshExecute('/bin/ls -la', 'SecurityDVM0')
1.1160 + #man.sshExecuteX11('/usr/bin/iceweasel', 'SecurityDVM0')
1.1161 + #man.removeVM('SecurityDVM0')
1.1162 + #man.netUse('192.168.56.134', 'USB\\')
1.1163 + #ip = '192.168.56.139'
1.1164 +
1.1165 + #man.cygwin_path = 'c:\\cygwin64\\bin\\'
1.1166 + #man.handleDeviceChange()
1.1167 + #print man.listSDVM()
1.1168 + #man.configureHostNetworking()
1.1169 + #new_vm = man.generateSDVMName()
1.1170 + #man.createVM(new_vm)
1.1171 +
1.1172 + #print Cygwin.cmd()
1.1173 + #man.isAvailable('c:')
1.1174 + #ip = man.getHostOnlyIP('SecurityDVM0')
1.1175 + #man.mapNetworkDrive('h:', '\\\\' + ip + '\Download', None, None)
1.1176 +
1.1177 + #man.genCertificateISO(new_vm)
1.1178 + #man.attachCertificateISO(new_vm)
1.1179 +
1.1180 + #man.attachCertificateISO(vm_name)
1.1181 + #man.guestExecute(vm_name, "ls")
1.1182 + #man.sshGuestX11Execute('SecurityDVM1', '/usr/bin/iceweasel')
1.1183 + #time.sleep(60)
1.1184 + #print man.cygwinPath("C:\Users\BarthaM\VirtualBox VMs\SecurityDVM\.ssh\*")
1.1185 + #man.genCertificateISO('SecurityDVM')
1.1186 + #man.attachCertificateISO('SecurityDVM')
1.1187 + #man.isStorageAttached('SecurityDVM')
1.1188 + #man.guestExecute('SecurityDVM', 'sudo apt-get -y update')
1.1189 + #man.guestExecute('SecurityDVM', 'sudo apt-get -y upgrade' )
1.1190 +
1.1191 + #man.stopVM('SecurityDVM')
1.1192 + #man.storageDetach('SecurityDVM')
1.1193 + #man.changeStorageType('C:\Users\BarthaM\VirtualBox VMs\SecurityDVM\SecurityDVM.vmdk','immutable')
1.1194 + #man.storageAttach('SecurityDVM')
1.1195 +
1.1196 +
1.1197 + #cmd = "c:\\cygwin64\\bin\\bash.exe --login -c \"/bin/ls\""
1.1198 + #man.execute(cmd)
1.1199 +