Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/net/winrm/stdin_shell.rb
Views: 11779
require 'winrm'1require 'winrm/wsmv/write_stdin'2require 'net/winrm/ctrl_c'3require 'net/winrm/receive_response_reader'45module Net6module MsfWinRM7# WinRM shell to use stdin, rather than sending isolated commands8class StdinShell < WinRM::Shells::Cmd9# We create our own empty finalizers because the built-in one triggers a10# request using the Rex HTTP client, which segfaults; possibly because it11# creates a thread, or something else that is not allowed in a finalizer.12# In this situation (observed only when the user quits MSF with active sessions),13# we'll just let the shell continue.14def remove_finalizer; end1516def add_finalizer; end1718def send_command(command, arguments = [])19open unless shell_id20super(command, arguments)21end2223# Runs a shell command synchronously, and returns the output24def shell_command_synchronous(command, args, timeout)25start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)26command_id = send_command(command, args)27buffer = []28begin29while (Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) - start_time) < (timeout * 1000)30read_stdout(command_id) do |stdout, stderr|31buffer << stdout if stdout32buffer << stderr if stderr33end34end35rescue EOFError36# Shell terminated of its own accord37ensure38cleanup_command(command_id)39end40buffer.join('')41end4243# Runs the specified command with optional arguments44# @param block [&block] The optional callback for any realtime output45# @yieldparam [string] standard out response text46# @yieldparam [string] standard error response text47# @yieldreturn [WinRM::Output] The command output48def read_stdout(command_id, &block)49open unless shell_id50begin51response_reader.read_output(command_output_message(shell_id, command_id), &block)52rescue WinRM::WinRMWSManFault => e53# If no output is available before the wsman:OperationTimeout expires,54# the server MUST return a WSManFault with the Code attribute equal to55# 2150858793. When the client receives this fault, it SHOULD issue56# another Receive request.57# http://msdn.microsoft.com/en-us/library/cc251676.aspx58if e.fault_code == '2150858793'59yield nil, nil60else61raise62end63end64end6566def send_ctrl_c(command_id)67ctrl_c_msg = CtrlC.new(68connection_opts,69shell_uri: shell_uri,70shell_id: shell_id,71command_id: command_id72)73transport.send_request(ctrl_c_msg.build)74end7576def send_stdin(input, command_id)77open unless shell_id7879stdin_msg = WinRM::WSMV::WriteStdin.new(80connection_opts,81shell_uri: shell_uri,82shell_id: shell_id,83command_id: command_id,84stdin: input85)86result = transport.send_request(stdin_msg.build)87result88rescue WinRM::WinRMWSManFault => e89raise unless [ERROR_OPERATION_ABORTED, SHELL_NOT_FOUND].include?(e.fault_code)90rescue WinRM::WinRMHTTPTransportError => e91# dont let the cleanup raise so we dont lose any errors from the command92logger.info("[WinRM] #{e.status_code} returned in cleanup with error: #{e.message}")93end9495def response_reader96@response_reader ||= ReceiveResponseReader.new(transport, logger)97end9899def open_shell100msg = WinRM::WSMV::CreateShell.new(connection_opts, shell_opts)101resp_doc = transport.send_request(msg.build)102match = REXML::XPath.first(resp_doc, '//rsp:Owner')103self.owner = match.text if match104REXML::XPath.first(resp_doc, "//*[@Name='ShellId']").text105end106107attr_accessor :owner108109end110end111end112113114