OpenSecurity/bin/vmmanager.pyw
author Oliver Maurhart <oliver.maurhart@ait.ac.at>
Fri, 25 Apr 2014 13:23:20 +0200
changeset 133 6649faffb63c
parent 131 8b4df474e577
child 135 c9499f5166c7
permissions -rwxr-xr-x
run download and import even as Non-Admin
     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 
    58     vmRootName = "SecurityDVM"
    59     systemProperties = None
    60     _instance = None
    61     machineFolder = ''
    62     rsdHandler = 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         else:
    77             logger.critical(self.status_message)
    78     
    79 
    80     @staticmethod
    81     def getInstance():
    82         if VMManager._instance == None:
    83             VMManager._instance = VMManager()
    84         return VMManager._instance
    85     
    86 
    87     def backend_ok(self):
    88 
    89         """check if the backend (VirtualBox) is sufficient for our task"""
    90 
    91         # ensure we have our system props
    92         if self.systemProperties == None:
    93             self.systemProperties = self.getSystemProperties()
    94         if self.systemProperties == None:
    95             self.status_message = 'Failed to get backend system properties. Is Backend (VirtualBox?) installed?'
    96             return False
    97 
    98         # check for existing Extension pack
    99         if not 'Remote desktop ExtPack' in self.systemProperties:
   100             self.status_message = 'No remote desktop extension pack found. Please install the "Oracle VM VirtualBox Extension Pack" from https://www.virtualbox.org/wiki/Downloads.'
   101             return False
   102         if self.systemProperties['Remote desktop ExtPack'] == 'Oracle VM VirtualBox Extension Pack ':
   103             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.'
   104             return False
   105 
   106         # check if we do have our root VMs installed
   107         vms = self.listVM()
   108         if not self.vmRootName in vms:
   109             self.status_message = 'Unable to locate root SecurityDVM. Please download and setup the initial image.'
   110             return False
   111 
   112         # basically all seems nice and ready to rumble
   113         self.status_message = 'All is ok.'
   114 
   115         return True
   116 
   117 
   118     def cleanup(self):
   119         if self.rsdHandler != None:
   120             self.rsdHandler.stop()
   121             self.rsdHandler.join()
   122         drives = self.getNetworkDrives()
   123         for drive in drives.keys():
   124             self.unmapNetworkDrive(drive)
   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 the availability of network resource.
   462     #def isAvailable(self, path):
   463         #return os.path.exists(path)
   464         #result = Cygwin.cmdExecute('IF EXIST "' + path + '" echo YES')
   465         #return string.find(result[1], 'YES',)
   466     
   467     #Small function to check if the mention location is a directory
   468     def isDirectory(self, path):
   469         result = checkResult(Cygwin.cmdExecute('dir ' + path + ' | FIND ".."'))
   470         return string.find(result[1], 'DIR',)
   471 
   472     def mapNetworkDrive(self, drive, networkPath, user, password):
   473         self.unmapNetworkDrive(drive)
   474         #Check for drive availability
   475         if os.path.exists(drive):
   476             logger.error("Drive letter is already in use: " + drive)
   477             return -1
   478         #Check for network resource availability
   479         retry = 5
   480         while not os.path.exists(networkPath):
   481             time.sleep(1)
   482             if retry == 0:
   483                 return -1
   484             logger.info("Path not accessible: " + networkPath + " retrying")
   485             retry-=1
   486             #return -1
   487     
   488         command = 'USE ' + drive + ' ' + networkPath + ' /PERSISTENT:NO'
   489         if user != None:
   490             command += ' ' + password + ' /User' + user
   491     
   492         #TODO: Execute 'NET USE' command with authentication
   493         result = checkResult(Cygwin.execute('C:\\Windows\\system32\\net.exe', command))
   494         if string.find(result[1], 'successfully',) == -1:
   495             logger.error("Failed: NET " + command)
   496             return -1
   497         return 1
   498     
   499     def unmapNetworkDrive(self, drive):
   500         drives = self.getNetworkDrives()
   501         if drive not in drives.keys():
   502             return 1 
   503         result = checkResult(Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE ' + drive + ' /DELETE /YES'))
   504         if string.find(str(result[1]), 'successfully',) == -1:
   505             logger.error(result[2])
   506             return -1
   507         return 1
   508     
   509     def getNetworkDrives(self):
   510         ip = VMManager.getHostOnlyIP(None)
   511         ip = ip[:ip.rindex('.')]
   512         drives = dict()    
   513         result = checkResult(Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE'))
   514         for line in result[1].splitlines():
   515             if ip in line:
   516                 parts = line.split()
   517                 drives[parts[1]] = parts[2]
   518         return drives
   519             
   520     def genNetworkDrive(self):
   521         network_drives = self.getNetworkDrives()
   522         logical_drives = VMManager.getLogicalDrives()
   523         drives = list(map(chr, range(68, 91)))  
   524         for drive in drives:
   525             if drive+':' not in network_drives and drive not in logical_drives:
   526                 return drive+':'
   527 
   528     def getNetworkDrive(self, vm_name):
   529         ip = self.getHostOnlyIP(vm_name)
   530         result = checkResult(Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE'))
   531         for line in result[1].splitlines():
   532             if line != None and ip in line:
   533                 parts = line.split()
   534                 return parts[0]
   535     @staticmethod
   536     def getLogicalDrives():
   537         drive_bitmask = ctypes.cdll.kernel32.GetLogicalDrives()
   538         return list(itertools.compress(string.ascii_uppercase,  map(lambda x:ord(x) - ord('0'), bin(drive_bitmask)[:1:-1])))
   539     
   540     @staticmethod
   541     def getDriveType(drive):
   542         return ctypes.cdll.kernel32.GetDriveTypeW(u"%s:\\"%drive)
   543     
   544     @staticmethod
   545     def getVolumeInfo(drive):
   546         volumeNameBuffer = ctypes.create_unicode_buffer(1024)
   547         fileSystemNameBuffer = ctypes.create_unicode_buffer(1024)
   548         serial_number = None
   549         max_component_length = None
   550         file_system_flags = None
   551         
   552         rc = ctypes.cdll.kernel32.GetVolumeInformationW(
   553             #ctypes.c_wchar_p("F:\\"),
   554             u"%s:\\"%drive,
   555             volumeNameBuffer,
   556             ctypes.sizeof(volumeNameBuffer),
   557             serial_number,
   558             max_component_length,
   559             file_system_flags,
   560             fileSystemNameBuffer,
   561             ctypes.sizeof(fileSystemNameBuffer)
   562         )
   563         
   564         return volumeNameBuffer.value, fileSystemNameBuffer.value
   565 
   566 def checkResult(result):
   567     if result[0] != 0:
   568         logger.error('Command failed:\n' + result[2])
   569         raise OpenSecurityException('Command failed:' + ''.join(result[2]))
   570     return result
   571 
   572 
   573             
   574 # handles browsing request                    
   575 class BrowsingHandler(threading.Thread):   
   576     vmm = None
   577     #Cygwin.start_X11()
   578     def __init__(self, vmmanager):
   579         threading.Thread.__init__(self)
   580         self.vmm = vmmanager
   581      
   582     def run(self):
   583         drive = None
   584         try:
   585             new_sdvm = self.vmm.generateSDVMName()
   586             self.vmm.createVM(new_sdvm)
   587             self.vmm.storageAttach(new_sdvm)
   588             self.vmm.genCertificateISO(new_sdvm)
   589             self.vmm.attachCertificateISO(new_sdvm)
   590             self.vmm.startVM(new_sdvm)
   591             new_ip = self.vmm.waitStartup(new_sdvm)
   592             drive = self.vmm.genNetworkDrive()
   593             if new_ip != None:
   594                 self.vmm.mapNetworkDrive(drive, '\\\\' + new_ip + '\\Download', None, None)
   595             #browser = '/usr/bin/iceweasel'
   596             #browser = '/usr/bin/midori'
   597             #browser = '/usr/bin/chromium '
   598             browser = '\\\"/usr/bin/chromium; pidof dbus-launch | xargs kill\\\"'
   599             Cygwin.start_X11()
   600            
   601             #if Cygwin.is_X11_running()==True:
   602             #result = checkResult(Cygwin.bashExecute('DISPLAY=:0 xhost '+new_ip))
   603             result = checkResult(Cygwin.sshExecuteX11(browser, new_ip, 'osecuser', Cygwin.cygPath(self.vmm.getMachineFolder()) + '/' + new_sdvm + '/dvm_key'))
   604         except:
   605             logger.error("BrowsingHandler failed. Cleaning up")
   606         if drive != None:    
   607             self.vmm.unmapNetworkDrive(drive)
   608         self.vmm.poweroffVM(new_sdvm)
   609         self.vmm.removeVM(new_sdvm)
   610                 
   611 class DeviceHandler(threading.Thread): 
   612     vmm = None
   613     attachedRSDs = None  
   614     connectedRSDs = None
   615     running = True
   616     def __init__(self, vmmanger): 
   617         threading.Thread.__init__(self)
   618         self.vmm = vmmanger
   619  
   620     def stop(self):
   621         self.running = False
   622         
   623     def run(self):
   624         self.connectedRSDs = dict()
   625         while self.running:
   626             tmp_rsds = self.vmm.getConnectedRSDS()
   627             
   628             self.attachedRSDs = self.vmm.getAttachedRSDs()
   629             for vm_name in self.attachedRSDs.keys():
   630                 if self.attachedRSDs[vm_name] not in tmp_rsds.values():
   631                     drive = self.vmm.getNetworkDrive(vm_name)
   632                     self.vmm.unmapNetworkDrive(drive)
   633                     #self.stopVM(vm_name)
   634                     self.vmm.detachRSD(vm_name)
   635                     self.vmm.poweroffVM(vm_name)
   636                     self.vmm.removeVM(vm_name)
   637                     break
   638                     
   639                     
   640             if tmp_rsds.keys() == self.connectedRSDs.keys():
   641                 logger.debug("Nothing's changed. sleep(3)")
   642                 time.sleep(3)
   643                 continue
   644             
   645             logger.info("Something's changed")          
   646             self.connectedRSDs = tmp_rsds
   647             
   648             
   649             
   650             #create new vm for attached device if any
   651             self.attachedRSDs = self.vmm.getAttachedRSDs()
   652             self.connectedRSDs = self.vmm.getConnectedRSDS()
   653             
   654             new_ip = None
   655             for connected_device in self.connectedRSDs.values():
   656                 if (self.attachedRSDs and False) or (connected_device not in self.attachedRSDs.values()):
   657                     new_sdvm = self.vmm.generateSDVMName()
   658                     self.vmm.createVM(new_sdvm)
   659                     self.vmm.storageAttach(new_sdvm)
   660                     self.vmm.attachRSD(new_sdvm, connected_device)
   661                     self.vmm.startVM(new_sdvm)
   662                     new_ip = self.vmm.waitStartup(new_sdvm)
   663                     drive = self.vmm.genNetworkDrive()
   664                     if new_ip != None:
   665                         self.vmm.mapNetworkDrive(drive, '\\\\' + new_ip + '\\USB', None, None)
   666 
   667 if __name__ == '__main__':
   668     #man = VMManager.getInstance()
   669     #man.listVM()
   670     #print man.getConnectedRSDs()
   671     #print man.getNetworkDrives()
   672     #man.genNetworkDrive()
   673     #drive_bitmask = ctypes.cdll.kernel32.GetLogicalDrives()
   674     #print list(itertools.compress(string.ascii_uppercase,  map(lambda x:ord(x) - ord('0'), bin(drive_bitmask)[:1:-1])))
   675     #print list(map(chr, range(68, 91))) 
   676     #print Cygwin.getRegEntry('SYSTEM\CurrentControlSet\Enum\USB', 'VID_1058&PID_0704')[0]
   677     #devices = VMManager.getConnectedRSDS()
   678     #print devices
   679     
   680     drives = VMManager.getLogicalDrives()
   681     print drives
   682     print VMManager.getDriveType("E")
   683     print VMManager.getVolumeInfo("E")
   684     #for device in devices.values():
   685     #    #print device
   686     #    if VMManager.isMassStorageDevice(device):
   687     #        print device
   688         
   689     
   690     
   691     #time.sleep(-1)
   692     #man.listVM()
   693     #man.listVM()
   694     #man.listVM()
   695     #man.listVM()
   696     #man.genCertificateISO('SecurityDVM0')
   697     #man.guestExecute('SecurityDVM0', '/bin/ls -la')
   698     #logger = setupLogger('VMManager')
   699     #c = Cygwin()
   700     
   701     #man.sshExecute('/bin/ls -la', 'SecurityDVM0')
   702     #man.sshExecuteX11('/usr/bin/iceweasel', 'SecurityDVM0')
   703     #man.removeVM('SecurityDVM0')
   704     #man.netUse('192.168.56.134', 'USB\\')
   705     #ip = '192.168.56.139'
   706     
   707     #man.cygwin_path = 'c:\\cygwin64\\bin\\'
   708     #man.handleDeviceChange()
   709     #print man.listSDVM()
   710     #man.configureHostNetworking()
   711     #new_vm = man.generateSDVMName()
   712     #man.createVM(new_vm)
   713     
   714     #print Cygwin.cmd()
   715     #man.isAvailable('c:')
   716     #ip = man.getHostOnlyIP('SecurityDVM0')
   717     #man.mapNetworkDrive('h:', '\\\\' + ip + '\Download', None, None)
   718     
   719     #man.genCertificateISO(new_vm)
   720     #man.attachCertificateISO(new_vm)
   721     
   722     #man.attachCertificateISO(vm_name)
   723     #man.guestExecute(vm_name, "ls")
   724     #man.sshGuestX11Execute('SecurityDVM1', '/usr/bin/iceweasel')
   725     #time.sleep(60)
   726     #print man.cygwinPath("C:\Users\BarthaM\VirtualBox VMs\SecurityDVM\.ssh\*")
   727     #man.genCertificateISO('SecurityDVM')
   728     #man.attachCertificateISO('SecurityDVM')
   729     #man.isStorageAttached('SecurityDVM')
   730     #man.guestExecute('SecurityDVM', 'sudo apt-get -y update')
   731     #man.guestExecute('SecurityDVM', 'sudo apt-get -y upgrade' )
   732     
   733     #man.stopVM('SecurityDVM')
   734     #man.storageDetach('SecurityDVM')
   735     #man.changeStorageType('C:\Users\BarthaM\VirtualBox VMs\SecurityDVM\SecurityDVM.vmdk','immutable')
   736     #man.storageAttach('SecurityDVM')
   737     
   738     
   739     #cmd = "c:\\cygwin64\\bin\\bash.exe --login -c \"/bin/ls\""
   740     #man.execute(cmd)