OpenSecurity/bin/cygwin.py
author BarthaM@N3SIM1218.D03.arc.local
Fri, 29 Aug 2014 10:56:26 +0100
changeset 219 9480e5ba1a82
parent 218 327f282364b9
child 240 d7ef04254e9c
permissions -rwxr-xr-x
Improoved the update functionality:
- Additional validation of template existance
- Faster termination of worker threads
- Forced template folder cleanup
- etc.
     1 #!/bin/env python
     2 # -*- coding: utf-8 -*-
     3 
     4 # ------------------------------------------------------------
     5 # cygwin command
     6 # 
     7 # executes a cygwin command inside the opensecurity project
     8 #
     9 # Autor: Mihai Bartha, <mihai.bartha@ait.ac.at>
    10 #        Oliver Maurhart, <oliver.maurhart@ait.ac.at>
    11 #
    12 # Copyright (C) 2013 AIT Austrian Institute of Technology
    13 # AIT Austrian Institute of Technology GmbH
    14 # Donau-City-Strasse 1 | 1220 Vienna | Austria
    15 # http://www.ait.ac.at
    16 #
    17 # This program is free software; you can redistribute it and/or
    18 # modify it under the terms of the GNU General Public License
    19 # as published by the Free Software Foundation version 2.
    20 # 
    21 # This program is distributed in the hope that it will be useful,
    22 # but WITHOUT ANY WARRANTY; without even the implied warranty of
    23 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    24 # GNU General Public License for more details.
    25 # 
    26 # You should have received a copy of the GNU General Public License
    27 # along with this program; if not, write to the Free Software
    28 # Foundation, Inc., 51 Franklin Street, Fifth Floor, 
    29 # Boston, MA  02110-1301, USA.
    30 # ------------------------------------------------------------
    31 
    32 
    33 # ------------------------------------------------------------
    34 # imports
    35 
    36 import os
    37 import subprocess
    38 import sys
    39 import _winreg
    40 from subprocess import Popen, PIPE, STARTUPINFO, _subprocess
    41 import threading
    42 
    43 # local
    44 from environment import Environment
    45 from opensecurity_util import logger, setupLogger, OpenSecurityException
    46 import time
    47 
    48 
    49 # ------------------------------------------------------------
    50 # code
    51 
    52 def once(theClass):
    53     """get the path to our local cygwin installment"""
    54     home_drive = os.path.expandvars("%HOMEDRIVE%") + os.sep
    55     e = Environment('OpenSecurity')
    56     path_hint = [ 
    57         os.path.abspath(os.path.join(e.prefix_path, 'cygwin')), 
    58         os.path.abspath(os.path.join(e.prefix_path, 'cygwin64')), 
    59         os.path.abspath(os.path.join(home_drive, 'cygwin')),
    60         os.path.abspath(os.path.join(home_drive, 'cygwin64'))
    61     ]
    62     path_valid = [ p for p in path_hint if os.path.exists(p) ]
    63     theClass.cygwin_root = path_valid[0]
    64     theClass.cygwin_bin = os.path.join(theClass.cygwin_root, 'bin') + os.path.sep
    65     theClass.cygwin_bash = os.path.join(theClass.cygwin_bin, 'bash.exe')
    66     theClass.cygwin_ssh = os.path.join(theClass.cygwin_bin, 'ssh.exe')
    67     theClass.cygwin_scp = os.path.join(theClass.cygwin_bin, 'scp.exe')
    68     theClass.cygwin_x11 = os.path.join(theClass.cygwin_bin, 'XWin.exe')
    69     theClass.win_cmd = os.environ.get("COMSPEC", "cmd.exe") 
    70     """get the path to the VirtualBox installation on this system"""
    71     theClass.vbox_root = theClass.getRegEntry('SOFTWARE\Oracle\VirtualBox', 'InstallDir')[0]  
    72     theClass.vbox_man = os.path.join(theClass.vbox_root, 'VBoxManage.exe')
    73     #theClass.user_home = os.path.expanduser("~")
    74     theClass.user_home = os.environ['APPDATA']#os.path.expandvars("%APPDATA%")
    75     theClass.allow_exec = True 
    76     return theClass
    77 
    78             
    79 @once
    80 class Cygwin(object):
    81     cygwin_root = ''
    82     cygwin_bin = ''
    83     cygwin_bash = ''
    84     cygwin_ssh = ''
    85     cygwin_x11 = ''
    86     cygwin_scp = ''
    87     vbox_root = ''
    88     vbox_man = ''
    89     win_cmd = ''
    90     user_home = ''
    91     allow_exec = True 
    92     """Some nifty methods working with Cygwin"""
    93     
    94     def __call__(self, command, arguments, wait_return=True, window = False):
    95         """make an instance of this object act as a function"""
    96         return self.execute(command, arguments, wait_return, window)
    97 
    98     @staticmethod
    99     def getRegEntry(key, value):
   100         try:
   101             k = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, key)
   102             value = _winreg.QueryValueEx(k, value)
   103             _winreg.CloseKey(k)
   104             return value
   105         except:
   106             pass
   107     
   108             
   109     @staticmethod
   110     def root():
   111         return Cygwin.cygwin_root
   112 
   113     @staticmethod
   114     def bin():
   115         return Cygwin.cygwin_bin
   116     
   117     @staticmethod
   118     def bash():
   119         return Cygwin.cygwin_bash
   120     
   121     @staticmethod    
   122     def ssh():
   123         return Cygwin.cygwin_ssh
   124     
   125     @staticmethod    
   126     def scp():
   127         return Cygwin.cygwin_scp
   128 
   129     @staticmethod    
   130     def x11():
   131         return Cygwin.cygwin_x11
   132     
   133     @staticmethod
   134     def vboxman():
   135         return Cygwin.vbox_man
   136     
   137     @staticmethod
   138     def cmd():
   139         return Cygwin.win_cmd
   140     
   141     @staticmethod
   142     def home():
   143         return Cygwin.user_home
   144     
   145     @staticmethod
   146     def allowExec():
   147         Cygwin.allow_exec = True
   148     
   149     @staticmethod
   150     def denyExec():
   151         Cygwin.allow_exec = False
   152     
   153     executeLock = threading.Lock()
   154     #executes command on host system
   155     @staticmethod
   156     def execute(program, arguments, wait_return=True, window = False, stdin = PIPE, stdout = PIPE, stderr = PIPE):
   157         if not Cygwin.allow_exec:
   158             logger.error('Execution cancelled by system (shutting down).')
   159             raise OpenSecurityException('Execution cancelled by system (shutting down).')
   160             
   161         _startupinfo = STARTUPINFO()
   162         if not window:
   163             _startupinfo.dwFlags |= _subprocess.STARTF_USESHOWWINDOW
   164             _startupinfo.wShowWindow = _subprocess.SW_HIDE
   165             #logger.debug('trying to launch: ' + program + ' ' + ''.join(arguments))
   166         
   167         result, res_stdout, res_stderr = None, None, None
   168         try:
   169             # quote the executable otherwise we run into troubles
   170             # when the path contains spaces and additional arguments
   171             # are presented as well.
   172             # special: invoking bash as login shell here with
   173             # an unquoted command does not execute /etc/profile
   174             args = '"' + program + '" ' + arguments
   175             logger.debug('Launching: ' + program + ' ' + ''.join(arguments))
   176             process = Popen(args, startupinfo = _startupinfo, stdin = stdin, stdout = stdout, stderr = stderr, shell = False)
   177             if not wait_return:
   178                 return [0, 'working in background', '']
   179             
   180             res_stdout, res_stderr = process.communicate()
   181             result = process.returncode
   182             logger.debug('Finished: ' + program + ' ' + ''.join(arguments))
   183 
   184         except Exception as ex:
   185             res_stderr = ''.join(str(ex.args))
   186             result = 1 
   187     
   188         if result != 0:
   189             logger.error('Command failed:' + ''.join(res_stderr))
   190             raise OpenSecurityException('Command failed:' + ''.join(res_stderr))
   191         
   192         return result, res_stdout, res_stderr
   193     
   194     @staticmethod
   195     def vboxExecute(command, wait_return=True, window = False, bash_opts='', try_count = 3):
   196         retry = 0
   197         result = None
   198         while retry < try_count:
   199             if Cygwin.executeLock.acquire(True):
   200                 try:
   201                     result = Cygwin.execute(Cygwin.vbox_man, command, wait_return, window)
   202                 except Exception as ex:
   203                     Cygwin.executeLock.release()
   204                     if (retry+1) == try_count:
   205                         raise ex
   206                 else:
   207                     Cygwin.executeLock.release()
   208                     return result
   209             retry+=1
   210         raise OpenSecurityException('Command max retry reached: ' + ''.join(command))
   211 
   212 
   213     @staticmethod
   214     def bashExecute(command, wait_return=True, window = False, bash_opts='', stdin = PIPE, stdout = PIPE, stderr = PIPE):
   215         # for some reason, the '-l' is ignored when started via python
   216         # so the same behavior is triggered by calling /etc/profile 
   217         # directly
   218         command = bash_opts + ' -l -c "'  + command + '"'
   219         return Cygwin.execute(Cygwin.cygwin_bash, command, wait_return, window, stdin = stdin, stdout = stdout, stderr = stderr)
   220     
   221     @staticmethod
   222     def cmdExecute(command, wait_return=True, window = False):
   223         command = ' /c ' + command 
   224         return Cygwin.execute(Cygwin.win_cmd, command, wait_return, window)
   225 
   226     # executes command over ssh on guest vm
   227     @staticmethod
   228     def sshExecute(command, address, user_name, certificate, wait_return=True, window = False):
   229         if command == None or address == None or user_name == None or certificate == None:
   230             raise OpenSecurityException('Invalid parameter value')
   231         command = ' -v -o StrictHostKeyChecking=no -i "' + certificate + '" ' + user_name + '@' + address + ' ' + command        
   232         return Cygwin.execute(Cygwin.cygwin_ssh, command, wait_return, window)
   233 
   234     # executes command over ssh on guest vm
   235     @staticmethod
   236     def sshBackgroundExecute(command, address, user_name, certificate, wait_return=True, window = False):
   237         command = ' -f -v -o StrictHostKeyChecking=no -i "' + certificate + '" ' + user_name + '@' + address + ' ' + command        
   238         return Cygwin.execute(Cygwin.cygwin_ssh, command, wait_return, window)
   239     
   240     #machineFolder + '/' + vm_name + '/dvm_key
   241     #address = self.getHostOnlyIP(vm_name)
   242     #machineFolder = self.getDefaultMachineFolder()
   243     #machineFolder = Cygwin.cygwinPath(machineFolder)
   244     
   245     # executes command over ssh on guest vm with X forwarding
   246     @staticmethod
   247     def sshExecuteX11(command, address, user_name, certificate, wait_return=True):
   248         return Cygwin.bashExecute('DISPLAY=:0.0 ssh -Y -o StrictHostKeyChecking=no -i \\\"' + certificate +'\\\" ' + user_name + '@' + address + ' ' + command + '')
   249 
   250     @staticmethod
   251     def is_X11_running():
   252         """check if we can connect to a X11 running instance"""
   253         p = Cygwin.bashExecute('xset -display :0 q', wait_return = True, window = False) 
   254         return p[0] == 0
   255         
   256     @staticmethod
   257     def start_X11():
   258         """start X11 in the background (if not already running) on DISPLAY=:0
   259         
   260         If there is already a X11 running then exit silently, calling this
   261         method as often as needed.
   262         """
   263         Popen('"' + Cygwin.cygwin_x11 + '" :0 -multiwindow -resize -silent-dup-error')
   264         return (0, None, None)
   265     
   266     @staticmethod    
   267     def cygPath(path):
   268         cmd = 'cygpath -u \'' + path + '\''
   269         return Cygwin.bashExecute(cmd)[1].rstrip('\n')
   270     
   271 # start
   272 import os
   273 import win32api
   274 import win32con
   275 import win32security
   276 
   277 if __name__ == "__main__":
   278     logger = setupLogger('Cygwin')
   279     c = Cygwin()
   280     logger.info(c.root())
   281     logger.info(c.bin())
   282     logger.info(c.bash())
   283     logger.info(c.ssh())
   284     logger.info(c.x11())
   285     logger.info(c.home())   
   286     
   287     #PSEXEC -i -s -d CMD
   288     #tasklist /v /fo list /fi "IMAGENAME eq explorer.exe"
   289     
   290     #runner = XRunner()
   291     #runner.start()
   292     
   293     #Cygwin.start_X11()
   294             
   295     #time.sleep(500)
   296     
   297     #Cygwin.start_X11()
   298     #print (Cygwin.is_X11_running())
   299     #print (Cygwin.is_X11_running())
   300     #new_sdvm = 'SecurityDVM0'
   301     #new_ip = Cygwin.vboxExecute('guestproperty get ' + new_sdvm + ' /VirtualBox/GuestInfo/Net/0/V4/IP')[1]
   302     #new_ip = new_ip[new_ip.index(':')+1:].strip()
   303     #new_ip = '+'
   304     #result = Cygwin.bashExecute('DISPLAY=:0.0 xhost '+new_ip)
   305     #browser = '/usr/bin/midori '
   306     #print(Cygwin.sshExecuteX11(browser, new_ip, 'osecuser', '/cygdrive/c/Users/BarthaM/VirtualBox VMs' + '/' + new_sdvm + '/dvm_key'))
   307             
   308     #print(Cygwin.bashExecute('echo $PATH')[1])
   309     #print(Cygwin.cygPath('C:'))
   310     #print('C:\\Program Files\\OpenSecurity: ' + c.cygPath('C:\\Program Files\\OpenSecurity'))
   311     
   312     sys.exit(0)
   313