From f1bde376b117cd3ba053ce09fb3b36f79395376d Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 26 Aug 2021 16:17:51 +0200 Subject: [PATCH] Raw channel send (#7255) * Added raw channel data write function * Use nego_set_state * Added ArrayList_ForEachAP * Provide va_copy for older VS compilers --- include/freerdp/freerdp.h | 11 +- include/freerdp/peer.h | 4 + libfreerdp/core/channels.c | 43 ++-- libfreerdp/core/channels.h | 2 + libfreerdp/core/freerdp.c | 14 ++ libfreerdp/core/nego.c | 217 ++++++++++++------- libfreerdp/core/peer.c | 12 + libfreerdp/core/rdp.c | 13 +- libfreerdp/core/rdp.h | 2 + winpr/include/winpr/collections.h | 1 + winpr/libwinpr/utils/collections/ArrayList.c | 27 ++- 11 files changed, 240 insertions(+), 106 deletions(-) diff --git a/include/freerdp/freerdp.h b/include/freerdp/freerdp.h index eeea7f972..98e8c650f 100644 --- a/include/freerdp/freerdp.h +++ b/include/freerdp/freerdp.h @@ -197,6 +197,8 @@ extern "C" typedef BOOL (*pSendChannelData)(freerdp* instance, UINT16 channelId, const BYTE* data, size_t size); + typedef BOOL (*pSendChannelPacket)(freerdp* instance, UINT16 channelId, size_t totalSize, + UINT32 flags, const BYTE* data, size_t chunkSize); typedef BOOL (*pReceiveChannelData)(freerdp* instance, UINT16 channelId, const BYTE* data, size_t size, UINT32 flags, size_t totalSize); @@ -429,7 +431,14 @@ fingerprint. DEPRECATED: Use VerifyChangedCertificateEx */ VerifyChangedCertificateEx; /**< (offset 67) Callback for changed certificate validation. Used when a certificate differs from stored fingerprint. */ - UINT64 paddingE[80 - 68]; /* 68 */ + + ALIGN64 pSendChannelPacket + SendChannelPacket; /* (offset 68) + * Callback for sending RAW data to a channel. In contrast to + * SendChannelData data fragmentation is up to the user and this + * function sends data as is with the provided flags. + */ + UINT64 paddingE[80 - 69]; /* 69 */ }; struct rdp_channel_handles diff --git a/include/freerdp/peer.h b/include/freerdp/peer.h index 2c504c8a1..be731a4ef 100644 --- a/include/freerdp/peer.h +++ b/include/freerdp/peer.h @@ -54,6 +54,8 @@ typedef BOOL (*psPeerClientCapabilities)(freerdp_peer* peer); typedef BOOL (*psPeerSendChannelData)(freerdp_peer* peer, UINT16 channelId, const BYTE* data, size_t size); +typedef BOOL (*psPeerSendChannelPacket)(freerdp_peer* client, UINT16 channelId, size_t totalSize, + UINT32 flags, const BYTE* data, size_t chunkSize); typedef BOOL (*psPeerReceiveChannelData)(freerdp_peer* peer, UINT16 channelId, const BYTE* data, size_t size, UINT32 flags, size_t totalSize); @@ -134,6 +136,8 @@ struct rdp_freerdp_peer psPeerClientCapabilities ClientCapabilities; psPeerComputeNtlmHash ComputeNtlmHash; psPeerLicenseCallback LicenseCallback; + + psPeerSendChannelPacket SendChannelPacket; }; #ifdef __cplusplus diff --git a/libfreerdp/core/channels.c b/libfreerdp/core/channels.c index 6beb706a6..4180bbfa6 100644 --- a/libfreerdp/core/channels.c +++ b/libfreerdp/core/channels.c @@ -53,7 +53,6 @@ BOOL freerdp_channel_send(rdpRdp* rdp, UINT16 channelId, const BYTE* data, size_ { DWORD i; size_t left; - wStream* s; UINT32 flags; size_t chunkSize; rdpMcs* mcs = rdp->mcs; @@ -80,11 +79,6 @@ BOOL freerdp_channel_send(rdpRdp* rdp, UINT16 channelId, const BYTE* data, size_ while (left > 0) { - s = rdp_send_stream_init(rdp); - - if (!s) - return FALSE; - if (left > rdp->settings->VirtualChannelChunkSize) { chunkSize = rdp->settings->VirtualChannelChunkSize; @@ -100,19 +94,7 @@ BOOL freerdp_channel_send(rdpRdp* rdp, UINT16 channelId, const BYTE* data, size_ flags |= CHANNEL_FLAG_SHOW_PROTOCOL; } - Stream_Write_UINT32(s, size); - Stream_Write_UINT32(s, flags); - - if (!Stream_EnsureCapacity(s, chunkSize)) - { - Stream_Release(s); - return FALSE; - } - - Stream_Write(s, data, chunkSize); - - /* WLog_DBG(TAG, "%s: sending data (flags=0x%x size=%d)", __FUNCTION__, flags, size); */ - if (!rdp_send(rdp, s, channelId)) + if (!freerdp_channel_send_packet(rdp, channelId, size, flags, data, chunkSize)) return FALSE; data += chunkSize; @@ -299,3 +281,26 @@ const WtsApiFunctionTable* FreeRDP_InitWtsApi(void) { return &FreeRDP_WtsApiFunctionTable; } + +BOOL freerdp_channel_send_packet(rdpRdp* rdp, UINT16 channelId, size_t totalSize, UINT32 flags, + const BYTE* data, size_t chunkSize) +{ + wStream* s = rdp_send_stream_init(rdp); + + if (!s) + return FALSE; + + Stream_Write_UINT32(s, totalSize); + Stream_Write_UINT32(s, flags); + + if (!Stream_EnsureCapacity(s, chunkSize)) + { + Stream_Release(s); + return FALSE; + } + + Stream_Write(s, data, chunkSize); + + /* WLog_DBG(TAG, "%s: sending data (flags=0x%x size=%d)", __FUNCTION__, flags, size); */ + return rdp_send(rdp, s, channelId); +} diff --git a/libfreerdp/core/channels.h b/libfreerdp/core/channels.h index de443cf20..3c9112630 100644 --- a/libfreerdp/core/channels.h +++ b/libfreerdp/core/channels.h @@ -25,6 +25,8 @@ FREERDP_LOCAL BOOL freerdp_channel_send(rdpRdp* rdp, UINT16 channelId, const BYTE* data, size_t size); +FREERDP_LOCAL BOOL freerdp_channel_send_packet(rdpRdp* rdp, UINT16 channelId, size_t totalSize, + UINT32 flags, const BYTE* data, size_t chunkSize); FREERDP_LOCAL BOOL freerdp_channel_process(freerdp* instance, wStream* s, UINT16 channelId, size_t packetLength); FREERDP_LOCAL BOOL freerdp_channel_peer_process(freerdp_peer* client, wStream* s, UINT16 channelId); diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index c18be72e7..491aa4853 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -410,9 +410,22 @@ int freerdp_message_queue_process_pending_messages(freerdp* instance, DWORD id) static BOOL freerdp_send_channel_data(freerdp* instance, UINT16 channelId, const BYTE* data, size_t size) { + WINPR_ASSERT(instance); + WINPR_ASSERT(instance->context); + WINPR_ASSERT(instance->context->rdp); return rdp_send_channel_data(instance->context->rdp, channelId, data, size); } +static BOOL freerdp_send_channel_packet(freerdp* instance, UINT16 channelId, size_t totalSize, + UINT32 flags, const BYTE* data, size_t chunkSize) +{ + WINPR_ASSERT(instance); + WINPR_ASSERT(instance->context); + WINPR_ASSERT(instance->context->rdp); + return rdp_channel_send_packet(instance->context->rdp, channelId, totalSize, flags, data, + chunkSize); +} + BOOL freerdp_disconnect(freerdp* instance) { BOOL rc = TRUE; @@ -869,6 +882,7 @@ freerdp* freerdp_new(void) instance->ContextSize = sizeof(rdpContext); instance->SendChannelData = freerdp_send_channel_data; + instance->SendChannelPacket = freerdp_send_channel_packet; instance->ReceiveChannelData = freerdp_channels_data; return instance; } diff --git a/libfreerdp/core/nego.c b/libfreerdp/core/nego.c index 5ec02bcc7..7e9462296 100644 --- a/libfreerdp/core/nego.c +++ b/libfreerdp/core/nego.c @@ -25,6 +25,7 @@ #endif #include +#include #include @@ -103,30 +104,33 @@ static BOOL nego_process_negotiation_failure(rdpNego* nego, wStream* s); BOOL nego_connect(rdpNego* nego) { - rdpSettings* settings = nego->transport->settings; - - if (nego->state == NEGO_STATE_INITIAL) + rdpSettings* settings; + WINPR_ASSERT(nego); + WINPR_ASSERT(nego->transport); + settings = nego->transport->settings; + WINPR_ASSERT(settings); + if (nego_get_state(nego) == NEGO_STATE_INITIAL) { if (nego->EnabledProtocols[PROTOCOL_HYBRID_EX]) { - nego->state = NEGO_STATE_EXT; + nego_set_state(nego, NEGO_STATE_EXT); } else if (nego->EnabledProtocols[PROTOCOL_HYBRID]) { - nego->state = NEGO_STATE_NLA; + nego_set_state(nego, NEGO_STATE_NLA); } else if (nego->EnabledProtocols[PROTOCOL_SSL]) { - nego->state = NEGO_STATE_TLS; + nego_set_state(nego, NEGO_STATE_TLS); } else if (nego->EnabledProtocols[PROTOCOL_RDP]) { - nego->state = NEGO_STATE_RDP; + nego_set_state(nego, NEGO_STATE_RDP); } else { WLog_ERR(TAG, "No security protocol is enabled"); - nego->state = NEGO_STATE_FAIL; + nego_set_state(nego, NEGO_STATE_FAIL); return FALSE; } @@ -139,26 +143,28 @@ BOOL nego_connect(rdpNego* nego) nego->EnabledProtocols[PROTOCOL_RDP] = FALSE; nego->EnabledProtocols[PROTOCOL_HYBRID_EX] = FALSE; - if (nego->state == NEGO_STATE_EXT) + switch (nego_get_state(nego)) { - nego->EnabledProtocols[PROTOCOL_HYBRID_EX] = TRUE; - nego->EnabledProtocols[PROTOCOL_HYBRID] = TRUE; - nego->SelectedProtocol = PROTOCOL_HYBRID_EX; - } - else if (nego->state == NEGO_STATE_NLA) - { - nego->EnabledProtocols[PROTOCOL_HYBRID] = TRUE; - nego->SelectedProtocol = PROTOCOL_HYBRID; - } - else if (nego->state == NEGO_STATE_TLS) - { - nego->EnabledProtocols[PROTOCOL_SSL] = TRUE; - nego->SelectedProtocol = PROTOCOL_SSL; - } - else if (nego->state == NEGO_STATE_RDP) - { - nego->EnabledProtocols[PROTOCOL_RDP] = TRUE; - nego->SelectedProtocol = PROTOCOL_RDP; + case NEGO_STATE_EXT: + nego->EnabledProtocols[PROTOCOL_HYBRID_EX] = TRUE; + nego->EnabledProtocols[PROTOCOL_HYBRID] = TRUE; + nego->SelectedProtocol = PROTOCOL_HYBRID_EX; + break; + case NEGO_STATE_NLA: + nego->EnabledProtocols[PROTOCOL_HYBRID] = TRUE; + nego->SelectedProtocol = PROTOCOL_HYBRID; + break; + case NEGO_STATE_TLS: + nego->EnabledProtocols[PROTOCOL_SSL] = TRUE; + nego->SelectedProtocol = PROTOCOL_SSL; + break; + case NEGO_STATE_RDP: + nego->EnabledProtocols[PROTOCOL_RDP] = TRUE; + nego->SelectedProtocol = PROTOCOL_RDP; + break; + default: + WLog_ERR(TAG, "Invalid NEGO state 0x%08" PRIx32, nego_get_state(nego)); + return FALSE; } } @@ -167,7 +173,7 @@ BOOL nego_connect(rdpNego* nego) if (!nego_send_preconnection_pdu(nego)) { WLog_ERR(TAG, "Failed to send preconnection pdu"); - nego->state = NEGO_STATE_FINAL; + nego_set_state(nego, NEGO_STATE_FINAL); return FALSE; } } @@ -175,24 +181,24 @@ BOOL nego_connect(rdpNego* nego) if (!nego->NegotiateSecurityLayer) { - nego->state = NEGO_STATE_FINAL; + nego_set_state(nego, NEGO_STATE_FINAL); } else { do { - WLog_DBG(TAG, "state: %s", nego_state_string(nego->state)); + WLog_DBG(TAG, "state: %s", nego_state_string(nego_get_state(nego))); nego_send(nego); - if (nego->state == NEGO_STATE_FAIL) + if (nego_get_state(nego) == NEGO_STATE_FAIL) { if (freerdp_get_last_error(nego->transport->context) == FREERDP_ERROR_SUCCESS) WLog_ERR(TAG, "Protocol Security Negotiation Failure"); - nego->state = NEGO_STATE_FINAL; + nego_set_state(nego, NEGO_STATE_FINAL); return FALSE; } - } while (nego->state != NEGO_STATE_FINAL); + } while (nego_get_state(nego) != NEGO_STATE_FINAL); } WLog_DBG(TAG, "Negotiated %s security", protocol_security_string(nego->SelectedProtocol)); @@ -229,13 +235,15 @@ BOOL nego_connect(rdpNego* nego) BOOL nego_disconnect(rdpNego* nego) { - nego->state = NEGO_STATE_INITIAL; + WINPR_ASSERT(nego); + nego_set_state(nego, NEGO_STATE_INITIAL); return nego_transport_disconnect(nego); } /* connect to selected security layer */ BOOL nego_security_connect(rdpNego* nego) { + WINPR_ASSERT(nego); if (!nego->TcpConnected) { nego->SecurityConnected = FALSE; @@ -275,6 +283,7 @@ BOOL nego_security_connect(rdpNego* nego) static BOOL nego_tcp_connect(rdpNego* nego) { + WINPR_ASSERT(nego); if (!nego->TcpConnected) { const UINT32 TcpConnectTimeout = freerdp_settings_get_uint32( @@ -318,6 +327,7 @@ static BOOL nego_tcp_connect(rdpNego* nego) BOOL nego_transport_connect(rdpNego* nego) { + WINPR_ASSERT(nego); if (!nego_tcp_connect(nego)) return FALSE; @@ -335,6 +345,7 @@ BOOL nego_transport_connect(rdpNego* nego) BOOL nego_transport_disconnect(rdpNego* nego) { + WINPR_ASSERT(nego); if (nego->TcpConnected) transport_disconnect(nego->transport); @@ -355,6 +366,9 @@ BOOL nego_send_preconnection_pdu(rdpNego* nego) UINT32 cbSize; UINT16 cchPCB = 0; WCHAR* wszPCB = NULL; + + WINPR_ASSERT(nego); + WLog_DBG(TAG, "Sending preconnection PDU"); if (!nego_tcp_connect(nego)) @@ -410,41 +424,42 @@ BOOL nego_send_preconnection_pdu(rdpNego* nego) static void nego_attempt_ext(rdpNego* nego) { + WINPR_ASSERT(nego); nego->RequestedProtocols = PROTOCOL_HYBRID | PROTOCOL_SSL | PROTOCOL_HYBRID_EX; WLog_DBG(TAG, "Attempting NLA extended security"); if (!nego_transport_connect(nego)) { - nego->state = NEGO_STATE_FAIL; + nego_set_state(nego, NEGO_STATE_FAIL); return; } if (!nego_send_negotiation_request(nego)) { - nego->state = NEGO_STATE_FAIL; + nego_set_state(nego, NEGO_STATE_FAIL); return; } if (!nego_recv_response(nego)) { - nego->state = NEGO_STATE_FAIL; + nego_set_state(nego, NEGO_STATE_FAIL); return; } - WLog_DBG(TAG, "state: %s", nego_state_string(nego->state)); + WLog_DBG(TAG, "state: %s", nego_state_string(nego_get_state(nego))); - if (nego->state != NEGO_STATE_FINAL) + if (nego_get_state(nego) != NEGO_STATE_FINAL) { nego_transport_disconnect(nego); if (nego->EnabledProtocols[PROTOCOL_HYBRID]) - nego->state = NEGO_STATE_NLA; + nego_set_state(nego, NEGO_STATE_NLA); else if (nego->EnabledProtocols[PROTOCOL_SSL]) - nego->state = NEGO_STATE_TLS; + nego_set_state(nego, NEGO_STATE_TLS); else if (nego->EnabledProtocols[PROTOCOL_RDP]) - nego->state = NEGO_STATE_RDP; + nego_set_state(nego, NEGO_STATE_RDP); else - nego->state = NEGO_STATE_FAIL; + nego_set_state(nego, NEGO_STATE_FAIL); } } @@ -455,39 +470,40 @@ static void nego_attempt_ext(rdpNego* nego) static void nego_attempt_nla(rdpNego* nego) { + WINPR_ASSERT(nego); nego->RequestedProtocols = PROTOCOL_HYBRID | PROTOCOL_SSL; WLog_DBG(TAG, "Attempting NLA security"); if (!nego_transport_connect(nego)) { - nego->state = NEGO_STATE_FAIL; + nego_set_state(nego, NEGO_STATE_FAIL); return; } if (!nego_send_negotiation_request(nego)) { - nego->state = NEGO_STATE_FAIL; + nego_set_state(nego, NEGO_STATE_FAIL); return; } if (!nego_recv_response(nego)) { - nego->state = NEGO_STATE_FAIL; + nego_set_state(nego, NEGO_STATE_FAIL); return; } - WLog_DBG(TAG, "state: %s", nego_state_string(nego->state)); + WLog_DBG(TAG, "state: %s", nego_state_string(nego_get_state(nego))); - if (nego->state != NEGO_STATE_FINAL) + if (nego_get_state(nego) != NEGO_STATE_FINAL) { nego_transport_disconnect(nego); if (nego->EnabledProtocols[PROTOCOL_SSL]) - nego->state = NEGO_STATE_TLS; + nego_set_state(nego, NEGO_STATE_TLS); else if (nego->EnabledProtocols[PROTOCOL_RDP]) - nego->state = NEGO_STATE_RDP; + nego_set_state(nego, NEGO_STATE_RDP); else - nego->state = NEGO_STATE_FAIL; + nego_set_state(nego, NEGO_STATE_FAIL); } } @@ -498,35 +514,36 @@ static void nego_attempt_nla(rdpNego* nego) static void nego_attempt_tls(rdpNego* nego) { + WINPR_ASSERT(nego); nego->RequestedProtocols = PROTOCOL_SSL; WLog_DBG(TAG, "Attempting TLS security"); if (!nego_transport_connect(nego)) { - nego->state = NEGO_STATE_FAIL; + nego_set_state(nego, NEGO_STATE_FAIL); return; } if (!nego_send_negotiation_request(nego)) { - nego->state = NEGO_STATE_FAIL; + nego_set_state(nego, NEGO_STATE_FAIL); return; } if (!nego_recv_response(nego)) { - nego->state = NEGO_STATE_FAIL; + nego_set_state(nego, NEGO_STATE_FAIL); return; } - if (nego->state != NEGO_STATE_FINAL) + if (nego_get_state(nego) != NEGO_STATE_FINAL) { nego_transport_disconnect(nego); if (nego->EnabledProtocols[PROTOCOL_RDP]) - nego->state = NEGO_STATE_RDP; + nego_set_state(nego, NEGO_STATE_RDP); else - nego->state = NEGO_STATE_FAIL; + nego_set_state(nego, NEGO_STATE_FAIL); } } @@ -537,24 +554,25 @@ static void nego_attempt_tls(rdpNego* nego) static void nego_attempt_rdp(rdpNego* nego) { + WINPR_ASSERT(nego); nego->RequestedProtocols = PROTOCOL_RDP; WLog_DBG(TAG, "Attempting RDP security"); if (!nego_transport_connect(nego)) { - nego->state = NEGO_STATE_FAIL; + nego_set_state(nego, NEGO_STATE_FAIL); return; } if (!nego_send_negotiation_request(nego)) { - nego->state = NEGO_STATE_FAIL; + nego_set_state(nego, NEGO_STATE_FAIL); return; } if (!nego_recv_response(nego)) { - nego->state = NEGO_STATE_FAIL; + nego_set_state(nego, NEGO_STATE_FAIL); return; } } @@ -568,6 +586,8 @@ BOOL nego_recv_response(rdpNego* nego) { int status; wStream* s; + + WINPR_ASSERT(nego); s = Stream_New(NULL, 1024); if (!s) @@ -608,6 +628,7 @@ int nego_recv(rdpTransport* transport, wStream* s, void* extra) UINT16 length; rdpNego* nego = (rdpNego*)extra; + WINPR_ASSERT(nego); if (!tpkt_read_header(s, &length)) return -1; @@ -633,18 +654,18 @@ int nego_recv(rdpTransport* transport, wStream* s, void* extra) if ((nego->SelectedProtocol == PROTOCOL_HYBRID) && (!nego->EnabledProtocols[PROTOCOL_HYBRID])) { - nego->state = NEGO_STATE_FAIL; + nego_set_state(nego, NEGO_STATE_FAIL); } if ((nego->SelectedProtocol == PROTOCOL_SSL) && (!nego->EnabledProtocols[PROTOCOL_SSL])) { - nego->state = NEGO_STATE_FAIL; + nego_set_state(nego, NEGO_STATE_FAIL); } } else if (!nego->EnabledProtocols[PROTOCOL_RDP]) { - nego->state = NEGO_STATE_FAIL; + nego_set_state(nego, NEGO_STATE_FAIL); } break; @@ -660,14 +681,14 @@ int nego_recv(rdpTransport* transport, wStream* s, void* extra) WLog_DBG(TAG, "no rdpNegData"); if (!nego->EnabledProtocols[PROTOCOL_RDP]) - nego->state = NEGO_STATE_FAIL; + nego_set_state(nego, NEGO_STATE_FAIL); else - nego->state = NEGO_STATE_FINAL; + nego_set_state(nego, NEGO_STATE_FINAL); } else { WLog_ERR(TAG, "invalid negotiation response"); - nego->state = NEGO_STATE_FAIL; + nego_set_state(nego, NEGO_STATE_FAIL); } if (!tpkt_ensure_stream_consumed(s, length)) @@ -701,6 +722,9 @@ static BOOL nego_read_request_token_or_cookie(rdpNego* nego, wStream* s) BOOL result = FALSE; BOOL isToken = FALSE; size_t remain = Stream_GetRemainingLength(s); + + WINPR_ASSERT(nego); + str = Stream_Pointer(s); pos = Stream_GetPosition(s); @@ -772,6 +796,9 @@ BOOL nego_read_request(rdpNego* nego, wStream* s) BYTE type; UINT16 length; + WINPR_ASSERT(nego); + WINPR_ASSERT(s); + if (!tpkt_read_header(s, &length)) return FALSE; @@ -815,16 +842,26 @@ BOOL nego_read_request(rdpNego* nego, wStream* s) void nego_send(rdpNego* nego) { - if (nego->state == NEGO_STATE_EXT) - nego_attempt_ext(nego); - else if (nego->state == NEGO_STATE_NLA) - nego_attempt_nla(nego); - else if (nego->state == NEGO_STATE_TLS) - nego_attempt_tls(nego); - else if (nego->state == NEGO_STATE_RDP) - nego_attempt_rdp(nego); - else - WLog_ERR(TAG, "invalid negotiation state for sending"); + WINPR_ASSERT(nego); + + switch (nego_get_state(nego)) + { + case NEGO_STATE_EXT: + nego_attempt_ext(nego); + break; + case NEGO_STATE_NLA: + nego_attempt_nla(nego); + break; + case NEGO_STATE_TLS: + nego_attempt_tls(nego); + break; + case NEGO_STATE_RDP: + nego_attempt_rdp(nego); + break; + default: + WLog_ERR(TAG, "invalid negotiation state for sending"); + break; + } } /** @@ -844,6 +881,7 @@ BOOL nego_send_negotiation_request(rdpNego* nego) size_t cookie_length; s = Stream_New(NULL, 512); + WINPR_ASSERT(nego); if (!s) { WLog_ERR(TAG, "Stream_New failed!"); @@ -930,13 +968,16 @@ BOOL nego_process_negotiation_request(rdpNego* nego, wStream* s) BYTE flags; UINT16 length; + WINPR_ASSERT(nego); + WINPR_ASSERT(s); + if (Stream_GetRemainingLength(s) < 7) return FALSE; Stream_Read_UINT8(s, flags); Stream_Read_UINT16(s, length); Stream_Read_UINT32(s, nego->RequestedProtocols); WLog_DBG(TAG, "RDP_NEG_REQ: RequestedProtocol: 0x%08" PRIX32 "", nego->RequestedProtocols); - nego->state = NEGO_STATE_FINAL; + nego_set_state(nego, NEGO_STATE_FINAL); return TRUE; } @@ -951,17 +992,20 @@ BOOL nego_process_negotiation_response(rdpNego* nego, wStream* s) UINT16 length; WLog_DBG(TAG, "RDP_NEG_RSP"); + WINPR_ASSERT(nego); + WINPR_ASSERT(s); + if (Stream_GetRemainingLength(s) < 7) { WLog_ERR(TAG, "Invalid RDP_NEG_RSP"); - nego->state = NEGO_STATE_FAIL; + nego_set_state(nego, NEGO_STATE_FAIL); return FALSE; } Stream_Read_UINT8(s, nego->flags); Stream_Read_UINT16(s, length); Stream_Read_UINT32(s, nego->SelectedProtocol); - nego->state = NEGO_STATE_FINAL; + nego_set_state(nego, NEGO_STATE_FINAL); return TRUE; } @@ -976,6 +1020,10 @@ BOOL nego_process_negotiation_failure(rdpNego* nego, wStream* s) BYTE flags; UINT16 length; UINT32 failureCode; + + WINPR_ASSERT(nego); + WINPR_ASSERT(s); + WLog_DBG(TAG, "RDP_NEG_FAILURE"); if (Stream_GetRemainingLength(s) < 7) return FALSE; @@ -1012,7 +1060,7 @@ BOOL nego_process_negotiation_failure(rdpNego* nego, wStream* s) break; } - nego->state = NEGO_STATE_FAIL; + nego_set_state(nego, NEGO_STATE_FAIL); return TRUE; } @@ -1029,8 +1077,14 @@ BOOL nego_send_negotiation_response(rdpNego* nego) wStream* s; BYTE flags; rdpSettings* settings; + + WINPR_ASSERT(nego); + WINPR_ASSERT(nego->transport); + status = TRUE; settings = nego->transport->settings; + WINPR_ASSERT(settings); + s = Stream_New(NULL, 512); if (!s) @@ -1151,7 +1205,8 @@ BOOL nego_send_negotiation_response(rdpNego* nego) void nego_init(rdpNego* nego) { - nego->state = NEGO_STATE_INITIAL; + WINPR_ASSERT(nego); + nego_set_state(nego, NEGO_STATE_INITIAL); nego->RequestedProtocols = PROTOCOL_RDP; nego->CookieMaxLength = DEFAULT_COOKIE_MAX_LENGTH; nego->sendNegoData = FALSE; diff --git a/libfreerdp/core/peer.c b/libfreerdp/core/peer.c index 173fe26ec..5413dc3d9 100644 --- a/libfreerdp/core/peer.c +++ b/libfreerdp/core/peer.c @@ -844,6 +844,17 @@ static BOOL freerdp_peer_send_channel_data(freerdp_peer* client, UINT16 channelI return rdp_send_channel_data(client->context->rdp, channelId, data, size); } +static BOOL freerdp_peer_send_channel_packet(freerdp_peer* client, UINT16 channelId, + size_t totalSize, UINT32 flags, const BYTE* data, + size_t chunkSize) +{ + WINPR_ASSERT(client); + WINPR_ASSERT(client->context); + WINPR_ASSERT(client->context->rdp); + return rdp_channel_send_packet(client->context->rdp, channelId, totalSize, flags, data, + chunkSize); +} + static BOOL freerdp_peer_is_write_blocked(freerdp_peer* peer) { rdpTransport* transport; @@ -1013,6 +1024,7 @@ freerdp_peer* freerdp_peer_new(int sockfd) client->Close = freerdp_peer_close; client->Disconnect = freerdp_peer_disconnect; client->SendChannelData = freerdp_peer_send_channel_data; + client->SendChannelPacket = freerdp_peer_send_channel_packet; client->IsWriteBlocked = freerdp_peer_is_write_blocked; client->DrainOutputBuffer = freerdp_peer_drain_output_buffer; client->HasMoreToRead = freerdp_peer_has_more_to_read; diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c index ffc6ff02f..5a1bfb70e 100644 --- a/libfreerdp/core/rdp.c +++ b/libfreerdp/core/rdp.c @@ -283,7 +283,12 @@ static BOOL rdp_security_stream_init(rdpRdp* rdp, wStream* s, BOOL sec_header) wStream* rdp_send_stream_init(rdpRdp* rdp) { - wStream* s = transport_send_stream_init(rdp->transport, 4096); + wStream* s; + + WINPR_ASSERT(rdp); + WINPR_ASSERT(rdp->transport); + + s = transport_send_stream_init(rdp->transport, 4096); if (!s) return NULL; @@ -1682,6 +1687,12 @@ BOOL rdp_send_channel_data(rdpRdp* rdp, UINT16 channelId, const BYTE* data, size return freerdp_channel_send(rdp, channelId, data, size); } +BOOL rdp_channel_send_packet(rdpRdp* rdp, UINT16 channelId, size_t totalSize, UINT32 flags, + const BYTE* data, size_t chunkSize) +{ + return freerdp_channel_send_packet(rdp, channelId, totalSize, flags, data, chunkSize); +} + BOOL rdp_send_error_info(rdpRdp* rdp) { wStream* s; diff --git a/libfreerdp/core/rdp.h b/libfreerdp/core/rdp.h index 67bfcd019..cbd0553f3 100644 --- a/libfreerdp/core/rdp.h +++ b/libfreerdp/core/rdp.h @@ -210,6 +210,8 @@ FREERDP_LOCAL BOOL rdp_send(rdpRdp* rdp, wStream* s, UINT16 channelId); FREERDP_LOCAL BOOL rdp_send_channel_data(rdpRdp* rdp, UINT16 channelId, const BYTE* data, size_t size); +FREERDP_LOCAL BOOL rdp_channel_send_packet(rdpRdp* rdp, UINT16 channelId, size_t totalSize, + UINT32 flags, const BYTE* data, size_t chunkSize); FREERDP_LOCAL wStream* rdp_message_channel_pdu_init(rdpRdp* rdp); FREERDP_LOCAL BOOL rdp_send_message_channel_pdu(rdpRdp* rdp, wStream* s, UINT16 sec_flags); diff --git a/winpr/include/winpr/collections.h b/winpr/include/winpr/collections.h index d0b985e78..c114e551a 100644 --- a/winpr/include/winpr/collections.h +++ b/winpr/include/winpr/collections.h @@ -120,6 +120,7 @@ extern "C" typedef BOOL (*ArrayList_ForEachFkt)(void* data, size_t index, va_list ap); WINPR_API BOOL ArrayList_ForEach(wArrayList* arrayList, ArrayList_ForEachFkt fkt, ...); + WINPR_API BOOL ArrayList_ForEachAP(wArrayList* arrayList, ArrayList_ForEachFkt fkt, va_list ap); WINPR_API void ArrayList_Clear(wArrayList* arrayList); WINPR_API BOOL ArrayList_Contains(wArrayList* arrayList, const void* obj); diff --git a/winpr/libwinpr/utils/collections/ArrayList.c b/winpr/libwinpr/utils/collections/ArrayList.c index 11e2f8b1c..e4f52fc75 100644 --- a/winpr/libwinpr/utils/collections/ArrayList.c +++ b/winpr/libwinpr/utils/collections/ArrayList.c @@ -21,10 +21,16 @@ #include "config.h" #endif +#include + #include #include #include +#if defined(_WIN32) && (_MSC_VER < 1800) +#define va_copy(dest, src) (dest = src) +#endif + struct _wArrayList { size_t capacity; @@ -508,23 +514,36 @@ wObject* ArrayList_Object(wArrayList* arrayList) BOOL ArrayList_ForEach(wArrayList* arrayList, ArrayList_ForEachFkt fkt, ...) { - size_t index, count; + BOOL rc; va_list ap; + va_start(ap, fkt); + rc = ArrayList_ForEachAP(arrayList, fkt, ap); + va_end(ap); + + return rc; +} + +BOOL ArrayList_ForEachAP(wArrayList* arrayList, ArrayList_ForEachFkt fkt, va_list ap) +{ + size_t index, count; BOOL rc = FALSE; + va_list cap; WINPR_ASSERT(arrayList); WINPR_ASSERT(fkt); ArrayList_Lock_Conditional(arrayList); count = ArrayList_Count(arrayList); - va_start(ap, fkt); for (index = 0; index < count; index++) { + BOOL rs; void* obj = ArrayList_GetItem(arrayList, index); - if (!fkt(obj, index, ap)) + va_copy(cap, ap); + rs = fkt(obj, index, cap); + va_end(cap); + if (!rs) goto fail; } - va_end(ap); rc = TRUE; fail: ArrayList_Unlock_Conditional(arrayList);