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