# Copyright 2015 Matt Wrock # Copyright 2016 Shawn Neal # # Licensed under the Apache License, Version 2.0 (the 'License'); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an 'AS IS' BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require_relative 'uuid' require_relative 'message_data' module WinRM # PowerShell Remoting Protcol module module PSRP # PowerShell Remoting Protocol base message. # http://download.microsoft.com/download/9/5/E/95EF66AF-9026-4BB0-A41D-A4F81802D92C/%5BMS-PSRP%5D.pdf class Message include UUID # Value of message destination when sent to a client CLIENT_DESTINATION = 1 # Value of message destination when sent to a server SERVER_DESTINATION = 2 # All known PSRP message types MESSAGE_TYPES = { session_capability: 0x00010002, init_runspacepool: 0x00010004, public_key: 0x00010005, encrypted_session_key: 0x00010006, public_key_request: 0x00010007, connect_runspacepool: 0x00010008, runspace_init_data: 0x0002100b, reset_runspace_state: 0x0002100c, set_max_runspaces: 0x00021002, set_min_runspaces: 0x00021003, runspace_availability: 0x00021004, runspacepool_state: 0x00021005, create_pipeline: 0x00021006, get_available_runspaces: 0x00021007, user_event: 0x00021008, application_private_data: 0x00021009, get_command_metadata: 0x0002100a, runspacepool_host_call: 0x00021100, runspacepool_host_response: 0x00021101, pipeline_input: 0x00041002, end_of_pipeline_input: 0x00041003, pipeline_output: 0x00041004, error_record: 0x00041005, pipeline_state: 0x00041006, debug_record: 0x00041007, verbose_record: 0x00041008, warning_record: 0x00041009, progress_record: 0x00041010, information_record: 0x00041011, pipeline_host_call: 0x00041100, pipeline_host_response: 0x00041101 }.freeze # Creates a new PSRP message instance # @param runspace_pool_id [String] The UUID of the remote shell/runspace pool. # @param pipeline_id [String] The UUID to correlate the command/pipeline response # @param type [Integer] The PSRP MessageType. This is most commonly # specified in hex, e.g. 0x00010002. # @param data [String] The PSRP payload as serialized XML # @param destination [Integer] The destination for this message - client or server def initialize( runspace_pool_id, type, data, pipeline_id = nil, destination = SERVER_DESTINATION ) raise 'invalid message type' unless MESSAGE_TYPES.value?(type) @data = data @destination = destination @type = type @pipeline_id = pipeline_id @runspace_pool_id = runspace_pool_id end attr_reader :destination, :type, :runspace_pool_id, :pipeline_id, :data # Returns the raw PSRP message bytes ready for transfer to Windows inside a # WinRM message. # @return [Array] Unencoded raw byte array of the PSRP message. def bytes [ int16le(destination), int16le(type), uuid_to_windows_guid_bytes(runspace_pool_id), uuid_to_windows_guid_bytes(pipeline_id), byte_order_mark, data_bytes ].flatten end # Parses the raw data to a MessageData class # @return [MessageData::Base] MessageData corresponding to this message type def parsed_data @parsed_data ||= MessageData.parse(self) end private def byte_order_mark [239, 187, 191] end def data_bytes @data_bytes ||= data.force_encoding('utf-8').bytes end def int16le(int16) [int16].pack('N').unpack('C4').reverse end end end end