eXtreme Programming session - changes by Mihai
authorOliver Maurhart <oliver.maurhart@ait.ac.at>
Thu, 22 May 2014 11:00:33 +0200
changeset 1671e1811fa44bc
parent 166 6718e19352e6
child 168 76267df09d71
eXtreme Programming session - changes by Mihai
OpenSecurity/bin/cygwin.py
OpenSecurity/bin/initial_vm.sh
OpenSecurity/bin/opensecurity_client_restful_server.py
OpenSecurity/bin/vmmanager.pyw
     1.1 --- a/OpenSecurity/bin/cygwin.py	Tue May 20 15:10:33 2014 +0100
     1.2 +++ b/OpenSecurity/bin/cygwin.py	Thu May 22 11:00:33 2014 +0200
     1.3 @@ -1,290 +1,301 @@
     1.4 -#!/bin/env python
     1.5 -# -*- coding: utf-8 -*-
     1.6 -
     1.7 -# ------------------------------------------------------------
     1.8 -# cygwin command
     1.9 -# 
    1.10 -# executes a cygwin command inside the opensecurity project
    1.11 -#
    1.12 -# Autor: Mihai Bartha, <mihai.bartha@ait.ac.at>
    1.13 -#        Oliver Maurhart, <oliver.maurhart@ait.ac.at>
    1.14 -#
    1.15 -# Copyright (C) 2013 AIT Austrian Institute of Technology
    1.16 -# AIT Austrian Institute of Technology GmbH
    1.17 -# Donau-City-Strasse 1 | 1220 Vienna | Austria
    1.18 -# http://www.ait.ac.at
    1.19 -#
    1.20 -# This program is free software; you can redistribute it and/or
    1.21 -# modify it under the terms of the GNU General Public License
    1.22 -# as published by the Free Software Foundation version 2.
    1.23 -# 
    1.24 -# This program is distributed in the hope that it will be useful,
    1.25 -# but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.26 -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.27 -# GNU General Public License for more details.
    1.28 -# 
    1.29 -# You should have received a copy of the GNU General Public License
    1.30 -# along with this program; if not, write to the Free Software
    1.31 -# Foundation, Inc., 51 Franklin Street, Fifth Floor, 
    1.32 -# Boston, MA  02110-1301, USA.
    1.33 -# ------------------------------------------------------------
    1.34 -
    1.35 -
    1.36 -# ------------------------------------------------------------
    1.37 -# imports
    1.38 -
    1.39 -import os
    1.40 -import subprocess
    1.41 -import sys
    1.42 -import _winreg
    1.43 -from subprocess import Popen, PIPE, STARTUPINFO, _subprocess
    1.44 -import threading
    1.45 -
    1.46 -# local
    1.47 -from environment import Environment
    1.48 -from opensecurity_util import logger, setupLogger, OpenSecurityException
    1.49 -import time
    1.50 -
    1.51 -
    1.52 -# ------------------------------------------------------------
    1.53 -# code
    1.54 -
    1.55 -def once(theClass):
    1.56 -    """get the path to our local cygwin installment"""
    1.57 -    home_drive = os.path.expandvars("%HOMEDRIVE%") + os.sep
    1.58 -    path_hint = [ 
    1.59 -        os.path.abspath(os.path.join(Environment('OpenSecurity').prefix_path, 'cygwin')), 
    1.60 -        os.path.abspath(os.path.join(Environment('OpenSecurity').prefix_path, 'cygwin64')), 
    1.61 -        os.path.abspath(os.path.join(home_drive, 'cygwin')),
    1.62 -        os.path.abspath(os.path.join(home_drive, 'cygwin64'))
    1.63 -    ]
    1.64 -    path_valid = [ p for p in path_hint if os.path.exists(p) ]
    1.65 -        
    1.66 -    theClass.cygwin_root = path_valid[0]
    1.67 -    theClass.cygwin_bin = os.path.join(theClass.cygwin_root, 'bin') + os.path.sep
    1.68 -    theClass.cygwin_bash = os.path.join(theClass.cygwin_bin, 'bash.exe')
    1.69 -    theClass.cygwin_ssh = os.path.join(theClass.cygwin_bin, 'ssh.exe')
    1.70 -    theClass.cygwin_scp = os.path.join(theClass.cygwin_bin, 'scp.exe')
    1.71 -    theClass.cygwin_x11 = os.path.join(theClass.cygwin_bin, 'XWin.exe')
    1.72 -    theClass.win_cmd = os.environ.get("COMSPEC", "cmd.exe") 
    1.73 -    """get the path to the VirtualBox installation on this system"""
    1.74 -    theClass.vbox_root = theClass.getRegEntry('SOFTWARE\Oracle\VirtualBox', 'InstallDir')[0]  
    1.75 -    theClass.vbox_man = os.path.join(theClass.vbox_root, 'VBoxManage.exe')
    1.76 -    #theClass.user_home = os.path.expanduser("~")
    1.77 -    theClass.user_home = os.environ['APPDATA']#os.path.expandvars("%APPDATA%")
    1.78 -    return theClass
    1.79 -
    1.80 -            
    1.81 -@once
    1.82 -class Cygwin(object):
    1.83 -    cygwin_root = ''
    1.84 -    cygwin_bin = ''
    1.85 -    cygwin_bash = ''
    1.86 -    cygwin_ssh = ''
    1.87 -    cygwin_x11 = ''
    1.88 -    cygwin_scp = ''
    1.89 -    vbox_root = ''
    1.90 -    vbox_man = ''
    1.91 -    win_cmd = ''
    1.92 -    user_home = ''
    1.93 -    """Some nifty methods working with Cygwin"""
    1.94 -    
    1.95 -    def __call__(self, command, arguments, wait_return=True, window = False):
    1.96 -        """make an instance of this object act as a function"""
    1.97 -        return self.execute(command, arguments, wait_return, window)
    1.98 -
    1.99 -    @staticmethod
   1.100 -    def getRegEntry(key, value):
   1.101 -        try:
   1.102 -            k = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, key)
   1.103 -            value = _winreg.QueryValueEx(k, value)
   1.104 -            _winreg.CloseKey(k)
   1.105 -            return value
   1.106 -        except:
   1.107 -            pass
   1.108 -    
   1.109 -            
   1.110 -    @staticmethod
   1.111 -    def root():
   1.112 -        return Cygwin.cygwin_root
   1.113 -
   1.114 -    @staticmethod
   1.115 -    def bin():
   1.116 -        return Cygwin.cygwin_bin
   1.117 -    
   1.118 -    @staticmethod
   1.119 -    def bash():
   1.120 -        return Cygwin.cygwin_bash
   1.121 -    
   1.122 -    @staticmethod    
   1.123 -    def ssh():
   1.124 -        return Cygwin.cygwin_ssh
   1.125 -    
   1.126 -    @staticmethod    
   1.127 -    def scp():
   1.128 -        return Cygwin.cygwin_scp
   1.129 -
   1.130 -    @staticmethod    
   1.131 -    def x11():
   1.132 -        return Cygwin.cygwin_x11
   1.133 -    
   1.134 -    @staticmethod
   1.135 -    def vboxman():
   1.136 -        return Cygwin.vbox_man
   1.137 -    
   1.138 -    @staticmethod
   1.139 -    def cmd():
   1.140 -        return Cygwin.win_cmd
   1.141 -    
   1.142 -    @staticmethod
   1.143 -    def home():
   1.144 -        return Cygwin.user_home
   1.145 -    
   1.146 -    executeLock = threading.Lock()
   1.147 -    #executes command on host system
   1.148 -    @staticmethod
   1.149 -    def execute(program, arguments, wait_return=True, window = False, stdin = PIPE, stdout = PIPE, stderr = PIPE):
   1.150 -        _startupinfo = STARTUPINFO()
   1.151 -        if not window:
   1.152 -            _startupinfo.dwFlags |= _subprocess.STARTF_USESHOWWINDOW
   1.153 -            _startupinfo.wShowWindow = _subprocess.SW_HIDE
   1.154 -
   1.155 -            #logger.debug('trying to launch: ' + program + ' ' + ''.join(arguments))
   1.156 -        res_stderr = None
   1.157 -        try:
   1.158 -            # quote the executable otherwise we run into troubles
   1.159 -            # when the path contains spaces and additonal arguments
   1.160 -            # are presented as well.
   1.161 -            # special: invoking bash as login shell here with
   1.162 -            # an unquoted command does not execute /etc/profile
   1.163 -            args = '"' + program + '" ' + arguments
   1.164 -            process = Popen(args, startupinfo = _startupinfo, stdin = stdin, stdout = stdout, stderr = stderr, shell = False)
   1.165 -            logger.debug('Launched: ' + program + ' ' + ''.join(arguments))
   1.166 -            if not wait_return:
   1.167 -                return [0, 'working in background', '']
   1.168 -            result = process.wait()
   1.169 -            res_stdout = process.stdout.read();
   1.170 -            res_stderr = process.stderr.read();
   1.171 -
   1.172 -        except Exception as ex:
   1.173 -            res_stderr = ''.join(str(ex.args))
   1.174 -            result = 1 
   1.175 -            
   1.176 -        return result, res_stdout, res_stderr
   1.177 -    
   1.178 -    @staticmethod
   1.179 -    def vboxExecute(command, wait_return=True, window = False, bash_opts=''):
   1.180 -        retry = 0
   1.181 -        result = None
   1.182 -        while retry < 3:
   1.183 -            if Cygwin.executeLock.acquire(True):
   1.184 -                result = Cygwin.execute(Cygwin.vbox_man, command, wait_return, window)
   1.185 -                Cygwin.executeLock.release()
   1.186 -                if result[0] == 0:
   1.187 -                    return result
   1.188 -                retry+=1
   1.189 -        return result
   1.190 -
   1.191 -
   1.192 -    @staticmethod
   1.193 -    def bashExecute(command, wait_return=True, window = False, bash_opts='', stdin = PIPE, stdout = PIPE, stderr = PIPE):
   1.194 -        # for some reason, the '-l' is ignored when started via python
   1.195 -        # so the same behavior is triggered by calling /etc/profile 
   1.196 -        # directly
   1.197 -        command = bash_opts + ' -l -c "'  + command + '"'
   1.198 -        return Cygwin.execute(Cygwin.cygwin_bash, command, wait_return, window, stdin = stdin, stdout = stdout, stderr = stderr)
   1.199 -    
   1.200 -    @staticmethod
   1.201 -    def cmdExecute(command, wait_return=True, window = False):
   1.202 -        command = ' /c ' + command 
   1.203 -        return Cygwin.execute(Cygwin.win_cmd, command, wait_return, window)
   1.204 -
   1.205 -    # executes command over ssh on guest vm
   1.206 -    @staticmethod
   1.207 -    def sshExecute(command, address, user_name, certificate, wait_return=True, window = False):
   1.208 -        command = ' -v -o StrictHostKeyChecking=no -i "' + certificate + '" ' + user_name + '@' + address + ' ' + command        
   1.209 -        return Cygwin.execute(Cygwin.cygwin_ssh, command, wait_return, window)
   1.210 -    
   1.211 -    #machineFolder + '/' + vm_name + '/dvm_key
   1.212 -    #address = self.getHostOnlyIP(vm_name)
   1.213 -    #machineFolder = self.getDefaultMachineFolder()
   1.214 -    #machineFolder = Cygwin.cygwinPath(machineFolder)
   1.215 -    
   1.216 -    # executes command over ssh on guest vm with X forwarding
   1.217 -    @staticmethod
   1.218 -    def sshExecuteX11(command, address, user_name, certificate, wait_return=True):
   1.219 -        return Cygwin.bashExecute('DISPLAY=:0.0 ssh -Y -o StrictHostKeyChecking=no -i \\\"' + certificate +'\\\" ' + user_name + '@' + address + ' ' + command + '')
   1.220 -
   1.221 -    @staticmethod
   1.222 -    def is_X11_running():
   1.223 -        """check if we can connect to a X11 running instance"""
   1.224 -        p = Cygwin.bashExecute('xset -display :0 q', wait_return = True, window = False) 
   1.225 -        return p[0] == 0
   1.226 -        
   1.227 -    @staticmethod
   1.228 -    def start_X11():
   1.229 -        """start X11 in the background (if not already running) on DISPLAY=:0
   1.230 -        
   1.231 -        If there is already a X11 running then exit silently, calling this
   1.232 -        method as often as needed.
   1.233 -        """
   1.234 -        Popen('"' + Cygwin.cygwin_x11 + '" :0 -multiwindow -resize -silent-dup-error')
   1.235 -        return (0, None, None)
   1.236 -    
   1.237 -    @staticmethod    
   1.238 -    def cygPath(path):
   1.239 -        cmd = 'cygpath -u \'' + path + '\''
   1.240 -        return Cygwin.bashExecute(cmd)[1].rstrip('\n')
   1.241 -    
   1.242 -    @staticmethod
   1.243 -    def checkResult(result):
   1.244 -        if result[0] != 0:
   1.245 -            logger.error('Command failed:' + ''.join(result[2]))
   1.246 -            raise OpenSecurityException('Command failed:' + ''.join(result[2]))
   1.247 -        return result
   1.248 -                
   1.249 -# start
   1.250 -import os
   1.251 -import win32api
   1.252 -import win32con
   1.253 -import win32security
   1.254 -
   1.255 -if __name__ == "__main__":
   1.256 -    logger = setupLogger('Cygwin')
   1.257 -    c = Cygwin()
   1.258 -    #logger.info(c.root())
   1.259 -    #logger.info(c.bin())
   1.260 -    #logger.info(c.bash())
   1.261 -    #logger.info(c.ssh())
   1.262 -    #logger.info(c.x11())
   1.263 -    #logger.info(c.home())   
   1.264 -    
   1.265 -    #PSEXEC -i -s -d CMD
   1.266 -    #tasklist /v /fo list /fi "IMAGENAME eq explorer.exe"
   1.267 -    
   1.268 -    #runner = XRunner()
   1.269 -    #runner.start()
   1.270 -    
   1.271 -    #Cygwin.start_X11()
   1.272 -    
   1.273 -    
   1.274 -            
   1.275 -    #time.sleep(500)
   1.276 -    
   1.277 -    #Cygwin.start_X11()
   1.278 -    #print (Cygwin.is_X11_running())
   1.279 -    #print (Cygwin.is_X11_running())
   1.280 -    #new_sdvm = 'SecurityDVM0'
   1.281 -    #new_ip = Cygwin.vboxExecute('guestproperty get ' + new_sdvm + ' /VirtualBox/GuestInfo/Net/0/V4/IP')[1]
   1.282 -    #new_ip = new_ip[new_ip.index(':')+1:].strip()
   1.283 -    #new_ip = '+'
   1.284 -    #result = Cygwin.bashExecute('DISPLAY=:0.0 xhost '+new_ip)
   1.285 -    #browser = '/usr/bin/midori '
   1.286 -    #print(Cygwin.sshExecuteX11(browser, new_ip, 'osecuser', '/cygdrive/c/Users/BarthaM/VirtualBox VMs' + '/' + new_sdvm + '/dvm_key'))
   1.287 -            
   1.288 -    #print(Cygwin.bashExecute('echo $PATH')[1])
   1.289 -    #print(Cygwin.cygPath('C:'))
   1.290 -    #print('C:\\Program Files\\OpenSecurity: ' + c.cygPath('C:\\Program Files\\OpenSecurity'))
   1.291 -    
   1.292 -    sys.exit(0)
   1.293 -    
   1.294 +#!/bin/env python
   1.295 +# -*- coding: utf-8 -*-
   1.296 +
   1.297 +# ------------------------------------------------------------
   1.298 +# cygwin command
   1.299 +# 
   1.300 +# executes a cygwin command inside the opensecurity project
   1.301 +#
   1.302 +# Autor: Mihai Bartha, <mihai.bartha@ait.ac.at>
   1.303 +#        Oliver Maurhart, <oliver.maurhart@ait.ac.at>
   1.304 +#
   1.305 +# Copyright (C) 2013 AIT Austrian Institute of Technology
   1.306 +# AIT Austrian Institute of Technology GmbH
   1.307 +# Donau-City-Strasse 1 | 1220 Vienna | Austria
   1.308 +# http://www.ait.ac.at
   1.309 +#
   1.310 +# This program is free software; you can redistribute it and/or
   1.311 +# modify it under the terms of the GNU General Public License
   1.312 +# as published by the Free Software Foundation version 2.
   1.313 +# 
   1.314 +# This program is distributed in the hope that it will be useful,
   1.315 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
   1.316 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   1.317 +# GNU General Public License for more details.
   1.318 +# 
   1.319 +# You should have received a copy of the GNU General Public License
   1.320 +# along with this program; if not, write to the Free Software
   1.321 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, 
   1.322 +# Boston, MA  02110-1301, USA.
   1.323 +# ------------------------------------------------------------
   1.324 +
   1.325 +
   1.326 +# ------------------------------------------------------------
   1.327 +# imports
   1.328 +
   1.329 +import os
   1.330 +import subprocess
   1.331 +import sys
   1.332 +import _winreg
   1.333 +from subprocess import Popen, PIPE, STARTUPINFO, _subprocess
   1.334 +import threading
   1.335 +
   1.336 +# local
   1.337 +from environment import Environment
   1.338 +from opensecurity_util import logger, setupLogger, OpenSecurityException
   1.339 +import time
   1.340 +
   1.341 +
   1.342 +# ------------------------------------------------------------
   1.343 +# code
   1.344 +
   1.345 +def once(theClass):
   1.346 +    """get the path to our local cygwin installment"""
   1.347 +    home_drive = os.path.expandvars("%HOMEDRIVE%") + os.sep
   1.348 +    path_hint = [ 
   1.349 +        os.path.abspath(os.path.join(Environment('OpenSecurity').prefix_path, 'cygwin')), 
   1.350 +        os.path.abspath(os.path.join(Environment('OpenSecurity').prefix_path, 'cygwin64')), 
   1.351 +        os.path.abspath(os.path.join(home_drive, 'cygwin')),
   1.352 +        os.path.abspath(os.path.join(home_drive, 'cygwin64'))
   1.353 +    ]
   1.354 +    path_valid = [ p for p in path_hint if os.path.exists(p) ]
   1.355 +        
   1.356 +    theClass.cygwin_root = path_valid[0]
   1.357 +    theClass.cygwin_bin = os.path.join(theClass.cygwin_root, 'bin') + os.path.sep
   1.358 +    theClass.cygwin_bash = os.path.join(theClass.cygwin_bin, 'bash.exe')
   1.359 +    theClass.cygwin_ssh = os.path.join(theClass.cygwin_bin, 'ssh.exe')
   1.360 +    theClass.cygwin_scp = os.path.join(theClass.cygwin_bin, 'scp.exe')
   1.361 +    theClass.cygwin_x11 = os.path.join(theClass.cygwin_bin, 'XWin.exe')
   1.362 +    theClass.win_cmd = os.environ.get("COMSPEC", "cmd.exe") 
   1.363 +    """get the path to the VirtualBox installation on this system"""
   1.364 +    theClass.vbox_root = theClass.getRegEntry('SOFTWARE\Oracle\VirtualBox', 'InstallDir')[0]  
   1.365 +    theClass.vbox_man = os.path.join(theClass.vbox_root, 'VBoxManage.exe')
   1.366 +    #theClass.user_home = os.path.expanduser("~")
   1.367 +    theClass.user_home = os.environ['APPDATA']#os.path.expandvars("%APPDATA%")
   1.368 +    return theClass
   1.369 +
   1.370 +            
   1.371 +@once
   1.372 +class Cygwin(object):
   1.373 +    cygwin_root = ''
   1.374 +    cygwin_bin = ''
   1.375 +    cygwin_bash = ''
   1.376 +    cygwin_ssh = ''
   1.377 +    cygwin_x11 = ''
   1.378 +    cygwin_scp = ''
   1.379 +    vbox_root = ''
   1.380 +    vbox_man = ''
   1.381 +    win_cmd = ''
   1.382 +    user_home = ''
   1.383 +    """Some nifty methods working with Cygwin"""
   1.384 +    
   1.385 +    def __call__(self, command, arguments, wait_return=True, window = False):
   1.386 +        """make an instance of this object act as a function"""
   1.387 +        return self.execute(command, arguments, wait_return, window)
   1.388 +
   1.389 +    @staticmethod
   1.390 +    def getRegEntry(key, value):
   1.391 +        try:
   1.392 +            k = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, key)
   1.393 +            value = _winreg.QueryValueEx(k, value)
   1.394 +            _winreg.CloseKey(k)
   1.395 +            return value
   1.396 +        except:
   1.397 +            pass
   1.398 +    
   1.399 +            
   1.400 +    @staticmethod
   1.401 +    def root():
   1.402 +        return Cygwin.cygwin_root
   1.403 +
   1.404 +    @staticmethod
   1.405 +    def bin():
   1.406 +        return Cygwin.cygwin_bin
   1.407 +    
   1.408 +    @staticmethod
   1.409 +    def bash():
   1.410 +        return Cygwin.cygwin_bash
   1.411 +    
   1.412 +    @staticmethod    
   1.413 +    def ssh():
   1.414 +        return Cygwin.cygwin_ssh
   1.415 +    
   1.416 +    @staticmethod    
   1.417 +    def scp():
   1.418 +        return Cygwin.cygwin_scp
   1.419 +
   1.420 +    @staticmethod    
   1.421 +    def x11():
   1.422 +        return Cygwin.cygwin_x11
   1.423 +    
   1.424 +    @staticmethod
   1.425 +    def vboxman():
   1.426 +        return Cygwin.vbox_man
   1.427 +    
   1.428 +    @staticmethod
   1.429 +    def cmd():
   1.430 +        return Cygwin.win_cmd
   1.431 +    
   1.432 +    @staticmethod
   1.433 +    def home():
   1.434 +        return Cygwin.user_home
   1.435 +    
   1.436 +    executeLock = threading.Lock()
   1.437 +    #executes command on host system
   1.438 +    @staticmethod
   1.439 +    def execute(program, arguments, wait_return=True, window = False, stdin = PIPE, stdout = PIPE, stderr = PIPE):
   1.440 +        _startupinfo = STARTUPINFO()
   1.441 +        if not window:
   1.442 +            _startupinfo.dwFlags |= _subprocess.STARTF_USESHOWWINDOW
   1.443 +            _startupinfo.wShowWindow = _subprocess.SW_HIDE
   1.444 +            #logger.debug('trying to launch: ' + program + ' ' + ''.join(arguments))
   1.445 +        
   1.446 +	    result, res_stdout, res_stderr = None, None, None
   1.447 +		
   1.448 +        try:
   1.449 +            # quote the executable otherwise we run into troubles
   1.450 +            # when the path contains spaces and additonal arguments
   1.451 +            # are presented as well.
   1.452 +            # special: invoking bash as login shell here with
   1.453 +            # an unquoted command does not execute /etc/profile
   1.454 +            args = '"' + program + '" ' + arguments
   1.455 +            process = Popen(args, startupinfo = _startupinfo, stdin = stdin, stdout = stdout, stderr = stderr, shell = False)
   1.456 +            logger.debug('Launched: ' + program + ' ' + ''.join(arguments))
   1.457 +            if not wait_return:
   1.458 +                return [0, 'working in background', '']
   1.459 +				
   1.460 +            res_stdout, res_stderr = process.communicate()
   1.461 +            result = process.returncode
   1.462 +			
   1.463 +			#result = process.wait()
   1.464 +            #res_stdout = process.stdout.read();
   1.465 +            #res_stderr = process.stderr.read();
   1.466 +
   1.467 +        except Exception as ex:
   1.468 +            res_stderr = ''.join(str(ex.args))
   1.469 +            result = 1 
   1.470 +            
   1.471 +        return result, res_stdout, res_stderr
   1.472 +    
   1.473 +    @staticmethod
   1.474 +    def vboxExecute(command, wait_return=True, window = False, bash_opts=''):
   1.475 +        retry = 0
   1.476 +        result = None
   1.477 +        while retry < 3:
   1.478 +            if Cygwin.executeLock.acquire(True):
   1.479 +                result = Cygwin.execute(Cygwin.vbox_man, command, wait_return, window)
   1.480 +                Cygwin.executeLock.release()
   1.481 +                if result[0] == 0:
   1.482 +                    return result
   1.483 +                retry+=1
   1.484 +        return result
   1.485 +
   1.486 +
   1.487 +    @staticmethod
   1.488 +    def bashExecute(command, wait_return=True, window = False, bash_opts='', stdin = PIPE, stdout = PIPE, stderr = PIPE):
   1.489 +        # for some reason, the '-l' is ignored when started via python
   1.490 +        # so the same behavior is triggered by calling /etc/profile 
   1.491 +        # directly
   1.492 +        command = bash_opts + ' -l -c "'  + command + '"'
   1.493 +        return Cygwin.execute(Cygwin.cygwin_bash, command, wait_return, window, stdin = stdin, stdout = stdout, stderr = stderr)
   1.494 +    
   1.495 +    @staticmethod
   1.496 +    def cmdExecute(command, wait_return=True, window = False):
   1.497 +        command = ' /c ' + command 
   1.498 +        return Cygwin.execute(Cygwin.win_cmd, command, wait_return, window)
   1.499 +
   1.500 +    # executes command over ssh on guest vm
   1.501 +    @staticmethod
   1.502 +    def sshExecute(command, address, user_name, certificate, wait_return=True, window = False):
   1.503 +        command = ' -v -o StrictHostKeyChecking=no -i "' + certificate + '" ' + user_name + '@' + address + ' ' + command        
   1.504 +        return Cygwin.execute(Cygwin.cygwin_ssh, command, wait_return, window)
   1.505 +	
   1.506 +	# executes command over ssh on guest vm
   1.507 +    @staticmethod
   1.508 +    def sshBackgroundExecute(command, address, user_name, certificate, wait_return=True, window = False):
   1.509 +        command = ' -f -v -o StrictHostKeyChecking=no -i "' + certificate + '" ' + user_name + '@' + address + ' ' + command        
   1.510 +        return Cygwin.execute(Cygwin.cygwin_ssh, command, wait_return, window)
   1.511 +    
   1.512 +    #machineFolder + '/' + vm_name + '/dvm_key
   1.513 +    #address = self.getHostOnlyIP(vm_name)
   1.514 +    #machineFolder = self.getDefaultMachineFolder()
   1.515 +    #machineFolder = Cygwin.cygwinPath(machineFolder)
   1.516 +    
   1.517 +    # executes command over ssh on guest vm with X forwarding
   1.518 +    @staticmethod
   1.519 +    def sshExecuteX11(command, address, user_name, certificate, wait_return=True):
   1.520 +        return Cygwin.bashExecute('DISPLAY=:0.0 ssh -Y -o StrictHostKeyChecking=no -i \\\"' + certificate +'\\\" ' + user_name + '@' + address + ' ' + command + '')
   1.521 +
   1.522 +    @staticmethod
   1.523 +    def is_X11_running():
   1.524 +        """check if we can connect to a X11 running instance"""
   1.525 +        p = Cygwin.bashExecute('xset -display :0 q', wait_return = True, window = False) 
   1.526 +        return p[0] == 0
   1.527 +        
   1.528 +    @staticmethod
   1.529 +    def start_X11():
   1.530 +        """start X11 in the background (if not already running) on DISPLAY=:0
   1.531 +        
   1.532 +        If there is already a X11 running then exit silently, calling this
   1.533 +        method as often as needed.
   1.534 +        """
   1.535 +        Popen('"' + Cygwin.cygwin_x11 + '" :0 -multiwindow -resize -silent-dup-error')
   1.536 +        return (0, None, None)
   1.537 +    
   1.538 +    @staticmethod    
   1.539 +    def cygPath(path):
   1.540 +        cmd = 'cygpath -u \'' + path + '\''
   1.541 +        return Cygwin.bashExecute(cmd)[1].rstrip('\n')
   1.542 +    
   1.543 +    @staticmethod
   1.544 +    def checkResult(result):
   1.545 +        if result[0] != 0:
   1.546 +            logger.error('Command failed:' + ''.join(result[2]))
   1.547 +            raise OpenSecurityException('Command failed:' + ''.join(result[2]))
   1.548 +        return result
   1.549 +                
   1.550 +# start
   1.551 +import os
   1.552 +import win32api
   1.553 +import win32con
   1.554 +import win32security
   1.555 +
   1.556 +if __name__ == "__main__":
   1.557 +    logger = setupLogger('Cygwin')
   1.558 +    c = Cygwin()
   1.559 +    #logger.info(c.root())
   1.560 +    #logger.info(c.bin())
   1.561 +    #logger.info(c.bash())
   1.562 +    #logger.info(c.ssh())
   1.563 +    #logger.info(c.x11())
   1.564 +    #logger.info(c.home())   
   1.565 +    
   1.566 +    #PSEXEC -i -s -d CMD
   1.567 +    #tasklist /v /fo list /fi "IMAGENAME eq explorer.exe"
   1.568 +    
   1.569 +    #runner = XRunner()
   1.570 +    #runner.start()
   1.571 +    
   1.572 +    #Cygwin.start_X11()
   1.573 +    
   1.574 +    
   1.575 +            
   1.576 +    #time.sleep(500)
   1.577 +    
   1.578 +    #Cygwin.start_X11()
   1.579 +    #print (Cygwin.is_X11_running())
   1.580 +    #print (Cygwin.is_X11_running())
   1.581 +    #new_sdvm = 'SecurityDVM0'
   1.582 +    #new_ip = Cygwin.vboxExecute('guestproperty get ' + new_sdvm + ' /VirtualBox/GuestInfo/Net/0/V4/IP')[1]
   1.583 +    #new_ip = new_ip[new_ip.index(':')+1:].strip()
   1.584 +    #new_ip = '+'
   1.585 +    #result = Cygwin.bashExecute('DISPLAY=:0.0 xhost '+new_ip)
   1.586 +    #browser = '/usr/bin/midori '
   1.587 +    #print(Cygwin.sshExecuteX11(browser, new_ip, 'osecuser', '/cygdrive/c/Users/BarthaM/VirtualBox VMs' + '/' + new_sdvm + '/dvm_key'))
   1.588 +            
   1.589 +    #print(Cygwin.bashExecute('echo $PATH')[1])
   1.590 +    #print(Cygwin.cygPath('C:'))
   1.591 +    #print('C:\\Program Files\\OpenSecurity: ' + c.cygPath('C:\\Program Files\\OpenSecurity'))
   1.592 +    
   1.593 +    sys.exit(0)
   1.594 +    
     2.1 --- a/OpenSecurity/bin/initial_vm.sh	Tue May 20 15:10:33 2014 +0100
     2.2 +++ b/OpenSecurity/bin/initial_vm.sh	Thu May 22 11:00:33 2014 +0200
     2.3 @@ -115,6 +115,9 @@
     2.4      exit 1
     2.5  fi
     2.6  
     2.7 +# kick useless IDE controller
     2.8 +"${VBOX_MANAGER}" storagectl SecurityDVM --name IDE --remove
     2.9 + 
    2.10  # grab VM storage controller and port 
    2.11  #
    2.12  VDISK_SETUP=$("${VBOX_MANAGER}" showvminfo SecurityDVM | grep SecurityDVM.vmdk | cut -d ':' -f 1 | tr '(),' '   ')
    2.13 @@ -132,17 +135,17 @@
    2.14  
    2.15  # detach disk image
    2.16  #
    2.17 -echo "detaching disk image ..."
    2.18 -"${VBOX_MANAGER}" storageattach SecurityDVM --storagectl ${VDISK_CONTROLLER} --port ${VDISK_PORT} --medium none
    2.19 +#echo "detaching disk image ..."
    2.20 +#"${VBOX_MANAGER}" storageattach SecurityDVM --storagectl ${VDISK_CONTROLLER} --port ${VDISK_PORT} --medium none
    2.21  
    2.22 -# turn disk image into writethrough
    2.23 +# turn disk image into normal
    2.24  #
    2.25 -echo "turning disk image into writetrough ..."
    2.26 -"${VBOX_MANAGER}" storageattach SecurityDVM --storagectl ${VDISK_CONTROLLER} --port ${VDISK_PORT} --device ${VDISK_DEVICE} --type hdd --mtype writethrough --medium "${VDISK_IMAGE}" 
    2.27 +#echo "turning disk image into normal ..."
    2.28 +#"${VBOX_MANAGER}" storageattach SecurityDVM --storagectl ${VDISK_CONTROLLER} --port ${VDISK_PORT} --device ${VDISK_DEVICE} --type hdd --mtype normal --medium "${VDISK_IMAGE}" 
    2.29  
    2.30  # detach disk image
    2.31  #
    2.32 -echo "detaching disk image ..."
    2.33 +echo "detach disk image ..."
    2.34  "${VBOX_MANAGER}" storageattach SecurityDVM --storagectl ${VDISK_CONTROLLER} --port ${VDISK_PORT} --medium none
    2.35  
    2.36  # immutablize disk
     3.1 --- a/OpenSecurity/bin/opensecurity_client_restful_server.py	Tue May 20 15:10:33 2014 +0100
     3.2 +++ b/OpenSecurity/bin/opensecurity_client_restful_server.py	Thu May 22 11:00:33 2014 +0200
     3.3 @@ -1,621 +1,623 @@
     3.4 -#!/bin/env python
     3.5 -# -*- coding: utf-8 -*-
     3.6 -
     3.7 -# ------------------------------------------------------------
     3.8 -# opensecurity_client_restful_server
     3.9 -# 
    3.10 -# the OpenSecurity client RESTful server
    3.11 -#
    3.12 -# Autor: Oliver Maurhart, <oliver.maurhart@ait.ac.at>
    3.13 -#
    3.14 -# Copyright (C) 2013 AIT Austrian Institute of Technology
    3.15 -# AIT Austrian Institute of Technology GmbH
    3.16 -# Donau-City-Strasse 1 | 1220 Vienna | Austria
    3.17 -# http://www.ait.ac.at
    3.18 -#
    3.19 -# This program is free software; you can redistribute it and/or
    3.20 -# modify it under the terms of the GNU General Public License
    3.21 -# as published by the Free Software Foundation version 2.
    3.22 -# 
    3.23 -# This program is distributed in the hope that it will be useful,
    3.24 -# but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.25 -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    3.26 -# GNU General Public License for more details.
    3.27 -# 
    3.28 -# You should have received a copy of the GNU General Public License
    3.29 -# along with this program; if not, write to the Free Software
    3.30 -# Foundation, Inc., 51 Franklin Street, Fifth Floor, 
    3.31 -# Boston, MA  02110-1301, USA.
    3.32 -# ------------------------------------------------------------
    3.33 -
    3.34 -
    3.35 -# ------------------------------------------------------------
    3.36 -# imports
    3.37 -
    3.38 -import getpass
    3.39 -import glob
    3.40 -import json
    3.41 -import os
    3.42 -import os.path
    3.43 -import pickle
    3.44 -import platform
    3.45 -import socket
    3.46 -import subprocess
    3.47 -import sys
    3.48 -import threading
    3.49 -import time
    3.50 -import urllib
    3.51 -import urllib2
    3.52 -import web
    3.53 -import threading
    3.54 -import time
    3.55 -import string
    3.56 -import win32api
    3.57 -import win32con
    3.58 -
    3.59 -from opensecurity_util import logger, setupLogger, OpenSecurityException
    3.60 -if sys.platform == 'win32' or sys.platform == 'cygwin':
    3.61 -    from cygwin import Cygwin
    3.62 -
    3.63 -# local
    3.64 -import __init__ as opensecurity
    3.65 -from environment import Environment
    3.66 -
    3.67 -
    3.68 -# ------------------------------------------------------------
    3.69 -# const
    3.70 -
    3.71 -
    3.72 -"""All the URLs we know mapping to class handler"""
    3.73 -opensecurity_urls = (
    3.74 -    '/credentials',             'os_credentials',
    3.75 -    '/keyfile',                 'os_keyfile',
    3.76 -    '/log',                     'os_log',
    3.77 -    '/notification',            'os_notification',
    3.78 -    '/password',                'os_password',
    3.79 -    '/netmount',                'os_netmount',
    3.80 -    '/netumount',               'os_netumount',
    3.81 -    '/',                        'os_root'
    3.82 -)
    3.83 -
    3.84 -
    3.85 -# ------------------------------------------------------------
    3.86 -# vars
    3.87 -
    3.88 -
    3.89 -"""lock for read/write log file"""
    3.90 -log_file_lock = threading.Lock()
    3.91 -
    3.92 -"""timer for the log file bouncer"""
    3.93 -log_file_bouncer = None
    3.94 -
    3.95 -
    3.96 -"""The REST server object"""
    3.97 -server = None
    3.98 -
    3.99 -
   3.100 -# ------------------------------------------------------------
   3.101 -# code
   3.102 -
   3.103 -
   3.104 -class os_credentials:
   3.105 -
   3.106 -    """OpenSecurity '/credentials' handler.
   3.107 -    
   3.108 -    This is called on GET /credentials?text=TEXT.
   3.109 -    Ideally this should pop up a user dialog to insert his
   3.110 -    credentials based the given TEXT.
   3.111 -    """
   3.112 -    
   3.113 -    def GET(self):
   3.114 -        
   3.115 -        # pick the arguments
   3.116 -        args = web.input()
   3.117 -        
   3.118 -        # we _need_ a text
   3.119 -        if not "text" in args:
   3.120 -            raise web.badrequest('no text given')
   3.121 -        
   3.122 -        # remember remote ip
   3.123 -        remote_ip = web.ctx.environ['REMOTE_ADDR']
   3.124 -
   3.125 -        # create the process which queries the user
   3.126 -        dlg_image = os.path.join(sys.path[0], 'opensecurity_dialog.pyw')
   3.127 -        process_command = [sys.executable, dlg_image, 'credentials', args.text]
   3.128 -        process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE)        
   3.129 -        
   3.130 -        # run process result handling in seprate thread (not to block main one)
   3.131 -        bouncer = ProcessResultBouncer(process, remote_ip, '/credentials')
   3.132 -        bouncer.start()
   3.133 -         
   3.134 -        return 'user queried for credentials'
   3.135 -
   3.136 -
   3.137 -class os_keyfile:
   3.138 -
   3.139 -    """OpenSecurity '/keyfile' handler.
   3.140 -    
   3.141 -    This is called on GET /keyfile?text=TEXT.
   3.142 -    Ideally this should pop up a user dialog to insert his
   3.143 -    password along with a keyfile.
   3.144 -    """
   3.145 -    
   3.146 -    def GET(self):
   3.147 -        
   3.148 -        # pick the arguments
   3.149 -        args = web.input()
   3.150 -        
   3.151 -        # we _need_ a text
   3.152 -        if not "text" in args:
   3.153 -            raise web.badrequest('no text given')
   3.154 -            
   3.155 -        # remember remote ip
   3.156 -        remote_ip = web.ctx.environ['REMOTE_ADDR']
   3.157 -        
   3.158 -        # create the process which queries the user
   3.159 -        dlg_image = os.path.join(sys.path[0], 'opensecurity_dialog.pyw')
   3.160 -        process_command = [sys.executable, dlg_image, 'keyfile', args.text]
   3.161 -        process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE)        
   3.162 -        
   3.163 -        # run process result handling in seprate thread (not to block main one)
   3.164 -        bouncer = ProcessResultBouncer(process, remote_ip, '/keyfile')
   3.165 -        bouncer.start()
   3.166 -         
   3.167 -        return 'user queried for password and keyfile'
   3.168 -
   3.169 -
   3.170 -class os_log:
   3.171 -
   3.172 -    """OpenSecurity '/log' handler.
   3.173 -    
   3.174 -    This is called on GET or POST on the log function /log
   3.175 -    """
   3.176 -    
   3.177 -    def GET(self):
   3.178 -        
   3.179 -        # pick the arguments
   3.180 -        self.POST()
   3.181 -
   3.182 -
   3.183 -    def POST(self):
   3.184 -        
   3.185 -        # pick the arguments
   3.186 -        args = web.input()
   3.187 -        args['user'] = getpass.getuser()
   3.188 -        args['system'] = platform.node() + " " + platform.system() + " " + platform.release()
   3.189 -
   3.190 -        # add these to new data to log
   3.191 -        global log_file_lock
   3.192 -        log_file_name = os.path.join(Environment('OpenSecurity').log_path, 'vm_new.log')
   3.193 -        log_file_lock.acquire()
   3.194 -        pickle.dump(args,  open(log_file_name, 'ab'))
   3.195 -        log_file_lock.release()
   3.196 -
   3.197 -        return "Ok"
   3.198 -
   3.199 -
   3.200 -class os_notification:
   3.201 -
   3.202 -    """OpenSecurity '/notification' handler.
   3.203 -    
   3.204 -    This is called on GET /notification?msgtype=TYPE&text=TEXT.
   3.205 -    This will pop up an OpenSecurity notifcation window
   3.206 -    """
   3.207 -    
   3.208 -    def GET(self):
   3.209 -        
   3.210 -        # pick the arguments
   3.211 -        args = web.input()
   3.212 -        
   3.213 -        # we _need_ a type
   3.214 -        if not "msgtype" in args:
   3.215 -            raise web.badrequest('no msgtype given')
   3.216 -            
   3.217 -        if not args.msgtype in ['information', 'warning', 'critical']:
   3.218 -            raise web.badrequest('Unknown value for msgtype')
   3.219 -            
   3.220 -        # we _need_ a text
   3.221 -        if not "text" in args:
   3.222 -            raise web.badrequest('no text given')
   3.223 -            
   3.224 -        # invoke the user dialog as a subprocess
   3.225 -        dlg_image = os.path.join(sys.path[0], 'opensecurity_dialog.py')
   3.226 -        process_command = [sys.executable, dlg_image, 'notification-' + args.msgtype, args.text]
   3.227 -        process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE)
   3.228 -
   3.229 -        return "Ok"
   3.230 -
   3.231 -
   3.232 -class os_password:
   3.233 -
   3.234 -    """OpenSecurity '/password' handler.
   3.235 -    
   3.236 -    This is called on GET /password?text=TEXT.
   3.237 -    Ideally this should pop up a user dialog to insert his
   3.238 -    password based device name.
   3.239 -    """
   3.240 -    
   3.241 -    def GET(self):
   3.242 -        
   3.243 -        # pick the arguments
   3.244 -        args = web.input()
   3.245 -        
   3.246 -        # we _need_ a text
   3.247 -        if not "text" in args:
   3.248 -            raise web.badrequest('no text given')
   3.249 -            
   3.250 -        # remember remote ip
   3.251 -        remote_ip = web.ctx.environ['REMOTE_ADDR']
   3.252 -        
   3.253 -        # create the process which queries the user
   3.254 -        dlg_image = os.path.join(sys.path[0], 'opensecurity_dialog.pyw')
   3.255 -        process_command = [sys.executable, dlg_image, 'password', args.text]
   3.256 -        process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE)        
   3.257 -        
   3.258 -        # run process result handling in seprate thread (not to block main one)
   3.259 -        bouncer = ProcessResultBouncer(process, remote_ip, '/password')
   3.260 -        bouncer.start()
   3.261 -        
   3.262 -        return 'user queried for password'
   3.263 -
   3.264 -# handles netumount request                    
   3.265 -class MountNetworkDriveHandler(threading.Thread): 
   3.266 -    drive = None
   3.267 -    resource = None
   3.268 -    
   3.269 -    def __init__(self, drv, net_path):
   3.270 -        threading.Thread.__init__(self)
   3.271 -        self.drive = drv
   3.272 -        self.networkPath = net_path
   3.273 -    
   3.274 -    def run(self):
   3.275 -        #Check for drive availability
   3.276 -        if os.path.exists(self.drive):
   3.277 -            logger.error("Drive letter is already in use: " + self.drive)
   3.278 -            return 1
   3.279 -        
   3.280 -        #Check for network resource availability
   3.281 -        retry = 5
   3.282 -        while not os.path.exists(self.networkPath):
   3.283 -            time.sleep(1)
   3.284 -            if retry == 0:
   3.285 -                return 1
   3.286 -            logger.info("Path not accessible: " + self.networkPath + " retrying")
   3.287 -            retry-=1
   3.288 -    
   3.289 -        command = 'USE ' + self.drive + ' ' + self.networkPath + ' /PERSISTENT:NO'
   3.290 -    
   3.291 -        result = Cygwin.checkResult(Cygwin.execute('C:\\Windows\\system32\\NET', command))
   3.292 -        if string.find(result[1], 'successfully',) == -1:
   3.293 -            logger.error("Failed: NET " + command)
   3.294 -            return 1
   3.295 -        return 0
   3.296 -
   3.297 -class os_netmount:
   3.298 -    
   3.299 -    """OpenSecurity '/netmount' handler"""
   3.300 -    
   3.301 -    def GET(self):
   3.302 -        # pick the arguments
   3.303 -        args = web.input()
   3.304 -        
   3.305 -        # we _need_ a net_resource
   3.306 -        if not "net_resource" in args:
   3.307 -            raise web.badrequest('no net_resource given')
   3.308 -        
   3.309 -        # we _need_ a drive_letter
   3.310 -        if not "drive_letter" in args:
   3.311 -            raise web.badrequest('no drive_letter given')
   3.312 -
   3.313 -        driveHandler = MountNetworkDriveHandler(args['drive_letter'], args['net_resource'])
   3.314 -        driveHandler.start()
   3.315 -        return 'Ok'
   3.316 -
   3.317 -         
   3.318 -        
   3.319 -# handles netumount request                    
   3.320 -class UmountNetworkDriveHandler(threading.Thread): 
   3.321 -    drive = None
   3.322 -    running = True
   3.323 -    
   3.324 -    def __init__(self, drv):
   3.325 -        threading.Thread.__init__(self)
   3.326 -        self.drive = drv
   3.327 -
   3.328 -    def run(self):
   3.329 -        while self.running:
   3.330 -            result = Cygwin.checkResult(Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE'))
   3.331 -            mappedDrives = list()
   3.332 -            for line in result[1].splitlines():
   3.333 -                if 'USB' in line or 'Download' in line:
   3.334 -                    parts = line.split()
   3.335 -                    mappedDrives.append(parts[1])
   3.336 -            
   3.337 -            logger.info(mappedDrives)
   3.338 -            logger.info(self.drive)
   3.339 -            if self.drive not in mappedDrives:
   3.340 -                self.running = False
   3.341 -            else:
   3.342 -                command = 'USE ' + self.drive + ' /DELETE /YES' 
   3.343 -                result = Cygwin.checkResult(Cygwin.execute('C:\\Windows\\system32\\net.exe', command)) 
   3.344 -                if string.find(str(result[1]), 'successfully',) == -1:
   3.345 -                    logger.error(result[2])
   3.346 -                    continue
   3.347 -                        
   3.348 -
   3.349 -class os_netumount:
   3.350 -    
   3.351 -    """OpenSecurity '/netumount' handler"""
   3.352 -    
   3.353 -    def GET(self):
   3.354 -        # pick the arguments
   3.355 -        args = web.input()
   3.356 -        
   3.357 -        # we _need_ a drive_letter
   3.358 -        if not "drive_letter" in args:
   3.359 -            raise web.badrequest('no drive_letter given')
   3.360 -        
   3.361 -        driveHandler = UmountNetworkDriveHandler(args['drive_letter'])
   3.362 -        driveHandler.start()
   3.363 -        return 'Ok'
   3.364 -    
   3.365 -
   3.366 -class os_root:
   3.367 -
   3.368 -    """OpenSecurity '/' handler"""
   3.369 -    
   3.370 -    def GET(self):
   3.371 -    
   3.372 -        res = "OpenSecurity-Client RESTFul Server { \"version\": \"%s\" }" % opensecurity.__version__
   3.373 -        
   3.374 -        # add some sample links
   3.375 -        res = res + """
   3.376 -        
   3.377 -USAGE EXAMPLES:
   3.378 -        
   3.379 -Request a password: 
   3.380 -    (copy paste this into your browser's address field after the host:port)
   3.381 -    
   3.382 -    /password?text=Give+me+a+password+for+device+%22My+USB+Drive%22+(ID%3A+32090-AAA-X0)
   3.383 -    
   3.384 -    (eg.: http://127.0.0.1:8090/password?text=Give+me+a+password+for+device+%22My+USB+Drive%22+(ID%3A+32090-AAA-X0))
   3.385 -    NOTE: check yout taskbar, the dialog window may not pop up in front of your browser window.
   3.386 -    
   3.387 -    
   3.388 -Request a combination of user and password:
   3.389 -    (copy paste this into your browser's address field after the host:port)
   3.390 -    
   3.391 -    /credentials?text=Tell+the+NSA+which+credentials+to+use+in+order+to+avoid+hacking+noise+on+wire.
   3.392 -    
   3.393 -    (eg.: http://127.0.0.1:8090/credentials?text=Tell+the+NSA+which+credentials+to+use+in+order+to+avoid+hacking+noise+on+wire.)
   3.394 -    NOTE: check yout taskbar, the dialog window may not pop up in front of your browser window.
   3.395 -    
   3.396 -
   3.397 -Request a combination of password and keyfile:
   3.398 -    (copy paste this into your browser's address field after the host:port)
   3.399 -    
   3.400 -    /keyfile?text=Your%20private%20RSA%20Keyfile%3A
   3.401 -    
   3.402 -    (eg.: http://127.0.0.1:8090//keyfile?text=Your%20private%20RSA%20Keyfile%3A)
   3.403 -    NOTE: check yout taskbar, the dialog window may not pop up in front of your browser window.
   3.404 -    
   3.405 -
   3.406 -Start a Browser:
   3.407 -    (copy paste this into your browser's address field after the host:port)
   3.408 -
   3.409 -    /application?vm=Debian+7&app=Browser
   3.410 -
   3.411 -    (e.g. http://127.0.0.1:8090/application?vm=Debian+7&app=Browser)
   3.412 -        """
   3.413 -    
   3.414 -        return res
   3.415 -
   3.416 -
   3.417 -class ProcessResultBouncer(threading.Thread):
   3.418 -
   3.419 -    """A class to post the result of a given process - assuming it to be in JSON - to a REST Api."""
   3.420 -
   3.421 -    def __init__(self, process, remote_ip, resource): 
   3.422 -
   3.423 -        """ctor"""
   3.424 -
   3.425 -        threading.Thread.__init__(self)
   3.426 -        self._process = process
   3.427 -        self._remote_ip = remote_ip
   3.428 -        self._resource = resource
   3.429 - 
   3.430 -    
   3.431 -    def stop(self):
   3.432 -
   3.433 -        """stop thread"""
   3.434 -        self.running = False
   3.435 -        
   3.436 -    
   3.437 -    def run(self):
   3.438 -
   3.439 -        """run the thread"""
   3.440 -
   3.441 -        # invoke the user dialog as a subprocess
   3.442 -        result = self._process.communicate()[0]
   3.443 -        if self._process.returncode != 0:
   3.444 -            print 'user request has been aborted.'
   3.445 -            return
   3.446 -        
   3.447 -        # all ok, tell send request back appropriate destination
   3.448 -        try:
   3.449 -            j = json.loads(result)
   3.450 -        except:
   3.451 -            print 'error in password parsing'
   3.452 -            return
   3.453 -        
   3.454 -        # by provided a 'data' we turn this into a POST statement
   3.455 -        url_addr = 'http://' + self._remote_ip + ':58080' + self._resource
   3.456 -        req = urllib2.Request(url_addr, urllib.urlencode(j))
   3.457 -        try:
   3.458 -            res = urllib2.urlopen(req)
   3.459 -        except:
   3.460 -            print 'failed to contact: ' + url_addr
   3.461 -            return 
   3.462 -
   3.463 -
   3.464 -class RESTServerThread(threading.Thread):
   3.465 -
   3.466 -    """Thread for serving the REST API."""
   3.467 -
   3.468 -    def __init__(self, port): 
   3.469 -
   3.470 -        """ctor"""
   3.471 -        threading.Thread.__init__(self)
   3.472 -        self._port = port 
   3.473 -    
   3.474 -    def stop(self):
   3.475 -
   3.476 -        """stop thread"""
   3.477 -        self.running = False
   3.478 -        
   3.479 -    
   3.480 -    def run(self):
   3.481 -
   3.482 -        """run the thread"""
   3.483 -        _serve(self._port)
   3.484 -
   3.485 -
   3.486 -
   3.487 -def is_already_running(port = 8090):
   3.488 -
   3.489 -    """check if this is started twice"""
   3.490 -
   3.491 -    try:
   3.492 -        s = socket.create_connection(('127.0.0.1', port), 0.5)
   3.493 -    except:
   3.494 -        return False
   3.495 -
   3.496 -    return True
   3.497 -
   3.498 -
   3.499 -def _bounce_vm_logs():
   3.500 -
   3.501 -    """grab all logs from the VMs and push them to the log servers"""
   3.502 -
   3.503 -    global log_file_lock
   3.504 -
   3.505 -    # pick the highest current number
   3.506 -    cur = 0
   3.507 -    for f in glob.iglob(os.path.join(Environment('OpenSecurity').log_path, 'vm_cur.log.*')):
   3.508 -        try:
   3.509 -            n = f.split('.')[-1:][0]
   3.510 -            if cur < int(n):
   3.511 -                cur = int(n)
   3.512 -        except:
   3.513 -            pass
   3.514 -
   3.515 -    cur = cur + 1
   3.516 -
   3.517 -    # first add new vm logs to our existing one: rename the log file
   3.518 -    log_file_name_new = os.path.join(Environment('OpenSecurity').log_path, 'vm_new.log')
   3.519 -    log_file_name_cur = os.path.join(Environment('OpenSecurity').log_path, 'vm_cur.log.' + str(cur))
   3.520 -    log_file_lock.acquire()
   3.521 -    try:
   3.522 -        os.rename(log_file_name_new, log_file_name_cur)
   3.523 -        print('new log file: ' + log_file_name_cur)
   3.524 -    except:
   3.525 -        pass
   3.526 -    log_file_lock.release()
   3.527 -
   3.528 -    # now we have a list of next log files to dump
   3.529 -    log_files = glob.glob(os.path.join(Environment('OpenSecurity').log_path, 'vm_cur.log.*'))
   3.530 -    log_files.sort()
   3.531 -    for log_file in log_files:
   3.532 -
   3.533 -        try:
   3.534 -            f = open(log_file, 'rb')
   3.535 -            while True:
   3.536 -                l = pickle.load(f)
   3.537 -                _push_log(l)
   3.538 -
   3.539 -        except EOFError:
   3.540 -
   3.541 -            try:
   3.542 -                os.remove(log_file)
   3.543 -            except:
   3.544 -                logger.warning('tried to delete log file (pushed to EOF) "' + log_file + '" but failed')
   3.545 -
   3.546 -        except:
   3.547 -            logger.warning('encountered error while pushing log file "' + log_file + '"')
   3.548 -            break
   3.549 -
   3.550 -    # start bouncer again ...
   3.551 -    global log_file_bouncer
   3.552 -    log_file_bouncer = threading.Timer(5.0, _bounce_vm_logs)
   3.553 -    log_file_bouncer.start()
   3.554 -
   3.555 -
   3.556 -def _push_log(log):
   3.557 -    """POST a single log to log server
   3.558 -
   3.559 -    @param  log     the log POST param
   3.560 -    """
   3.561 -
   3.562 -    try:
   3.563 -        key = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\OpenSecurity')
   3.564 -        log_server_url = str(win32api.RegQueryValueEx(key, 'LogServerURL')[0])
   3.565 -        win32api.RegCloseKey(key)
   3.566 -    except:
   3.567 -        logger.critical('Cannot open Registry HKEY_LOCAL_MACHINE\SOFTWARE\OpenSecurity and get LogServerURL value')
   3.568 -        raise
   3.569 -
   3.570 -    # by provided a 'data' we turn this into a POST statement
   3.571 -    d = urllib.urlencode(log)
   3.572 -    req = urllib2.Request(log_server_url, d)
   3.573 -    urllib2.urlopen(req)
   3.574 -    logger.debug('pushed log to server: ' + str(log_server_url))
   3.575 -
   3.576 -
   3.577 -def _serve(port):
   3.578 -
   3.579 -    """Start the REST server"""
   3.580 -
   3.581 -    global server
   3.582 -
   3.583 -    # start the VM-log bouncer timer
   3.584 -    global log_file_bouncer
   3.585 -    log_file_bouncer = threading.Timer(5.0, _bounce_vm_logs)
   3.586 -    log_file_bouncer.start()
   3.587 -
   3.588 -    # trick the web.py server 
   3.589 -    sys.argv = [__file__, str(port)]
   3.590 -    server = web.application(opensecurity_urls, globals())
   3.591 -    server.run()
   3.592 -
   3.593 -
   3.594 -def serve(port = 8090, background = False):
   3.595 -
   3.596 -    """Start serving the REST Api
   3.597 -    port ... port number to listen on
   3.598 -    background ... cease into background (spawn thread) and return immediately"""
   3.599 -
   3.600 -    # start threaded or direct version
   3.601 -    if background == True:
   3.602 -        t = RESTServerThread(port)
   3.603 -        t.start()
   3.604 -    else:
   3.605 -        _serve(port)
   3.606 -
   3.607 -def stop():
   3.608 -
   3.609 -    """Stop serving the REST Api"""
   3.610 -
   3.611 -    global server
   3.612 -    if server is None:
   3.613 -        return
   3.614 -
   3.615 -    global log_file_bouncer
   3.616 -    if log_file_bouncer is not None:
   3.617 -        log_file_bouncer.cancel()
   3.618 -
   3.619 -    server.stop()
   3.620 -
   3.621 -# start
   3.622 -if __name__ == "__main__":
   3.623 -    serve()
   3.624 -
   3.625 +#!/bin/env python
   3.626 +# -*- coding: utf-8 -*-
   3.627 +
   3.628 +# ------------------------------------------------------------
   3.629 +# opensecurity_client_restful_server
   3.630 +# 
   3.631 +# the OpenSecurity client RESTful server
   3.632 +#
   3.633 +# Autor: Oliver Maurhart, <oliver.maurhart@ait.ac.at>
   3.634 +#
   3.635 +# Copyright (C) 2013 AIT Austrian Institute of Technology
   3.636 +# AIT Austrian Institute of Technology GmbH
   3.637 +# Donau-City-Strasse 1 | 1220 Vienna | Austria
   3.638 +# http://www.ait.ac.at
   3.639 +#
   3.640 +# This program is free software; you can redistribute it and/or
   3.641 +# modify it under the terms of the GNU General Public License
   3.642 +# as published by the Free Software Foundation version 2.
   3.643 +# 
   3.644 +# This program is distributed in the hope that it will be useful,
   3.645 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
   3.646 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   3.647 +# GNU General Public License for more details.
   3.648 +# 
   3.649 +# You should have received a copy of the GNU General Public License
   3.650 +# along with this program; if not, write to the Free Software
   3.651 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, 
   3.652 +# Boston, MA  02110-1301, USA.
   3.653 +# ------------------------------------------------------------
   3.654 +
   3.655 +
   3.656 +# ------------------------------------------------------------
   3.657 +# imports
   3.658 +
   3.659 +import getpass
   3.660 +import glob
   3.661 +import json
   3.662 +import os
   3.663 +import os.path
   3.664 +import pickle
   3.665 +import platform
   3.666 +import socket
   3.667 +import subprocess
   3.668 +import sys
   3.669 +import threading
   3.670 +import time
   3.671 +import urllib
   3.672 +import urllib2
   3.673 +import web
   3.674 +import threading
   3.675 +import time
   3.676 +import string
   3.677 +import win32api
   3.678 +import win32con
   3.679 +
   3.680 +from opensecurity_util import logger, setupLogger, OpenSecurityException
   3.681 +if sys.platform == 'win32' or sys.platform == 'cygwin':
   3.682 +    from cygwin import Cygwin
   3.683 +
   3.684 +# local
   3.685 +import __init__ as opensecurity
   3.686 +from environment import Environment
   3.687 +
   3.688 +
   3.689 +# ------------------------------------------------------------
   3.690 +# const
   3.691 +
   3.692 +
   3.693 +"""All the URLs we know mapping to class handler"""
   3.694 +opensecurity_urls = (
   3.695 +    '/credentials',             'os_credentials',
   3.696 +    '/keyfile',                 'os_keyfile',
   3.697 +    '/log',                     'os_log',
   3.698 +    '/notification',            'os_notification',
   3.699 +    '/password',                'os_password',
   3.700 +    '/netmount',                'os_netmount',
   3.701 +    '/netumount',               'os_netumount',
   3.702 +    '/',                        'os_root'
   3.703 +)
   3.704 +
   3.705 +
   3.706 +# ------------------------------------------------------------
   3.707 +# vars
   3.708 +
   3.709 +
   3.710 +"""lock for read/write log file"""
   3.711 +log_file_lock = threading.Lock()
   3.712 +
   3.713 +"""timer for the log file bouncer"""
   3.714 +log_file_bouncer = None
   3.715 +
   3.716 +
   3.717 +"""The REST server object"""
   3.718 +server = None
   3.719 +
   3.720 +
   3.721 +# ------------------------------------------------------------
   3.722 +# code
   3.723 +
   3.724 +
   3.725 +class os_credentials:
   3.726 +
   3.727 +    """OpenSecurity '/credentials' handler.
   3.728 +    
   3.729 +    This is called on GET /credentials?text=TEXT.
   3.730 +    Ideally this should pop up a user dialog to insert his
   3.731 +    credentials based the given TEXT.
   3.732 +    """
   3.733 +    
   3.734 +    def GET(self):
   3.735 +        
   3.736 +        # pick the arguments
   3.737 +        args = web.input()
   3.738 +        
   3.739 +        # we _need_ a text
   3.740 +        if not "text" in args:
   3.741 +            raise web.badrequest('no text given')
   3.742 +        
   3.743 +        # remember remote ip
   3.744 +        remote_ip = web.ctx.environ['REMOTE_ADDR']
   3.745 +
   3.746 +        # create the process which queries the user
   3.747 +        dlg_image = os.path.join(sys.path[0], 'opensecurity_dialog.pyw')
   3.748 +        process_command = [sys.executable, dlg_image, 'credentials', args.text]
   3.749 +        process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE)        
   3.750 +        
   3.751 +        # run process result handling in seprate thread (not to block main one)
   3.752 +        bouncer = ProcessResultBouncer(process, remote_ip, '/credentials')
   3.753 +        bouncer.start()
   3.754 +         
   3.755 +        return 'user queried for credentials'
   3.756 +
   3.757 +
   3.758 +class os_keyfile:
   3.759 +
   3.760 +    """OpenSecurity '/keyfile' handler.
   3.761 +    
   3.762 +    This is called on GET /keyfile?text=TEXT.
   3.763 +    Ideally this should pop up a user dialog to insert his
   3.764 +    password along with a keyfile.
   3.765 +    """
   3.766 +    
   3.767 +    def GET(self):
   3.768 +        
   3.769 +        # pick the arguments
   3.770 +        args = web.input()
   3.771 +        
   3.772 +        # we _need_ a text
   3.773 +        if not "text" in args:
   3.774 +            raise web.badrequest('no text given')
   3.775 +            
   3.776 +        # remember remote ip
   3.777 +        remote_ip = web.ctx.environ['REMOTE_ADDR']
   3.778 +        
   3.779 +        # create the process which queries the user
   3.780 +        dlg_image = os.path.join(sys.path[0], 'opensecurity_dialog.pyw')
   3.781 +        process_command = [sys.executable, dlg_image, 'keyfile', args.text]
   3.782 +        process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE)        
   3.783 +        
   3.784 +        # run process result handling in seprate thread (not to block main one)
   3.785 +        bouncer = ProcessResultBouncer(process, remote_ip, '/keyfile')
   3.786 +        bouncer.start()
   3.787 +         
   3.788 +        return 'user queried for password and keyfile'
   3.789 +
   3.790 +
   3.791 +class os_log:
   3.792 +
   3.793 +    """OpenSecurity '/log' handler.
   3.794 +    
   3.795 +    This is called on GET or POST on the log function /log
   3.796 +    """
   3.797 +    
   3.798 +    def GET(self):
   3.799 +        
   3.800 +        # pick the arguments
   3.801 +        self.POST()
   3.802 +
   3.803 +
   3.804 +    def POST(self):
   3.805 +        
   3.806 +        # pick the arguments
   3.807 +        args = web.input()
   3.808 +        args['user'] = getpass.getuser()
   3.809 +        args['system'] = platform.node() + " " + platform.system() + " " + platform.release()
   3.810 +
   3.811 +        # add these to new data to log
   3.812 +        global log_file_lock
   3.813 +        log_file_name = os.path.join(Environment('OpenSecurity').log_path, 'vm_new.log')
   3.814 +        log_file_lock.acquire()
   3.815 +        pickle.dump(args,  open(log_file_name, 'ab'))
   3.816 +        log_file_lock.release()
   3.817 +
   3.818 +        return "Ok"
   3.819 +
   3.820 +
   3.821 +class os_notification:
   3.822 +
   3.823 +    """OpenSecurity '/notification' handler.
   3.824 +    
   3.825 +    This is called on GET /notification?msgtype=TYPE&text=TEXT.
   3.826 +    This will pop up an OpenSecurity notifcation window
   3.827 +    """
   3.828 +    
   3.829 +    def GET(self):
   3.830 +        
   3.831 +        # pick the arguments
   3.832 +        args = web.input()
   3.833 +        
   3.834 +        # we _need_ a type
   3.835 +        if not "msgtype" in args:
   3.836 +            raise web.badrequest('no msgtype given')
   3.837 +            
   3.838 +        if not args.msgtype in ['information', 'warning', 'critical']:
   3.839 +            raise web.badrequest('Unknown value for msgtype')
   3.840 +            
   3.841 +        # we _need_ a text
   3.842 +        if not "text" in args:
   3.843 +            raise web.badrequest('no text given')
   3.844 +            
   3.845 +        # invoke the user dialog as a subprocess
   3.846 +        dlg_image = os.path.join(sys.path[0], 'opensecurity_dialog.py')
   3.847 +        process_command = [sys.executable, dlg_image, 'notification-' + args.msgtype, args.text]
   3.848 +        process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE)
   3.849 +
   3.850 +        return "Ok"
   3.851 +
   3.852 +
   3.853 +class os_password:
   3.854 +
   3.855 +    """OpenSecurity '/password' handler.
   3.856 +    
   3.857 +    This is called on GET /password?text=TEXT.
   3.858 +    Ideally this should pop up a user dialog to insert his
   3.859 +    password based device name.
   3.860 +    """
   3.861 +    
   3.862 +    def GET(self):
   3.863 +        
   3.864 +        # pick the arguments
   3.865 +        args = web.input()
   3.866 +        
   3.867 +        # we _need_ a text
   3.868 +        if not "text" in args:
   3.869 +            raise web.badrequest('no text given')
   3.870 +            
   3.871 +        # remember remote ip
   3.872 +        remote_ip = web.ctx.environ['REMOTE_ADDR']
   3.873 +        
   3.874 +        # create the process which queries the user
   3.875 +        dlg_image = os.path.join(sys.path[0], 'opensecurity_dialog.pyw')
   3.876 +        process_command = [sys.executable, dlg_image, 'password', args.text]
   3.877 +        process = subprocess.Popen(process_command, shell = False, stdout = subprocess.PIPE)        
   3.878 +        
   3.879 +        # run process result handling in seprate thread (not to block main one)
   3.880 +        bouncer = ProcessResultBouncer(process, remote_ip, '/password')
   3.881 +        bouncer.start()
   3.882 +        
   3.883 +        return 'user queried for password'
   3.884 +
   3.885 +# handles netumount request                    
   3.886 +class MountNetworkDriveHandler(threading.Thread): 
   3.887 +    drive = None
   3.888 +    resource = None
   3.889 +    
   3.890 +    def __init__(self, drv, net_path):
   3.891 +        threading.Thread.__init__(self)
   3.892 +        self.drive = drv
   3.893 +        self.networkPath = net_path
   3.894 +    
   3.895 +    def run(self):
   3.896 +        #Check for drive availability
   3.897 +        if os.path.exists(self.drive):
   3.898 +            logger.error("Drive letter is already in use: " + self.drive)
   3.899 +            return 1
   3.900 +        
   3.901 +        #Check for network resource availability
   3.902 +        retry = 5
   3.903 +        while not os.path.exists(self.networkPath):
   3.904 +            time.sleep(1)
   3.905 +            if retry == 0:
   3.906 +                return 1
   3.907 +            logger.info("Path not accessible: " + self.networkPath + " retrying")
   3.908 +            retry-=1
   3.909 +    
   3.910 +        command = 'USE ' + self.drive + ' ' + self.networkPath + ' /PERSISTENT:NO'
   3.911 +    
   3.912 +        result = Cygwin.checkResult(Cygwin.execute('C:\\Windows\\system32\\NET', command))
   3.913 +        if string.find(result[1], 'successfully',) == -1:
   3.914 +            logger.error("Failed: NET " + command)
   3.915 +            return 1
   3.916 +        return 0
   3.917 +
   3.918 +class os_netmount:
   3.919 +    
   3.920 +    """OpenSecurity '/netmount' handler"""
   3.921 +    
   3.922 +    def GET(self):
   3.923 +        # pick the arguments
   3.924 +        args = web.input()
   3.925 +        
   3.926 +        # we _need_ a net_resource
   3.927 +        if not "net_resource" in args:
   3.928 +            raise web.badrequest('no net_resource given')
   3.929 +        
   3.930 +        # we _need_ a drive_letter
   3.931 +        if not "drive_letter" in args:
   3.932 +            raise web.badrequest('no drive_letter given')
   3.933 +
   3.934 +        driveHandler = MountNetworkDriveHandler(args['drive_letter'], args['net_resource'])
   3.935 +        driveHandler.start()
   3.936 +        driveHandler.join(None)
   3.937 +        return 'Ok'
   3.938 +
   3.939 +         
   3.940 +        
   3.941 +# handles netumount request                    
   3.942 +class UmountNetworkDriveHandler(threading.Thread): 
   3.943 +    drive = None
   3.944 +    running = True
   3.945 +    
   3.946 +    def __init__(self, drv):
   3.947 +        threading.Thread.__init__(self)
   3.948 +        self.drive = drv
   3.949 +
   3.950 +    def run(self):
   3.951 +        while self.running:
   3.952 +            result = Cygwin.checkResult(Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE'))
   3.953 +            mappedDrives = list()
   3.954 +            for line in result[1].splitlines():
   3.955 +                if 'USB' in line or 'Download' in line:
   3.956 +                    parts = line.split()
   3.957 +                    mappedDrives.append(parts[1])
   3.958 +            
   3.959 +            logger.info(mappedDrives)
   3.960 +            logger.info(self.drive)
   3.961 +            if self.drive not in mappedDrives:
   3.962 +                self.running = False
   3.963 +            else:
   3.964 +                command = 'USE ' + self.drive + ' /DELETE /YES' 
   3.965 +                result = Cygwin.checkResult(Cygwin.execute('C:\\Windows\\system32\\net.exe', command)) 
   3.966 +                if string.find(str(result[1]), 'successfully',) == -1:
   3.967 +                    logger.error(result[2])
   3.968 +                    continue
   3.969 +                        
   3.970 +
   3.971 +class os_netumount:
   3.972 +    
   3.973 +    """OpenSecurity '/netumount' handler"""
   3.974 +    
   3.975 +    def GET(self):
   3.976 +        # pick the arguments
   3.977 +        args = web.input()
   3.978 +        
   3.979 +        # we _need_ a drive_letter
   3.980 +        if not "drive_letter" in args:
   3.981 +            raise web.badrequest('no drive_letter given')
   3.982 +        
   3.983 +        driveHandler = UmountNetworkDriveHandler(args['drive_letter'])
   3.984 +        driveHandler.start()
   3.985 +        driveHandler.join(None)
   3.986 +        return 'Ok'
   3.987 +    
   3.988 +
   3.989 +class os_root:
   3.990 +
   3.991 +    """OpenSecurity '/' handler"""
   3.992 +    
   3.993 +    def GET(self):
   3.994 +    
   3.995 +        res = "OpenSecurity-Client RESTFul Server { \"version\": \"%s\" }" % opensecurity.__version__
   3.996 +        
   3.997 +        # add some sample links
   3.998 +        res = res + """
   3.999 +        
  3.1000 +USAGE EXAMPLES:
  3.1001 +        
  3.1002 +Request a password: 
  3.1003 +    (copy paste this into your browser's address field after the host:port)
  3.1004 +    
  3.1005 +    /password?text=Give+me+a+password+for+device+%22My+USB+Drive%22+(ID%3A+32090-AAA-X0)
  3.1006 +    
  3.1007 +    (eg.: http://127.0.0.1:8090/password?text=Give+me+a+password+for+device+%22My+USB+Drive%22+(ID%3A+32090-AAA-X0))
  3.1008 +    NOTE: check yout taskbar, the dialog window may not pop up in front of your browser window.
  3.1009 +    
  3.1010 +    
  3.1011 +Request a combination of user and password:
  3.1012 +    (copy paste this into your browser's address field after the host:port)
  3.1013 +    
  3.1014 +    /credentials?text=Tell+the+NSA+which+credentials+to+use+in+order+to+avoid+hacking+noise+on+wire.
  3.1015 +    
  3.1016 +    (eg.: http://127.0.0.1:8090/credentials?text=Tell+the+NSA+which+credentials+to+use+in+order+to+avoid+hacking+noise+on+wire.)
  3.1017 +    NOTE: check yout taskbar, the dialog window may not pop up in front of your browser window.
  3.1018 +    
  3.1019 +
  3.1020 +Request a combination of password and keyfile:
  3.1021 +    (copy paste this into your browser's address field after the host:port)
  3.1022 +    
  3.1023 +    /keyfile?text=Your%20private%20RSA%20Keyfile%3A
  3.1024 +    
  3.1025 +    (eg.: http://127.0.0.1:8090//keyfile?text=Your%20private%20RSA%20Keyfile%3A)
  3.1026 +    NOTE: check yout taskbar, the dialog window may not pop up in front of your browser window.
  3.1027 +    
  3.1028 +
  3.1029 +Start a Browser:
  3.1030 +    (copy paste this into your browser's address field after the host:port)
  3.1031 +
  3.1032 +    /application?vm=Debian+7&app=Browser
  3.1033 +
  3.1034 +    (e.g. http://127.0.0.1:8090/application?vm=Debian+7&app=Browser)
  3.1035 +        """
  3.1036 +    
  3.1037 +        return res
  3.1038 +
  3.1039 +
  3.1040 +class ProcessResultBouncer(threading.Thread):
  3.1041 +
  3.1042 +    """A class to post the result of a given process - assuming it to be in JSON - to a REST Api."""
  3.1043 +
  3.1044 +    def __init__(self, process, remote_ip, resource): 
  3.1045 +
  3.1046 +        """ctor"""
  3.1047 +
  3.1048 +        threading.Thread.__init__(self)
  3.1049 +        self._process = process
  3.1050 +        self._remote_ip = remote_ip
  3.1051 +        self._resource = resource
  3.1052 + 
  3.1053 +    
  3.1054 +    def stop(self):
  3.1055 +
  3.1056 +        """stop thread"""
  3.1057 +        self.running = False
  3.1058 +        
  3.1059 +    
  3.1060 +    def run(self):
  3.1061 +
  3.1062 +        """run the thread"""
  3.1063 +
  3.1064 +        # invoke the user dialog as a subprocess
  3.1065 +        result = self._process.communicate()[0]
  3.1066 +        if self._process.returncode != 0:
  3.1067 +            print 'user request has been aborted.'
  3.1068 +            return
  3.1069 +        
  3.1070 +        # all ok, tell send request back appropriate destination
  3.1071 +        try:
  3.1072 +            j = json.loads(result)
  3.1073 +        except:
  3.1074 +            print 'error in password parsing'
  3.1075 +            return
  3.1076 +        
  3.1077 +        # by provided a 'data' we turn this into a POST statement
  3.1078 +        url_addr = 'http://' + self._remote_ip + ':58080' + self._resource
  3.1079 +        req = urllib2.Request(url_addr, urllib.urlencode(j))
  3.1080 +        try:
  3.1081 +            res = urllib2.urlopen(req)
  3.1082 +        except:
  3.1083 +            print 'failed to contact: ' + url_addr
  3.1084 +            return 
  3.1085 +
  3.1086 +
  3.1087 +class RESTServerThread(threading.Thread):
  3.1088 +
  3.1089 +    """Thread for serving the REST API."""
  3.1090 +
  3.1091 +    def __init__(self, port): 
  3.1092 +
  3.1093 +        """ctor"""
  3.1094 +        threading.Thread.__init__(self)
  3.1095 +        self._port = port 
  3.1096 +    
  3.1097 +    def stop(self):
  3.1098 +
  3.1099 +        """stop thread"""
  3.1100 +        self.running = False
  3.1101 +        
  3.1102 +    
  3.1103 +    def run(self):
  3.1104 +
  3.1105 +        """run the thread"""
  3.1106 +        _serve(self._port)
  3.1107 +
  3.1108 +
  3.1109 +
  3.1110 +def is_already_running(port = 8090):
  3.1111 +
  3.1112 +    """check if this is started twice"""
  3.1113 +
  3.1114 +    try:
  3.1115 +        s = socket.create_connection(('127.0.0.1', port), 0.5)
  3.1116 +    except:
  3.1117 +        return False
  3.1118 +
  3.1119 +    return True
  3.1120 +
  3.1121 +
  3.1122 +def _bounce_vm_logs():
  3.1123 +
  3.1124 +    """grab all logs from the VMs and push them to the log servers"""
  3.1125 +
  3.1126 +    global log_file_lock
  3.1127 +
  3.1128 +    # pick the highest current number
  3.1129 +    cur = 0
  3.1130 +    for f in glob.iglob(os.path.join(Environment('OpenSecurity').log_path, 'vm_cur.log.*')):
  3.1131 +        try:
  3.1132 +            n = f.split('.')[-1:][0]
  3.1133 +            if cur < int(n):
  3.1134 +                cur = int(n)
  3.1135 +        except:
  3.1136 +            pass
  3.1137 +
  3.1138 +    cur = cur + 1
  3.1139 +
  3.1140 +    # first add new vm logs to our existing one: rename the log file
  3.1141 +    log_file_name_new = os.path.join(Environment('OpenSecurity').log_path, 'vm_new.log')
  3.1142 +    log_file_name_cur = os.path.join(Environment('OpenSecurity').log_path, 'vm_cur.log.' + str(cur))
  3.1143 +    log_file_lock.acquire()
  3.1144 +    try:
  3.1145 +        os.rename(log_file_name_new, log_file_name_cur)
  3.1146 +        print('new log file: ' + log_file_name_cur)
  3.1147 +    except:
  3.1148 +        pass
  3.1149 +    log_file_lock.release()
  3.1150 +
  3.1151 +    # now we have a list of next log files to dump
  3.1152 +    log_files = glob.glob(os.path.join(Environment('OpenSecurity').log_path, 'vm_cur.log.*'))
  3.1153 +    log_files.sort()
  3.1154 +    for log_file in log_files:
  3.1155 +
  3.1156 +        try:
  3.1157 +            f = open(log_file, 'rb')
  3.1158 +            while True:
  3.1159 +                l = pickle.load(f)
  3.1160 +                _push_log(l)
  3.1161 +
  3.1162 +        except EOFError:
  3.1163 +
  3.1164 +            try:
  3.1165 +                os.remove(log_file)
  3.1166 +            except:
  3.1167 +                logger.warning('tried to delete log file (pushed to EOF) "' + log_file + '" but failed')
  3.1168 +
  3.1169 +        except:
  3.1170 +            logger.warning('encountered error while pushing log file "' + log_file + '"')
  3.1171 +            break
  3.1172 +
  3.1173 +    # start bouncer again ...
  3.1174 +    global log_file_bouncer
  3.1175 +    log_file_bouncer = threading.Timer(5.0, _bounce_vm_logs)
  3.1176 +    log_file_bouncer.start()
  3.1177 +
  3.1178 +
  3.1179 +def _push_log(log):
  3.1180 +    """POST a single log to log server
  3.1181 +
  3.1182 +    @param  log     the log POST param
  3.1183 +    """
  3.1184 +
  3.1185 +    try:
  3.1186 +        key = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\OpenSecurity')
  3.1187 +        log_server_url = str(win32api.RegQueryValueEx(key, 'LogServerURL')[0])
  3.1188 +        win32api.RegCloseKey(key)
  3.1189 +    except:
  3.1190 +        logger.critical('Cannot open Registry HKEY_LOCAL_MACHINE\SOFTWARE\OpenSecurity and get LogServerURL value')
  3.1191 +        raise
  3.1192 +
  3.1193 +    # by provided a 'data' we turn this into a POST statement
  3.1194 +    d = urllib.urlencode(log)
  3.1195 +    req = urllib2.Request(log_server_url, d)
  3.1196 +    urllib2.urlopen(req)
  3.1197 +    logger.debug('pushed log to server: ' + str(log_server_url))
  3.1198 +
  3.1199 +
  3.1200 +def _serve(port):
  3.1201 +
  3.1202 +    """Start the REST server"""
  3.1203 +
  3.1204 +    global server
  3.1205 +
  3.1206 +    # start the VM-log bouncer timer
  3.1207 +    global log_file_bouncer
  3.1208 +    log_file_bouncer = threading.Timer(5.0, _bounce_vm_logs)
  3.1209 +    log_file_bouncer.start()
  3.1210 +
  3.1211 +    # trick the web.py server 
  3.1212 +    sys.argv = [__file__, str(port)]
  3.1213 +    server = web.application(opensecurity_urls, globals())
  3.1214 +    server.run()
  3.1215 +
  3.1216 +
  3.1217 +def serve(port = 8090, background = False):
  3.1218 +
  3.1219 +    """Start serving the REST Api
  3.1220 +    port ... port number to listen on
  3.1221 +    background ... cease into background (spawn thread) and return immediately"""
  3.1222 +
  3.1223 +    # start threaded or direct version
  3.1224 +    if background == True:
  3.1225 +        t = RESTServerThread(port)
  3.1226 +        t.start()
  3.1227 +    else:
  3.1228 +        _serve(port)
  3.1229 +
  3.1230 +def stop():
  3.1231 +
  3.1232 +    """Stop serving the REST Api"""
  3.1233 +
  3.1234 +    global server
  3.1235 +    if server is None:
  3.1236 +        return
  3.1237 +
  3.1238 +    global log_file_bouncer
  3.1239 +    if log_file_bouncer is not None:
  3.1240 +        log_file_bouncer.cancel()
  3.1241 +
  3.1242 +    server.stop()
  3.1243 +
  3.1244 +# start
  3.1245 +if __name__ == "__main__":
  3.1246 +    serve()
  3.1247 +
     4.1 --- a/OpenSecurity/bin/vmmanager.pyw	Tue May 20 15:10:33 2014 +0100
     4.2 +++ b/OpenSecurity/bin/vmmanager.pyw	Thu May 22 11:00:33 2014 +0200
     4.3 @@ -183,6 +183,10 @@
     4.4      # check if the device is mass storage type
     4.5      @staticmethod
     4.6      def isMassStorageDevice(device):
     4.7 +        #TODO: implement filtering for card readers (this is olivers) 
     4.8 +        #      alternatively implement handling of multiple drives on same USB client
     4.9 +        if device.vendorid == '058f' and  device.productid=='6362':
    4.10 +            return False
    4.11          keyname = 'SYSTEM\CurrentControlSet\Enum\USB' + '\VID_' + device.vendorid+'&'+'PID_'+ device.productid
    4.12          key = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, keyname)
    4.13          #subkeys = _winreg.QueryInfoKey(key)[0]
    4.14 @@ -375,7 +379,7 @@
    4.15      # stop VM
    4.16      def hibernateVM(self, vm_name):
    4.17          logger.info('Sending hibernate-disk signal to ' + vm_name)
    4.18 -        Cygwin.checkResult(Cygwin.sshExecute( '"sudo hibernate-disk&"', VMManager.getHostOnlyIP(vm_name), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + vm_name + '/dvm_key', wait_return=False))
    4.19 +        Cygwin.checkResult(Cygwin.sshBackgroundExecute( '"sudo hibernate-disk"', VMManager.getHostOnlyIP(vm_name), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + vm_name + '/dvm_key', wait_return=False))
    4.20              
    4.21      # poweroff VM
    4.22      def poweroffVM(self, vm_name):
    4.23 @@ -481,19 +485,14 @@
    4.24          ip = ip[:ip.rindex('.')]
    4.25          drives = dict()    
    4.26          result = Cygwin.checkResult(Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE'))
    4.27 +
    4.28 +        #logger.info( result[1] )
    4.29          for line in result[1].splitlines():
    4.30              if ip in line:
    4.31                  parts = line.split()
    4.32                  drives[parts[1]] = parts[2]
    4.33 +
    4.34          return drives
    4.35 -            
    4.36 -    def genNetworkDrive(self):
    4.37 -        network_drives = self.getNetworkDrives()
    4.38 -        logical_drives = VMManager.getLogicalDrives()
    4.39 -        drives = list(map(chr, range(68, 91)))  
    4.40 -        for drive in drives:
    4.41 -            if drive+':' not in network_drives and drive not in logical_drives:
    4.42 -                return drive+':'
    4.43  
    4.44      def getNetworkDrive(self, vm_name):
    4.45          ip = self.getHostOnlyIP(vm_name)
    4.46 @@ -502,6 +501,16 @@
    4.47              if line != None and ip in line:
    4.48                  parts = line.split()
    4.49                  return parts[1]
    4.50 +    
    4.51 +    def genNetworkDrive(self):
    4.52 +        network_drives = self.getNetworkDrives()
    4.53 +        logger.info("Used network drive letters: "+ str(network_drives.keys()).strip('[]') ) 
    4.54 +        logical_drives = VMManager.getLogicalDrives()
    4.55 +        logger.info("Used logical drive letters: "+ str(logical_drives).strip('[]') )
    4.56 +        drives = list(map(chr, range(68, 91)))  
    4.57 +        for drive in drives:
    4.58 +            if drive+':' not in network_drives and drive not in logical_drives:
    4.59 +                return drive+':'
    4.60              
    4.61      @staticmethod
    4.62      def getLogicalDrives():
    4.63 @@ -548,8 +557,15 @@
    4.64          return user_name
    4.65          
    4.66      def getUserSID(self, user_name):
    4.67 -        account_name = win32security.LookupAccountName(None, user_name)
    4.68 +        domain, user = user_name.split("\\")
    4.69 +        account_name = win32security.LookupAccountName(domain, user)
    4.70 +        if account_name == None:
    4.71 +            logger.error("Failed lookup account name for user " + user_name)
    4.72 +            return None
    4.73          sid = win32security.ConvertSidToStringSid(account_name[0])
    4.74 +        if sid == None:
    4.75 +            logger.error("Failed converting SID for account " + account_name[0])
    4.76 +            return None
    4.77          return sid
    4.78          
    4.79      def getAppDataDir(self, sid):    
    4.80 @@ -643,10 +659,17 @@
    4.81                  self.vmm.startVM(self.vm_name)
    4.82                  self.ip_addr = self.vmm.waitStartup(self.vm_name)
    4.83                  if self.ip_addr == None:
    4.84 +                    logger.error("Failed to get ip address")
    4.85                      continue
    4.86 +                else:
    4.87 +                    logger.info("Got IP address for " + self.vm_name + ' ' + self.ip_addr)
    4.88 +                
    4.89                  self.drive = self.vmm.genNetworkDrive()
    4.90                  if self.drive == None:
    4.91 +                    logger.error("Failed to assign Network drive letter")
    4.92                      continue
    4.93 +                else:
    4.94 +                    logger.info("Assigned drive " + self.drive + " to " + self.vm_name)
    4.95                  
    4.96                  try:
    4.97                      net_resource = '\\\\' + self.ip_addr + '\\Download'
    4.98 @@ -655,14 +678,29 @@
    4.99                      logger.error("Network drive connect failed. OpenSecurity Tray client not running.")
   4.100                      self.drive = None
   4.101                      continue
   4.102 -                        
   4.103 -                
   4.104 -                self.started.set()
   4.105                  
   4.106                  user = self.vmm.getActiveUserName()
   4.107 +                if user == None:
   4.108 +                    logger.error("Cannot get active user name")
   4.109 +                    continue
   4.110 +                else:
   4.111 +                    logger.info('Got active user name ' + user)
   4.112                  sid = self.vmm.getUserSID(user)
   4.113 +                if sid == None:
   4.114 +                    logger.error("Cannot get SID for active user")
   4.115 +                    continue
   4.116 +                else:
   4.117 +                    logger.info("Got active user SID " + sid + " for user " + user)
   4.118 +                    
   4.119                  path = self.vmm.getAppDataDir(sid)
   4.120 +                if path == None:
   4.121 +                    logger.error("Cannot get AppDataDir for active user")
   4.122 +                    continue
   4.123 +                else:
   4.124 +                    logger.info("Got AppData dir for user " + user + ': ' + path)
   4.125 +                
   4.126                  self.appDataDir = Cygwin.cygPath(path)
   4.127 +                logger.info("Restoring browser settings in AppData dir " + self.appDataDir)
   4.128                  # create OpenSecurity settings dir on local machine user home /AppData/Roaming 
   4.129                  Cygwin.checkResult(Cygwin.bashExecute('/usr/bin/mkdir -p \\\"' + self.appDataDir + '/OpenSecurity\\\"'))
   4.130                  # create chromium settings dir on local machine if not existing
   4.131 @@ -671,6 +709,8 @@
   4.132                  Cygwin.checkResult(Cygwin.sshExecute('"mkdir -p \\\"/home/osecuser/.config\\\""', self.ip_addr, 'osecuser', Cygwin.cygPath(self.vmm.getMachineFolder()) + '/' + self.vm_name + '/dvm_key'))
   4.133                  #restore settings on vm
   4.134                  self.vmm.restoreFile(self.appDataDir + '/OpenSecurity/chromium', '/home/osecuser/.config/')
   4.135 +                self.started.set()
   4.136 +                logger.error("Browsing SDVM running.")
   4.137                  self.restart.wait()
   4.138              except:
   4.139                  logger.error("BrowsingHandler failed. Cleaning up")