/** * FreeRDP: A Remote Desktop Protocol Implementation * RPC over HTTP * * Copyright 2012 Fujitsu Technology Solutions GmbH * Copyright 2012 Dmitrij Jasnov * Copyright 2012 Marc-Andre Moreau * * 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. */ #ifndef FREERDP_LIB_CORE_GATEWAY_RPC_H #define FREERDP_LIB_CORE_GATEWAY_RPC_H #include #include #include #include #include #include typedef struct rdp_rpc rdpRpc; #pragma pack(push, 1) typedef struct { BYTE rpc_vers; BYTE rpc_vers_minor; BYTE ptype; BYTE pfc_flags; BYTE packed_drep[4]; UINT16 frag_length; UINT16 auth_length; UINT32 call_id; } rpcconn_common_hdr_t; #define RPC_COMMON_FIELDS_LENGTH sizeof(rpcconn_common_hdr_t) typedef struct { rpcconn_common_hdr_t header; UINT16 Flags; UINT16 NumberOfCommands; } rpcconn_rts_hdr_t; #define RTS_PDU_HEADER_LENGTH 20 #define RPC_PDU_FLAG_STUB 0x00000001 typedef struct _RPC_PDU { wStream* s; UINT32 Type; UINT32 Flags; UINT32 CallId; } RPC_PDU, *PRPC_PDU; #pragma pack(pop) #include "../tcp.h" #include "../transport.h" #include "http.h" #include "ntlm.h" #include #include #include #include #include #include #include #include #include /** * CAE Specification * DCE 1.1: Remote Procedure Call * Document Number: C706 * http://pubs.opengroup.org/onlinepubs/9629399/ */ #define PTYPE_REQUEST 0x00 #define PTYPE_PING 0x01 #define PTYPE_RESPONSE 0x02 #define PTYPE_FAULT 0x03 #define PTYPE_WORKING 0x04 #define PTYPE_NOCALL 0x05 #define PTYPE_REJECT 0x06 #define PTYPE_ACK 0x07 #define PTYPE_CL_CANCEL 0x08 #define PTYPE_FACK 0x09 #define PTYPE_CANCEL_ACK 0x0A #define PTYPE_BIND 0x0B #define PTYPE_BIND_ACK 0x0C #define PTYPE_BIND_NAK 0x0D #define PTYPE_ALTER_CONTEXT 0x0E #define PTYPE_ALTER_CONTEXT_RESP 0x0F #define PTYPE_RPC_AUTH_3 0x10 #define PTYPE_SHUTDOWN 0x11 #define PTYPE_CO_CANCEL 0x12 #define PTYPE_ORPHANED 0x13 #define PTYPE_RTS 0x14 #define PFC_FIRST_FRAG 0x01 #define PFC_LAST_FRAG 0x02 #define PFC_PENDING_CANCEL 0x04 #define PFC_SUPPORT_HEADER_SIGN 0x04 #define PFC_RESERVED_1 0x08 #define PFC_CONC_MPX 0x10 #define PFC_DID_NOT_EXECUTE 0x20 #define PFC_MAYBE 0x40 #define PFC_OBJECT_UUID 0x80 /* Minimum fragment sizes */ #define RPC_CO_MUST_RECV_FRAG_SIZE 1432 #define RPC_CL_MUST_RECV_FRAG_SIZE 1464 /** * The PDU maximum header length is enough * to contain either the RPC common fields * or all fields up to the stub data in PDUs * that use it (request, response, fault) */ #define RPC_PDU_HEADER_MAX_LENGTH 32 #pragma pack(push, 1) typedef UINT16 p_context_id_t; typedef UINT16 p_reject_reason_t; typedef struct { UINT32 time_low; UINT16 time_mid; UINT16 time_hi_and_version; BYTE clock_seq_hi_and_reserved; BYTE clock_seq_low; BYTE node[6]; } p_uuid_t; #define ndr_c_int_big_endian 0 #define ndr_c_int_little_endian 1 #define ndr_c_float_ieee 0 #define ndr_c_float_vax 1 #define ndr_c_float_cray 2 #define ndr_c_float_ibm 3 #define ndr_c_char_ascii 0 #define ndr_c_char_ebcdic 1 typedef struct { BYTE int_rep; BYTE char_rep; BYTE float_rep; BYTE reserved; } ndr_format_t, *ndr_format_p_t; typedef struct ndr_context_handle { UINT32 context_handle_attributes; p_uuid_t context_handle_uuid; } ndr_context_handle; typedef struct { p_uuid_t if_uuid; UINT32 if_version; } p_syntax_id_t; typedef struct { p_context_id_t p_cont_id; BYTE n_transfer_syn; /* number of items */ BYTE reserved; /* alignment pad, m.b.z. */ p_syntax_id_t abstract_syntax; /* transfer syntax list */ p_syntax_id_t* transfer_syntaxes; /* size_is(n_transfer_syn) */ } p_cont_elem_t; typedef struct { BYTE n_context_elem; /* number of items */ BYTE reserved; /* alignment pad, m.b.z. */ UINT16 reserved2; /* alignment pad, m.b.z. */ p_cont_elem_t* p_cont_elem; /* size_is(n_cont_elem) */ } p_cont_list_t; typedef enum { acceptance, user_rejection, provider_rejection } p_cont_def_result_t; typedef enum { reason_not_specified, abstract_syntax_not_supported, proposed_transfer_syntaxes_not_supported, local_limit_exceeded } p_provider_reason_t; typedef struct { p_cont_def_result_t result; p_provider_reason_t reason; p_syntax_id_t transfer_syntax; } p_result_t; /* Same order and number of elements as in bind request */ typedef struct { BYTE n_results; /* count */ BYTE reserved; /* alignment pad, m.b.z. */ UINT16 reserved2; /* alignment pad, m.b.z. */ p_result_t* p_results; /* size_is(n_results) */ } p_result_list_t; typedef struct { BYTE major; BYTE minor; } version_t; typedef version_t p_rt_version_t; typedef struct { BYTE n_protocols; /* count */ p_rt_version_t* p_protocols; /* size_is(n_protocols) */ } p_rt_versions_supported_t; typedef struct { UINT16 length; char* port_spec; /* port string spec; size_is(length) */ } port_any_t; #define REASON_NOT_SPECIFIED 0 #define TEMPORARY_CONGESTION 1 #define LOCAL_LIMIT_EXCEEDED 2 #define CALLED_PADDR_UNKNOWN 3 #define PROTOCOL_VERSION_NOT_SUPPORTED 4 #define DEFAULT_CONTEXT_NOT_SUPPORTED 5 #define USER_DATA_NOT_READABLE 6 #define NO_PSAP_AVAILABLE 7 typedef UINT16 rpcrt_reason_code_t; typedef struct { BYTE rpc_vers; BYTE rpc_vers_minor; BYTE reserved[2]; BYTE packed_drep[4]; UINT32 reject_status; BYTE reserved2[4]; } rpcrt_optional_data_t; typedef struct { rpcrt_reason_code_t reason_code; rpcrt_optional_data_t rpc_info; } rpcconn_reject_optional_data_t; typedef struct { rpcrt_reason_code_t reason_code; rpcrt_optional_data_t rpc_info; } rpcconn_disc_optional_data_t; typedef struct { BYTE signature[8]; } rpc_sec_verification_trailer; struct auth_verifier_co_s { /* restore 4-byte alignment */ BYTE auth_type; BYTE auth_level; BYTE auth_pad_length; BYTE auth_reserved; UINT32 auth_context_id; BYTE* auth_value; }; typedef struct auth_verifier_co_s rpc_sec_trailer; typedef struct auth_verifier_co_s auth_verifier_co_t; /* Connection-oriented PDU Definitions */ typedef struct { rpcconn_common_hdr_t header; UINT16 max_xmit_frag; UINT16 max_recv_frag; UINT32 assoc_group_id; p_cont_list_t p_context_elem; auth_verifier_co_t auth_verifier; } rpcconn_alter_context_hdr_t; typedef struct { rpcconn_common_hdr_t header; UINT16 max_xmit_frag; UINT16 max_recv_frag; UINT32 assoc_group_id; port_any_t sec_addr; /* restore 4-octet alignment */ p_result_list_t p_result_list; auth_verifier_co_t auth_verifier; } rpcconn_alter_context_response_hdr_t; /* bind header */ typedef struct { rpcconn_common_hdr_t header; UINT16 max_xmit_frag; UINT16 max_recv_frag; UINT32 assoc_group_id; p_cont_list_t p_context_elem; auth_verifier_co_t auth_verifier; } rpcconn_bind_hdr_t; typedef struct { rpcconn_common_hdr_t header; UINT16 max_xmit_frag; UINT16 max_recv_frag; UINT32 assoc_group_id; port_any_t sec_addr; /* restore 4-octet alignment */ p_result_list_t p_result_list; auth_verifier_co_t auth_verifier; } rpcconn_bind_ack_hdr_t; typedef struct { rpcconn_common_hdr_t header; UINT16 max_xmit_frag; UINT16 max_recv_frag; auth_verifier_co_t auth_verifier; } rpcconn_rpc_auth_3_hdr_t; typedef struct { rpcconn_common_hdr_t header; p_reject_reason_t provider_reject_reason; p_rt_versions_supported_t versions; } rpcconn_bind_nak_hdr_t; typedef struct { rpcconn_common_hdr_t header; auth_verifier_co_t auth_verifier; } rpcconn_cancel_hdr_t; /* fault codes */ struct _RPC_FAULT_CODE { UINT32 code; const char* name; const char* category; }; typedef struct _RPC_FAULT_CODE RPC_FAULT_CODE; #define DEFINE_RPC_FAULT_CODE(_code, cat) \ { \ _code, #_code, cat \ } #define nca_s_comm_failure 0x1C010001 #define nca_s_op_rng_error 0x1C010002 #define nca_s_unk_if 0x1C010003 #define nca_s_wrong_boot_time 0x1C010006 #define nca_s_you_crashed 0x1C010009 #define nca_s_proto_error 0x1C01000B #define nca_s_out_args_too_big 0x1C010013 #define nca_s_server_too_busy 0x1C010014 #define nca_s_fault_string_too_long 0x1C010015 #define nca_s_unsupported_type 0x1C010017 #define nca_s_fault_int_div_by_zero 0x1C000001 #define nca_s_fault_addr_error 0x1C000002 #define nca_s_fault_fp_div_zero 0x1C000003 #define nca_s_fault_fp_underflow 0x1C000004 #define nca_s_fault_fp_overflow 0x1C000005 #define nca_s_fault_invalid_tag 0x1C000006 #define nca_s_fault_invalid_bound 0x1C000007 #define nca_s_rpc_version_mismatch 0x1C000008 #define nca_s_unspec_reject 0x1C000009 #define nca_s_bad_actid 0x1C00000A #define nca_s_who_are_you_failed 0x1C00000B #define nca_s_manager_not_entered 0x1C00000C #define nca_s_fault_cancel 0x1C00000D #define nca_s_fault_ill_inst 0x1C00000E #define nca_s_fault_fp_error 0x1C00000F #define nca_s_fault_int_overflow 0x1C000010 #define nca_s_fault_unspec 0x1C000012 #define nca_s_fault_remote_comm_failure 0x1C000013 #define nca_s_fault_pipe_empty 0x1C000014 #define nca_s_fault_pipe_closed 0x1C000015 #define nca_s_fault_pipe_order 0x1C000016 #define nca_s_fault_pipe_discipline 0x1C000017 #define nca_s_fault_pipe_comm_error 0x1C000018 #define nca_s_fault_pipe_memory 0x1C000019 #define nca_s_fault_context_mismatch 0x1C00001A #define nca_s_fault_remote_no_memory 0x1C00001B #define nca_s_invalid_pres_context_id 0x1C00001C #define nca_s_unsupported_authn_level 0x1C00001D #define nca_s_invalid_checksum 0x1C00001F #define nca_s_invalid_crc 0x1C000020 #define nca_s_fault_user_defined 0x1C000021 #define nca_s_fault_tx_open_failed 0x1C000022 #define nca_s_fault_codeset_conv_error 0x1C000023 #define nca_s_fault_object_not_found 0x1C000024 #define nca_s_fault_no_client_stub 0x1C000025 typedef struct { rpcconn_common_hdr_t header; UINT32 alloc_hint; p_context_id_t p_cont_id; BYTE cancel_count; BYTE reserved; UINT32 status; /* align(8) */ BYTE* stub_data; auth_verifier_co_t auth_verifier; } rpcconn_fault_hdr_t; typedef struct { rpcconn_common_hdr_t header; auth_verifier_co_t auth_verifier; } rpcconn_orphaned_hdr_t; typedef struct { rpcconn_common_hdr_t header; UINT32 alloc_hint; p_context_id_t p_cont_id; UINT16 opnum; /* optional field for request, only present if the PFC_OBJECT_UUID field is non-zero */ p_uuid_t object; /* align(8) */ BYTE* stub_data; auth_verifier_co_t auth_verifier; } rpcconn_request_hdr_t; typedef struct { rpcconn_common_hdr_t header; UINT32 alloc_hint; p_context_id_t p_cont_id; BYTE cancel_count; BYTE reserved; /* align(8) */ BYTE* stub_data; auth_verifier_co_t auth_verifier; } rpcconn_response_hdr_t; typedef struct { rpcconn_common_hdr_t header; } rpcconn_shutdown_hdr_t; typedef union { rpcconn_common_hdr_t common; rpcconn_alter_context_hdr_t alter_context; rpcconn_alter_context_response_hdr_t alter_context_response; rpcconn_bind_hdr_t bind; rpcconn_bind_ack_hdr_t bind_ack; rpcconn_rpc_auth_3_hdr_t rpc_auth_3; rpcconn_bind_nak_hdr_t bind_nak; rpcconn_cancel_hdr_t cancel; rpcconn_fault_hdr_t fault; rpcconn_orphaned_hdr_t orphaned; rpcconn_request_hdr_t request; rpcconn_response_hdr_t response; rpcconn_shutdown_hdr_t shutdown; rpcconn_rts_hdr_t rts; } rpcconn_hdr_t; #pragma pack(pop) struct _RPC_SECURITY_PROVIDER_INFO { UINT32 Id; LONG EvenLegs; LONG NumLegs; }; typedef struct _RPC_SECURITY_PROVIDER_INFO RPC_SECURITY_PROVIDER_INFO; enum _RPC_CLIENT_STATE { RPC_CLIENT_STATE_INITIAL, RPC_CLIENT_STATE_ESTABLISHED, RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK, RPC_CLIENT_STATE_WAIT_UNSECURE_BIND_ACK, RPC_CLIENT_STATE_WAIT_SECURE_ALTER_CONTEXT_RESPONSE, RPC_CLIENT_STATE_CONTEXT_NEGOTIATED, RPC_CLIENT_STATE_WAIT_RESPONSE, RPC_CLIENT_STATE_FINAL }; typedef enum _RPC_CLIENT_STATE RPC_CLIENT_STATE; enum _RPC_CLIENT_CALL_STATE { RPC_CLIENT_CALL_STATE_INITIAL, RPC_CLIENT_CALL_STATE_SEND_PDUS, RPC_CLIENT_CALL_STATE_DISPATCHED, RPC_CLIENT_CALL_STATE_RECEIVE_PDU, RPC_CLIENT_CALL_STATE_COMPLETE, RPC_CLIENT_CALL_STATE_FAULT, RPC_CLIENT_CALL_STATE_FINAL }; typedef enum _RPC_CLIENT_CALL_STATE RPC_CLIENT_CALL_STATE; struct rpc_client_call { UINT32 CallId; UINT32 OpNum; RPC_CLIENT_CALL_STATE State; }; typedef struct rpc_client_call RpcClientCall; struct rpc_client { rdpContext* context; RPC_PDU* pdu; HANDLE PipeEvent; RingBuffer ReceivePipe; wStream* ReceiveFragment; CRITICAL_SECTION PipeLock; wArrayList* ClientCallList; char* host; UINT16 port; BOOL isProxy; }; typedef struct rpc_client RpcClient; struct rpc_channel { RpcClient* client; BIO* bio; rdpTls* tls; rdpNtlm* ntlm; HttpContext* http; BYTE Cookie[16]; }; typedef struct rpc_channel RpcChannel; /* Ping Originator */ struct rpc_ping_originator { UINT32 ConnectionTimeout; UINT32 LastPacketSentTimestamp; UINT32 KeepAliveInterval; }; typedef struct rpc_ping_originator RpcPingOriginator; /* Client In Channel */ enum _CLIENT_IN_CHANNEL_STATE { CLIENT_IN_CHANNEL_STATE_INITIAL, CLIENT_IN_CHANNEL_STATE_CONNECTED, CLIENT_IN_CHANNEL_STATE_SECURITY, CLIENT_IN_CHANNEL_STATE_NEGOTIATED, CLIENT_IN_CHANNEL_STATE_OPENED, CLIENT_IN_CHANNEL_STATE_OPENED_A4W, CLIENT_IN_CHANNEL_STATE_FINAL }; typedef enum _CLIENT_IN_CHANNEL_STATE CLIENT_IN_CHANNEL_STATE; struct rpc_in_channel { /* Sending Channel */ RpcChannel common; CLIENT_IN_CHANNEL_STATE State; UINT32 PlugState; void* SendQueue; UINT32 BytesSent; UINT32 SenderAvailableWindow; UINT32 PeerReceiveWindow; /* Ping Originator */ RpcPingOriginator PingOriginator; }; typedef struct rpc_in_channel RpcInChannel; /* Client Out Channel */ enum _CLIENT_OUT_CHANNEL_STATE { CLIENT_OUT_CHANNEL_STATE_INITIAL, CLIENT_OUT_CHANNEL_STATE_CONNECTED, CLIENT_OUT_CHANNEL_STATE_SECURITY, CLIENT_OUT_CHANNEL_STATE_NEGOTIATED, CLIENT_OUT_CHANNEL_STATE_OPENED, CLIENT_OUT_CHANNEL_STATE_OPENED_A6W, CLIENT_OUT_CHANNEL_STATE_OPENED_A10W, CLIENT_OUT_CHANNEL_STATE_OPENED_B3W, CLIENT_OUT_CHANNEL_STATE_RECYCLED, CLIENT_OUT_CHANNEL_STATE_FINAL }; typedef enum _CLIENT_OUT_CHANNEL_STATE CLIENT_OUT_CHANNEL_STATE; struct rpc_out_channel { /* Receiving Channel */ RpcChannel common; CLIENT_OUT_CHANNEL_STATE State; UINT32 ReceiveWindow; UINT32 ReceiveWindowSize; UINT32 ReceiverAvailableWindow; UINT32 BytesReceived; UINT32 AvailableWindowAdvertised; }; typedef struct rpc_out_channel RpcOutChannel; /* Client Virtual Connection */ enum _VIRTUAL_CONNECTION_STATE { VIRTUAL_CONNECTION_STATE_INITIAL, VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT, VIRTUAL_CONNECTION_STATE_WAIT_A3W, VIRTUAL_CONNECTION_STATE_WAIT_C2, VIRTUAL_CONNECTION_STATE_OPENED, VIRTUAL_CONNECTION_STATE_FINAL }; typedef enum _VIRTUAL_CONNECTION_STATE VIRTUAL_CONNECTION_STATE; struct rpc_virtual_connection { BYTE Cookie[16]; BYTE AssociationGroupId[16]; VIRTUAL_CONNECTION_STATE State; RpcInChannel* DefaultInChannel; RpcInChannel* NonDefaultInChannel; RpcOutChannel* DefaultOutChannel; RpcOutChannel* NonDefaultOutChannel; }; typedef struct rpc_virtual_connection RpcVirtualConnection; /* Virtual Connection Cookie Table */ #define RPC_UUID_FORMAT_STRING \ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" #define RPC_UUID_FORMAT_ARGUMENTS(_rpc_uuid) \ _rpc_uuid[0], _rpc_uuid[1], _rpc_uuid[2], _rpc_uuid[3], _rpc_uuid[4], _rpc_uuid[5], \ _rpc_uuid[6], _rpc_uuid[7], _rpc_uuid[8], _rpc_uuid[9], _rpc_uuid[10], _rpc_uuid[11], \ _rpc_uuid[12], _rpc_uuid[13], _rpc_uuid[14], _rpc_uuid[15] struct rpc_virtual_connection_cookie_entry { BYTE Cookie[16]; UINT32 ReferenceCount; RpcVirtualConnection* Reference; }; typedef struct rpc_virtual_connection_cookie_entry RpcVirtualConnectionCookieEntry; struct rdp_rpc { RPC_CLIENT_STATE State; UINT32 result; rdpNtlm* ntlm; int SendSeqNum; RpcClient* client; rdpContext* context; rdpSettings* settings; rdpTransport* transport; UINT32 CallId; UINT32 PipeCallId; UINT32 StubCallId; UINT32 StubFragCount; BYTE rpc_vers; BYTE rpc_vers_minor; BYTE packed_drep[4]; UINT16 max_xmit_frag; UINT16 max_recv_frag; UINT32 ReceiveWindow; UINT32 ChannelLifetime; UINT32 KeepAliveInterval; UINT32 CurrentKeepAliveTime; UINT32 CurrentKeepAliveInterval; RpcVirtualConnection* VirtualConnection; }; FREERDP_LOCAL void rpc_pdu_header_print(const rpcconn_hdr_t* header); FREERDP_LOCAL rpcconn_common_hdr_t rpc_pdu_header_init(const rdpRpc* rpc); FREERDP_LOCAL size_t rpc_offset_align(size_t* offset, size_t alignment); FREERDP_LOCAL size_t rpc_offset_pad(size_t* offset, size_t pad); FREERDP_LOCAL BOOL rpc_get_stub_data_info(const rpcconn_hdr_t* header, size_t* offset, size_t* length); FREERDP_LOCAL SSIZE_T rpc_channel_write(RpcChannel* channel, const BYTE* data, size_t length); FREERDP_LOCAL SSIZE_T rpc_channel_read(RpcChannel* channel, wStream* s, size_t length); FREERDP_LOCAL void rpc_channel_free(RpcChannel* channel); FREERDP_LOCAL RpcOutChannel* rpc_out_channel_new(rdpRpc* rpc); FREERDP_LOCAL int rpc_out_channel_replacement_connect(RpcOutChannel* outChannel, int timeout); FREERDP_LOCAL BOOL rpc_in_channel_transition_to_state(RpcInChannel* inChannel, CLIENT_IN_CHANNEL_STATE state); FREERDP_LOCAL BOOL rpc_out_channel_transition_to_state(RpcOutChannel* outChannel, CLIENT_OUT_CHANNEL_STATE state); FREERDP_LOCAL BOOL rpc_virtual_connection_transition_to_state(rdpRpc* rpc, RpcVirtualConnection* connection, VIRTUAL_CONNECTION_STATE state); FREERDP_LOCAL BOOL rpc_connect(rdpRpc* rpc, UINT32 timeout); FREERDP_LOCAL rdpRpc* rpc_new(rdpTransport* transport); FREERDP_LOCAL void rpc_free(rdpRpc* rpc); #endif /* FREERDP_LIB_CORE_GATEWAY_RPC_H */