Skip to content

Commit

Permalink
Merge pull request #271 from rustyscottweber/stdin_development
Browse files Browse the repository at this point in the history
Add a function to send input to a running process.
  • Loading branch information
badcure committed Aug 23, 2019
2 parents fe59460 + ccc8cff commit 946c7c1
Show file tree
Hide file tree
Showing 3 changed files with 237 additions and 0 deletions.
33 changes: 33 additions & 0 deletions winrm/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,39 @@ def cleanup_command(self, shell_id, command_id):
# TODO change assert into user-friendly exception
assert uuid.UUID(relates_to.replace('uuid:', '')) == message_id

def send_command_input(self, shell_id, command_id, stdin_input, end=False):
"""
Send input to the given shell and command.
@param string shell_id: The shell id on the remote machine.
See #open_shell
@param string command_id: The command id on the remote machine.
See #run_command
@param string stdin_input: The input unicode string or byte string to be sent.
@param bool end: Boolean value which will close the stdin stream. If end=True then the stdin pipe to the
remotely running process will be closed causing the next read by the remote process to stdin to return a
EndOfFile error; the behavior of each process when this error is encountered is defined by the process, but most
processes ( like CMD and powershell for instance) will just exit. Setting this value to 'True' means that no
more input will be able to be sent to the process and attempting to do so should result in an error.
@return: None
"""
if isinstance(stdin_input, text_type):
stdin_input = stdin_input.encode("437")
req = {'env:Envelope': self._get_soap_header(
resource_uri='http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd', # NOQA
action='http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Send', # NOQA
shell_id=shell_id)}
stdin_envelope = req['env:Envelope'].setdefault('env:Body', {}).setdefault(
'rsp:Send', {}).setdefault('rsp:Stream', {})
stdin_envelope['@CommandId'] = command_id
stdin_envelope['@Name'] = 'stdin'
if end:
stdin_envelope['@End'] = "true"
else:
stdin_envelope['@End'] = "false"
stdin_envelope['@xmlns:rsp'] = 'http://schemas.microsoft.com/wbem/wsman/1/windows/shell'
stdin_envelope['#text'] = base64.b64encode(stdin_input)
self.send_message(xmltodict.unparse(req))

def get_command_output(self, shell_id, command_id):
"""
Get the Output of the given shell and command
Expand Down
190 changes: 190 additions & 0 deletions winrm/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,188 @@
</s:Envelope>"""


run_cmd_req_input = """\
<?xml version="1.0" encoding="utf-8"?>
<env:Envelope xmlns:x="http://schemas.xmlsoap.org/ws/2004/09/transfer" xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:cfg="http://schemas.microsoft.com/wbem/wsman/1/config" xmlns:p="http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd" xmlns:n="http://schemas.xmlsoap.org/ws/2004/09/enumeration" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:b="http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing">
<env:Header>
<a:To>http://windows-host:5985/wsman</a:To>
<a:ReplyTo>
<a:Address mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address>
</a:ReplyTo>
<w:MaxEnvelopeSize mustUnderstand="true">153600</w:MaxEnvelopeSize>
<a:MessageID>uuid:11111111-1111-1111-1111-111111111111</a:MessageID>
<w:Locale mustUnderstand="false" xml:lang="en-US" />
<p:DataLocale mustUnderstand="false" xml:lang="en-US" />
<w:OperationTimeout>PT20S</w:OperationTimeout>
<w:ResourceURI mustUnderstand="true">http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd</w:ResourceURI>
<a:Action mustUnderstand="true">http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Command</a:Action>
<w:SelectorSet>
<w:Selector Name="ShellId">11111111-1111-1111-1111-111111111113</w:Selector>
</w:SelectorSet>
<w:OptionSet>
<w:Option Name="WINRS_CONSOLEMODE_STDIN">TRUE</w:Option>
<w:Option Name="WINRS_SKIP_CMD_SHELL">FALSE</w:Option>
</w:OptionSet>
</env:Header>
<env:Body>
<rsp:CommandLine>
<rsp:Command>cmd</rsp:Command>
</rsp:CommandLine>
</env:Body>
</env:Envelope>"""


run_cmd_req_input_response = """\
<?xml version="1.0"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:x="http://schemas.xmlsoap.org/ws/2004/09/transfer" xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell" xmlns:p="http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd" xml:lang="en-US">
<s:Header>
<a:Action>http://schemas.microsoft.com/wbem/wsman/1/windows/shell/CommandResponse</a:Action>
<a:MessageID>uuid:11111111-1111-1111-1111-111111111114</a:MessageID>
<a:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:To>
<a:RelatesTo>uuid:11111111-1111-1111-1111-111111111112</a:RelatesTo>
</s:Header>
<s:Body>
<rsp:CommandResponse>
<rsp:CommandId>11111111-1111-1111-1111-111111111111</rsp:CommandId>
</rsp:CommandResponse>
</s:Body>
</s:Envelope>
"""

run_cmd_send_input = """\
<?xml version="1.0" encoding="utf-8"?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:b="http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd" xmlns:n="http://schemas.xmlsoap.org/ws/2004/09/enumeration" xmlns:x="http://schemas.xmlsoap.org/ws/2004/09/transfer" xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:p="http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd" xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell" xmlns:cfg="http://schemas.microsoft.com/wbem/wsman/1/config">
<env:Header>
<a:To>http://windows-host:5985/wsman</a:To>
<a:ReplyTo>
<a:Address mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address>
</a:ReplyTo>
<w:MaxEnvelopeSize mustUnderstand="true">153600</w:MaxEnvelopeSize>
<a:MessageID>uuid:11111111-1111-1111-1111-111111111111</a:MessageID>
<w:Locale mustUnderstand="false" xml:lang="en-US"/>
<p:DataLocale mustUnderstand="false" xml:lang="en-US"/>
<w:OperationTimeout>PT20S</w:OperationTimeout>
<w:ResourceURI mustUnderstand="true">http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd</w:ResourceURI>
<a:Action mustUnderstand="true">http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Send</a:Action>
<w:SelectorSet>
<w:Selector Name="ShellId">11111111-1111-1111-1111-111111111113</w:Selector>
</w:SelectorSet>
</env:Header>
<env:Body>
<rsp:Send>
<rsp:Stream xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell" CommandId="11111111-1111-1111-1111-111111111111" Name="stdin" End="false" >ZWNobyAiaGVsbG8gd29ybGQiICYmIGV4aXQNCg==</rsp:Stream>
</rsp:Send>
</env:Body>
</env:Envelope>
"""

run_cmd_send_input_response = """\
<?xml version="1.0" ?>
<s:Envelope xml:lang="en-US" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:p="http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd" xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell" xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:x="http://schemas.xmlsoap.org/ws/2004/09/transfer">
<s:Header>
<a:Action>http://schemas.microsoft.com/wbem/wsman/1/windows/shell/SendResponse</a:Action>
<a:MessageID>uuid:72371E37-E073-474B-B4BA-6559D8D94632</a:MessageID>
<a:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:To>
<a:RelatesTo>uuid:9c3de121-c3a4-452b-8f82-36b84e25b7fe</a:RelatesTo>
</s:Header>
<s:Body>
<rsp:SendResponse/>
</s:Body>
</s:Envelope>
"""

run_cmd_send_input_get_output = """\
<?xml version="1.0" encoding="utf-8"?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:b="http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd" xmlns:n="http://schemas.xmlsoap.org/ws/2004/09/enumeration" xmlns:x="http://schemas.xmlsoap.org/ws/2004/09/transfer" xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:p="http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd" xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell" xmlns:cfg="http://schemas.microsoft.com/wbem/wsman/1/config">
<env:Header>
<a:To>http://windows-host:5985/wsman</a:To>
<a:ReplyTo>
<a:Address mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address>
</a:ReplyTo>
<w:MaxEnvelopeSize mustUnderstand="true">153600</w:MaxEnvelopeSize>
<a:MessageID>uuid:11111111-1111-1111-1111-111111111111</a:MessageID>
<w:Locale mustUnderstand="false" xml:lang="en-US"/>
<p:DataLocale mustUnderstand="false" xml:lang="en-US"/>
<w:OperationTimeout>PT20S</w:OperationTimeout>
<w:ResourceURI mustUnderstand="true">http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd</w:ResourceURI>
<a:Action mustUnderstand="true">http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Receive</a:Action>
<w:SelectorSet>
<w:Selector Name="ShellId">11111111-1111-1111-1111-111111111113</w:Selector>
</w:SelectorSet>
</env:Header>
<env:Body>
<rsp:Receive>
<rsp:DesiredStream CommandId="11111111-1111-1111-1111-111111111111">stdout stderr</rsp:DesiredStream>
</rsp:Receive>
</env:Body>
</env:Envelope>
"""

run_cmd_send_input_get_output_response = """\
<?xml version="1.0"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell" xmlns:p="http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd" xml:lang="en-US">
<s:Header>
<a:Action>http://schemas.microsoft.com/wbem/wsman/1/windows/shell/ReceiveResponse</a:Action>
<a:MessageID>uuid:6468086A-377E-4BE3-AC71-1155F0F1D4E1</a:MessageID>
<a:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:To>
<a:RelatesTo>uuid:02f258b6-186f-4ac0-adc3-51550a131e64</a:RelatesTo>
</s:Header>
<s:Body>
<rsp:ReceiveResponse>
<rsp:Stream Name="stdout" CommandId="11111111-1111-1111-1111-111111111111">TWljcm9zb2Z0IFdpbmRvd3MgW1ZlcnNpb24gMTAuMC4xNzc2My4xMDdd</rsp:Stream>
<rsp:Stream Name="stdout" CommandId="11111111-1111-1111-1111-111111111111">DQooYykgMjAxOCBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQoNCkM6XFVzZXJzXHJ3ZWJlcj5lY2hvIGhlbGxvIHdvcmxkICYmIGV4aXQNCmhlbGxvIHdvcmxkIA0K</rsp:Stream>
<rsp:Stream Name="stdout" CommandId="11111111-1111-1111-1111-111111111111" End="true"/>
<rsp:Stream Name="stderr" CommandId="11111111-1111-1111-1111-111111111111" End="true"/>
<rsp:CommandState CommandId="11111111-1111-1111-1111-111111111111" State="http://schemas.microsoft.com/wbem/wsman/1/windows/shell/CommandState/Done">
<rsp:ExitCode>0</rsp:ExitCode>
</rsp:CommandState>
</rsp:ReceiveResponse>
</s:Body>
</s:Envelope>
"""

stdin_cmd_cleanup = """\
<?xml version="1.0" encoding="utf-8"?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:b="http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd" xmlns:n="http://schemas.xmlsoap.org/ws/2004/09/enumeration" xmlns:x="http://schemas.xmlsoap.org/ws/2004/09/transfer" xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:p="http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd" xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell" xmlns:cfg="http://schemas.microsoft.com/wbem/wsman/1/config">
<env:Header>
<a:To>http://windows-host:5985/wsman</a:To>
<a:ReplyTo>
<a:Address mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address>
</a:ReplyTo>
<w:MaxEnvelopeSize mustUnderstand="true">153600</w:MaxEnvelopeSize>
<a:MessageID>uuid:11111111-1111-1111-1111-111111111111</a:MessageID>
<w:Locale mustUnderstand="false" xml:lang="en-US"/>
<p:DataLocale mustUnderstand="false" xml:lang="en-US"/>
<w:OperationTimeout>PT20S</w:OperationTimeout>
<w:ResourceURI mustUnderstand="true">http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd</w:ResourceURI>
<a:Action mustUnderstand="true">http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Signal</a:Action>
<w:SelectorSet>
<w:Selector Name="ShellId">11111111-1111-1111-1111-111111111113</w:Selector>
</w:SelectorSet>
</env:Header>
<env:Body>
<rsp:Signal CommandId="11111111-1111-1111-1111-111111111111">
<rsp:Code>http://schemas.microsoft.com/wbem/wsman/1/windows/shell/signal/terminate</rsp:Code>
</rsp:Signal>
</env:Body>
</env:Envelope>
"""

stdin_cmd_cleanup_response = """\
<?xml version="1.0"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:x="http://schemas.xmlsoap.org/ws/2004/09/transfer" xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell" xmlns:p="http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd" xml:lang="en-US">
<s:Header>
<a:Action>http://schemas.microsoft.com/wbem/wsman/1/windows/shell/SignalResponse</a:Action>
<a:MessageID>uuid:8A875405-3494-4400-A988-B47A563922E7</a:MessageID>
<a:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:To>
<a:RelatesTo>uuid:11111111-1111-1111-1111-111111111111</a:RelatesTo>
</s:Header>
<s:Body>
<rsp:SignalResponse/>
</s:Body>
</s:Envelope>
"""

def sort_dict(ordered_dict):
items = sorted(ordered_dict.items(), key=lambda x: x[0])
ordered_dict.clear()
Expand Down Expand Up @@ -348,6 +530,14 @@ def send_message(self, message):
return get_cmd_output_response
elif xml_str_compare(message, get_cmd_ps_output_request % '2'):
return get_ps_output_response
elif xml_str_compare(message, run_cmd_req_input):
return run_cmd_req_input_response
elif xml_str_compare(message, run_cmd_send_input):
return run_cmd_send_input_response
elif xml_str_compare(message, run_cmd_send_input_get_output):
return run_cmd_send_input_get_output_response
elif xml_str_compare(message, stdin_cmd_cleanup):
return stdin_cmd_cleanup_response
else:
raise Exception('Message was not expected\n\n%s' % message)

Expand Down
14 changes: 14 additions & 0 deletions winrm/tests/test_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ def test_get_command_output(protocol_fake):
protocol_fake.close_shell(shell_id)


def test_send_command_input(protocol_fake):
shell_id = protocol_fake.open_shell()
command_id = protocol_fake.run_command(shell_id, u'cmd')
protocol_fake.send_command_input(shell_id, command_id, u'echo "hello world" && exit\r\n')
std_out, std_err, status_code = protocol_fake.get_command_output(
shell_id, command_id)
assert status_code == 0
assert b'hello world' in std_out
assert len(std_err) == 0

protocol_fake.cleanup_command(shell_id, command_id)
protocol_fake.close_shell(shell_id)


def test_set_timeout_as_sec():
protocol = Protocol('endpoint',
username='username',
Expand Down

0 comments on commit 946c7c1

Please sign in to comment.