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")