OpenSecurity/bin/vmmanager.pyw
author BarthaM@N3SIM1218.D03.arc.local
Fri, 05 Sep 2014 12:28:30 +0100
changeset 221 853af9cfab6a
parent 219 9480e5ba1a82
child 223 a4fb6694e6fe
permissions -rwxr-xr-x
Integrated import script (rewritten in python) into opensecurity/vmmanager.py
Improoved user feedback upon import and update as well as logging.
Reduced system shutdown times and ui response times
Improoved the decoupling between UI and OSec subsystem.
Various other fixes
BarthaM@212
     1
#!/bin/env python
BarthaM@212
     2
# -*- coding: utf-8 -*-
mb@90
     3
BarthaM@212
     4
# ------------------------------------------------------------
BarthaM@212
     5
# opensecurityd
BarthaM@212
     6
#   
BarthaM@212
     7
# the opensecurityd as RESTful server
BarthaM@212
     8
#
BarthaM@212
     9
# Autor: Mihai Bartha, <mihai.bartha@ait.ac.at>
BarthaM@212
    10
#
BarthaM@212
    11
# Copyright (C) 2013 AIT Austrian Institute of Technology
BarthaM@212
    12
# AIT Austrian Institute of Technology GmbH
BarthaM@212
    13
# Donau-City-Strasse 1 | 1220 Vienna | Austria
BarthaM@212
    14
# http://www.ait.ac.at
BarthaM@212
    15
#
BarthaM@212
    16
# This program is free software; you can redistribute it and/or
BarthaM@212
    17
# modify it under the terms of the GNU General Public License
BarthaM@212
    18
# as published by the Free Software Foundation version 2.
BarthaM@212
    19
# 
BarthaM@212
    20
# This program is distributed in the hope that it will be useful,
BarthaM@212
    21
# but WITHOUT ANY WARRANTY; without even the implied warranty of
BarthaM@212
    22
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
BarthaM@212
    23
# GNU General Public License for more details.
BarthaM@212
    24
# 
BarthaM@212
    25
# You should have received a copy of the GNU General Public License
BarthaM@212
    26
# along with this program; if not, write to the Free Software
BarthaM@212
    27
# Foundation, Inc., 51 Franklin Street, Fifth Floor, 
BarthaM@212
    28
# Boston, MA  02110-1301, USA.
BarthaM@212
    29
# ------------------------------------------------------------
BarthaM@212
    30
BarthaM@212
    31
BarthaM@212
    32
# ------------------------------------------------------------
BarthaM@212
    33
# imports
BarthaM@212
    34
mb@90
    35
import os
mb@90
    36
import os.path
mb@90
    37
from subprocess import Popen, PIPE, call, STARTUPINFO, _subprocess
mb@90
    38
import sys
mb@90
    39
import re
mb@90
    40
mb@90
    41
from cygwin import Cygwin
mb@90
    42
from environment import Environment
mb@90
    43
import threading
mb@90
    44
import time
mb@90
    45
import string
mb@90
    46
mb@90
    47
import shutil
mb@90
    48
import stat
mb@90
    49
import tempfile
BarthaM@221
    50
from opensecurity_util import logger, import_logger, setupLogger, OpenSecurityException, showTrayMessage
mb@90
    51
import ctypes
mb@90
    52
import itertools
BarthaM@143
    53
import win32api
BarthaM@143
    54
import win32con
BarthaM@143
    55
import win32security
BarthaM@176
    56
import win32wnet
BarthaM@151
    57
import urllib
BarthaM@151
    58
import urllib2
BarthaM@212
    59
import unittest
mb@90
    60
DEBUG = True
mb@90
    61
BarthaM@159
    62
BarthaM@159
    63
new_sdvm_lock = threading.Lock()
BarthaM@159
    64
mb@90
    65
class VMManagerException(Exception):
mb@90
    66
    def __init__(self, value):
mb@90
    67
        self.value = value
mb@90
    68
    def __str__(self):
mb@90
    69
        return repr(self.value)
mb@90
    70
mb@90
    71
class USBFilter:
BarthaM@172
    72
    uuid = ""
mb@90
    73
    vendorid = ""
mb@90
    74
    productid = ""
mb@90
    75
    revision = ""
BarthaM@172
    76
    serial = ""
mb@90
    77
    
BarthaM@172
    78
    def __init__(self, uuid, vendorid, productid, revision, serial):
BarthaM@172
    79
        self.uuid = uuid
mb@90
    80
        self.vendorid = vendorid.lower()
mb@90
    81
        self.productid = productid.lower()
mb@90
    82
        self.revision = revision.lower()
BarthaM@172
    83
        self.serial = serial
mb@90
    84
        return
mb@90
    85
    
mb@90
    86
    def __eq__(self, other):
BarthaM@172
    87
        return self.uuid == other.uuid #self.vendorid == other.vendorid and self.productid == other.productid and self.revision == other.revision
mb@90
    88
    
mb@90
    89
    def __hash__(self):
BarthaM@172
    90
        return hash(self.uuid) ^ hash(self.vendorid) ^ hash(self.productid) ^ hash(self.revision) ^ hash(self.serial)
mb@90
    91
    
mb@90
    92
    def __repr__(self):
BarthaM@172
    93
        return "UUID:" + str(self.uuid) + " VendorId = \'" + str(self.vendorid) + "\' ProductId = \'" + str(self.productid) + "\'" + "\' Revision = \'" + str(self.revision) + "\' SerialNumber = \'" + str(self.serial)
mb@90
    94
    
mb@90
    95
    #def __getitem__(self, item):
mb@90
    96
    #    return self.coords[item]
BarthaM@212
    97
def once(theClass):
BarthaM@212
    98
    theClass.systemProperties = theClass.getSystemProperties()
BarthaM@212
    99
    theClass.machineFolder =    theClass.systemProperties["Default machine folder"]
BarthaM@217
   100
    #theClass.hostonlyIF =       theClass.getHostOnlyIFs()["VirtualBox Host-Only Ethernet Adapter"]
BarthaM@212
   101
    theClass.blacklistedRSD =   theClass.loadRSDBlacklist()
BarthaM@221
   102
    theClass.templateImage =    theClass.machineFolder + '\\' + theClass.vmRootName + '\\' + theClass.vmRootName + '.vmdk'
BarthaM@212
   103
    return theClass
BarthaM@212
   104
    
BarthaM@212
   105
@once
mb@90
   106
class VMManager(object):
mb@90
   107
    vmRootName = "SecurityDVM"
mb@90
   108
    systemProperties = None
mb@90
   109
    _instance = None
mb@90
   110
    machineFolder = ''
mb@90
   111
    rsdHandler = None
BarthaM@217
   112
    hostonlyIF = None
BarthaM@141
   113
    browsingManager = None
BarthaM@183
   114
    blacklistedRSD = None
oliver@131
   115
    status_message = 'Starting up...'
BarthaM@221
   116
    templateImage = None
BarthaM@221
   117
    importHandler = None
BarthaM@221
   118
    updateHandler = None
oliver@131
   119
 
oliver@131
   120
    def __init__(self):
oliver@131
   121
        # only proceed if we have a working background environment
oliver@131
   122
        if self.backend_ok():
BarthaM@217
   123
            VMManager.hostonlyIF = self.getHostOnlyIFs()["VirtualBox Host-Only Ethernet Adapter"]
oliver@131
   124
            self.cleanup()
oliver@131
   125
        else:
oliver@131
   126
            logger.critical(self.status_message)
mb@90
   127
    
oliver@131
   128
mb@90
   129
    @staticmethod
mb@90
   130
    def getInstance():
mb@90
   131
        if VMManager._instance == None:
mb@90
   132
            VMManager._instance = VMManager()
mb@90
   133
        return VMManager._instance
mb@90
   134
    
BarthaM@176
   135
    #list the hostonly IFs exposed by the VBox host
BarthaM@176
   136
    @staticmethod    
BarthaM@176
   137
    def getHostOnlyIFs():
BarthaM@217
   138
        results = Cygwin.vboxExecute('list hostonlyifs')[1]
BarthaM@217
   139
        ifs = dict()
BarthaM@217
   140
        if results=='':
BarthaM@217
   141
            return ifs
BarthaM@217
   142
        items = list( "Name:    " + result for result in results.split('Name:    ') if result != '')
BarthaM@217
   143
        for item in items:
BarthaM@217
   144
            if item != "":
BarthaM@217
   145
                props = dict((k.strip(),v.strip().strip('"')) for k,v in (line.split(':', 1) for line in item.strip().splitlines()))
BarthaM@217
   146
                ifs[props["Name"]] = props
BarthaM@217
   147
        return ifs
BarthaM@217
   148
                    
BarthaM@217
   149
        #props = dict((k.strip(),v.strip().strip('"')) for k,v in (line.split(':', 1) for line in result.strip().splitlines()))
BarthaM@217
   150
        #return props
BarthaM@217
   151
    
BarthaM@217
   152
    #list the hostonly IFs exposed by the VBox host
BarthaM@217
   153
    @staticmethod    
BarthaM@217
   154
    def getDHCPServers():
BarthaM@217
   155
        results = Cygwin.vboxExecute('list dhcpservers')[1]
BarthaM@217
   156
        if results=='':
BarthaM@217
   157
            return dict()
BarthaM@217
   158
        items = list( "NetworkName:    " + result for result in results.split('NetworkName:    ') if result != '')
BarthaM@217
   159
        dhcps = dict()   
BarthaM@217
   160
        for item in items:
BarthaM@217
   161
            if item != "":
BarthaM@217
   162
                props = dict((k.strip(),v.strip().strip('"')) for k,v in (line.split(':', 1) for line in item.strip().splitlines()))
BarthaM@217
   163
                dhcps[props["NetworkName"]] = props
BarthaM@217
   164
        return dhcps 
BarthaM@176
   165
        
BarthaM@176
   166
    # return hosty system properties
BarthaM@176
   167
    @staticmethod
BarthaM@176
   168
    def getSystemProperties():
BarthaM@218
   169
        result = Cygwin.vboxExecute('list systemproperties')
BarthaM@176
   170
        if result[1]=='':
BarthaM@176
   171
            return None
BarthaM@176
   172
        props = dict((k.strip(),v.strip().strip('"')) for k,v in (line.split(':', 1) for line in result[1].strip().splitlines()))
BarthaM@176
   173
        return props
BarthaM@176
   174
    
BarthaM@176
   175
    # return the folder containing the guest VMs     
BarthaM@176
   176
    def getMachineFolder(self):
BarthaM@212
   177
        return VMManager.machineFolder
BarthaM@217
   178
    
BarthaM@217
   179
    # verifies the hostonly interface and DHCP server settings
BarthaM@217
   180
    def verifyHostOnlySettings(self):
BarthaM@217
   181
        interfaceName = "VirtualBox Host-Only Ethernet Adapter"
BarthaM@217
   182
        networkName = "HostInterfaceNetworking-VirtualBox Host-Only Ethernet Adapter"
BarthaM@217
   183
        
BarthaM@217
   184
        hostonlyifs = self.getHostOnlyIFs()
BarthaM@217
   185
        if not interfaceName in hostonlyifs.keys():
BarthaM@217
   186
            Cygwin.vboxExecute('hostonlyif create')
BarthaM@217
   187
            hostonlyifs = self.getHostOnlyIFs()
BarthaM@217
   188
            if not interfaceName in hostonlyifs.keys():
BarthaM@217
   189
                return False
BarthaM@217
   190
        
BarthaM@217
   191
        interface = hostonlyifs[interfaceName]
BarthaM@217
   192
        if interface['VBoxNetworkName'] != networkName or interface['DHCP'] != 'Disabled' or interface['IPAddress'] != '192.168.56.1':
BarthaM@217
   193
            Cygwin.vboxExecute('hostonlyif ipconfig "' + interfaceName + '" --ip 192.168.56.1 --netmask 255.255.255.0')
BarthaM@217
   194
            
BarthaM@217
   195
        dhcpservers = self.getDHCPServers()
BarthaM@217
   196
        if not networkName in dhcpservers.keys():
BarthaM@217
   197
            Cygwin.vboxExecute('dhcpserver add --ifname "' + interfaceName + '" --ip 192.168.56.100 --netmask 255.255.255.0 --lowerip 192.168.56.101 --upperip 192.168.56.254 --enable')
BarthaM@217
   198
            dhcpservers = self.getDHCPServers()
BarthaM@217
   199
            if not networkName in dhcpservers.keys():
BarthaM@217
   200
                return False
BarthaM@217
   201
            
BarthaM@217
   202
        server = dhcpservers[networkName]
BarthaM@217
   203
        if server['IP'] != '192.168.56.100' or server['NetworkMask'] != '255.255.255.0' or server['lowerIPAddress'] != '192.168.56.101' or server['upperIPAddress'] != '192.168.56.254' or server['Enabled'] != 'Yes':
BarthaM@217
   204
            Cygwin.vboxExecute('VBoxManage dhcpserver modify --netname "' + networkName + '" --ip 192.168.56.100 --netmask 255.255.255.0 --lowerip 192.168.56.101 --upperip 192.168.56.254 --enable')
BarthaM@217
   205
        
BarthaM@217
   206
        return True
oliver@131
   207
BarthaM@219
   208
    def template_installed(self):
BarthaM@219
   209
        """ check if we do have our root VMs installed """
BarthaM@221
   210
        vms = self.listVMS()
BarthaM@219
   211
        if not self.vmRootName in vms:
BarthaM@219
   212
            self.status_message = 'Unable to locate root SecurityDVM. Please download and setup the initial image.'
BarthaM@219
   213
            return False
BarthaM@219
   214
        return True
BarthaM@219
   215
        
oliver@131
   216
    def backend_ok(self):
oliver@131
   217
        """check if the backend (VirtualBox) is sufficient for our task"""
oliver@131
   218
oliver@131
   219
        # ensure we have our system props
BarthaM@212
   220
        if VMManager.systemProperties == None:
BarthaM@212
   221
            VMManager.systemProperties = self.getSystemProperties()
BarthaM@212
   222
        if VMManager.systemProperties == None:
oliver@131
   223
            self.status_message = 'Failed to get backend system properties. Is Backend (VirtualBox?) installed?'
oliver@131
   224
            return False
oliver@131
   225
oliver@131
   226
        # check for existing Extension pack
BarthaM@212
   227
        if not 'Remote desktop ExtPack' in VMManager.systemProperties:
oliver@131
   228
            self.status_message = 'No remote desktop extension pack found. Please install the "Oracle VM VirtualBox Extension Pack" from https://www.virtualbox.org/wiki/Downloads.'
oliver@131
   229
            return False
BarthaM@212
   230
        if VMManager.systemProperties['Remote desktop ExtPack'] == 'Oracle VM VirtualBox Extension Pack ':
oliver@131
   231
            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.'
oliver@131
   232
            return False
oliver@131
   233
BarthaM@219
   234
        # check the existing hostOnly network settings and try to reconfigure if faulty
BarthaM@219
   235
        if not self.verifyHostOnlySettings():
oliver@131
   236
            return False
BarthaM@219
   237
        
oliver@131
   238
        # basically all seems nice and ready to rumble
oliver@131
   239
        self.status_message = 'All is ok.'
oliver@131
   240
        return True
BarthaM@170
   241
    
BarthaM@170
   242
    def stop(self):
BarthaM@219
   243
        Cygwin.denyExec()
mb@90
   244
        if self.rsdHandler != None:
mb@90
   245
            self.rsdHandler.stop()
mb@90
   246
            self.rsdHandler.join()
BarthaM@170
   247
            self.rsdHandler = None
BarthaM@170
   248
            
BarthaM@170
   249
        if self.browsingManager != None:
BarthaM@170
   250
            self.browsingManager.stop()
BarthaM@170
   251
            self.browsingManager.join()
BarthaM@170
   252
            self.browsingManager = None
BarthaM@219
   253
        Cygwin.allowExec()
BarthaM@170
   254
    
BarthaM@221
   255
    def start(self, force = False):
BarthaM@221
   256
        if not force:
BarthaM@221
   257
            if self.importHandler and self.importHandler.isAlive():
BarthaM@221
   258
                logger.info("Initial update running canceling start.")
BarthaM@221
   259
                return
BarthaM@221
   260
        
BarthaM@221
   261
            if self.updateHandler and self.updateHandler.isAlive():
BarthaM@221
   262
                logger.info("Update running canceling start.")
BarthaM@221
   263
                return
BarthaM@221
   264
        
BarthaM@170
   265
        self.stop()
BarthaM@219
   266
        Cygwin.allowExec()
BarthaM@219
   267
        if self.backend_ok() and self.template_installed():
BarthaM@219
   268
            self.browsingManager = BrowsingManager(self)
BarthaM@219
   269
            self.browsingManager.start()
BarthaM@219
   270
            self.rsdHandler = DeviceHandler(self)
BarthaM@219
   271
            self.rsdHandler.start()
BarthaM@170
   272
        
BarthaM@170
   273
BarthaM@170
   274
    def cleanup(self):
BarthaM@170
   275
        self.stop()
BarthaM@219
   276
        Cygwin.allowExec()
BarthaM@176
   277
        ip = self.getHostOnlyIP(None)
BarthaM@176
   278
        try:
BarthaM@176
   279
            result = urllib2.urlopen('http://127.0.0.1:8090/netcleanup?'+'hostonly_ip='+ip).readline()
BarthaM@176
   280
        except urllib2.URLError:
BarthaM@176
   281
            logger.info("Network drive cleanup all skipped. OpenSecurity Tray client not started yet.")
BarthaM@151
   282
            
mb@90
   283
        for vm in self.listSDVM():
mb@90
   284
            self.poweroffVM(vm)
mb@90
   285
            self.removeVM(vm)
mb@90
   286
mb@90
   287
    # list all existing VMs registered with VBox
BarthaM@221
   288
    def listVMS(self):
BarthaM@218
   289
        result = Cygwin.vboxExecute('list vms')[1]
mb@90
   290
        vms = list(k.strip().strip('"') for k,_ in (line.split(' ') for line in result.splitlines()))
mb@90
   291
        return vms
mb@90
   292
    
mb@90
   293
    # list running VMs
mb@90
   294
    def listRunningVMS(self):
BarthaM@218
   295
        result = Cygwin.vboxExecute('list runningvms')[1]
mb@90
   296
        vms = list(k.strip().strip('"') for k,_ in (line.split(' ') for line in result.splitlines()))
mb@90
   297
        return vms
mb@90
   298
    
mb@90
   299
    # list existing SDVMs
mb@90
   300
    def listSDVM(self):
BarthaM@221
   301
        vms = self.listVMS()
mb@90
   302
        svdms = []
mb@90
   303
        for vm in vms:
mb@90
   304
            if vm.startswith(self.vmRootName) and vm != self.vmRootName:
mb@90
   305
                svdms.append(vm)
mb@90
   306
        return svdms
mb@90
   307
    
mb@90
   308
    # generate valid (not already existing SDVM name). necessary for creating a new VM
BarthaM@159
   309
    def genSDVMName(self):
BarthaM@221
   310
        vms = self.listVMS()
mb@90
   311
        for i in range(0,999):
mb@90
   312
            if(not self.vmRootName+str(i) in vms):
mb@90
   313
                return self.vmRootName+str(i)
mb@90
   314
        return ''
mb@90
   315
    
BarthaM@183
   316
    @staticmethod
BarthaM@183
   317
    def loadRSDBlacklist():
BarthaM@183
   318
        blacklist = dict()
BarthaM@183
   319
        try:
BarthaM@183
   320
            fo = open(Environment('OpenSecurity').prefix_path +"\\bin\\blacklist.usb", "r")
BarthaM@183
   321
        except IOError:
BarthaM@183
   322
            logger.error("Could not open RSD blacklist file.")
BarthaM@183
   323
            return blacklist
BarthaM@183
   324
        
BarthaM@183
   325
        lines = fo.readlines()
BarthaM@183
   326
        for line in lines:
BarthaM@183
   327
            if line != "":  
BarthaM@183
   328
                parts = line.strip().split(' ')
BarthaM@183
   329
                blacklist[parts[0].lower()] = parts[1].lower()
BarthaM@183
   330
        return blacklist
BarthaM@183
   331
         
BarthaM@183
   332
    @staticmethod
BarthaM@183
   333
    def isBlacklisted(device):
BarthaM@183
   334
        if VMManager.blacklistedRSD:
BarthaM@183
   335
            blacklisted = device.vendorid.lower() in VMManager.blacklistedRSD.keys() and device.productid.lower() == VMManager.blacklistedRSD[device.vendorid]
BarthaM@183
   336
            return blacklisted
BarthaM@183
   337
        return False 
BarthaM@183
   338
    
mb@90
   339
    # check if the device is mass storage type
mb@90
   340
    @staticmethod
mb@90
   341
    def isMassStorageDevice(device):
BarthaM@219
   342
        vidkey = None
BarthaM@219
   343
        devinfokey = None
BarthaM@219
   344
        value = ""
BarthaM@219
   345
        try:
BarthaM@219
   346
            keyname = 'SYSTEM\CurrentControlSet\Enum\USB' + '\VID_' + device.vendorid+'&'+'PID_'+ device.productid
BarthaM@219
   347
            vidkey = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, keyname)
BarthaM@219
   348
            devinfokeyname = win32api.RegEnumKey(vidkey, 0)
BarthaM@219
   349
            win32api.RegCloseKey(vidkey)
BarthaM@219
   350
    
BarthaM@219
   351
            devinfokey = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, keyname+'\\'+devinfokeyname)
BarthaM@219
   352
            value = win32api.RegQueryValueEx(devinfokey, 'SERVICE')[0]
BarthaM@219
   353
            win32api.RegCloseKey(devinfokey)
BarthaM@219
   354
        except Exception as ex:
BarthaM@219
   355
            logger.error('Error reading registry.Exception details: %s' %ex)
BarthaM@219
   356
        finally:
BarthaM@219
   357
            if vidkey is not None:
BarthaM@219
   358
                win32api.RegCloseKey(vidkey)
BarthaM@219
   359
            if devinfokey is not None:
BarthaM@219
   360
                win32api.RegCloseKey(devinfokey)
mb@90
   361
        
mb@90
   362
        return 'USBSTOR' in value
mb@90
   363
    
mb@90
   364
    # return the RSDs connected to the host
mb@90
   365
    @staticmethod
BarthaM@172
   366
    def getExistingRSDs():
BarthaM@218
   367
        results = Cygwin.vboxExecute('list usbhost')[1]
mb@90
   368
        results = results.split('Host USB Devices:')[1].strip()
mb@90
   369
        
mb@90
   370
        items = list( "UUID:"+result for result in results.split('UUID:') if result != '')
mb@90
   371
        rsds = dict()   
mb@90
   372
        for item in items:
mb@90
   373
            props = dict()
BarthaM@172
   374
            for line in item.splitlines():     
mb@90
   375
                if line != "":         
mb@90
   376
                    k,v = line[:line.index(':')].strip(), line[line.index(':')+1:].strip()
mb@90
   377
                    props[k] = v
mb@90
   378
            
BarthaM@172
   379
            uuid = re.search(r"(?P<uuid>[0-9A-Fa-f\-]+)", props['UUID']).groupdict()['uuid']
BarthaM@172
   380
            vid = re.search(r"\((?P<vid>[0-9A-Fa-f]+)\)", props['VendorId']).groupdict()['vid']
BarthaM@172
   381
            pid = re.search(r"\((?P<pid>[0-9A-Fa-f]+)\)", props['ProductId']).groupdict()['pid']
BarthaM@172
   382
            rev = re.search(r"\((?P<rev>[0-9A-Fa-f]+)\)", props['Revision']).groupdict()['rev']
BarthaM@172
   383
            serial = None
BarthaM@172
   384
            if 'SerialNumber' in props.keys():
BarthaM@172
   385
                serial = re.search(r"(?P<ser>[0-9A-Fa-f]+)", props['SerialNumber']).groupdict()['ser']
BarthaM@183
   386
            usb_filter = USBFilter( uuid, vid, pid, rev, serial)
BarthaM@183
   387
             
BarthaM@183
   388
            if VMManager.isMassStorageDevice(usb_filter) and not VMManager.isBlacklisted(usb_filter):
BarthaM@172
   389
                rsds[uuid] = usb_filter
mb@90
   390
                logger.debug(usb_filter)
mb@90
   391
        return rsds
mb@90
   392
    
BarthaM@172
   393
   
BarthaM@172
   394
    # return the attached USB device as usb descriptor for an existing VM 
BarthaM@172
   395
    def getAttachedRSD(self, vm_name):
BarthaM@172
   396
        props = self.getVMInfo(vm_name)
BarthaM@172
   397
        keys = set(['USBAttachedUUID1', 'USBAttachedVendorId1', 'USBAttachedProductId1', 'USBAttachedRevision1', 'USBAttachedSerialNumber1'])
BarthaM@172
   398
        keyset = set(props.keys())
BarthaM@172
   399
        usb_filter = None
BarthaM@172
   400
        if keyset.issuperset(keys):
BarthaM@172
   401
            usb_filter = USBFilter(props['USBAttachedUUID1'], props['USBAttachedVendorId1'], props['USBAttachedProductId1'], props['USBAttachedRevision1'], props['USBAttachedSerialNumber1'])
BarthaM@172
   402
        return usb_filter
BarthaM@172
   403
        
mb@90
   404
    # return the RSDs attached to all existing SDVMs
mb@90
   405
    def getAttachedRSDs(self):
mb@90
   406
        vms = self.listSDVM()
mb@90
   407
        attached_devices = dict()
mb@90
   408
        for vm in vms:
BarthaM@172
   409
            rsd_filter = self.getAttachedRSD(vm)
mb@90
   410
            if rsd_filter != None:
mb@90
   411
                attached_devices[vm] = rsd_filter
mb@90
   412
        return attached_devices
mb@90
   413
    
BarthaM@172
   414
    # attach removable storage device to VM by provision of filter
BarthaM@172
   415
    def attachRSD(self, vm_name, rsd_filter):
BarthaM@218
   416
        #return Cygwin.vboxExecute('usbfilter add 0 --target ' + vm_name + ' --name OpenSecurityRSD --vendorid ' + rsd_filter.vendorid + ' --productid ' + rsd_filter.productid + ' --revision ' + rsd_filter.revision + ' --serialnumber ' + rsd_filter.serial)
BarthaM@218
   417
        return Cygwin.vboxExecute('controlvm ' + vm_name + ' usbattach ' + rsd_filter.uuid )
BarthaM@172
   418
    
BarthaM@172
   419
    # detach removable storage from VM by 
BarthaM@172
   420
    def detachRSD(self, vm_name, rsd_filter):
BarthaM@218
   421
        #return Cygwin.vboxExecute('usbfilter remove 0 --target ' + vm_name)
BarthaM@218
   422
        return Cygwin.vboxExecute('controlvm ' + vm_name + ' usbdetach ' + rsd_filter.uuid )
BarthaM@172
   423
        
mb@90
   424
    # configures hostonly networking and DHCP server. requires admin rights
mb@90
   425
    def configureHostNetworking(self):
mb@90
   426
        #cmd = 'vboxmanage list hostonlyifs'
mb@90
   427
        #Cygwin.vboxExecute(cmd)
mb@90
   428
        #cmd = 'vboxmanage hostonlyif remove \"VirtualBox Host-Only Ethernet Adapter\"'
mb@90
   429
        #Cygwin.vboxExecute(cmd)
mb@90
   430
        #cmd = 'vboxmanage hostonlyif create'
mb@90
   431
        #Cygwin.vboxExecute(cmd)
BarthaM@218
   432
        Cygwin.vboxExecute('hostonlyif ipconfig \"VirtualBox Host-Only Ethernet Adapter\" --ip 192.168.56.1 --netmask 255.255.255.0')
mb@90
   433
        #cmd = 'vboxmanage dhcpserver add'
mb@90
   434
        #Cygwin.vboxExecute(cmd)
BarthaM@218
   435
        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')
mb@90
   436
    
BarthaM@125
   437
    def isSDVMExisting(self, vm_name):
BarthaM@125
   438
        sdvms = self.listSDVM()
BarthaM@125
   439
        return vm_name in sdvms
BarthaM@125
   440
        
mb@90
   441
    #create new virtual machine instance based on template vm named SecurityDVM (\SecurityDVM\SecurityDVM.vmdk)
mb@90
   442
    def createVM(self, vm_name):
BarthaM@125
   443
        if self.isSDVMExisting(vm_name):
BarthaM@125
   444
            return
BarthaM@125
   445
        #remove eventually existing SDVM folder
BarthaM@212
   446
        machineFolder = Cygwin.cygPath(VMManager.machineFolder)
BarthaM@218
   447
        Cygwin.bashExecute('/usr/bin/rm -rf \\\"' + machineFolder + '/' + vm_name + '\\\"')
BarthaM@218
   448
        Cygwin.vboxExecute('createvm --name ' + vm_name + ' --ostype Debian --register')
BarthaM@218
   449
        Cygwin.vboxExecute('modifyvm ' + vm_name + ' --memory 768 --vram 10 --cpus 1 --usb on --usbehci on --nic1 hostonly --hostonlyadapter1 \"' + self.hostonlyIF['Name'] + '\" --nic2 nat')
BarthaM@218
   450
        Cygwin.vboxExecute('storagectl ' + vm_name + ' --name SATA --add sata --portcount 2')
BarthaM@159
   451
BarthaM@159
   452
    #create new SecurityDVM with automatically generated name from template (thread safe)        
BarthaM@159
   453
    def newSDVM(self):
BarthaM@159
   454
        with new_sdvm_lock:
BarthaM@159
   455
            vm_name = self.genSDVMName()
BarthaM@159
   456
            self.createVM(vm_name)
BarthaM@159
   457
        return vm_name
mb@90
   458
    
BarthaM@221
   459
    #VMManager.machineFolder + '\SecurityDVM\SecurityDVM.vmdk
mb@90
   460
    # attach storage image to controller
BarthaM@221
   461
    def attachVDisk(self, vm_name, vdisk_controller, vdisk_port, vdisk_device, vdisk_image):
BarthaM@221
   462
        if self.isVDiskAttached(vm_name, vdisk_controller, vdisk_port, vdisk_device):
BarthaM@221
   463
            self.detachVDisk(vm_name, vdisk_controller, vdisk_port, vdisk_device)
BarthaM@221
   464
        Cygwin.vboxExecute('storageattach ' + vm_name + ' --storagectl '+ vdisk_controller + ' --port ' + vdisk_port + ' --device ' + vdisk_device + ' --type hdd --medium "'+ vdisk_image + '"')
mb@90
   465
    
mb@90
   466
    # return true if storage is attached 
BarthaM@221
   467
    def isVDiskAttached(self, vm_name, vdisk_controller, vdisk_port, vdisk_device):
mb@90
   468
        info = self.getVMInfo(vm_name)
BarthaM@221
   469
        return (info[vdisk_controller+'-'+vdisk_port+'-'+vdisk_device] != 'none')
mb@90
   470
    
mb@90
   471
    # detach storage from controller
BarthaM@221
   472
    def detachVDisk(self, vm_name, vdisk_controller, vdisk_port, vdisk_device):
BarthaM@221
   473
        if self.isVDiskAttached(vm_name, vdisk_controller, vdisk_port, vdisk_device):
BarthaM@221
   474
            Cygwin.vboxExecute('storageattach ' + vm_name + ' --storagectl ' + vdisk_controller + ' --port ' + vdisk_port + ' --device ' + vdisk_device + ' --medium none')
mb@90
   475
    
BarthaM@221
   476
    # modify type of the vdisk_image
BarthaM@221
   477
    def changeVDiskType(self, vdisk_image, storage_type):
BarthaM@221
   478
        Cygwin.vboxExecute('modifyhd "' + vdisk_image + '" --type ' + storage_type)
BarthaM@171
   479
        
BarthaM@221
   480
    # grab VM storage controller, port and device for vdisk image name
BarthaM@221
   481
    def getVDiskController(self, vm_name, image_name = '.vmdk'):
BarthaM@221
   482
        vm_description = self.getVMInfo(vm_name)
BarthaM@221
   483
        vdisk_controller = None
BarthaM@221
   484
        for key, value in vm_description.iteritems():
BarthaM@221
   485
            if image_name in value:
BarthaM@221
   486
                vdisk_controller = key
BarthaM@221
   487
                break
BarthaM@221
   488
        return vdisk_controller
BarthaM@221
   489
    
BarthaM@221
   490
    # return attached vmdk image name containing image_name 
BarthaM@221
   491
    def getVDiskImage(self, vm_name, image_name = '.vmdk'):
BarthaM@221
   492
        vmInfo = self.getVMInfo(vm_name)
BarthaM@221
   493
        vdisk_image = None
BarthaM@221
   494
        for value in vmInfo.values():
BarthaM@221
   495
            if image_name in value:
BarthaM@221
   496
                break
BarthaM@221
   497
        return vdisk_image 
BarthaM@212
   498
        
BarthaM@212
   499
    @staticmethod    
BarthaM@221
   500
    def getVDiskImages():
BarthaM@218
   501
        results = Cygwin.vboxExecute('list hdds')[1]
mb@90
   502
        results = results.replace('Parent UUID', 'Parent')
mb@90
   503
        items = list( "UUID:"+result for result in results.split('UUID:') if result != '')
mb@90
   504
        
mb@90
   505
        snaps = dict()   
mb@90
   506
        for item in items:
mb@90
   507
            props = dict()
mb@90
   508
            for line in item.splitlines():
mb@90
   509
                if line != "":         
mb@90
   510
                    k,v = line[:line.index(':')].strip(), line[line.index(':')+1:].strip()
mb@90
   511
                    props[k] = v;
mb@90
   512
            snaps[props['UUID']] = props
BarthaM@171
   513
        return snaps
BarthaM@171
   514
    
BarthaM@212
   515
    @staticmethod 
BarthaM@221
   516
    def getVDiskUUID(vdisk_image):
BarthaM@221
   517
        images = VMManager.getVDiskImages()
mb@90
   518
        # find template uuid
BarthaM@171
   519
        template_uuid = None
BarthaM@171
   520
        for hdd in images.values():
BarthaM@221
   521
            if hdd['Location'] == vdisk_image:
mb@90
   522
                template_uuid = hdd['UUID']
BarthaM@171
   523
                break
BarthaM@171
   524
        return template_uuid
BarthaM@221
   525
    
BarthaM@171
   526
    def removeSnapshots(self, imageUUID):
BarthaM@221
   527
        snaps = self.getVDiskImages()
mb@90
   528
        # remove snapshots 
mb@90
   529
        for hdd in snaps.values():
BarthaM@171
   530
            if hdd['Parent'] == imageUUID:
BarthaM@171
   531
                snapshotUUID = hdd['UUID']
BarthaM@171
   532
                self.removeImage(snapshotUUID)
BarthaM@170
   533
                
BarthaM@171
   534
    def removeImage(self, imageUUID):
BarthaM@171
   535
        logger.debug('removing snapshot ' + imageUUID)
BarthaM@218
   536
        Cygwin.vboxExecute('closemedium disk {' + imageUUID + '} --delete')
BarthaM@171
   537
        # parse result 0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
mb@90
   538
    
mb@90
   539
    #remove VM from the system. should be used on VMs returned by listSDVMs    
mb@90
   540
    def removeVM(self, vm_name):
mb@90
   541
        logger.info('Removing ' + vm_name)
BarthaM@218
   542
        Cygwin.vboxExecute('unregistervm ' + vm_name + ' --delete')
BarthaM@221
   543
        #try to close medium if still existing
BarthaM@218
   544
        #Cygwin.vboxExecute('closemedium disk {' + hdd['UUID'] + '} --delete')
BarthaM@170
   545
        self.removeVMFolder(vm_name)
BarthaM@170
   546
    
BarthaM@170
   547
    def removeVMFolder(self, vm_name):
BarthaM@212
   548
        machineFolder = Cygwin.cygPath(VMManager.machineFolder)
BarthaM@221
   549
        Cygwin.bashExecute('/usr/bin/rm -rf \\\"' + machineFolder + '\\' + vm_name + '\\\"')
mb@90
   550
    
mb@90
   551
    # start VM
mb@90
   552
    def startVM(self, vm_name):
mb@90
   553
        logger.info('Starting ' +  vm_name)
BarthaM@218
   554
        Cygwin.vboxExecute('guestproperty set ' + vm_name + ' SDVMStarted False')
BarthaM@212
   555
        result = Cygwin.vboxExecute('startvm ' + vm_name + ' --type headless' )
mb@90
   556
        while 'successfully started' not in result[1]:
mb@90
   557
            logger.error("Failed to start SDVM: " + vm_name + " retrying")
oliver@129
   558
            logger.error("Command returned:\n" + result[2])
mb@90
   559
            time.sleep(1)
BarthaM@212
   560
            result = Cygwin.vboxExecute('startvm ' + vm_name + ' --type headless')
mb@90
   561
        return result[0]
mb@90
   562
    
mb@90
   563
    # return wether VM is running or not
mb@90
   564
    def isVMRunning(self, vm_name):
mb@90
   565
        return vm_name in self.listRunningVMS()    
mb@90
   566
    
mb@90
   567
    # stop VM
mb@90
   568
    def stopVM(self, vm_name):
mb@90
   569
        logger.info('Sending shutdown signal to ' + vm_name)
BarthaM@218
   570
        Cygwin.sshExecute( '"sudo shutdown -h now"', self.getHostOnlyIP(vm_name), 'osecuser', Cygwin.cygPath(VMManager.machineFolder) + '/' + vm_name + '/dvm_key' )
BarthaM@218
   571
        Cygwin.vboxExecute('guestproperty set ' + vm_name + ' SDVMStarted False')
mb@90
   572
    
mb@90
   573
    # stop VM
mb@90
   574
    def hibernateVM(self, vm_name):
mb@95
   575
        logger.info('Sending hibernate-disk signal to ' + vm_name)
BarthaM@218
   576
        Cygwin.sshBackgroundExecute( '"sudo hibernate-disk"', self.getHostOnlyIP(vm_name), 'osecuser', Cygwin.cygPath(VMManager.machineFolder) + '/' + vm_name + '/dvm_key', wait_return=False)
BarthaM@218
   577
        Cygwin.vboxExecute('guestproperty set ' + vm_name + ' SDVMStarted False')
mb@90
   578
            
mb@90
   579
    # poweroff VM
mb@90
   580
    def poweroffVM(self, vm_name):
mb@90
   581
        if not self.isVMRunning(vm_name):
mb@90
   582
            return
mb@90
   583
        logger.info('Powering off ' + vm_name)
BarthaM@218
   584
        Cygwin.vboxExecute('controlvm ' + vm_name + ' poweroff')
BarthaM@218
   585
        Cygwin.vboxExecute('guestproperty set ' + vm_name + ' SDVMStarted False')
BarthaM@218
   586
    
mb@90
   587
    
BarthaM@176
   588
    # return the hostOnly IP for a running guest or the host    
BarthaM@176
   589
    def getHostOnlyIP(self, vm_name):
mb@90
   590
        if vm_name == None:
oliver@129
   591
            logger.info('Getting hostOnly IP address for Host')
BarthaM@217
   592
            return VMManager.hostonlyIF['IPAddress']
mb@90
   593
        else:
oliver@129
   594
            logger.info('Getting hostOnly IP address ' + vm_name)
BarthaM@218
   595
            result = Cygwin.vboxExecute('guestproperty get ' + vm_name + ' /VirtualBox/GuestInfo/Net/0/V4/IP')
mb@90
   596
            if result=='':
mb@90
   597
                return None
mb@90
   598
            result = result[1]
mb@90
   599
            if result.startswith('No value set!'):
mb@90
   600
                return None
mb@90
   601
            return result[result.index(':')+1:].strip()
mb@90
   602
        
mb@90
   603
    # return the description set for an existing VM
mb@90
   604
    def getVMInfo(self, vm_name):
BarthaM@218
   605
        results = Cygwin.vboxExecute('showvminfo ' + vm_name + ' --machinereadable')[1]
mb@90
   606
        props = dict((k.strip().strip('"'),v.strip().strip('"')) for k,v in (line.split('=', 1) for line in results.splitlines()))
mb@90
   607
        return props
mb@90
   608
    
mb@90
   609
    #generates ISO containing authorized_keys for use with guest VM
BarthaM@218
   610
    def genCertificate(self, vm_name):
BarthaM@212
   611
        machineFolder = Cygwin.cygPath(VMManager.machineFolder)
mb@90
   612
        # remove .ssh folder if exists
BarthaM@218
   613
        Cygwin.bashExecute('/usr/bin/rm -rf \\\"' + machineFolder + '/' + vm_name + '/.ssh\\\"')
mb@90
   614
        # remove .ssh folder if exists
BarthaM@218
   615
        Cygwin.bashExecute('/usr/bin/rm -rf \\\"' + machineFolder + '/' + vm_name + '/dvm_key\\\"')
mb@90
   616
        # create .ssh folder in vm_name
BarthaM@218
   617
        Cygwin.bashExecute('/usr/bin/mkdir -p \\\"' + machineFolder + '/' + vm_name + '/.ssh\\\"')
mb@90
   618
        # generate dvm_key pair in vm_name / .ssh     
BarthaM@218
   619
        Cygwin.bashExecute('/usr/bin/ssh-keygen -q -t rsa -N \\\"\\\" -C \\\"' + vm_name + '\\\" -f \\\"' + machineFolder + '/' + vm_name + '/.ssh/dvm_key\\\"')
mb@90
   620
        # move out private key
BarthaM@218
   621
        Cygwin.bashExecute('/usr/bin/mv \\\"' + machineFolder + '/' + vm_name + '/.ssh/dvm_key\\\" \\\"' + machineFolder + '/' + vm_name + '\\\"')
mb@90
   622
        # set permissions for private key
BarthaM@218
   623
        Cygwin.bashExecute('/usr/bin/chmod 500 \\\"' + machineFolder + '/' + vm_name + '/dvm_key\\\"')
mb@90
   624
        # rename public key to authorized_keys
BarthaM@218
   625
        Cygwin.bashExecute('/usr/bin/mv \\\"' + machineFolder + '/' + vm_name + '/.ssh/dvm_key.pub\\\" \\\"' + machineFolder + '/' + vm_name + '/.ssh/authorized_keys\\\"')
mb@90
   626
        # set permissions for authorized_keys
BarthaM@218
   627
        Cygwin.bashExecute('/usr/bin/chmod 500 \\\"' + machineFolder + '/' + vm_name + '/.ssh/authorized_keys\\\"')
mb@90
   628
        # generate iso image with .ssh/authorized keys
BarthaM@218
   629
        Cygwin.bashExecute('/usr/bin/genisoimage -J -R -o \\\"' + machineFolder + '/' + vm_name + '/'+ vm_name + '.iso\\\" \\\"' + machineFolder + '/' + vm_name + '/.ssh\\\"')
mb@90
   630
    
mb@90
   631
    # attaches generated ssh public cert to guest vm
BarthaM@218
   632
    def attachCertificate(self, vm_name):
BarthaM@218
   633
        if self.isCertificateAttached(vm_name):
BarthaM@218
   634
            self.detachCertificate(vm_name)
BarthaM@218
   635
        Cygwin.vboxExecute('storageattach ' + vm_name + ' --storagectl SATA --port 1 --device 0 --type dvddrive --mtype readonly --medium \"' + VMManager.machineFolder + '\\' + vm_name + '\\'+ vm_name + '.iso\"')
mb@90
   636
    
BarthaM@218
   637
    # return true if storage is attached 
BarthaM@218
   638
    def isCertificateAttached(self, vm_name):
BarthaM@218
   639
        info = self.getVMInfo(vm_name)
BarthaM@218
   640
        return (info['SATA-1-0']!='none')
BarthaM@218
   641
    
BarthaM@218
   642
    # detach storage from controller
BarthaM@218
   643
    def detachCertificate(self, vm_name):
BarthaM@218
   644
        if self.isCertificateAttached(vm_name):
BarthaM@218
   645
            Cygwin.vboxExecute('storageattach ' + vm_name + ' --storagectl SATA --port 1 --device 0 --type hdd --medium none')
BarthaM@218
   646
            
mb@90
   647
    # wait for machine to come up
BarthaM@218
   648
    def waitStartup(self, vm_name):
BarthaM@218
   649
        #Cygwin.vboxExecute('guestproperty wait ' + vm_name + ' SDVMStarted --timeout ' + str(timeout_ms) + ' --fail-on-timeout', try_count = 60)
BarthaM@217
   650
        started = False
BarthaM@217
   651
        while not started:
BarthaM@218
   652
            result = Cygwin.vboxExecute('guestproperty get ' + vm_name + ' SDVMStarted')[1]
BarthaM@217
   653
            if "Value: True" in result:
BarthaM@217
   654
                started = True
BarthaM@217
   655
            else:
BarthaM@217
   656
                time.sleep(3) 
BarthaM@176
   657
        return self.getHostOnlyIP(vm_name)
mb@90
   658
    
mb@90
   659
    # wait for machine to shutdown
mb@90
   660
    def waitShutdown(self, vm_name):
mb@90
   661
        while vm_name in self.listRunningVMS():
mb@90
   662
            time.sleep(1)
mb@90
   663
        return
mb@90
   664
    
BarthaM@135
   665
    #Small function to check if the mentioned location is a directory
mb@90
   666
    def isDirectory(self, path):
BarthaM@218
   667
        result = Cygwin.cmdExecute('dir ' + path + ' | FIND ".."')
mb@90
   668
        return string.find(result[1], 'DIR',)
mb@90
   669
    
oliver@167
   670
    def genNetworkDrive(self):
oliver@167
   671
        logical_drives = VMManager.getLogicalDrives()
oliver@167
   672
        logger.info("Used logical drive letters: "+ str(logical_drives).strip('[]') )
oliver@167
   673
        drives = list(map(chr, range(68, 91)))  
oliver@167
   674
        for drive in drives:
BarthaM@176
   675
            if drive not in logical_drives:
BarthaM@176
   676
                return drive
BarthaM@151
   677
            
mb@90
   678
    @staticmethod
mb@90
   679
    def getLogicalDrives():
mb@90
   680
        drive_bitmask = ctypes.cdll.kernel32.GetLogicalDrives()
BarthaM@176
   681
        drives = list(itertools.compress(string.ascii_uppercase,  map(lambda x:ord(x) - ord('0'), bin(drive_bitmask)[:1:-1])))
BarthaM@176
   682
        return drives
mb@90
   683
    
mb@90
   684
    @staticmethod
mb@90
   685
    def getDriveType(drive):
mb@90
   686
        return ctypes.cdll.kernel32.GetDriveTypeW(u"%s:\\"%drive)
mb@90
   687
    
mb@90
   688
    @staticmethod
BarthaM@176
   689
    def getNetworkPath(drive):
BarthaM@176
   690
        return win32wnet.WNetGetConnection(drive+':')
BarthaM@176
   691
    
BarthaM@176
   692
    @staticmethod
mb@90
   693
    def getVolumeInfo(drive):
mb@90
   694
        volumeNameBuffer = ctypes.create_unicode_buffer(1024)
mb@90
   695
        fileSystemNameBuffer = ctypes.create_unicode_buffer(1024)
mb@90
   696
        serial_number = None
mb@90
   697
        max_component_length = None
mb@90
   698
        file_system_flags = None
mb@90
   699
        
mb@90
   700
        rc = ctypes.cdll.kernel32.GetVolumeInformationW(
mb@90
   701
            u"%s:\\"%drive,
mb@90
   702
            volumeNameBuffer,
mb@90
   703
            ctypes.sizeof(volumeNameBuffer),
mb@90
   704
            serial_number,
mb@90
   705
            max_component_length,
mb@90
   706
            file_system_flags,
mb@90
   707
            fileSystemNameBuffer,
mb@90
   708
            ctypes.sizeof(fileSystemNameBuffer)
mb@90
   709
        )
mb@90
   710
        return volumeNameBuffer.value, fileSystemNameBuffer.value
BarthaM@141
   711
    
BarthaM@176
   712
    def getNetworkDrive(self, vm_name):
BarthaM@176
   713
        ip = self.getHostOnlyIP(vm_name)
BarthaM@176
   714
        if ip == None:
BarthaM@176
   715
            logger.error("Failed getting hostonly IP for " + vm_name)
BarthaM@176
   716
            return None
BarthaM@176
   717
        logger.info("Got IP address for " + vm_name + ': ' + ip)
BarthaM@176
   718
        for drive in VMManager.getLogicalDrives():
BarthaM@176
   719
            #if is a network drive
BarthaM@176
   720
            if VMManager.getDriveType(drive) == 4:
BarthaM@176
   721
                network_path = VMManager.getNetworkPath(drive)
BarthaM@176
   722
                if ip in network_path:
BarthaM@176
   723
                    return drive
BarthaM@176
   724
        return None
BarthaM@176
   725
    
BarthaM@176
   726
    def getNetworkDrives(self):
BarthaM@176
   727
        ip = self.getHostOnlyIP(None)
BarthaM@176
   728
        if ip == None:
BarthaM@176
   729
            logger.error("Failed getting hostonly IP for system")
BarthaM@176
   730
            return None
BarthaM@176
   731
        logger.info("Got IP address for system: " + ip)
BarthaM@176
   732
        ip = ip[:ip.rindex('.')]
BarthaM@176
   733
        network_drives = dict()
BarthaM@176
   734
        for drive in VMManager.getLogicalDrives():
BarthaM@176
   735
            #if is a network drive
BarthaM@176
   736
            if VMManager.getDriveType(drive) == 4:
BarthaM@176
   737
                network_path = VMManager.getNetworkPath(drive)
BarthaM@176
   738
                if ip in network_path:
BarthaM@176
   739
                    network_drives[drive] = network_path  
BarthaM@176
   740
        return network_drives
BarthaM@176
   741
    
BarthaM@141
   742
    # handles browsing request    
BarthaM@213
   743
    def handleBrowsingRequest(self, proxy):
oliver@193
   744
        showTrayMessage('Starting Secure Browsing...', 7000)
BarthaM@213
   745
        handler = BrowsingHandler(self, proxy)
BarthaM@141
   746
        handler.start()
BarthaM@141
   747
        return 'ok'
BarthaM@143
   748
    
BarthaM@143
   749
    def getActiveUserName(self):
BarthaM@143
   750
        key = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI')
BarthaM@143
   751
        v = str(win32api.RegQueryValueEx(key, 'LastLoggedOnUser')[0])
BarthaM@143
   752
        win32api.RegCloseKey(key)
BarthaM@143
   753
        user_name = win32api.ExpandEnvironmentStrings(v)
BarthaM@143
   754
        return user_name
BarthaM@143
   755
        
BarthaM@143
   756
    def getUserSID(self, user_name):
oliver@167
   757
        domain, user = user_name.split("\\")
oliver@167
   758
        account_name = win32security.LookupAccountName(domain, user)
oliver@167
   759
        if account_name == None:
oliver@167
   760
            logger.error("Failed lookup account name for user " + user_name)
oliver@167
   761
            return None
BarthaM@143
   762
        sid = win32security.ConvertSidToStringSid(account_name[0])
oliver@167
   763
        if sid == None:
oliver@167
   764
            logger.error("Failed converting SID for account " + account_name[0])
oliver@167
   765
            return None
BarthaM@143
   766
        return sid
BarthaM@143
   767
        
BarthaM@143
   768
    def getAppDataDir(self, sid):    
BarthaM@143
   769
        key = win32api.RegOpenKey(win32con.HKEY_USERS, sid + '\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders')
BarthaM@221
   770
        value, _ = win32api.RegQueryValueEx(key, "AppData")
BarthaM@143
   771
        win32api.RegCloseKey(key)
BarthaM@143
   772
        return value
BarthaM@143
   773
        #key = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList' + '\\' + sid)
BarthaM@143
   774
        #value, type = win32api.RegQueryValueEx(key, "ProfileImagePath")
BarthaM@143
   775
        #print value
BarthaM@143
   776
    
BarthaM@143
   777
    def backupFile(self, src, dest):
BarthaM@143
   778
        certificate = Cygwin.cygPath(self.getMachineFolder()) + '/' + self.browsingManager.vm_name + '/dvm_key'
BarthaM@143
   779
        command = '-r -o StrictHostKeyChecking=no -i "' + certificate + '" "osecuser@' + self.browsingManager.ip_addr + ':' + src + '" "' + dest + '"'
BarthaM@143
   780
        return Cygwin.execute(Cygwin.cygwin_scp, command, wait_return=True, window=False)
BarthaM@143
   781
    
BarthaM@143
   782
    def restoreFile(self, src, dest):
BarthaM@143
   783
        certificate = Cygwin.cygPath(self.getMachineFolder()) + '/' + self.browsingManager.vm_name + '/dvm_key'
BarthaM@143
   784
        #command = '-r -v -o StrictHostKeyChecking=no -i \"' + certificate + '\" \"' + src + '\" \"osecuser@' + self.browsingManager.ip_addr + ':' + dest + '\"'
BarthaM@143
   785
        command = '-r -o StrictHostKeyChecking=no -i "' + certificate + '" "' + src + '" "osecuser@' + self.browsingManager.ip_addr + ':' + dest + '"'
BarthaM@221
   786
        return Cygwin.execute(Cygwin.cygwin_scp, command, wait_return=True, window=False)
BarthaM@221
   787
    
BarthaM@221
   788
    #import initial template
BarthaM@221
   789
    def importTemplate(self, image_path):
BarthaM@221
   790
        import_logger.info('Stopping Opensecurity...')
BarthaM@221
   791
        self.stop()
BarthaM@221
   792
        
BarthaM@221
   793
        import_logger.info('Cleaning up system in preparation for import...')
BarthaM@221
   794
        self.cleanup()
BarthaM@221
   795
        
BarthaM@221
   796
        import_logger.info('Removing template SDVM...')
BarthaM@221
   797
        # if template exists
BarthaM@221
   798
        if self.vmRootName in self.listVMS():
BarthaM@221
   799
            # shutdown template if running
BarthaM@221
   800
            self.poweroffVM(self.vmRootName)
BarthaM@221
   801
            # detach and remove VDisk
BarthaM@221
   802
            tmplateUUID = self.getVDiskUUID(self.templateImage)
BarthaM@221
   803
            if tmplateUUID != None:
BarthaM@221
   804
                logger.debug('Found template VDisk uuid ' + tmplateUUID)
BarthaM@221
   805
                controller = self.getVDiskController(self.vmRootName)
BarthaM@221
   806
                if controller:
BarthaM@221
   807
                    controller = controller.split('-')
BarthaM@221
   808
                    self.detachVDisk(self.vmRootName, controller[0], controller[1], controller[2])
BarthaM@221
   809
                self.removeSnapshots(tmplateUUID)
BarthaM@221
   810
                self.removeImage(tmplateUUID)
BarthaM@221
   811
            else:
BarthaM@221
   812
                logger.info('Template uuid not found')
BarthaM@221
   813
            # remove VM    
BarthaM@221
   814
            self.removeVM(self.vmRootName)
BarthaM@221
   815
        # remove template VM folder 
BarthaM@221
   816
        self.removeVMFolder(self.vmRootName)
BarthaM@221
   817
        import_logger.info('Cleanup finished...')
BarthaM@221
   818
        
BarthaM@221
   819
        import_logger.info('Checking privileges...')
BarthaM@221
   820
        result = Cygwin.bashExecute('id -G')
BarthaM@221
   821
        if '544' not in result[1]:
BarthaM@221
   822
            import_logger.debug('Insufficient privileges.')
BarthaM@221
   823
            import_logger.debug("Trying to continue...")
BarthaM@221
   824
        
BarthaM@221
   825
        # check OpenSecurity Initial VM Image
BarthaM@221
   826
        import_logger.debug('Looking for VM image: ' + image_path)
BarthaM@221
   827
        result = os.path.isfile(image_path)
BarthaM@221
   828
      
BarthaM@221
   829
        if not result:
BarthaM@221
   830
            import_logger.debug('Warning: no OpenSecurity Initial Image found.')
BarthaM@221
   831
            import_logger.debug('Please download using the OpenSecurity download tool.')
BarthaM@221
   832
            raise OpenSecurityException('OpenSecurity Initial Image not found.')
BarthaM@221
   833
        logger.debug('Initial VM image: ' + image_path + ' found')
BarthaM@221
   834
        
BarthaM@221
   835
        if not self.template_installed():
BarthaM@221
   836
            import_logger.info('Importing SDVm template: ' + image_path)
BarthaM@221
   837
            Cygwin.vboxExecute('import "' + image_path + '" --vsys 0 --vmname ' + VMManager.vmRootName + ' --unit 12 --disk "' + self.templateImage + '"')
BarthaM@221
   838
        else:
BarthaM@221
   839
            import_logger.info('Found ' + VMManager.vmRootName + ' already present in VBox reusing it.')
BarthaM@221
   840
            import_logger.info('if you want a complete new import please remove the VM first.')
BarthaM@221
   841
            import_logger.info('starting OpenSecurity service...')
BarthaM@221
   842
            return
mb@90
   843
BarthaM@221
   844
        # remove unnecessary IDE controller
BarthaM@221
   845
        Cygwin.vboxExecute('storagectl ' + VMManager.vmRootName + ' --name IDE --remove')
BarthaM@221
   846
BarthaM@221
   847
        info = self.getVDiskController(VMManager.vmRootName, self.templateImage)
BarthaM@221
   848
        if info:
BarthaM@221
   849
            info = info.split('-')
BarthaM@221
   850
            self.detachVDisk(VMManager.vmRootName, info[0], info[1], info[2])
BarthaM@221
   851
        
BarthaM@221
   852
        self.changeVDiskType(self.templateImage, 'immutable')
BarthaM@221
   853
        self.attachVDisk(VMManager.vmRootName, info[0], info[1], info[2], self.templateImage)
BarthaM@221
   854
        import_logger.info('Initial import finished.')    
BarthaM@221
   855
        
BarthaM@221
   856
    # update template 
BarthaM@221
   857
    def updateTemplate(self):
BarthaM@221
   858
        import_logger.debug('Stopping Opensecurity...')
BarthaM@221
   859
        self.stop()
BarthaM@221
   860
        
BarthaM@221
   861
        import_logger.debug('Cleaning up system in preparation for update...')
BarthaM@221
   862
        self.cleanup()
BarthaM@221
   863
        
BarthaM@221
   864
        import_logger.info('Cleanup finished...')
BarthaM@221
   865
        
BarthaM@221
   866
        # shutdown template if running
BarthaM@221
   867
        self.poweroffVM(self.vmRootName)
BarthaM@221
   868
        
BarthaM@221
   869
        import_logger.info('Starting template VM...')
BarthaM@221
   870
        # check for updates
BarthaM@221
   871
        self.genCertificate(self.vmRootName)
BarthaM@221
   872
        self.attachCertificate(self.vmRootName)
BarthaM@221
   873
BarthaM@221
   874
        import_logger.info('Removing snapshots...')        
BarthaM@221
   875
        
BarthaM@221
   876
        self.detachVDisk(self.vmRootName, 'SATA', '0', '0')
BarthaM@221
   877
        templateUUID = self.getVDiskUUID(self.templateImage)
BarthaM@221
   878
        self.removeSnapshots(templateUUID)
BarthaM@221
   879
        
BarthaM@221
   880
        import_logger.info('Setting VDisk image to normal...')
BarthaM@221
   881
        self.changeVDiskType(self.templateImage, 'normal')
BarthaM@221
   882
        self.attachVDisk(self.vmRootName, 'SATA', '0', '0', self.templateImage)
BarthaM@221
   883
        
BarthaM@221
   884
        import_logger.info('Starting VM...')
BarthaM@221
   885
        self.startVM(self.vmRootName)
BarthaM@221
   886
        self.waitStartup(self.vmRootName)
BarthaM@221
   887
        
BarthaM@221
   888
        import_logger.info('Updating components...')
BarthaM@221
   889
        tmp_ip = self.getHostOnlyIP(self.vmRootName)
BarthaM@221
   890
        tmp_machine_folder = Cygwin.cygPath(VMManager.machineFolder)
BarthaM@221
   891
        Cygwin.sshExecute('"sudo apt-get -y update"', tmp_ip, 'osecuser', tmp_machine_folder + '/' + self.vmRootName + '/dvm_key')
BarthaM@221
   892
        Cygwin.sshExecute('"sudo apt-get -y upgrade"', tmp_ip, 'osecuser', tmp_machine_folder + '/' + self.vmRootName + '/dvm_key')
BarthaM@221
   893
        
BarthaM@221
   894
        import_logger.info('Restarting template VM...')
BarthaM@221
   895
        #check if reboot is required
BarthaM@221
   896
        result = Cygwin.sshExecute('"if [ -f /var/run/reboot-required ]; then echo \\\"Yes\\\"; fi"', tmp_ip, 'osecuser', tmp_machine_folder + '/' + self.vmRootName + '/dvm_key')
BarthaM@221
   897
        if "Yes" in result[1]:
BarthaM@221
   898
            self.stopVM(self.vmRootName)
BarthaM@221
   899
            self.waitShutdown(self.vmRootName)
BarthaM@221
   900
            self.startVM(self.vmRootName)
BarthaM@221
   901
            self.waitStartup(self.vmRootName)
BarthaM@221
   902
        
BarthaM@221
   903
        import_logger.info('Stopping template VM...')
BarthaM@221
   904
        self.stopVM(self.vmRootName)
BarthaM@221
   905
        self.waitShutdown(self.vmRootName)
BarthaM@221
   906
        
BarthaM@221
   907
        import_logger.info('Setting VDisk image to immutable...')
BarthaM@221
   908
        self.detachVDisk(self.vmRootName, 'SATA', '0', '0') 
BarthaM@221
   909
        self.changeVDiskType(self.templateImage, 'immutable')
BarthaM@221
   910
        self.attachVDisk(self.vmRootName,  'SATA', '0', '0', self.templateImage)
BarthaM@221
   911
        
BarthaM@221
   912
        import_logger.info('Update template finished...')
BarthaM@221
   913
    
BarthaM@221
   914
    def startInitialImport(self):
BarthaM@221
   915
        if self.importHandler and self.importHandler.isAlive():
BarthaM@221
   916
            import_logger.info("Initial import already running.")
BarthaM@221
   917
            return
BarthaM@221
   918
        self.importHandler = InitialImportHandler(self)
BarthaM@221
   919
        self.importHandler.start()
BarthaM@221
   920
        import_logger.info("Initial import started.")
BarthaM@221
   921
        
BarthaM@221
   922
    def startUpdateTemplate(self):
BarthaM@221
   923
        if self.updateHandler and self.updateHandler.isAlive():
BarthaM@221
   924
            import_logger.info("Initial import already running.")
BarthaM@221
   925
            return
BarthaM@221
   926
        self.updateHandler = UpdateHandler(self)
BarthaM@221
   927
        self.updateHandler.start()
BarthaM@221
   928
        import_logger.info("Initial import started.")
BarthaM@221
   929
BarthaM@221
   930
class UpdateHandler(threading.Thread):
BarthaM@221
   931
    vmm = None    
BarthaM@221
   932
    def __init__(self, vmmanager):
BarthaM@221
   933
        threading.Thread.__init__(self)
BarthaM@221
   934
        self.vmm = vmmanager
BarthaM@221
   935
    
BarthaM@221
   936
    def run(self):
BarthaM@221
   937
        try:
BarthaM@221
   938
            self.vmm.updateTemplate()
BarthaM@221
   939
        except:
BarthaM@221
   940
            import_logger.info("Update template failed. Refer to service log for details.")
BarthaM@221
   941
        self.vmm.start(force=True)
BarthaM@221
   942
    
BarthaM@221
   943
class InitialImportHandler(threading.Thread):
BarthaM@221
   944
    vmm = None    
BarthaM@221
   945
    def __init__(self, vmmanager):
BarthaM@221
   946
        threading.Thread.__init__(self)
BarthaM@221
   947
        self.vmm = vmmanager
BarthaM@221
   948
    
BarthaM@221
   949
    def run(self):
BarthaM@221
   950
        try:
BarthaM@221
   951
            self.vmm.importTemplate(self.vmm.getMachineFolder() + '\\OsecVM.ova')
BarthaM@221
   952
            self.vmm.updateTemplate()
BarthaM@221
   953
        except:
BarthaM@221
   954
            import_logger.info("Initial import failed. Refer to service log for details.")
BarthaM@221
   955
        self.vmm.start(force=True)
BarthaM@221
   956
            
BarthaM@141
   957
#handles browsing session creation 
BarthaM@141
   958
class BrowsingHandler(threading.Thread):
mb@90
   959
    vmm = None
BarthaM@213
   960
    proxy = None
BarthaM@213
   961
    def __init__(self, vmmanager, proxy):
BarthaM@213
   962
        threading.Thread.__init__(self)
BarthaM@213
   963
        self.vmm = vmmanager
BarthaM@213
   964
        self.proxy = proxy
BarthaM@141
   965
        
BarthaM@141
   966
    def run(self):
oliver@169
   967
        #browser = '\\\"/usr/bin/chromium; pidof dbus-launch | xargs kill\\\"'
BarthaM@213
   968
        #browser = '\\\"/usr/bin/chromium\\\"'
BarthaM@213
   969
        
BarthaM@141
   970
        try:
BarthaM@213
   971
            if self.proxy:
BarthaM@213
   972
                browser = '\\\"export http_proxy='+self.proxy+'; /usr/bin/chromium\\\"'
BarthaM@213
   973
            else:
BarthaM@213
   974
                browser = '\\\"/usr/bin/chromium\\\"'
BarthaM@143
   975
            self.vmm.browsingManager.started.wait() 
BarthaM@218
   976
            result = Cygwin.sshExecuteX11(browser, self.vmm.browsingManager.ip_addr, 'osecuser', Cygwin.cygPath(self.vmm.getMachineFolder()) + '/' + self.vmm.browsingManager.vm_name + '/dvm_key')
oliver@169
   977
            self.vmm.backupFile('/home/osecuser/.config/chromium', self.vmm.browsingManager.appDataDir + '/OpenSecurity/')
BarthaM@141
   978
        except:
oliver@169
   979
            logger.info("BrowsingHandler closing. Restarting browsing SDVM.")
oliver@169
   980
BarthaM@141
   981
        self.vmm.browsingManager.restart.set()
BarthaM@141
   982
        
BarthaM@141
   983
            
BarthaM@141
   984
# handles browsing Vm creation and destruction                    
BarthaM@141
   985
class BrowsingManager(threading.Thread):   
BarthaM@141
   986
    vmm = None
BarthaM@141
   987
    running = True
BarthaM@141
   988
    restart = None
BarthaM@141
   989
    ip_addr = None
BarthaM@141
   990
    vm_name = None
BarthaM@176
   991
    net_resource = None
BarthaM@143
   992
    appDataDir = None
BarthaM@141
   993
    
mb@90
   994
    def __init__(self, vmmanager):
mb@90
   995
        threading.Thread.__init__(self)
mb@90
   996
        self.vmm = vmmanager
BarthaM@141
   997
        self.restart = threading.Event()
BarthaM@141
   998
        self.started = threading.Event()
BarthaM@170
   999
    
BarthaM@170
  1000
    def stop(self):
BarthaM@170
  1001
        self.running = False
BarthaM@170
  1002
        self.restart.set()   
mb@90
  1003
     
mb@90
  1004
    def run(self):
BarthaM@141
  1005
        while self.running:
BarthaM@141
  1006
            self.restart.clear()
BarthaM@141
  1007
            self.started.clear()
BarthaM@166
  1008
            
BarthaM@176
  1009
            if self.net_resource == None:
BarthaM@176
  1010
                logger.info("Missing browsing SDVM's network share. Skipping disconnect")
BarthaM@166
  1011
            else:
BarthaM@166
  1012
                try:
BarthaM@176
  1013
                    browsing_vm = urllib2.urlopen('http://127.0.0.1:8090/netumount?'+'net_resource='+self.net_resource).readline()
BarthaM@176
  1014
                    self.net_resource = None
BarthaM@166
  1015
                except urllib2.URLError:
BarthaM@176
  1016
                    logger.error("Network share disconnect failed. OpenSecurity Tray client not running.")
BarthaM@166
  1017
                    continue
BarthaM@135
  1018
            
BarthaM@141
  1019
            self.ip_addr = None
BarthaM@166
  1020
BarthaM@141
  1021
            if self.vm_name != None:
BarthaM@141
  1022
                self.vmm.poweroffVM(self.vm_name)
BarthaM@141
  1023
                self.vmm.removeVM(self.vm_name)
BarthaM@141
  1024
            
BarthaM@141
  1025
            try:
BarthaM@159
  1026
                self.vm_name = self.vmm.newSDVM()
BarthaM@221
  1027
                self.vmm.attachVDisk(self.vm_name, 'SATA', '0', '0', self.vmm.templateImage)
BarthaM@218
  1028
                self.vmm.genCertificate(self.vm_name)
BarthaM@218
  1029
                self.vmm.attachCertificate(self.vm_name)
BarthaM@212
  1030
                
BarthaM@141
  1031
                self.vmm.startVM(self.vm_name)
BarthaM@212
  1032
                
BarthaM@218
  1033
                self.ip_addr = self.vmm.waitStartup(self.vm_name)
BarthaM@141
  1034
                if self.ip_addr == None:
oliver@167
  1035
                    logger.error("Failed to get ip address")
BarthaM@141
  1036
                    continue
oliver@167
  1037
                else:
oliver@167
  1038
                    logger.info("Got IP address for " + self.vm_name + ' ' + self.ip_addr)
oliver@167
  1039
                
BarthaM@166
  1040
                try:
BarthaM@176
  1041
                    self.net_resource = '\\\\' + self.ip_addr + '\\Download'
BarthaM@176
  1042
                    result = urllib2.urlopen('http://127.0.0.1:8090/netmount?'+'net_resource='+self.net_resource).readline()
BarthaM@166
  1043
                except urllib2.URLError:
BarthaM@166
  1044
                    logger.error("Network drive connect failed. OpenSecurity Tray client not running.")
BarthaM@176
  1045
                    self.net_resource = None
BarthaM@166
  1046
                    continue
BarthaM@143
  1047
                
BarthaM@143
  1048
                user = self.vmm.getActiveUserName()
oliver@167
  1049
                if user == None:
oliver@167
  1050
                    logger.error("Cannot get active user name")
oliver@167
  1051
                    continue
oliver@167
  1052
                else:
oliver@167
  1053
                    logger.info('Got active user name ' + user)
BarthaM@143
  1054
                sid = self.vmm.getUserSID(user)
oliver@167
  1055
                if sid == None:
oliver@167
  1056
                    logger.error("Cannot get SID for active user")
oliver@167
  1057
                    continue
oliver@167
  1058
                else:
oliver@167
  1059
                    logger.info("Got active user SID " + sid + " for user " + user)
oliver@167
  1060
                    
BarthaM@143
  1061
                path = self.vmm.getAppDataDir(sid)
oliver@167
  1062
                if path == None:
oliver@167
  1063
                    logger.error("Cannot get AppDataDir for active user")
oliver@167
  1064
                    continue
oliver@167
  1065
                else:
oliver@167
  1066
                    logger.info("Got AppData dir for user " + user + ': ' + path)
oliver@167
  1067
                
BarthaM@143
  1068
                self.appDataDir = Cygwin.cygPath(path)
oliver@167
  1069
                logger.info("Restoring browser settings in AppData dir " + self.appDataDir)
BarthaM@149
  1070
                # create OpenSecurity settings dir on local machine user home /AppData/Roaming 
BarthaM@218
  1071
                Cygwin.bashExecute('/usr/bin/mkdir -p \\\"' + self.appDataDir + '/OpenSecurity\\\"')
BarthaM@143
  1072
                # create chromium settings dir on local machine if not existing
BarthaM@218
  1073
                Cygwin.bashExecute('/usr/bin/mkdir -p \\\"' + self.appDataDir + '/OpenSecurity/chromium\\\"')
BarthaM@143
  1074
                # create chromium settings dir on remote machine if not existing
BarthaM@218
  1075
                Cygwin.sshExecute('"mkdir -p \\\"/home/osecuser/.config\\\""', self.ip_addr, 'osecuser', Cygwin.cygPath(self.vmm.getMachineFolder()) + '/' + self.vm_name + '/dvm_key')
BarthaM@143
  1076
                #restore settings on vm
BarthaM@143
  1077
                self.vmm.restoreFile(self.appDataDir + '/OpenSecurity/chromium', '/home/osecuser/.config/')
oliver@167
  1078
                self.started.set()
oliver@180
  1079
                logger.info("Browsing SDVM running.")
BarthaM@141
  1080
                self.restart.wait()
BarthaM@219
  1081
            except Exception as e:
BarthaM@219
  1082
                logger.error("Unexpected error: ".join(e))
BarthaM@141
  1083
                logger.error("BrowsingHandler failed. Cleaning up")
BarthaM@212
  1084
                #self.running= False
mb@90
  1085
                
mb@90
  1086
class DeviceHandler(threading.Thread): 
mb@90
  1087
    vmm = None
BarthaM@172
  1088
    existingRSDs = None
mb@90
  1089
    attachedRSDs = None  
mb@90
  1090
    running = True
mb@90
  1091
    def __init__(self, vmmanger): 
mb@90
  1092
        threading.Thread.__init__(self)
mb@90
  1093
        self.vmm = vmmanger
mb@90
  1094
 
mb@90
  1095
    def stop(self):
mb@90
  1096
        self.running = False
mb@90
  1097
        
mb@90
  1098
    def run(self):
BarthaM@176
  1099
        self.existingRSDs = dict()
BarthaM@172
  1100
        self.attachedRSDs = self.vmm.getAttachedRSDs()
BarthaM@135
  1101
        
mb@90
  1102
        while self.running:
BarthaM@172
  1103
            tmp_rsds = self.vmm.getExistingRSDs()
BarthaM@176
  1104
            if tmp_rsds.keys() == self.existingRSDs.keys():
BarthaM@176
  1105
                logger.debug("Nothing's changed. sleep(3)")
BarthaM@176
  1106
                time.sleep(3)
BarthaM@176
  1107
                continue
BarthaM@176
  1108
            
oliver@193
  1109
            showTrayMessage('System changed.\nEvaluating...', 7000)
BarthaM@182
  1110
            logger.info("Something's changed")
BarthaM@182
  1111
            tmp_attached = self.attachedRSDs     
BarthaM@182
  1112
            for vm_name in tmp_attached.keys():
BarthaM@182
  1113
                if tmp_attached[vm_name] not in tmp_rsds.values():
BarthaM@176
  1114
                    ip = self.vmm.getHostOnlyIP(vm_name)
BarthaM@176
  1115
                    if ip == None:
BarthaM@176
  1116
                        logger.error("Failed getting hostonly IP for " + vm_name)
BarthaM@176
  1117
                        continue
BarthaM@166
  1118
                    try:
BarthaM@176
  1119
                        net_resource = '\\\\' + ip + '\\USB'
BarthaM@176
  1120
                        result = urllib2.urlopen('http://127.0.0.1:8090/netumount?'+'net_resource='+net_resource).readline()
BarthaM@166
  1121
                    except urllib2.URLError:
BarthaM@166
  1122
                        logger.error("Network drive disconnect failed. OpenSecurity Tray client not running.")
BarthaM@166
  1123
                        continue
BarthaM@172
  1124
                    
BarthaM@172
  1125
                    # detach not necessary as already removed from vm description upon disconnect
BarthaM@172
  1126
                    #self.vmm.detachRSD(vm_name, self.attachedRSDs[vm_name])
BarthaM@172
  1127
                    del self.attachedRSDs[vm_name]
mb@95
  1128
                    self.vmm.poweroffVM(vm_name)
mb@95
  1129
                    self.vmm.removeVM(vm_name)
BarthaM@176
  1130
                    #break
mb@95
  1131
                    
BarthaM@176
  1132
            #create new vms for new devices if any
mb@90
  1133
            new_ip = None
BarthaM@176
  1134
            for new_device in tmp_rsds.values():
oliver@193
  1135
                showTrayMessage('Mounting device...', 7000)
BarthaM@172
  1136
                if (self.attachedRSDs and False) or (new_device not in self.attachedRSDs.values()):
BarthaM@159
  1137
                    new_sdvm = self.vmm.newSDVM()
BarthaM@221
  1138
                    self.vmm.attachVDisk(new_sdvm, 'SATA', '0', '0', self.vmm.templateImage)
mb@90
  1139
                    self.vmm.startVM(new_sdvm)
BarthaM@218
  1140
                    new_ip = self.vmm.waitStartup(new_sdvm)
BarthaM@166
  1141
                    if new_ip == None:
BarthaM@172
  1142
                        logger.error("Error getting IP address of SDVM. Cleaning up.")
BarthaM@172
  1143
                        self.vmm.poweroffVM(new_sdvm)
BarthaM@172
  1144
                        self.vmm.removeVM(new_sdvm)
BarthaM@172
  1145
                        continue
BarthaM@172
  1146
                    else:
BarthaM@172
  1147
                        logger.info("Got IP address for " + new_sdvm + ' ' + new_ip)
BarthaM@172
  1148
                    try:
BarthaM@172
  1149
                        self.vmm.attachRSD(new_sdvm, new_device)
BarthaM@172
  1150
                        self.attachedRSDs[new_sdvm] = new_device
BarthaM@172
  1151
                    except:
BarthaM@172
  1152
                        logger.info("RSD prematurely removed. Cleaning up.")
BarthaM@172
  1153
                        self.vmm.poweroffVM(new_sdvm)
BarthaM@172
  1154
                        self.vmm.removeVM(new_sdvm)
BarthaM@166
  1155
                        continue
BarthaM@166
  1156
                    try:
BarthaM@151
  1157
                        net_resource = '\\\\' + new_ip + '\\USB'
BarthaM@176
  1158
                        result = urllib2.urlopen('http://127.0.0.1:8090/netmount?'+'net_resource='+net_resource).readline()
BarthaM@166
  1159
                    except urllib2.URLError:
BarthaM@172
  1160
                        logger.error("Network drive connect failed (tray client not accessible). Cleaning up.")
BarthaM@172
  1161
                        self.vmm.poweroffVM(new_sdvm)
BarthaM@172
  1162
                        self.vmm.removeVM(new_sdvm)
BarthaM@166
  1163
                        continue
BarthaM@176
  1164
                    
BarthaM@176
  1165
            self.existingRSDs = tmp_rsds