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