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