OpenSecurity/bin/vmmanager.pyw
author mb
Fri, 07 Mar 2014 14:32:12 +0100
changeset 90 bfd41c38d156
parent 87 d5b04809faca
child 91 a26757850ea9
child 95 cdebb7e0ba10
permissions -rwxr-xr-x
new version. many bugfixes and new functionality
     1 '''
     2 Created on Nov 19, 2013
     3 
     4 @author: BarthaM
     5 '''
     6 import os
     7 import os.path
     8 from subprocess import Popen, PIPE, call, STARTUPINFO, _subprocess
     9 import sys
    10 import re
    11 
    12 from cygwin import Cygwin
    13 from environment import Environment
    14 import threading
    15 import time
    16 import string
    17 
    18 import shutil
    19 import stat
    20 import tempfile
    21 from opensecurity_util import logger, setupLogger, OpenSecurityException
    22 import ctypes
    23 import itertools
    24 import _winreg
    25 DEBUG = True
    26 
    27 class VMManagerException(Exception):
    28     def __init__(self, value):
    29         self.value = value
    30     def __str__(self):
    31         return repr(self.value)
    32 
    33 class USBFilter:
    34     vendorid = ""
    35     productid = ""
    36     revision = ""
    37     
    38     def __init__(self, vendorid, productid, revision):
    39         self.vendorid = vendorid.lower()
    40         self.productid = productid.lower()
    41         self.revision = revision.lower()
    42         return
    43     
    44     def __eq__(self, other):
    45         return self.vendorid == other.vendorid and self.productid == other.productid and self.revision == other.revision
    46     
    47     def __hash__(self):
    48         return hash(self.vendorid) ^ hash(self.productid) ^ hash(self.revision)
    49     
    50     def __repr__(self):
    51         return "VendorId = \'" + str(self.vendorid) + "\' ProductId = \'" + str(self.productid) + "\' Revision = \'" + str(self.revision) + "\'"
    52     
    53     #def __getitem__(self, item):
    54     #    return self.coords[item]
    55  
    56 class VMManager(object):
    57     vmRootName = "SecurityDVM"
    58     systemProperties = None
    59     _instance = None
    60     machineFolder = ''
    61     rsdHandler = None
    62     
    63     def __init__(self):
    64         self.systemProperties = self.getSystemProperties()
    65         self.machineFolder = self.systemProperties["Default machine folder"]
    66         self.cleanup()
    67         self.rsdHandler = DeviceHandler(self)
    68         self.rsdHandler.start()
    69         return
    70     
    71     @staticmethod
    72     def getInstance():
    73         if VMManager._instance == None:
    74             VMManager._instance = VMManager()
    75         return VMManager._instance
    76     
    77     def cleanup(self):
    78         if self.rsdHandler != None:
    79             self.rsdHandler.stop()
    80             self.rsdHandler.join()
    81         drives = self.getNetworkDrives()
    82         for drive in drives.keys():
    83             self.unmapNetworkDrive(drive)
    84         for vm in self.listSDVM():
    85             self.poweroffVM(vm)
    86             self.removeVM(vm)
    87         
    88     # return hosty system properties
    89     def getSystemProperties(self):
    90         result = checkResult(Cygwin.vboxExecute('list systemproperties'))
    91         if result[1]=='':
    92             return None
    93         props = dict((k.strip(),v.strip().strip('"')) for k,v in (line.split(':', 1) for line in result[1].strip().splitlines()))
    94         return props
    95     
    96     # return the folder containing the guest VMs     
    97     def getMachineFolder(self):
    98         return self.machineFolder
    99 
   100     # list all existing VMs registered with VBox
   101     def listVM(self):
   102         result = checkResult(Cygwin.vboxExecute('list vms'))[1]
   103         vms = list(k.strip().strip('"') for k,_ in (line.split(' ') for line in result.splitlines()))
   104         return vms
   105     
   106     # list running VMs
   107     def listRunningVMS(self):
   108         result = checkResult(Cygwin.vboxExecute('list runningvms'))[1]
   109         vms = list(k.strip().strip('"') for k,_ in (line.split(' ') for line in result.splitlines()))
   110         return vms
   111     
   112     # list existing SDVMs
   113     def listSDVM(self):
   114         vms = self.listVM()
   115         svdms = []
   116         for vm in vms:
   117             if vm.startswith(self.vmRootName) and vm != self.vmRootName:
   118                 svdms.append(vm)
   119         return svdms
   120     
   121     # generate valid (not already existing SDVM name). necessary for creating a new VM
   122     def generateSDVMName(self):
   123         vms = self.listVM()
   124         for i in range(0,999):
   125             if(not self.vmRootName+str(i) in vms):
   126                 return self.vmRootName+str(i)
   127         return ''
   128     
   129     # check if the device is mass storage type
   130     @staticmethod
   131     def isMassStorageDevice(device):
   132         keyname = 'SYSTEM\CurrentControlSet\Enum\USB' + '\VID_' + device.vendorid+'&'+'PID_'+ device.productid
   133         key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, keyname)
   134         #subkeys = _winreg.QueryInfoKey(key)[0]
   135         #for i in range(0, subkeys):
   136         #    print _winreg.EnumKey(key, i)     
   137         devinfokeyname = _winreg.EnumKey(key, 0)
   138         _winreg.CloseKey(key)
   139 
   140         devinfokey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, keyname+'\\'+devinfokeyname)
   141         value = _winreg.QueryValueEx(devinfokey, 'SERVICE')[0]
   142         _winreg.CloseKey(devinfokey)
   143         
   144         return 'USBSTOR' in value
   145     
   146     # return the RSDs connected to the host
   147     @staticmethod
   148     def getConnectedRSDS():
   149         results = checkResult(Cygwin.vboxExecute('list usbhost'))[1]
   150         results = results.split('Host USB Devices:')[1].strip()
   151         
   152         items = list( "UUID:"+result for result in results.split('UUID:') if result != '')
   153         rsds = dict()   
   154         for item in items:
   155             props = dict()
   156             for line in item.splitlines():
   157                 if line != "":         
   158                     k,v = line[:line.index(':')].strip(), line[line.index(':')+1:].strip()
   159                     props[k] = v
   160             
   161             #if 'Product' in props.keys() and props['Product'] == 'Mass Storage':
   162             
   163             usb_filter = USBFilter( re.search(r"\((?P<vid>[0-9A-Fa-f]+)\)", props['VendorId']).groupdict()['vid'], 
   164                                     re.search(r"\((?P<pid>[0-9A-Fa-f]+)\)", props['ProductId']).groupdict()['pid'],
   165                                     re.search(r"\((?P<rev>[0-9A-Fa-f]+)\)", props['Revision']).groupdict()['rev'] )
   166             if VMManager.isMassStorageDevice(usb_filter):
   167                 rsds[props['UUID']] = usb_filter;
   168                 logger.debug(usb_filter)
   169         return rsds
   170     
   171     # return the RSDs attached to all existing SDVMs
   172     def getAttachedRSDs(self):
   173         vms = self.listSDVM()
   174         attached_devices = dict()
   175         for vm in vms:
   176             rsd_filter = self.getUSBFilter(vm)
   177             if rsd_filter != None:
   178                 attached_devices[vm] = rsd_filter
   179         return attached_devices
   180     
   181     # configures hostonly networking and DHCP server. requires admin rights
   182     def configureHostNetworking(self):
   183         #cmd = 'vboxmanage list hostonlyifs'
   184         #Cygwin.vboxExecute(cmd)
   185         #cmd = 'vboxmanage hostonlyif remove \"VirtualBox Host-Only Ethernet Adapter\"'
   186         #Cygwin.vboxExecute(cmd)
   187         #cmd = 'vboxmanage hostonlyif create'
   188         #Cygwin.vboxExecute(cmd)
   189         checkResult(Cygwin.vboxExecute('hostonlyif ipconfig \"VirtualBox Host-Only Ethernet Adapter\" --ip 192.168.56.1 --netmask 255.255.255.0'))
   190         #cmd = 'vboxmanage dhcpserver add'
   191         #Cygwin.vboxExecute(cmd)
   192         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'))
   193     
   194     #create new virtual machine instance based on template vm named SecurityDVM (\SecurityDVM\SecurityDVM.vmdk)
   195     def createVM(self, vm_name):
   196         hostonly_if = self.getHostOnlyIFs()
   197         checkResult(Cygwin.vboxExecute('createvm --name ' + vm_name + ' --ostype Debian --register'))
   198         checkResult(Cygwin.vboxExecute('modifyvm ' + vm_name + ' --memory 512 --vram 10 --cpus 1 --usb on --usbehci on --nic1 hostonly --hostonlyadapter1 \"' + hostonly_if['Name'] + '\" --nic2 nat'))
   199         checkResult(Cygwin.vboxExecute('storagectl ' + vm_name + ' --name SATA --add sata --portcount 2'))
   200         return
   201     
   202     # attach storage image to controller
   203     def storageAttach(self, vm_name):
   204         if self.isStorageAttached(vm_name):
   205             self.storageDetach(vm_name)
   206         checkResult(Cygwin.vboxExecute('storageattach ' + vm_name + ' --storagectl SATA --port 0 --device 0 --type hdd --medium \"'+ self.machineFolder + '\SecurityDVM\SecurityDVM.vmdk\"'))
   207     
   208     # return true if storage is attached 
   209     def isStorageAttached(self, vm_name):
   210         info = self.getVMInfo(vm_name)
   211         return (info['SATA-0-0']!='none')
   212     
   213     # detach storage from controller
   214     def storageDetach(self, vm_name):
   215         if self.isStorageAttached(vm_name):
   216             checkResult(Cygwin.vboxExecute('storageattach ' + vm_name + ' --storagectl SATA --port 0 --device 0 --type hdd --medium none'))
   217     
   218     def changeStorageType(self, filename, storage_type):
   219         checkResult(Cygwin.vboxExecute('modifyhd \"' + filename + '\" --type ' + storage_type))
   220     
   221     # list storage snaphots for VM
   222     def updateTemplate(self):
   223         self.cleanup()
   224         self.poweroffVM('SecurityDVM')
   225         self.waitShutdown('SecurityDVM')
   226         
   227         # check for updates
   228         self.genCertificateISO('SecurityDVM')
   229         self.attachCertificateISO('SecurityDVM')
   230         
   231         self.storageDetach('SecurityDVM')
   232         results = checkResult(Cygwin.vboxExecute('list hdds'))[1]
   233         results = results.replace('Parent UUID', 'Parent')
   234         items = list( "UUID:"+result for result in results.split('UUID:') if result != '')
   235         
   236         snaps = dict()   
   237         for item in items:
   238             props = dict()
   239             for line in item.splitlines():
   240                 if line != "":         
   241                     k,v = line[:line.index(':')].strip(), line[line.index(':')+1:].strip()
   242                     props[k] = v;
   243             snaps[props['UUID']] = props
   244         
   245         
   246         template_storage = self.machineFolder + '\SecurityDVM\SecurityDVM.vmdk'
   247         
   248         # find template uuid
   249         template_uuid = ''
   250         for hdd in snaps.values():
   251             if hdd['Location'] == template_storage:
   252                 template_uuid = hdd['UUID']
   253         logger.debug('found parent uuid ' + template_uuid)
   254         
   255         # remove snapshots 
   256         for hdd in snaps.values():
   257             if hdd['Parent'] == template_uuid:
   258                 #template_uuid = hdd['UUID']
   259                 logger.debug('removing snapshot ' + hdd['UUID'])
   260                 checkResult(Cygwin.vboxExecute('closemedium disk {' + hdd['UUID'] + '} --delete'))#[1]
   261                 # parse result 0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
   262         
   263         self.changeStorageType(template_storage,'normal')
   264         self.storageAttach('SecurityDVM')
   265         self.startVM('SecurityDVM')
   266         self.waitStartup('SecurityDVM')
   267         checkResult(Cygwin.sshExecute('"sudo apt-get -y update"', VMManager.getHostOnlyIP('SecurityDVM'), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + 'SecurityDVM' + '/dvm_key'))
   268         checkResult(Cygwin.sshExecute('"sudo apt-get -y upgrade"', VMManager.getHostOnlyIP('SecurityDVM'), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + 'SecurityDVM' + '/dvm_key'))
   269         #self.stopVM('SecurityDVM')
   270         self.hibernateVM('SecurityDVM')
   271         self.waitShutdown('SecurityDVM')
   272         self.storageDetach('SecurityDVM')
   273         self.changeStorageType(template_storage,'immutable')
   274         self.storageAttach('SecurityDVM')
   275         self.rsdHandler = DeviceHandler(self)
   276         self.rsdHandler.start()
   277     
   278     #remove VM from the system. should be used on VMs returned by listSDVMs    
   279     def removeVM(self, vm_name):
   280         logger.info('Removing ' + vm_name)
   281         checkResult(Cygwin.vboxExecute('unregistervm ' + vm_name + ' --delete'))
   282         machineFolder = Cygwin.cygPath(self.machineFolder)
   283         checkResult(Cygwin.bashExecute('"/usr/bin/rm -rf ' + machineFolder + '/' + vm_name + '"'))
   284     
   285     # start VM
   286     def startVM(self, vm_name):
   287         logger.info('Starting ' +  vm_name)
   288         result = checkResult(Cygwin.vboxExecute('startvm ' + vm_name + ' --type headless' ))
   289         while 'successfully started' not in result[1]:
   290             logger.error("Failed to start SDVM: " + vm_name + " retrying")
   291             time.sleep(1)
   292             result = checkResult(Cygwin.vboxExecute('startvm ' + vm_name + ' --type headless'))
   293         return result[0]
   294     
   295     # return wether VM is running or not
   296     def isVMRunning(self, vm_name):
   297         return vm_name in self.listRunningVMS()    
   298     
   299     # stop VM
   300     def stopVM(self, vm_name):
   301         logger.info('Sending shutdown signal to ' + vm_name)
   302         checkResult(Cygwin.sshExecute( '"sudo shutdown -h now"', VMManager.getHostOnlyIP(vm_name), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + vm_name + '/dvm_key' ))
   303     
   304     # stop VM
   305     def hibernateVM(self, vm_name):
   306         logger.info('Sending shutdown signal to ' + vm_name)
   307         checkResult(Cygwin.sshExecute( '"sudo hibernate-disk&"', VMManager.getHostOnlyIP(vm_name), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + vm_name + '/dvm_key', wait_return=False))
   308             
   309     # poweroff VM
   310     def poweroffVM(self, vm_name):
   311         if not self.isVMRunning(vm_name):
   312             return
   313         logger.info('Powering off ' + vm_name)
   314         return checkResult(Cygwin.vboxExecute('controlvm ' + vm_name + ' poweroff'))
   315     
   316     #list the hostonly IFs exposed by the VBox host
   317     @staticmethod    
   318     def getHostOnlyIFs():
   319         result = Cygwin.vboxExecute('list hostonlyifs')[1]
   320         if result=='':
   321             return None
   322         props = dict((k.strip(),v.strip().strip('"')) for k,v in (line.split(':', 1) for line in result.strip().splitlines()))
   323         return props
   324     
   325     # return the hostOnly IP for a running guest or the host
   326     @staticmethod    
   327     def getHostOnlyIP(vm_name):
   328         if vm_name == None:
   329             logger.info('Gettting hostOnly IP address for Host')
   330             return VMManager.getHostOnlyIFs()['IPAddress']
   331         else:
   332             logger.info('Gettting hostOnly IP address ' + vm_name)
   333             result = checkResult(Cygwin.vboxExecute('guestproperty get ' + vm_name + ' /VirtualBox/GuestInfo/Net/0/V4/IP'))
   334             if result=='':
   335                 return None
   336             result = result[1]
   337             if result.startswith('No value set!'):
   338                 return None
   339             return result[result.index(':')+1:].strip()
   340             
   341     # attach removable storage device to VM by provision of filter
   342     def attachRSD(self, vm_name, rsd_filter):
   343         return checkResult(Cygwin.vboxExecute('usbfilter add 0 --target ' + vm_name + ' --name OpenSecurityRSD --vendorid ' + rsd_filter.vendorid + ' --productid ' + rsd_filter.productid + ' --revision ' + rsd_filter.revision))
   344     
   345     # detach removable storage from VM by 
   346     def detachRSD(self, vm_name):
   347         return checkResult(Cygwin.vboxExecute('usbfilter remove 0 --target ' + vm_name))
   348         
   349     # return the description set for an existing VM
   350     def getVMInfo(self, vm_name):
   351         results = checkResult(Cygwin.vboxExecute('showvminfo ' + vm_name + ' --machinereadable'))[1]
   352         props = dict((k.strip().strip('"'),v.strip().strip('"')) for k,v in (line.split('=', 1) for line in results.splitlines()))
   353         return props
   354     
   355     # return the configured USB filter for an existing VM 
   356     def getUSBFilter(self, vm_name):
   357         props = self.getVMInfo(vm_name)
   358         keys = set(['USBFilterVendorId1', 'USBFilterProductId1', 'USBFilterRevision1'])
   359         keyset = set(props.keys())
   360         usb_filter = None
   361         if keyset.issuperset(keys):
   362             usb_filter = USBFilter(props['USBFilterVendorId1'], props['USBFilterProductId1'], props['USBFilterRevision1'])
   363         return usb_filter
   364     
   365     #generates ISO containing authorized_keys for use with guest VM
   366     def genCertificateISO(self, vm_name):
   367         machineFolder = Cygwin.cygPath(self.machineFolder)
   368         # remove .ssh folder if exists
   369         checkResult(Cygwin.bashExecute('\"/usr/bin/rm -rf \\\"' + machineFolder + '/' + vm_name + '/.ssh\\\"\"'))
   370         # remove .ssh folder if exists
   371         checkResult(Cygwin.bashExecute('\"/usr/bin/rm -rf \\\"' + machineFolder + '/' + vm_name + '/dvm_key\\\"\"'))
   372         # create .ssh folder in vm_name
   373         checkResult(Cygwin.bashExecute('\"/usr/bin/mkdir -p \\\"' + machineFolder + '/' + vm_name + '/.ssh\\\"\"'))
   374         # generate dvm_key pair in vm_name / .ssh     
   375         checkResult(Cygwin.bashExecute('\"/usr/bin/ssh-keygen -q -t rsa -N \\"\\" -C \\\"' + vm_name + '\\\" -f \\\"' + machineFolder + '/' + vm_name + '/.ssh/dvm_key\\\"\"'))
   376         # move out private key
   377         checkResult(Cygwin.bashExecute('\"/usr/bin/mv \\\"' + machineFolder + '/' + vm_name + '/.ssh/dvm_key\\\" \\\"' + machineFolder + '/' + vm_name + '\\\"'))
   378         # set permissions for private key
   379         checkResult(Cygwin.bashExecute('\"/usr/bin/chmod 500 \\\"' + machineFolder + '/' + vm_name + '/dvm_key\\\"\"'))
   380         # rename public key to authorized_keys
   381         checkResult(Cygwin.bashExecute('\"/usr/bin/mv \\\"' + machineFolder + '/' + vm_name + '/.ssh/dvm_key.pub\\\" \\\"' + machineFolder + '/' + vm_name + '/.ssh/authorized_keys\\\"'))
   382         # set permissions for authorized_keys
   383         checkResult(Cygwin.bashExecute('\"/usr/bin/chmod 500 \\\"' + machineFolder + '/' + vm_name + '/.ssh/authorized_keys\\\"\"'))
   384         # generate iso image with .ssh/authorized keys
   385         checkResult(Cygwin.bashExecute('\"/usr/bin/genisoimage -J -R -o \\\"' + machineFolder + '/' + vm_name + '/'+ vm_name + '.iso\\\" \\\"' + machineFolder + '/' + vm_name + '/.ssh\\\"\"'))
   386     
   387     # attaches generated ssh public cert to guest vm
   388     def attachCertificateISO(self, vm_name):
   389         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\"'))
   390         return result
   391     
   392     # wait for machine to come up
   393     def waitStartup(self, vm_name, timeout_ms = 30000):
   394         checkResult(Cygwin.vboxExecute('guestproperty wait ' + vm_name + ' SDVMStarted --timeout ' + str(timeout_ms) + ' --fail-on-timeout'))
   395         return VMManager.getHostOnlyIP(vm_name)
   396     
   397     # wait for machine to shutdown
   398     def waitShutdown(self, vm_name):
   399         while vm_name in self.listRunningVMS():
   400             time.sleep(1)
   401         return
   402         
   403     # handles browsing request    
   404     def handleBrowsingRequest(self):
   405         handler = BrowsingHandler(self)
   406         handler.start()
   407         return 'ok'
   408     
   409     #Small function to check the availability of network resource.
   410     #def isAvailable(self, path):
   411         #return os.path.exists(path)
   412         #result = Cygwin.cmdExecute('IF EXIST "' + path + '" echo YES')
   413         #return string.find(result[1], 'YES',)
   414     
   415     #Small function to check if the mention location is a directory
   416     def isDirectory(self, path):
   417         result = checkResult(Cygwin.cmdExecute('dir ' + path + ' | FIND ".."'))
   418         return string.find(result[1], 'DIR',)
   419 
   420     def mapNetworkDrive(self, drive, networkPath, user, password):
   421         self.unmapNetworkDrive(drive)
   422         #Check for drive availability
   423         if os.path.exists(drive):
   424             logger.error("Drive letter is already in use: " + drive)
   425             return -1
   426         #Check for network resource availability
   427         retry = 5
   428         while not os.path.exists(networkPath):
   429             time.sleep(1)
   430             if retry == 0:
   431                 return -1
   432             logger.info("Path not accessible: " + networkPath + " retrying")
   433             retry-=1
   434             #return -1
   435     
   436         command = 'USE ' + drive + ' ' + networkPath + ' /PERSISTENT:NO'
   437         if user != None:
   438             command += ' ' + password + ' /User' + user
   439     
   440         #TODO: Execute 'NET USE' command with authentication
   441         result = checkResult(Cygwin.execute('C:\\Windows\\system32\\net.exe', command))
   442         if string.find(result[1], 'successfully',) == -1:
   443             logger.error("Failed: NET " + command)
   444             return -1
   445         return 1
   446     
   447     def unmapNetworkDrive(self, drive):
   448         drives = self.getNetworkDrives()
   449         if drive not in drives.keys():
   450             return 1 
   451         result = checkResult(Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE ' + drive + ' /DELETE /YES'))
   452         if string.find(str(result[1]), 'successfully',) == -1:
   453             logger.error(result[2])
   454             return -1
   455         return 1
   456     
   457     def getNetworkDrives(self):
   458         ip = VMManager.getHostOnlyIP(None)
   459         ip = ip[:ip.rindex('.')]
   460         drives = dict()    
   461         result = checkResult(Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE'))
   462         for line in result[1].splitlines():
   463             if ip in line:
   464                 parts = line.split()
   465                 drives[parts[1]] = parts[2]
   466         return drives
   467             
   468     def genNetworkDrive(self):
   469         network_drives = self.getNetworkDrives()
   470         logical_drives = VMManager.getLogicalDrives()
   471         drives = list(map(chr, range(68, 91)))  
   472         for drive in drives:
   473             if drive+':' not in network_drives and drive not in logical_drives:
   474                 return drive+':'
   475 
   476     def getNetworkDrive(self, vm_name):
   477         ip = self.getHostOnlyIP(vm_name)
   478         result = checkResult(Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE'))
   479         for line in result[1].splitlines():
   480             if line != None and ip in line:
   481                 parts = line.split()
   482                 return parts[0]
   483     @staticmethod
   484     def getLogicalDrives():
   485         drive_bitmask = ctypes.cdll.kernel32.GetLogicalDrives()
   486         return list(itertools.compress(string.ascii_uppercase,  map(lambda x:ord(x) - ord('0'), bin(drive_bitmask)[:1:-1])))
   487     
   488     @staticmethod
   489     def getDriveType(drive):
   490         return ctypes.cdll.kernel32.GetDriveTypeW(u"%s:\\"%drive)
   491     
   492     @staticmethod
   493     def getVolumeInfo(drive):
   494         volumeNameBuffer = ctypes.create_unicode_buffer(1024)
   495         fileSystemNameBuffer = ctypes.create_unicode_buffer(1024)
   496         serial_number = None
   497         max_component_length = None
   498         file_system_flags = None
   499         
   500         rc = ctypes.cdll.kernel32.GetVolumeInformationW(
   501             #ctypes.c_wchar_p("F:\\"),
   502             u"%s:\\"%drive,
   503             volumeNameBuffer,
   504             ctypes.sizeof(volumeNameBuffer),
   505             serial_number,
   506             max_component_length,
   507             file_system_flags,
   508             fileSystemNameBuffer,
   509             ctypes.sizeof(fileSystemNameBuffer)
   510         )
   511         
   512         return volumeNameBuffer.value, fileSystemNameBuffer.value
   513 
   514 def checkResult(result):
   515     if result[0] != 0:
   516         logger.error('Command failed:' + ''.join(result[2]))
   517         raise OpenSecurityException('Command failed:' + ''.join(result[2]))
   518     return result
   519 
   520 # handles browsing request                    
   521 class BrowsingHandler(threading.Thread):
   522     vmm = None
   523     def __init__(self, vmmanager):
   524         threading.Thread.__init__(self)
   525         self.vmm = vmmanager
   526      
   527     def run(self):
   528         try:
   529             new_sdvm = self.vmm.generateSDVMName()
   530             self.vmm.createVM(new_sdvm)
   531             self.vmm.storageAttach(new_sdvm)
   532             self.vmm.genCertificateISO(new_sdvm)
   533             self.vmm.attachCertificateISO(new_sdvm)
   534             self.vmm.startVM(new_sdvm)
   535             new_ip = self.vmm.waitStartup(new_sdvm)
   536             drive = self.vmm.genNetworkDrive()
   537             if new_ip != None:
   538                 self.vmm.mapNetworkDrive(drive, '\\\\' + new_ip + '\\Download', None, None)
   539             result = checkResult(Cygwin.sshExecuteX11('/usr/bin/iceweasel', new_ip, 'osecuser', Cygwin.cygPath(self.vmm.getMachineFolder()) + '/' + new_sdvm + '/dvm_key'))
   540         except:
   541             logger.error("BrowsingHandler failed. Cleaning up")
   542             
   543         self.vmm.unmapNetworkDrive(drive)
   544         self.vmm.poweroffVM(new_sdvm)
   545         self.vmm.removeVM(new_sdvm)
   546                 
   547 class DeviceHandler(threading.Thread): 
   548     vmm = None
   549     #handleDeviceChangeLock = threading.Lock()
   550     attachedRSDs = None  
   551     connectedRSDs = None
   552     running = True
   553     def __init__(self, vmmanger): 
   554         threading.Thread.__init__(self)
   555         self.vmm = vmmanger
   556  
   557     def stop(self):
   558         self.running = False
   559         
   560     def run(self):
   561         self.connectedRSDs = dict()
   562         self.attachedRSDs = self.vmm.getAttachedRSDs()
   563         while self.running:
   564             tmp_rsds = self.vmm.getConnectedRSDS()
   565             if tmp_rsds.keys() == self.connectedRSDs.keys():
   566                 logger.debug("Nothing's changed. sleep(3)")
   567                 time.sleep(3)
   568                 continue
   569             
   570             logger.info("Something's changed")          
   571             self.connectedRSDs = tmp_rsds
   572             self.attachedRSDs = self.vmm.getAttachedRSDs()
   573             
   574             for vm_name in self.attachedRSDs.keys():
   575                 if self.attachedRSDs[vm_name] not in self.connectedRSDs.values():
   576                     drive = self.vmm.getNetworkDrive(vm_name)
   577                     self.vmm.unmapNetworkDrive(drive)
   578                     #self.stopVM(vm_name)
   579                     self.vmm.detachRSD(vm_name)
   580                     self.vmm.poweroffVM(vm_name)
   581                     self.vmm.removeVM(vm_name)
   582             #create new vm for attached device if any
   583             self.attachedRSDs = self.vmm.getAttachedRSDs()
   584             self.connectedRSDs = self.vmm.getConnectedRSDS()
   585             
   586             new_ip = None
   587             for connected_device in self.connectedRSDs.values():
   588                 if (self.attachedRSDs and False) or (connected_device not in self.attachedRSDs.values()):
   589                     new_sdvm = self.vmm.generateSDVMName()
   590                     self.vmm.createVM(new_sdvm)
   591                     self.vmm.storageAttach(new_sdvm)
   592                     self.vmm.attachRSD(new_sdvm, connected_device)
   593                     self.vmm.startVM(new_sdvm)
   594                     new_ip = self.vmm.waitStartup(new_sdvm)
   595                     drive = self.vmm.genNetworkDrive()
   596                     if new_ip != None:
   597                         self.vmm.mapNetworkDrive(drive, '\\\\' + new_ip + '\\USB', None, None)
   598 
   599 if __name__ == '__main__':
   600     #man = VMManager.getInstance()
   601     #man.listVM()
   602     #print man.getConnectedRSDs()
   603     #print man.getNetworkDrives()
   604     #man.genNetworkDrive()
   605     #drive_bitmask = ctypes.cdll.kernel32.GetLogicalDrives()
   606     #print list(itertools.compress(string.ascii_uppercase,  map(lambda x:ord(x) - ord('0'), bin(drive_bitmask)[:1:-1])))
   607     #print list(map(chr, range(68, 91))) 
   608     #print Cygwin.getRegEntry('SYSTEM\CurrentControlSet\Enum\USB', 'VID_1058&PID_0704')[0]
   609     #devices = VMManager.getConnectedRSDS()
   610     #print devices
   611     
   612     drives = VMManager.getLogicalDrives()
   613     print drives
   614     print VMManager.getDriveType("E")
   615     print VMManager.getVolumeInfo("E")
   616     #for device in devices.values():
   617     #    #print device
   618     #    if VMManager.isMassStorageDevice(device):
   619     #        print device
   620         
   621     
   622     
   623     #time.sleep(-1)
   624     #man.listVM()
   625     #man.listVM()
   626     #man.listVM()
   627     #man.listVM()
   628     #man.genCertificateISO('SecurityDVM0')
   629     #man.guestExecute('SecurityDVM0', '/bin/ls -la')
   630     #logger = setupLogger('VMManager')
   631     #c = Cygwin()
   632     
   633     #man.sshExecute('/bin/ls -la', 'SecurityDVM0')
   634     #man.sshExecuteX11('/usr/bin/iceweasel', 'SecurityDVM0')
   635     #man.removeVM('SecurityDVM0')
   636     #man.netUse('192.168.56.134', 'USB\\')
   637     #ip = '192.168.56.139'
   638     
   639     #man.cygwin_path = 'c:\\cygwin64\\bin\\'
   640     #man.handleDeviceChange()
   641     #print man.listSDVM()
   642     #man.configureHostNetworking()
   643     #new_vm = man.generateSDVMName()
   644     #man.createVM(new_vm)
   645     
   646     #print Cygwin.cmd()
   647     #man.isAvailable('c:')
   648     #ip = man.getHostOnlyIP('SecurityDVM0')
   649     #man.mapNetworkDrive('h:', '\\\\' + ip + '\Download', None, None)
   650     
   651     #man.genCertificateISO(new_vm)
   652     #man.attachCertificateISO(new_vm)
   653     
   654     #man.attachCertificateISO(vm_name)
   655     #man.guestExecute(vm_name, "ls")
   656     #man.sshGuestX11Execute('SecurityDVM1', '/usr/bin/iceweasel')
   657     #time.sleep(60)
   658     #print man.cygwinPath("C:\Users\BarthaM\VirtualBox VMs\SecurityDVM\.ssh\*")
   659     #man.genCertificateISO('SecurityDVM')
   660     #man.attachCertificateISO('SecurityDVM')
   661     #man.isStorageAttached('SecurityDVM')
   662     #man.guestExecute('SecurityDVM', 'sudo apt-get -y update')
   663     #man.guestExecute('SecurityDVM', 'sudo apt-get -y upgrade' )
   664     
   665     #man.stopVM('SecurityDVM')
   666     #man.storageDetach('SecurityDVM')
   667     #man.changeStorageType('C:\Users\BarthaM\VirtualBox VMs\SecurityDVM\SecurityDVM.vmdk','immutable')
   668     #man.storageAttach('SecurityDVM')
   669     
   670     
   671     #cmd = "c:\\cygwin64\\bin\\bash.exe --login -c \"/bin/ls\""
   672     #man.execute(cmd)