OpenSecurity/bin/vmmanager.pyw
author mb
Tue, 18 Mar 2014 18:00:12 +0100
changeset 97 f274426bdbb4
parent 96 630b62946c9e
child 110 490a78181935
permissions -rwxr-xr-x
corrrected merge
     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 
   224         self.cleanup()
   225         self.poweroffVM('SecurityDVM')
   226         self.waitShutdown('SecurityDVM')
   227         
   228         # check for updates
   229         self.genCertificateISO('SecurityDVM')
   230         self.attachCertificateISO('SecurityDVM')
   231         
   232         self.storageDetach('SecurityDVM')
   233         results = checkResult(Cygwin.vboxExecute('list hdds'))[1]
   234         results = results.replace('Parent UUID', 'Parent')
   235         items = list( "UUID:"+result for result in results.split('UUID:') if result != '')
   236         
   237         snaps = dict()   
   238         for item in items:
   239             props = dict()
   240             for line in item.splitlines():
   241                 if line != "":         
   242                     k,v = line[:line.index(':')].strip(), line[line.index(':')+1:].strip()
   243                     props[k] = v;
   244             snaps[props['UUID']] = props
   245         
   246         
   247         template_storage = self.machineFolder + '\SecurityDVM\SecurityDVM.vmdk'
   248         
   249         # find template uuid
   250         template_uuid = ''
   251         for hdd in snaps.values():
   252             if hdd['Location'] == template_storage:
   253                 template_uuid = hdd['UUID']
   254         logger.debug('found parent uuid ' + template_uuid)
   255         
   256         # remove snapshots 
   257         for hdd in snaps.values():
   258             if hdd['Parent'] == template_uuid:
   259                 #template_uuid = hdd['UUID']
   260                 logger.debug('removing snapshot ' + hdd['UUID'])
   261                 checkResult(Cygwin.vboxExecute('closemedium disk {' + hdd['UUID'] + '} --delete'))#[1]
   262                 # parse result 0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
   263         
   264         self.changeStorageType(template_storage,'normal')
   265         self.storageAttach('SecurityDVM')
   266         self.startVM('SecurityDVM')
   267         self.waitStartup('SecurityDVM')
   268         checkResult(Cygwin.sshExecute('"sudo apt-get -y update"', VMManager.getHostOnlyIP('SecurityDVM'), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + 'SecurityDVM' + '/dvm_key'))
   269         checkResult(Cygwin.sshExecute('"sudo apt-get -y upgrade"', VMManager.getHostOnlyIP('SecurityDVM'), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + 'SecurityDVM' + '/dvm_key'))
   270         #self.stopVM('SecurityDVM')
   271         self.hibernateVM('SecurityDVM')
   272         self.waitShutdown('SecurityDVM')
   273         self.storageDetach('SecurityDVM')
   274         self.changeStorageType(template_storage,'immutable')
   275         self.storageAttach('SecurityDVM')
   276         self.rsdHandler = DeviceHandler(self)
   277         self.rsdHandler.start()
   278     
   279     #remove VM from the system. should be used on VMs returned by listSDVMs    
   280     def removeVM(self, vm_name):
   281         logger.info('Removing ' + vm_name)
   282         checkResult(Cygwin.vboxExecute('unregistervm ' + vm_name + ' --delete'))
   283         machineFolder = Cygwin.cygPath(self.machineFolder)
   284         checkResult(Cygwin.bashExecute('/usr/bin/rm -rf \\\"' + machineFolder + '/' + vm_name + '\\\"'))
   285     
   286     # start VM
   287     def startVM(self, vm_name):
   288         logger.info('Starting ' +  vm_name)
   289         result = checkResult(Cygwin.vboxExecute('startvm ' + vm_name + ' --type headless' ))
   290         while 'successfully started' not in result[1]:
   291             logger.error("Failed to start SDVM: " + vm_name + " retrying")
   292             time.sleep(1)
   293             result = checkResult(Cygwin.vboxExecute('startvm ' + vm_name + ' --type headless'))
   294         return result[0]
   295     
   296     # return wether VM is running or not
   297     def isVMRunning(self, vm_name):
   298         return vm_name in self.listRunningVMS()    
   299     
   300     # stop VM
   301     def stopVM(self, vm_name):
   302         logger.info('Sending shutdown signal to ' + vm_name)
   303         checkResult(Cygwin.sshExecute( '"sudo shutdown -h now"', VMManager.getHostOnlyIP(vm_name), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + vm_name + '/dvm_key' ))
   304     
   305     # stop VM
   306     def hibernateVM(self, vm_name):
   307         logger.info('Sending hibernate-disk signal to ' + vm_name)
   308         checkResult(Cygwin.sshExecute( '"sudo hibernate-disk&"', VMManager.getHostOnlyIP(vm_name), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + vm_name + '/dvm_key', wait_return=False))
   309             
   310     # poweroff VM
   311     def poweroffVM(self, vm_name):
   312         if not self.isVMRunning(vm_name):
   313             return
   314         logger.info('Powering off ' + vm_name)
   315         return checkResult(Cygwin.vboxExecute('controlvm ' + vm_name + ' poweroff'))
   316     
   317     #list the hostonly IFs exposed by the VBox host
   318     @staticmethod    
   319     def getHostOnlyIFs():
   320         result = Cygwin.vboxExecute('list hostonlyifs')[1]
   321         if result=='':
   322             return None
   323         props = dict((k.strip(),v.strip().strip('"')) for k,v in (line.split(':', 1) for line in result.strip().splitlines()))
   324         return props
   325     
   326     # return the hostOnly IP for a running guest or the host
   327     @staticmethod    
   328     def getHostOnlyIP(vm_name):
   329         if vm_name == None:
   330             logger.info('Gettting hostOnly IP address for Host')
   331             return VMManager.getHostOnlyIFs()['IPAddress']
   332         else:
   333             logger.info('Gettting hostOnly IP address ' + vm_name)
   334             result = checkResult(Cygwin.vboxExecute('guestproperty get ' + vm_name + ' /VirtualBox/GuestInfo/Net/0/V4/IP'))
   335             if result=='':
   336                 return None
   337             result = result[1]
   338             if result.startswith('No value set!'):
   339                 return None
   340             return result[result.index(':')+1:].strip()
   341             
   342     # attach removable storage device to VM by provision of filter
   343     def attachRSD(self, vm_name, rsd_filter):
   344         return checkResult(Cygwin.vboxExecute('usbfilter add 0 --target ' + vm_name + ' --name OpenSecurityRSD --vendorid ' + rsd_filter.vendorid + ' --productid ' + rsd_filter.productid + ' --revision ' + rsd_filter.revision))
   345     
   346     # detach removable storage from VM by 
   347     def detachRSD(self, vm_name):
   348         return checkResult(Cygwin.vboxExecute('usbfilter remove 0 --target ' + vm_name))
   349         
   350     # return the description set for an existing VM
   351     def getVMInfo(self, vm_name):
   352         results = checkResult(Cygwin.vboxExecute('showvminfo ' + vm_name + ' --machinereadable'))[1]
   353         props = dict((k.strip().strip('"'),v.strip().strip('"')) for k,v in (line.split('=', 1) for line in results.splitlines()))
   354         return props
   355     
   356     # return the configured USB filter for an existing VM 
   357     def getUSBFilter(self, vm_name):
   358         props = self.getVMInfo(vm_name)
   359         keys = set(['USBFilterVendorId1', 'USBFilterProductId1', 'USBFilterRevision1'])
   360         keyset = set(props.keys())
   361         usb_filter = None
   362         if keyset.issuperset(keys):
   363             usb_filter = USBFilter(props['USBFilterVendorId1'], props['USBFilterProductId1'], props['USBFilterRevision1'])
   364         return usb_filter
   365     
   366     #generates ISO containing authorized_keys for use with guest VM
   367     def genCertificateISO(self, vm_name):
   368         machineFolder = Cygwin.cygPath(self.machineFolder)
   369         # remove .ssh folder if exists
   370         checkResult(Cygwin.bashExecute('/usr/bin/rm -rf \\\"' + machineFolder + '/' + vm_name + '/.ssh\\\"'))
   371         # remove .ssh folder if exists
   372         checkResult(Cygwin.bashExecute('/usr/bin/rm -rf \\\"' + machineFolder + '/' + vm_name + '/dvm_key\\\"'))
   373         # create .ssh folder in vm_name
   374         checkResult(Cygwin.bashExecute('/usr/bin/mkdir -p \\\"' + machineFolder + '/' + vm_name + '/.ssh\\\"'))
   375         # generate dvm_key pair in vm_name / .ssh     
   376         checkResult(Cygwin.bashExecute('/usr/bin/ssh-keygen -q -t rsa -N \\\"\\\" -C \\\"' + vm_name + '\\\" -f \\\"' + machineFolder + '/' + vm_name + '/.ssh/dvm_key\\\"'))
   377         # move out private key
   378         checkResult(Cygwin.bashExecute('/usr/bin/mv \\\"' + machineFolder + '/' + vm_name + '/.ssh/dvm_key\\\" \\\"' + machineFolder + '/' + vm_name + '\\\"'))
   379         # set permissions for private key
   380         checkResult(Cygwin.bashExecute('/usr/bin/chmod 500 \\\"' + machineFolder + '/' + vm_name + '/dvm_key\\\"'))
   381         # rename public key to authorized_keys
   382         checkResult(Cygwin.bashExecute('/usr/bin/mv \\\"' + machineFolder + '/' + vm_name + '/.ssh/dvm_key.pub\\\" \\\"' + machineFolder + '/' + vm_name + '/.ssh/authorized_keys\\\"'))
   383         # set permissions for authorized_keys
   384         checkResult(Cygwin.bashExecute('/usr/bin/chmod 500 \\\"' + machineFolder + '/' + vm_name + '/.ssh/authorized_keys\\\"'))
   385         # generate iso image with .ssh/authorized keys
   386         checkResult(Cygwin.bashExecute('/usr/bin/genisoimage -J -R -o \\\"' + machineFolder + '/' + vm_name + '/'+ vm_name + '.iso\\\" \\\"' + machineFolder + '/' + vm_name + '/.ssh\\\"'))
   387     
   388     # attaches generated ssh public cert to guest vm
   389     def attachCertificateISO(self, vm_name):
   390         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\"'))
   391         return result
   392     
   393     # wait for machine to come up
   394     def waitStartup(self, vm_name, timeout_ms = 30000):
   395         checkResult(Cygwin.vboxExecute('guestproperty wait ' + vm_name + ' SDVMStarted --timeout ' + str(timeout_ms) + ' --fail-on-timeout'))
   396         return VMManager.getHostOnlyIP(vm_name)
   397     
   398     # wait for machine to shutdown
   399     def waitShutdown(self, vm_name):
   400         while vm_name in self.listRunningVMS():
   401             time.sleep(1)
   402         return
   403         
   404     # handles browsing request    
   405     def handleBrowsingRequest(self):
   406         handler = BrowsingHandler(self)
   407         handler.start()
   408         return 'ok'
   409     
   410     #Small function to check the availability of network resource.
   411     #def isAvailable(self, path):
   412         #return os.path.exists(path)
   413         #result = Cygwin.cmdExecute('IF EXIST "' + path + '" echo YES')
   414         #return string.find(result[1], 'YES',)
   415     
   416     #Small function to check if the mention location is a directory
   417     def isDirectory(self, path):
   418         result = checkResult(Cygwin.cmdExecute('dir ' + path + ' | FIND ".."'))
   419         return string.find(result[1], 'DIR',)
   420 
   421     def mapNetworkDrive(self, drive, networkPath, user, password):
   422         self.unmapNetworkDrive(drive)
   423         #Check for drive availability
   424         if os.path.exists(drive):
   425             logger.error("Drive letter is already in use: " + drive)
   426             return -1
   427         #Check for network resource availability
   428         retry = 5
   429         while not os.path.exists(networkPath):
   430             time.sleep(1)
   431             if retry == 0:
   432                 return -1
   433             logger.info("Path not accessible: " + networkPath + " retrying")
   434             retry-=1
   435             #return -1
   436     
   437         command = 'USE ' + drive + ' ' + networkPath + ' /PERSISTENT:NO'
   438         if user != None:
   439             command += ' ' + password + ' /User' + user
   440     
   441         #TODO: Execute 'NET USE' command with authentication
   442         result = checkResult(Cygwin.execute('C:\\Windows\\system32\\net.exe', command))
   443         if string.find(result[1], 'successfully',) == -1:
   444             logger.error("Failed: NET " + command)
   445             return -1
   446         return 1
   447     
   448     def unmapNetworkDrive(self, drive):
   449         drives = self.getNetworkDrives()
   450         if drive not in drives.keys():
   451             return 1 
   452         result = checkResult(Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE ' + drive + ' /DELETE /YES'))
   453         if string.find(str(result[1]), 'successfully',) == -1:
   454             logger.error(result[2])
   455             return -1
   456         return 1
   457     
   458     def getNetworkDrives(self):
   459         ip = VMManager.getHostOnlyIP(None)
   460         ip = ip[:ip.rindex('.')]
   461         drives = dict()    
   462         result = checkResult(Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE'))
   463         for line in result[1].splitlines():
   464             if ip in line:
   465                 parts = line.split()
   466                 drives[parts[1]] = parts[2]
   467         return drives
   468             
   469     def genNetworkDrive(self):
   470         network_drives = self.getNetworkDrives()
   471         logical_drives = VMManager.getLogicalDrives()
   472         drives = list(map(chr, range(68, 91)))  
   473         for drive in drives:
   474             if drive+':' not in network_drives and drive not in logical_drives:
   475                 return drive+':'
   476 
   477     def getNetworkDrive(self, vm_name):
   478         ip = self.getHostOnlyIP(vm_name)
   479         result = checkResult(Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE'))
   480         for line in result[1].splitlines():
   481             if line != None and ip in line:
   482                 parts = line.split()
   483                 return parts[0]
   484     @staticmethod
   485     def getLogicalDrives():
   486         drive_bitmask = ctypes.cdll.kernel32.GetLogicalDrives()
   487         return list(itertools.compress(string.ascii_uppercase,  map(lambda x:ord(x) - ord('0'), bin(drive_bitmask)[:1:-1])))
   488     
   489     @staticmethod
   490     def getDriveType(drive):
   491         return ctypes.cdll.kernel32.GetDriveTypeW(u"%s:\\"%drive)
   492     
   493     @staticmethod
   494     def getVolumeInfo(drive):
   495         volumeNameBuffer = ctypes.create_unicode_buffer(1024)
   496         fileSystemNameBuffer = ctypes.create_unicode_buffer(1024)
   497         serial_number = None
   498         max_component_length = None
   499         file_system_flags = None
   500         
   501         rc = ctypes.cdll.kernel32.GetVolumeInformationW(
   502             #ctypes.c_wchar_p("F:\\"),
   503             u"%s:\\"%drive,
   504             volumeNameBuffer,
   505             ctypes.sizeof(volumeNameBuffer),
   506             serial_number,
   507             max_component_length,
   508             file_system_flags,
   509             fileSystemNameBuffer,
   510             ctypes.sizeof(fileSystemNameBuffer)
   511         )
   512         
   513         return volumeNameBuffer.value, fileSystemNameBuffer.value
   514 
   515 def checkResult(result):
   516     if result[0] != 0:
   517         logger.error('Command failed:' + ''.join(result[2]))
   518         raise OpenSecurityException('Command failed:' + ''.join(result[2]))
   519     return result
   520 
   521 # handles browsing request                    
   522 class BrowsingHandler(threading.Thread):   
   523     vmm = None
   524     def __init__(self, vmmanager):
   525         threading.Thread.__init__(self)
   526         self.vmm = vmmanager
   527      
   528     def run(self):
   529         drive = None
   530         try:
   531             Cygwin.start_X11()
   532             new_sdvm = self.vmm.generateSDVMName()
   533             self.vmm.createVM(new_sdvm)
   534             self.vmm.storageAttach(new_sdvm)
   535             self.vmm.genCertificateISO(new_sdvm)
   536             self.vmm.attachCertificateISO(new_sdvm)
   537             self.vmm.startVM(new_sdvm)
   538             new_ip = self.vmm.waitStartup(new_sdvm)
   539             drive = self.vmm.genNetworkDrive()
   540             if new_ip != None:
   541                 self.vmm.mapNetworkDrive(drive, '\\\\' + new_ip + '\\Download', None, None)
   542             #browser = '/usr/bin/iceweasel'
   543             #browser = '/usr/bin/midori'
   544             browser = '/usr/bin/chromium'
   545             result = checkResult(Cygwin.sshExecuteX11(browser, new_ip, 'osecuser', Cygwin.cygPath(self.vmm.getMachineFolder()) + '/' + new_sdvm + '/dvm_key'))
   546         except:
   547             logger.error("BrowsingHandler failed. Cleaning up")
   548         if drive != None:    
   549             self.vmm.unmapNetworkDrive(drive)
   550         self.vmm.poweroffVM(new_sdvm)
   551         self.vmm.removeVM(new_sdvm)
   552                 
   553 class DeviceHandler(threading.Thread): 
   554     vmm = None
   555     attachedRSDs = None  
   556     connectedRSDs = None
   557     running = True
   558     def __init__(self, vmmanger): 
   559         threading.Thread.__init__(self)
   560         self.vmm = vmmanger
   561  
   562     def stop(self):
   563         self.running = False
   564         
   565     def run(self):
   566         self.connectedRSDs = dict()
   567         while self.running:
   568             tmp_rsds = self.vmm.getConnectedRSDS()
   569             
   570             self.attachedRSDs = self.vmm.getAttachedRSDs()
   571             for vm_name in self.attachedRSDs.keys():
   572                 if self.attachedRSDs[vm_name] not in tmp_rsds.values():
   573                     drive = self.vmm.getNetworkDrive(vm_name)
   574                     self.vmm.unmapNetworkDrive(drive)
   575                     #self.stopVM(vm_name)
   576                     self.vmm.detachRSD(vm_name)
   577                     self.vmm.poweroffVM(vm_name)
   578                     self.vmm.removeVM(vm_name)
   579                     break
   580                     
   581                     
   582             if tmp_rsds.keys() == self.connectedRSDs.keys():
   583                 logger.debug("Nothing's changed. sleep(3)")
   584                 time.sleep(3)
   585                 continue
   586             
   587             logger.info("Something's changed")          
   588             self.connectedRSDs = tmp_rsds
   589             
   590             
   591             
   592             #create new vm for attached device if any
   593             self.attachedRSDs = self.vmm.getAttachedRSDs()
   594             self.connectedRSDs = self.vmm.getConnectedRSDS()
   595             
   596             new_ip = None
   597             for connected_device in self.connectedRSDs.values():
   598                 if (self.attachedRSDs and False) or (connected_device not in self.attachedRSDs.values()):
   599                     new_sdvm = self.vmm.generateSDVMName()
   600                     self.vmm.createVM(new_sdvm)
   601                     self.vmm.storageAttach(new_sdvm)
   602                     self.vmm.attachRSD(new_sdvm, connected_device)
   603                     self.vmm.startVM(new_sdvm)
   604                     new_ip = self.vmm.waitStartup(new_sdvm)
   605                     drive = self.vmm.genNetworkDrive()
   606                     if new_ip != None:
   607                         self.vmm.mapNetworkDrive(drive, '\\\\' + new_ip + '\\USB', None, None)
   608 
   609 if __name__ == '__main__':
   610     #man = VMManager.getInstance()
   611     #man.listVM()
   612     #print man.getConnectedRSDs()
   613     #print man.getNetworkDrives()
   614     #man.genNetworkDrive()
   615     #drive_bitmask = ctypes.cdll.kernel32.GetLogicalDrives()
   616     #print list(itertools.compress(string.ascii_uppercase,  map(lambda x:ord(x) - ord('0'), bin(drive_bitmask)[:1:-1])))
   617     #print list(map(chr, range(68, 91))) 
   618     #print Cygwin.getRegEntry('SYSTEM\CurrentControlSet\Enum\USB', 'VID_1058&PID_0704')[0]
   619     #devices = VMManager.getConnectedRSDS()
   620     #print devices
   621     
   622     drives = VMManager.getLogicalDrives()
   623     print drives
   624     print VMManager.getDriveType("E")
   625     print VMManager.getVolumeInfo("E")
   626     #for device in devices.values():
   627     #    #print device
   628     #    if VMManager.isMassStorageDevice(device):
   629     #        print device
   630         
   631     
   632     
   633     #time.sleep(-1)
   634     #man.listVM()
   635     #man.listVM()
   636     #man.listVM()
   637     #man.listVM()
   638     #man.genCertificateISO('SecurityDVM0')
   639     #man.guestExecute('SecurityDVM0', '/bin/ls -la')
   640     #logger = setupLogger('VMManager')
   641     #c = Cygwin()
   642     
   643     #man.sshExecute('/bin/ls -la', 'SecurityDVM0')
   644     #man.sshExecuteX11('/usr/bin/iceweasel', 'SecurityDVM0')
   645     #man.removeVM('SecurityDVM0')
   646     #man.netUse('192.168.56.134', 'USB\\')
   647     #ip = '192.168.56.139'
   648     
   649     #man.cygwin_path = 'c:\\cygwin64\\bin\\'
   650     #man.handleDeviceChange()
   651     #print man.listSDVM()
   652     #man.configureHostNetworking()
   653     #new_vm = man.generateSDVMName()
   654     #man.createVM(new_vm)
   655     
   656     #print Cygwin.cmd()
   657     #man.isAvailable('c:')
   658     #ip = man.getHostOnlyIP('SecurityDVM0')
   659     #man.mapNetworkDrive('h:', '\\\\' + ip + '\Download', None, None)
   660     
   661     #man.genCertificateISO(new_vm)
   662     #man.attachCertificateISO(new_vm)
   663     
   664     #man.attachCertificateISO(vm_name)
   665     #man.guestExecute(vm_name, "ls")
   666     #man.sshGuestX11Execute('SecurityDVM1', '/usr/bin/iceweasel')
   667     #time.sleep(60)
   668     #print man.cygwinPath("C:\Users\BarthaM\VirtualBox VMs\SecurityDVM\.ssh\*")
   669     #man.genCertificateISO('SecurityDVM')
   670     #man.attachCertificateISO('SecurityDVM')
   671     #man.isStorageAttached('SecurityDVM')
   672     #man.guestExecute('SecurityDVM', 'sudo apt-get -y update')
   673     #man.guestExecute('SecurityDVM', 'sudo apt-get -y upgrade' )
   674     
   675     #man.stopVM('SecurityDVM')
   676     #man.storageDetach('SecurityDVM')
   677     #man.changeStorageType('C:\Users\BarthaM\VirtualBox VMs\SecurityDVM\SecurityDVM.vmdk','immutable')
   678     #man.storageAttach('SecurityDVM')
   679     
   680     
   681     #cmd = "c:\\cygwin64\\bin\\bash.exe --login -c \"/bin/ls\""
   682     #man.execute(cmd)