diff --git a/contents/nb_popen.py b/contents/nb_popen.py new file mode 100644 index 0000000..13f3eb3 --- /dev/null +++ b/contents/nb_popen.py @@ -0,0 +1,234 @@ +# -*- coding: utf-8 -*- +''' + Non blocking subprocess Popen. + + This functionality has been adapted to work on windows following the recipe + found on: http://code.activestate.com/recipes/440554/ +''' +from __future__ import absolute_import + +# Import python libs +import os +import sys +import time +import errno +import select +import logging +import tempfile +import subprocess + +mswindows = (sys.platform == "win32") + +try: + from win32file import ReadFile, WriteFile + from win32pipe import PeekNamedPipe + import msvcrt +except ImportError: + import fcntl + +log = logging.getLogger(__name__) + + +class NonBlockingPopen(subprocess.Popen): + + # _stdin_logger_name_ = 'nb_popen.STDIN.PID-{pid}' + _stdout_logger_name_ = 'nb_popen.STDOUT.PID-{pid}' + _stderr_logger_name_ = 'nb_popen.STDERR.PID-{pid}' + + def __init__(self, *args, **kwargs): + self.stream_stds = kwargs.pop('stream_stds', False) + + # Half a megabyte in memory is more than enough to start writing to + # a temporary file. + self.max_size_in_mem = kwargs.pop('max_size_in_mem', 512000) + + # Let's configure the std{in, out,err} logging handler names + # self._stdin_logger_name_ = kwargs.pop( + # 'stdin_logger_name', self._stdin_logger_name_ + # ) + self._stdout_logger_name_ = kwargs.pop( + 'stdout_logger_name', self._stdout_logger_name_ + ) + self._stderr_logger_name_ = kwargs.pop( + 'stderr_logger_name', self._stderr_logger_name_ + ) + + logging_command = kwargs.pop('logging_command', None) + stderr = kwargs.get('stderr', None) + + super(NonBlockingPopen, self).__init__(*args, **kwargs) + + # self._stdin_logger = logging.getLogger( + # self._stdin_logger_name_.format(pid=self.pid) + # ) + + self.stdout_buff = tempfile.SpooledTemporaryFile(self.max_size_in_mem) + self._stdout_logger = logging.getLogger( + self._stdout_logger_name_.format(pid=self.pid) + ) + + if stderr is subprocess.STDOUT: + self.stderr_buff = self.stdout_buff + self._stderr_logger = self._stdout_logger + else: + self.stderr_buff = tempfile.SpooledTemporaryFile( + self.max_size_in_mem + ) + self._stderr_logger = logging.getLogger( + self._stderr_logger_name_.format(pid=self.pid) + ) + + self._stderr_logger = logging.getLogger( + self._stderr_logger_name_.format(pid=self.pid) + ) + + log.info( + 'Running command under pid %s: \'%s\'', + self.pid, + args if logging_command is None else logging_command + ) + + def recv(self, maxsize=None): + return self._recv('stdout', maxsize) + + def recv_err(self, maxsize=None): + return self._recv('stderr', maxsize) + + def send_recv(self, input='', maxsize=None): + return self.send(input), self.recv(maxsize), self.recv_err(maxsize) + + def get_conn_maxsize(self, which, maxsize): + if maxsize is None: + maxsize = 1024 + elif maxsize < 1: + maxsize = 1 + return getattr(self, which), maxsize + + def _close(self, which): + getattr(self, which).close() + setattr(self, which, None) + + if mswindows: + def send(self, input): + if not self.stdin: + return None + + try: + x = msvcrt.get_osfhandle(self.stdin.fileno()) + (errCode, written) = WriteFile(x, input) + # self._stdin_logger.debug(input.rstrip()) + except ValueError: + return self._close('stdin') + except (subprocess.pywintypes.error, Exception) as why: + if why.args[0] in (109, errno.ESHUTDOWN): + return self._close('stdin') + raise + + return written + + def _recv(self, which, maxsize): + conn, maxsize = self.get_conn_maxsize(which, maxsize) + if conn is None: + return None + + try: + x = msvcrt.get_osfhandle(conn.fileno()) + (read, nAvail, nMessage) = PeekNamedPipe(x, 0) + if maxsize < nAvail: + nAvail = maxsize + if nAvail > 0: + (errCode, read) = ReadFile(x, nAvail, None) + except ValueError: + return self._close(which) + except (subprocess.pywintypes.error, Exception) as why: + if why.args[0] in (109, errno.ESHUTDOWN): + return self._close(which) + raise + + getattr(self, '{0}_buff'.format(which)).write(read) + getattr(self, '_{0}_logger'.format(which)).debug(read.rstrip()) + if self.stream_stds: + getattr(sys, which).write(read) + + if self.universal_newlines: + read = self._translate_newlines(read) + return read + + else: + + def send(self, input): + if not self.stdin: + return None + + if not select.select([], [self.stdin], [], 0)[1]: + return 0 + + try: + written = os.write(self.stdin.fileno(), input) + # self._stdin_logger.debug(input.rstrip()) + except OSError as why: + if why.args[0] == errno.EPIPE: # broken pipe + return self._close('stdin') + raise + + return written + + def _recv(self, which, maxsize): + conn, maxsize = self.get_conn_maxsize(which, maxsize) + if conn is None: + return None + + flags = fcntl.fcntl(conn, fcntl.F_GETFL) + if not conn.closed: + fcntl.fcntl(conn, fcntl.F_SETFL, flags | os.O_NONBLOCK) + + try: + if not select.select([conn], [], [], 0)[0]: + return '' + + buff = conn.read(maxsize) + if not buff: + return self._close(which) + + if self.universal_newlines: + buff = self._translate_newlines(buff) + + getattr(self, '{0}_buff'.format(which)).write(buff) + getattr(self, '_{0}_logger'.format(which)).debug(buff.rstrip()) + if self.stream_stds: + getattr(sys, which).write(buff) + + return buff + finally: + if not conn.closed: + fcntl.fcntl(conn, fcntl.F_SETFL, flags) + + def poll_and_read_until_finish(self, interval=0.01): + silent_iterations = 0 + while self.poll() is None: + if self.stdout is not None: + silent_iterations = 0 + self.recv() + + if self.stderr is not None: + silent_iterations = 0 + self.recv_err() + + silent_iterations += 1 + + if silent_iterations > 100: + silent_iterations = 0 + (stdoutdata, stderrdata) = self.communicate() + if stdoutdata: + log.debug(stdoutdata) + if stderrdata: + log.error(stderrdata) + time.sleep(interval) + + def communicate(self, input=None): + super(NonBlockingPopen, self).communicate(input) + self.stdout_buff.flush() + self.stdout_buff.seek(0) + self.stderr_buff.flush() + self.stderr_buff.seek(0) + return self.stdout_buff.read(), self.stderr_buff.read() diff --git a/contents/winsmbcp.py b/contents/winsmbcp.py new file mode 100644 index 0000000..da1fabc --- /dev/null +++ b/contents/winsmbcp.py @@ -0,0 +1,102 @@ +#!/usr/bin/python + +import os +import sys + +try: + import impacket.smbconnection + from impacket.smbconnection import SessionError as smbSessionError + from impacket.smb3 import SessionError as smb3SessionError + HAS_IMPACKET = True +except ImportError: + HAS_IMPACKET = False + + +def get_conn(host=None, username=None, password=None): + ''' + Get an SMB connection + ''' + if not HAS_IMPACKET: + return False + + conn = impacket.smbconnection.SMBConnection( + remoteName='*SMBSERVER', + remoteHost=host, ) + conn.login(user=username, password=password) + return conn + + +def mkdirs(path, + share='C$', + conn=None, + host=None, + username=None, + password=None): + ''' + Recursively create a directory structure on an SMB share + Paths should be passed in with forward-slash delimiters, and should not + start with a forward-slash. + ''' + if conn is None: + conn = get_conn(host, username, password) + + if conn is False: + return False + + with open('/tmp/winsmbcp.log', 'a+') as fp_: + fp_.write('path:{0}\n'.format(path)) + + comps = path.split('/') + pos = 1 + for comp in comps: + cwd = '/'.join(comps[0:pos]) + with open('/tmp/winsmbcp.log', 'a+') as fp_: + fp_.write('cwd:{0}\n'.format(cwd)) + try: + # print 'list path:{0}'.format(cwd) + conn.listPath(share, cwd) + except (smbSessionError, smb3SessionError) as exc: + # print 'create directory {0}\{1}'.format(share, cwd) + conn.createDirectory(share, cwd) + pos += 1 + + +def put_file(src_file, dest_dir, hostname, username, password): + + src_comps = src_file.split('/') + file_name = src_comps[-1] + + dest_dir = dest_dir.replace('\\', '/') + dest_comps = dest_dir.split('/') + share = dest_comps[0].replace(':', '$') + suffix = dest_comps[-1][-3:] + if dest_comps[-1] != file_name and suffix not in ['ps1', 'bat']: + dest_comps.append(file_name) + dest_file = '/'.join(dest_comps[1:]) + mid_path = '/'.join(dest_comps[1:-1]) + + # smb_conn = salt.utils.smb.get_conn(hostname, username, password) + smb_conn = get_conn(hostname, username, password) + mkdirs(mid_path, share, smb_conn) + + # with salt.utils.fopen(src_file, 'rb') as inst_fh: + with open(src_file, 'rb') as inst_fh: + smb_conn.putFile(share, '{0}'.format(dest_file), inst_fh.read) + + +hostname = os.getenv('RD_NODE_HOSTNAME') +username = os.getenv('RD_NODE_USERNAME') +password = os.getenv('RD_CONFIG_PASS') + +src_file = sys.argv[1] +dest_dir = sys.argv[2] + +with open('/tmp/winsmbcp.log', 'a+') as fp_: + fp_.write('src_file:{0}\n dest_dir:{1}\n'.format(src_file, dest_dir)) + +put_file(src_file, dest_dir, hostname, username, password) + + +import os + +os.path.join() \ No newline at end of file diff --git a/contents/winsmbexe.py b/contents/winsmbexe.py new file mode 100644 index 0000000..cb93cd2 --- /dev/null +++ b/contents/winsmbexe.py @@ -0,0 +1,89 @@ +#!/usr/bin/python + +import os +import logging +import subprocess + +from nb_popen import NonBlockingPopen + +try: + import impacket.smbconnection + from impacket.smbconnection import SessionError as smbSessionError + from impacket.smb3 import SessionError as smb3SessionError + HAS_IMPACKET = True +except ImportError: + HAS_IMPACKET = False + +log = logging.getLogger(__name__) + + +def get_conn(host=None, username=None, password=None): + ''' + Get an SMB connection + ''' + if not HAS_IMPACKET: + return False + + conn = impacket.smbconnection.SMBConnection( + remoteName='*SMBSERVER', + remoteHost=host, ) + conn.login(user=username, password=password) + return conn + + +def win_cmd(exe_command, **kwargs): + ''' + Wrapper for commands to be run against Windows boxes + ''' + logging_command = kwargs.get('logging_command', None) + + try: + proc = NonBlockingPopen( + exe_command, + shell=True, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + stream_stds=kwargs.get('display_ssh_output', True), + logging_command=logging_command, ) + + if logging_command is None: + log.info('Executing command(PID %s): \'%s\'', proc.pid, exe_command) + else: + log.info('Executing command(PID %s): \'%s\'', proc.pid, + logging_command) + + proc.poll_and_read_until_finish() + proc.communicate() + return proc.returncode + except Exception as err: + log.info( + 'Failed to execute command \'{0}\': {1}\n'.format(logging_command, + err), + exc_info=True) + # Signal an error + return 1 + + +def execute_cmd(exe_cmd, host, user, passwd): + creds = "-U '{0}%{1}' //{2}".format(user, passwd, host) + logging_creds = "-U '{0}%XXX-REDACTED-XXX' //{1}".format(user, host) + cmd = 'winexe {0} "{1}"'.format(creds, exe_cmd) + logging_cmd = 'winexe {0} "{1}"'.format(logging_creds, exe_cmd) + return win_cmd(cmd, logging_command=logging_cmd) + + +hostname = os.getenv('RD_NODE_HOSTNAME') +username = os.getenv('RD_NODE_USERNAME') +password = os.getenv('RD_CONFIG_PASS') +command = os.getenv('RD_EXEC_COMMAND') + +if '.ps1' in command: + command = "powershell {0}".format(command) + +with open('/tmp/winsmbexe.log', 'a+') as fp_: + fp_.write('command:{0}\n'.format(command)) + +ret = execute_cmd(command, hostname, username, password) +with open('/tmp/winsmbexe.log', 'a+') as fp_: + fp_.write('ret:{0}\n'.format(ret)) +exit(ret)