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