diff --git a/libfreerdp/core/multitransport.c b/libfreerdp/core/multitransport.c index e96c47dd3..a4a3fcf66 100644 --- a/libfreerdp/core/multitransport.c +++ b/libfreerdp/core/multitransport.c @@ -17,35 +17,155 @@ * limitations under the License. */ +#include #include - -#include "multitransport.h" - #include +#include "rdp.h" +#include "multitransport.h" + #define TAG FREERDP_TAG("core.multitransport") -int rdp_recv_multitransport_packet(rdpRdp* rdp, wStream* s) +struct rdp_multitransport { - UINT32 requestId; - UINT16 requestedProtocol; - UINT16 reserved; - BYTE securityCookie[16]; + rdpRdp* rdp; + + UINT32 requestId; /* requestId (4 bytes) */ + UINT16 requestedProtocol; /* requestedProtocol (2 bytes) */ + UINT16 reserved; /* reserved (2 bytes) */ + BYTE securityCookie[16]; /* securityCookie (16 bytes) */ +}; + +static BOOL multitransport_compare(const rdpMultitransport* srv, const rdpMultitransport* client) +{ + BOOL abortOnError = !freerdp_settings_get_bool(srv->rdp->settings, FreeRDP_TransportDumpReplay); + WINPR_ASSERT(srv); + WINPR_ASSERT(client); + + if (srv->requestId != client->requestId) + { + WLog_WARN(TAG, + "Multitransport PDU::requestId mismatch expected 0x08%" PRIx32 + ", got 0x08%" PRIx32, + srv->requestId, client->requestId); + if (abortOnError) + return FALSE; + } + + if (srv->requestedProtocol != client->requestedProtocol) + { + WLog_WARN(TAG, + "Multitransport PDU::requestedProtocol mismatch expected 0x08%" PRIx32 + ", got 0x08%" PRIx32, + srv->requestedProtocol, client->requestedProtocol); + if (abortOnError) + return FALSE; + } + + if (memcmp(srv->securityCookie, client->securityCookie, sizeof(srv->securityCookie)) != 0) + { + WLog_WARN(TAG, "Multitransport PDU::securityCookie mismatch"); + if (abortOnError) + return FALSE; + } + + return TRUE; +} + +int multitransport_client_recv_request(rdpMultitransport* multitransport, wStream* s) +{ + WINPR_ASSERT(multitransport); if (!Stream_CheckAndLogRequiredLength(TAG, s, 24)) return -1; - Stream_Read_UINT32(s, requestId); /* requestId (4 bytes) */ - Stream_Read_UINT16(s, requestedProtocol); /* requestedProtocol (2 bytes) */ - Stream_Read_UINT16(s, reserved); /* reserved (2 bytes) */ - Stream_Read(s, securityCookie, 16); /* securityCookie (16 bytes) */ + Stream_Read_UINT32(s, multitransport->requestId); /* requestId (4 bytes) */ + Stream_Read_UINT16(s, multitransport->requestedProtocol); /* requestedProtocol (2 bytes) */ + Stream_Read_UINT16(s, multitransport->reserved); /* reserved (2 bytes) */ + Stream_Read(s, multitransport->securityCookie, + sizeof(multitransport->securityCookie)); /* securityCookie (16 bytes) */ return 0; } -rdpMultitransport* multitransport_new(void) +BOOL multitransport_server_send_request(rdpMultitransport* multitransport) { - return (rdpMultitransport*)calloc(1, sizeof(rdpMultitransport)); + WINPR_ASSERT(multitransport); + wStream* s = rdp_message_channel_pdu_init(multitransport->rdp); + if (!s) + return FALSE; + + if (!Stream_EnsureRemainingCapacity(s, 24)) + { + Stream_Release(s); + return FALSE; + } + + Stream_Write_UINT32(s, multitransport->requestId); /* requestId (4 bytes) */ + Stream_Write_UINT16(s, multitransport->requestedProtocol); /* requestedProtocol (2 bytes) */ + Stream_Write_UINT16(s, multitransport->reserved); /* reserved (2 bytes) */ + Stream_Write(s, multitransport->securityCookie, + sizeof(multitransport->securityCookie)); /* securityCookie (16 bytes) */ + + return rdp_send_message_channel_pdu(multitransport->rdp, s, SEC_TRANSPORT_REQ); +} + +BOOL multitransport_client_send_response(rdpMultitransport* multitransport, HRESULT hr) +{ + WINPR_ASSERT(multitransport); + + wStream* s = rdp_message_channel_pdu_init(multitransport->rdp); + if (!s) + return FALSE; + + if (!Stream_EnsureRemainingCapacity(s, 28)) + { + Stream_Release(s); + return FALSE; + } + + Stream_Write_UINT32(s, multitransport->requestId); /* requestId (4 bytes) */ + Stream_Write_UINT16(s, multitransport->requestedProtocol); /* requestedProtocol (2 bytes) */ + Stream_Write_UINT16(s, multitransport->reserved); /* reserved (2 bytes) */ + Stream_Write(s, multitransport->securityCookie, + sizeof(multitransport->securityCookie)); /* securityCookie (16 bytes) */ + Stream_Write_UINT32(s, hr); + return rdp_send_message_channel_pdu(multitransport->rdp, s, SEC_TRANSPORT_REQ); +} + +BOOL multitransport_server_recv_response(rdpMultitransport* multitransport, wStream* s, HRESULT* hr) +{ + rdpMultitransport multi = { 0 }; + + WINPR_ASSERT(multitransport); + WINPR_ASSERT(hr); + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 28)) + return FALSE; + + Stream_Read_UINT32(s, multi.requestId); /* requestId (4 bytes) */ + Stream_Read_UINT16(s, multi.requestedProtocol); /* requestedProtocol (2 bytes) */ + Stream_Read_UINT16(s, multi.reserved); /* reserved (2 bytes) */ + Stream_Read(s, multi.securityCookie, + sizeof(multi.securityCookie)); /* securityCookie (16 bytes) */ + Stream_Read_UINT32(s, *hr); + if (!multitransport_compare(multitransport, &multi)) + return FALSE; + return TRUE; +} + +rdpMultitransport* multitransport_new(rdpRdp* rdp, UINT16 protocol) +{ + rdpMultitransport* multi = calloc(1, sizeof(rdpMultitransport)); + if (multi) + { + WINPR_ASSERT(rdp); + multi->rdp = rdp; + winpr_RAND(&multi->requestId, sizeof(multi->requestId)); + multi->requestedProtocol = protocol; + winpr_RAND(&multi->securityCookie, sizeof(multi->securityCookie)); + } + return multi; } void multitransport_free(rdpMultitransport* multitransport) diff --git a/libfreerdp/core/multitransport.h b/libfreerdp/core/multitransport.h index 631bc0af0..fac3c93c8 100644 --- a/libfreerdp/core/multitransport.h +++ b/libfreerdp/core/multitransport.h @@ -29,14 +29,21 @@ typedef struct rdp_multitransport rdpMultitransport; #include -struct rdp_multitransport +typedef enum { - UINT32 placeholder; -}; + INITIATE_REQUEST_PROTOCOL_UDPFECR = 0x01, + INITIATE_REQUEST_PROTOCOL_UDPFECL = 0x02 +} MultitransportRequestProtocol; -FREERDP_LOCAL int rdp_recv_multitransport_packet(rdpRdp* rdp, wStream* s); +FREERDP_LOCAL int multitransport_client_recv_request(rdpMultitransport* multitransport, wStream* s); +FREERDP_LOCAL BOOL multitransport_server_send_request(rdpMultitransport* multitransport); -FREERDP_LOCAL rdpMultitransport* multitransport_new(void); +FREERDP_LOCAL BOOL multitransport_server_recv_response(rdpMultitransport* multitransport, + wStream* s, HRESULT* hr); +FREERDP_LOCAL BOOL multitransport_client_send_response(rdpMultitransport* multitransport, + HRESULT hr); + +FREERDP_LOCAL rdpMultitransport* multitransport_new(rdpRdp* rdp, UINT16 protocol); FREERDP_LOCAL void multitransport_free(rdpMultitransport* multitransport); #endif /* FREERDP_LIB_CORE_MULTITRANSPORT_H */ diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c index 2253f1d70..b10aed05a 100644 --- a/libfreerdp/core/rdp.c +++ b/libfreerdp/core/rdp.c @@ -1194,11 +1194,26 @@ int rdp_recv_message_channel_pdu(rdpRdp* rdp, wStream* s, UINT16 securityFlags) if (securityFlags & SEC_TRANSPORT_REQ) { + HRESULT hr = E_ABORT; /* Initiate Multitransport Request PDU */ - return rdp_recv_multitransport_packet(rdp, s); + // TODO: This message is server -> client only + int rc = multitransport_client_recv_request(rdp->multitransport, s); + if (rc < 0) + return rc; + if (!multitransport_client_send_response(rdp->multitransport, hr)) + return -1; + return 1; } - return -1; + if (securityFlags & SEC_TRANSPORT_RSP) + { + /* Initiate Multitransport Request PDU */ + HRESULT hr; // TODO: Do something with this result + // TODO: This message is client -> server only + return multitransport_server_recv_response(rdp->multitransport, s, &hr) ? 0 : -1; + } + + return 1; } int rdp_recv_out_of_sequence_pdu(rdpRdp* rdp, wStream* s) @@ -1969,7 +1984,8 @@ rdpRdp* rdp_new(rdpContext* context) if (!rdp->heartbeat) goto fail; - rdp->multitransport = multitransport_new(); + rdp->multitransport = multitransport_new(rdp, INITIATE_REQUEST_PROTOCOL_UDPFECL | + INITIATE_REQUEST_PROTOCOL_UDPFECR); if (!rdp->multitransport) goto fail;