diff --git a/libfreerdp/core/gateway/http.c b/libfreerdp/core/gateway/http.c index 46bcd800c..e205a483e 100644 --- a/libfreerdp/core/gateway/http.c +++ b/libfreerdp/core/gateway/http.c @@ -502,6 +502,7 @@ HttpResponse* http_response_recv(rdpTls* tls) char* content; char* header_end; HttpResponse* http_response; + nbytes = 0; length = 10000; content = NULL; @@ -545,17 +546,18 @@ HttpResponse* http_response_recv(rdpTls* tls) if (!header_end) { - WLog_ERR(TAG, "invalid response:"); + WLog_ERR(TAG, "invalid response"); winpr_HexDump(TAG, WLOG_ERROR, buffer, status); goto out_error; } header_end += 2; - if (header_end != NULL) + if (header_end) { int count; char* line; + header_end[0] = '\0'; header_end[1] = '\0'; content = header_end + 2; @@ -581,7 +583,7 @@ HttpResponse* http_response_recv(rdpTls* tls) count = 0; line = strtok((char*) buffer, "\r\n"); - while ((line != NULL) && http_response->lines) + while (line && http_response->lines) { http_response->lines[count] = _strdup(line); diff --git a/libfreerdp/core/gateway/rpc.c b/libfreerdp/core/gateway/rpc.c index fee5a6b1b..baf915de3 100644 --- a/libfreerdp/core/gateway/rpc.c +++ b/libfreerdp/core/gateway/rpc.c @@ -387,6 +387,7 @@ int rpc_write(rdpRpc* rpc, BYTE* data, int length, UINT16 opnum) request_pdu->alloc_hint = length; request_pdu->p_cont_id = 0x0000; request_pdu->opnum = opnum; + clientCall = rpc_client_call_new(request_pdu->call_id, request_pdu->opnum); if (!clientCall) @@ -465,7 +466,56 @@ out_free_pdu: return -1; } -BOOL rpc_connect(rdpRpc* rpc) +int rpc_check(rdpRpc* rpc) +{ + RPC_PDU* pdu; + + if (rpc->State == RPC_CLIENT_STATE_ESTABLISHED) + { + if (rpc_send_bind_pdu(rpc) < 0) + { + WLog_ERR(TAG, "rpc_send_bind_pdu failure"); + return -1; + } + + rpc->State = RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK; + } + else if (rpc->State == RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK) + { + pdu = rpc_recv_dequeue_pdu(rpc, TRUE); + + if (!pdu) + { + WLog_ERR(TAG, "rpc_recv_dequeue_pdu failure"); + return -1; + } + + if (rpc_recv_bind_ack_pdu(rpc, Stream_Buffer(pdu->s), Stream_Length(pdu->s)) <= 0) + { + WLog_ERR(TAG, "rpc_recv_bind_ack_pdu failure"); + return -1; + } + + rpc_client_receive_pool_return(rpc, pdu); + + if (rpc_send_rpc_auth_3_pdu(rpc) <= 0) + { + WLog_ERR(TAG, "rpc_secure_bind: error sending rpc_auth_3 pdu!"); + return -1; + } + + rpc->State = RPC_CLIENT_STATE_CONTEXT_NEGOTIATED; + } + else + { + WLog_ERR(TAG, "rpc_check: invalid state: %d", rpc->State); + return -1; + } + + return 1; +} + +int rpc_connect(rdpRpc* rpc) { rpc->TlsIn = rpc->transport->TlsIn; rpc->TlsOut = rpc->transport->TlsOut; @@ -473,18 +523,19 @@ BOOL rpc_connect(rdpRpc* rpc) if (!rts_connect(rpc)) { WLog_ERR(TAG, "rts_connect error!"); - return FALSE; + return -1; } - rpc->State = RPC_CLIENT_STATE_ESTABLISHED; - - if (rpc_secure_bind(rpc) != 0) + while (rpc->State != RPC_CLIENT_STATE_CONTEXT_NEGOTIATED) { - WLog_ERR(TAG, "rpc_secure_bind error!"); - return FALSE; + if (rpc_check(rpc) < 0) + { + WLog_ERR(TAG, "rpc_check failure"); + return -1; + } } - return TRUE; + return 1; } void rpc_client_virtual_connection_init(rdpRpc* rpc, RpcVirtualConnection* connection) @@ -494,7 +545,6 @@ void rpc_client_virtual_connection_init(rdpRpc* rpc, RpcVirtualConnection* conne connection->DefaultInChannel->SenderAvailableWindow = rpc->ReceiveWindow; connection->DefaultInChannel->PingOriginator.ConnectionTimeout = 30; connection->DefaultInChannel->PingOriginator.KeepAliveInterval = 0; - connection->DefaultInChannel->Mutex = CreateMutex(NULL, FALSE, NULL); connection->DefaultOutChannel->State = CLIENT_OUT_CHANNEL_STATE_INITIAL; connection->DefaultOutChannel->BytesReceived = 0; @@ -502,7 +552,6 @@ void rpc_client_virtual_connection_init(rdpRpc* rpc, RpcVirtualConnection* conne connection->DefaultOutChannel->ReceiveWindow = rpc->ReceiveWindow; connection->DefaultOutChannel->ReceiveWindowSize = rpc->ReceiveWindow; connection->DefaultOutChannel->AvailableWindowAdvertised = rpc->ReceiveWindow; - connection->DefaultOutChannel->Mutex = CreateMutex(NULL, FALSE, NULL); } RpcVirtualConnection* rpc_client_virtual_connection_new(rdpRpc* rpc) @@ -536,8 +585,6 @@ void rpc_client_virtual_connection_free(RpcVirtualConnection* virtualConnection) { if (virtualConnection) { - CloseHandle(virtualConnection->DefaultInChannel->Mutex); - CloseHandle(virtualConnection->DefaultOutChannel->Mutex); free(virtualConnection->DefaultInChannel); free(virtualConnection->DefaultOutChannel); free(virtualConnection); diff --git a/libfreerdp/core/gateway/rpc.h b/libfreerdp/core/gateway/rpc.h index 90d1f0449..0a730bf0c 100644 --- a/libfreerdp/core/gateway/rpc.h +++ b/libfreerdp/core/gateway/rpc.h @@ -618,8 +618,6 @@ struct rpc_in_channel CLIENT_IN_CHANNEL_STATE State; - HANDLE Mutex; - UINT32 PlugState; void* SendQueue; UINT32 BytesSent; @@ -651,8 +649,6 @@ struct rpc_out_channel CLIENT_OUT_CHANNEL_STATE State; - HANDLE Mutex; - UINT32 ReceiveWindow; UINT32 ReceiveWindowSize; UINT32 ReceiverAvailableWindow; @@ -778,7 +774,7 @@ struct rdp_rpc wArrayList* VirtualConnectionCookieTable; }; -BOOL rpc_connect(rdpRpc* rpc); +int rpc_connect(rdpRpc* rpc); void rpc_pdu_header_print(rpcconn_hdr_t* header); void rpc_pdu_header_init(rdpRpc* rpc, rpcconn_hdr_t* header); diff --git a/libfreerdp/core/gateway/rpc_bind.c b/libfreerdp/core/gateway/rpc_bind.c index 0f0dddb2f..7ede69dbd 100644 --- a/libfreerdp/core/gateway/rpc_bind.c +++ b/libfreerdp/core/gateway/rpc_bind.c @@ -68,6 +68,29 @@ const p_uuid_t BTFN_UUID = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } /* node[6] */ }; +/** + * Secure Connection-Oriented RPC Packet Sequence + * + * Client Server + * | | + * |-------------------SECURE_BIND-------------------->| + * | | + * |<----------------SECURE_BIND_ACK-------------------| + * | | + * |--------------------RPC_AUTH_3-------------------->| + * | | + * | | + * |------------------REQUEST_PDU_#1------------------>| + * |------------------REQUEST_PDU_#2------------------>| + * | | + * | ... | + * | | + * |<-----------------RESPONSE_PDU_#1------------------| + * |<-----------------RESPONSE_PDU_#2------------------| + * | | + * | ... | + */ + /** * SECURE_BIND: RPC bind PDU with sec_trailer and auth_token. Auth_token is generated by calling * the implementation equivalent of the abstract GSS_Init_sec_context call. Upon receiving that, the @@ -375,87 +398,3 @@ int rpc_send_rpc_auth_3_pdu(rdpRpc* rpc) return status; } - -/** - * Secure Connection-Oriented RPC Packet Sequence - * - * Client Server - * | | - * |-------------------SECURE_BIND-------------------->| - * | | - * |<----------------SECURE_BIND_ACK-------------------| - * | | - * |--------------------RPC_AUTH_3-------------------->| - * | | - * | | - * |------------------REQUEST_PDU_#1------------------>| - * |------------------REQUEST_PDU_#2------------------>| - * | | - * | ... | - * | | - * |<-----------------RESPONSE_PDU_#1------------------| - * |<-----------------RESPONSE_PDU_#2------------------| - * | | - * | ... | - */ - -int rpc_secure_bind(rdpRpc* rpc) -{ - int status; - RPC_PDU* pdu; - - rpc->client->SynchronousSend = TRUE; - rpc->client->SynchronousReceive = TRUE; - - while (rpc->State != RPC_CLIENT_STATE_CONTEXT_NEGOTIATED) - { - if (rpc->State == RPC_CLIENT_STATE_ESTABLISHED) - { - status = rpc_send_bind_pdu(rpc); - - if (status <= 0) - { - WLog_ERR(TAG, "rpc_secure_bind: error sending bind pdu!"); - return -1; - } - - rpc->State = RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK; - } - else if (rpc->State == RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK) - { - pdu = rpc_recv_dequeue_pdu(rpc); - - if (!pdu) - { - WLog_ERR(TAG, "rpc_secure_bind: error receiving bind ack pdu!"); - return -1; - } - - if (rpc_recv_bind_ack_pdu(rpc, Stream_Buffer(pdu->s), Stream_Length(pdu->s)) <= 0) - { - WLog_ERR(TAG, "rpc_secure_bind: error receiving bind ack pdu!"); - return -1; - } - - rpc_client_receive_pool_return(rpc, pdu); - - if (rpc_send_rpc_auth_3_pdu(rpc) <= 0) - { - WLog_ERR(TAG, "rpc_secure_bind: error sending rpc_auth_3 pdu!"); - return -1; - } - - rpc->State = RPC_CLIENT_STATE_CONTEXT_NEGOTIATED; - } - else - { - WLog_ERR(TAG, "rpc_secure_bind: invalid state: %d", rpc->State); - return -1; - } - } - - rpc->client->SynchronousSend = TRUE; - rpc->client->SynchronousReceive = TRUE; - - return 0; -} diff --git a/libfreerdp/core/gateway/rpc_bind.h b/libfreerdp/core/gateway/rpc_bind.h index 136680661..e8a7960b6 100644 --- a/libfreerdp/core/gateway/rpc_bind.h +++ b/libfreerdp/core/gateway/rpc_bind.h @@ -37,6 +37,4 @@ int rpc_send_bind_pdu(rdpRpc* rpc); int rpc_recv_bind_ack_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length); int rpc_send_rpc_auth_3_pdu(rdpRpc* rpc); -int rpc_secure_bind(rdpRpc* rpc); - #endif /* FREERDP_CORE_RPC_BIND_H */ diff --git a/libfreerdp/core/gateway/rpc_client.c b/libfreerdp/core/gateway/rpc_client.c index f356e41d3..601b1124b 100644 --- a/libfreerdp/core/gateway/rpc_client.c +++ b/libfreerdp/core/gateway/rpc_client.c @@ -119,13 +119,13 @@ int rpc_client_receive_pipe_read(rdpRpc* rpc, BYTE* buffer, size_t length) return status; } -int rpc_client_on_pdu_received_event(rdpRpc* rpc, RPC_PDU* pdu) +int rpc_client_on_pdu_received(rdpRpc* rpc, RPC_PDU* pdu) { Queue_Enqueue(rpc->client->ReceiveQueue, pdu); return 1; } -int rpc_client_on_fragment_received_event(rdpRpc* rpc, wStream* fragment) +int rpc_client_on_fragment_received(rdpRpc* rpc, wStream* fragment) { BYTE* buffer; RPC_PDU* pdu; @@ -203,7 +203,7 @@ int rpc_client_on_fragment_received_event(rdpRpc* rpc, wStream* fragment) pdu->Type = PTYPE_RESPONSE; pdu->CallId = rpc->StubCallId; Stream_SealLength(pdu->s); - rpc_client_on_pdu_received_event(rpc, pdu); + rpc_client_on_pdu_received(rpc, pdu); rpc->client->pdu = NULL; rpc->StubFragCount = 0; rpc->StubCallId = 0; @@ -238,7 +238,7 @@ int rpc_client_on_fragment_received_event(rdpRpc* rpc, wStream* fragment) Stream_EnsureCapacity(pdu->s, Stream_Length(fragment)); Stream_Write(pdu->s, buffer, Stream_Length(fragment)); Stream_SealLength(pdu->s); - rpc_client_on_pdu_received_event(rpc, pdu); + rpc_client_on_pdu_received(rpc, pdu); rpc->client->pdu = NULL; return 0; } @@ -264,7 +264,7 @@ int rpc_client_on_fragment_received_event(rdpRpc* rpc, wStream* fragment) Stream_EnsureCapacity(pdu->s, Stream_Length(fragment)); Stream_Write(pdu->s, buffer, Stream_Length(fragment)); Stream_SealLength(pdu->s); - rpc_client_on_pdu_received_event(rpc, pdu); + rpc_client_on_pdu_received(rpc, pdu); rpc->client->pdu = NULL; return 0; } @@ -281,7 +281,7 @@ int rpc_client_on_fragment_received_event(rdpRpc* rpc, wStream* fragment) return 0; } -int rpc_client_on_read_event(rdpRpc* rpc) +int rpc_client_on_read(rdpRpc* rpc) { int position; int status = -1; @@ -347,7 +347,7 @@ int rpc_client_on_read_event(rdpRpc* rpc) Stream_SealLength(rpc->client->ReceiveFragment); Stream_SetPosition(rpc->client->ReceiveFragment, 0); - status = rpc_client_on_fragment_received_event(rpc, rpc->client->ReceiveFragment); + status = rpc_client_on_fragment_received(rpc, rpc->client->ReceiveFragment); if (status < 0) return status; @@ -468,12 +468,10 @@ int rpc_send_dequeue_pdu(rdpRpc* rpc) return 0; inChannel = rpc->VirtualConnection->DefaultInChannel; - WaitForSingleObject(inChannel->Mutex, INFINITE); status = rpc_in_write(rpc, Stream_Buffer(pdu->s), Stream_Length(pdu->s)); header = (rpcconn_common_hdr_t*) Stream_Buffer(pdu->s); clientCall = rpc_client_call_find_by_id(rpc, header->call_id); clientCall->State = RPC_CLIENT_CALL_STATE_DISPATCHED; - ReleaseMutex(inChannel->Mutex); /* * This protocol specifies that only RPC PDUs are subject to the flow control abstract @@ -497,13 +495,13 @@ int rpc_send_dequeue_pdu(rdpRpc* rpc) return status; } -RPC_PDU* rpc_recv_dequeue_pdu(rdpRpc* rpc) +RPC_PDU* rpc_recv_dequeue_pdu(rdpRpc* rpc, BOOL blocking) { RPC_PDU* pdu; DWORD timeout; DWORD waitStatus; - timeout = rpc->client->SynchronousReceive ? SYNCHRONOUS_TIMEOUT * 4 : 0; + timeout = blocking ? SYNCHRONOUS_TIMEOUT * 4 : 0; waitStatus = WaitForSingleObject(Queue_Event(rpc->client->ReceiveQueue), timeout); @@ -543,7 +541,7 @@ static void* rpc_client_thread(void* arg) * the problem for now. */ - if (rpc_client_on_read_event(rpc) < 0) + if (rpc_client_on_read(rpc) < 0) { rpc->transport->layer = TRANSPORT_LAYER_CLOSED; return NULL; @@ -558,7 +556,7 @@ static void* rpc_client_thread(void* arg) if (WaitForSingleObject(ReadEvent, 0) == WAIT_OBJECT_0) { - if (rpc_client_on_read_event(rpc) < 0) + if (rpc_client_on_read(rpc) < 0) { rpc->transport->layer = TRANSPORT_LAYER_CLOSED; break; diff --git a/libfreerdp/core/gateway/rpc_client.h b/libfreerdp/core/gateway/rpc_client.h index 56ae00ba8..88da091da 100644 --- a/libfreerdp/core/gateway/rpc_client.h +++ b/libfreerdp/core/gateway/rpc_client.h @@ -39,7 +39,7 @@ int rpc_send_enqueue_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length); int rpc_send_dequeue_pdu(rdpRpc* rpc); int rpc_recv_enqueue_pdu(rdpRpc* rpc); -RPC_PDU* rpc_recv_dequeue_pdu(rdpRpc* rpc); +RPC_PDU* rpc_recv_dequeue_pdu(rdpRpc* rpc, BOOL blocking); int rpc_client_receive_pipe_read(rdpRpc* rpc, BYTE* buffer, size_t length); diff --git a/libfreerdp/core/gateway/rts.c b/libfreerdp/core/gateway/rts.c index f511280b7..b0bede196 100644 --- a/libfreerdp/core/gateway/rts.c +++ b/libfreerdp/core/gateway/rts.c @@ -94,9 +94,6 @@ BOOL rts_connect(rdpRpc* rpc) rpc->VirtualConnection->State = VIRTUAL_CONNECTION_STATE_INITIAL; WLog_DBG(TAG, "VIRTUAL_CONNECTION_STATE_INITIAL"); - rpc->client->SynchronousSend = TRUE; - rpc->client->SynchronousReceive = TRUE; - if (!rpc_ntlm_http_out_connect(rpc)) { WLog_ERR(TAG, "rpc_out_connect_http error!"); @@ -184,8 +181,6 @@ BOOL rts_connect(rdpRpc* rpc) http_response_free(httpResponse); - rpc_client_start(rpc); - rpc->VirtualConnection->State = VIRTUAL_CONNECTION_STATE_WAIT_A3W; WLog_DBG(TAG, "VIRTUAL_CONNECTION_STATE_WAIT_A3W"); @@ -205,7 +200,9 @@ BOOL rts_connect(rdpRpc* rpc) * */ - pdu = rpc_recv_dequeue_pdu(rpc); + rpc_client_start(rpc); + + pdu = rpc_recv_dequeue_pdu(rpc, TRUE); if (!pdu) return FALSE; @@ -246,7 +243,7 @@ BOOL rts_connect(rdpRpc* rpc) * */ - pdu = rpc_recv_dequeue_pdu(rpc); + pdu = rpc_recv_dequeue_pdu(rpc, TRUE); if (!pdu) return FALSE; @@ -266,8 +263,7 @@ BOOL rts_connect(rdpRpc* rpc) rpc->VirtualConnection->State = VIRTUAL_CONNECTION_STATE_OPENED; WLog_DBG(TAG, "VIRTUAL_CONNECTION_STATE_OPENED"); - rpc->client->SynchronousSend = TRUE; - rpc->client->SynchronousReceive = TRUE; + rpc->State = RPC_CLIENT_STATE_ESTABLISHED; return TRUE; } diff --git a/libfreerdp/core/gateway/tsg.c b/libfreerdp/core/gateway/tsg.c index d9f815cec..7edb5c318 100644 --- a/libfreerdp/core/gateway/tsg.c +++ b/libfreerdp/core/gateway/tsg.c @@ -177,8 +177,6 @@ BOOL TsProxyCreateTunnelWriteRequest(rdpTsg* tsg) *((UINT32*) &buffer[44]) = NapCapabilities; /* capabilities */ - //CopyMemory(&buffer[48], TsProxyCreateTunnelUnknownTrailerBytes, 60); - /** * The following 60-byte structure is apparently undocumented, * but parts of it can be matched to known C706 data structures. @@ -223,6 +221,7 @@ BOOL TsProxyCreateTunnelWriteRequest(rdpTsg* tsg) return FALSE; free(buffer); + return TRUE; } @@ -1093,7 +1092,7 @@ HRESULT TsProxyCloseChannel(rdpTsg* tsg, PCHANNEL_CONTEXT_HANDLE_NOSERIALIZE* co return FALSE; } - pdu = rpc_recv_dequeue_pdu(tsg->rpc); + pdu = rpc_recv_dequeue_pdu(tsg->rpc, TRUE); if (!TsProxyCloseChannelReadResponse(tsg, pdu)) { @@ -1169,7 +1168,7 @@ HRESULT TsProxyCloseTunnel(rdpTsg* tsg, PTUNNEL_CONTEXT_HANDLE_SERIALIZE* contex return FALSE; } - pdu = rpc_recv_dequeue_pdu(tsg->rpc); + pdu = rpc_recv_dequeue_pdu(tsg->rpc, TRUE); if (!TsProxyCloseTunnelReadResponse(tsg, pdu)) { @@ -1250,7 +1249,7 @@ int tsg_check(rdpTsg* tsg) return -1; } - pdu = rpc_recv_dequeue_pdu(rpc); + pdu = rpc_recv_dequeue_pdu(rpc, TRUE); if (!TsProxyCreateTunnelReadResponse(tsg, pdu)) { @@ -1271,7 +1270,7 @@ int tsg_check(rdpTsg* tsg) return -1; } - pdu = rpc_recv_dequeue_pdu(rpc); + pdu = rpc_recv_dequeue_pdu(rpc, TRUE); if (!TsProxyAuthorizeTunnelReadResponse(tsg, pdu)) { @@ -1297,7 +1296,7 @@ int tsg_check(rdpTsg* tsg) return -1; } - pdu = rpc_recv_dequeue_pdu(rpc); + pdu = rpc_recv_dequeue_pdu(rpc, TRUE); if (!pdu) { @@ -1315,7 +1314,7 @@ int tsg_check(rdpTsg* tsg) return -1; } - pdu = rpc_recv_dequeue_pdu(rpc); + pdu = rpc_recv_dequeue_pdu(rpc, TRUE); } if (!TsProxyCreateChannelReadResponse(tsg, pdu)) diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index 79b9a4381..2e6696270 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -351,7 +351,7 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 return FALSE; } - if (!rpc_connect(tsg->rpc)) + if (rpc_connect(tsg->rpc) < 0) { WLog_ERR(TAG, "rpc_connect failed!"); return FALSE;