diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index c248d270b..5d39af6be 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -273,7 +273,7 @@ BOOL rdp_client_connect(rdpRdp* rdp) return FALSE; } - if ((rdp->nego->selected_protocol & PROTOCOL_TLS) || (rdp->nego->selected_protocol == PROTOCOL_RDP)) + if ((rdp->nego->SelectedProtocol & PROTOCOL_TLS) || (rdp->nego->SelectedProtocol == PROTOCOL_RDP)) { if ((settings->Username != NULL) && ((settings->Password != NULL) || (settings->RedirectionPassword != NULL && settings->RedirectionPasswordLength > 0))) @@ -973,26 +973,26 @@ BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s) if (!nego_read_request(nego, s)) return FALSE; - nego->selected_protocol = 0; + nego->SelectedProtocol = 0; WLog_INFO(TAG, "Client Security: NLA:%d TLS:%d RDP:%d", - (nego->requested_protocols & PROTOCOL_NLA) ? 1 : 0, - (nego->requested_protocols & PROTOCOL_TLS) ? 1 : 0, - (nego->requested_protocols == PROTOCOL_RDP) ? 1 : 0 + (nego->RequestedProtocols & PROTOCOL_NLA) ? 1 : 0, + (nego->RequestedProtocols & PROTOCOL_TLS) ? 1 : 0, + (nego->RequestedProtocols == PROTOCOL_RDP) ? 1 : 0 ); WLog_INFO(TAG, "Server Security: NLA:%d TLS:%d RDP:%d", settings->NlaSecurity, settings->TlsSecurity, settings->RdpSecurity); - if ((settings->NlaSecurity) && (nego->requested_protocols & PROTOCOL_NLA)) + if ((settings->NlaSecurity) && (nego->RequestedProtocols & PROTOCOL_NLA)) { - nego->selected_protocol = PROTOCOL_NLA; + nego->SelectedProtocol = PROTOCOL_NLA; } - else if ((settings->TlsSecurity) && (nego->requested_protocols & PROTOCOL_TLS)) + else if ((settings->TlsSecurity) && (nego->RequestedProtocols & PROTOCOL_TLS)) { - nego->selected_protocol = PROTOCOL_TLS; + nego->SelectedProtocol = PROTOCOL_TLS; } - else if ((settings->RdpSecurity) && (nego->selected_protocol == PROTOCOL_RDP)) + else if ((settings->RdpSecurity) && (nego->SelectedProtocol == PROTOCOL_RDP)) { - nego->selected_protocol = PROTOCOL_RDP; + nego->SelectedProtocol = PROTOCOL_RDP; } else { @@ -1000,9 +1000,9 @@ BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s) } WLog_INFO(TAG, "Negotiated Security: NLA:%d TLS:%d RDP:%d", - (nego->selected_protocol & PROTOCOL_NLA) ? 1 : 0, - (nego->selected_protocol & PROTOCOL_TLS) ? 1 : 0, - (nego->selected_protocol == PROTOCOL_RDP) ? 1: 0 + (nego->SelectedProtocol & PROTOCOL_NLA) ? 1 : 0, + (nego->SelectedProtocol & PROTOCOL_TLS) ? 1 : 0, + (nego->SelectedProtocol == PROTOCOL_RDP) ? 1: 0 ); if (!nego_send_negotiation_response(nego)) @@ -1010,11 +1010,11 @@ BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s) status = FALSE; - if (nego->selected_protocol & PROTOCOL_NLA) + if (nego->SelectedProtocol & PROTOCOL_NLA) status = transport_accept_nla(rdp->transport); - else if (nego->selected_protocol & PROTOCOL_TLS) + else if (nego->SelectedProtocol & PROTOCOL_TLS) status = transport_accept_tls(rdp->transport); - else if (nego->selected_protocol == PROTOCOL_RDP) /* 0 */ + else if (nego->SelectedProtocol == PROTOCOL_RDP) /* 0 */ status = transport_accept_rdp(rdp->transport); if (!status) diff --git a/libfreerdp/core/gateway/http.c b/libfreerdp/core/gateway/http.c index 77b7ef938..f7a855b17 100644 --- a/libfreerdp/core/gateway/http.c +++ b/libfreerdp/core/gateway/http.c @@ -34,6 +34,51 @@ #define TAG "gateway" +static char* string_strnstr(const char* str1, const char* str2, size_t slen) +{ + char c, sc; + size_t len; + + if ((c = *str2++) != '\0') + { + len = strlen(str2); + + do + { + do + { + if (slen-- < 1 || (sc = *str1++) == '\0') + return NULL; + } + while(sc != c); + + if (len > slen) + return NULL; + } + while(strncmp(str1, str2, len) != 0); + + str1--; + } + + return ((char*) str1); +} + +static BOOL strings_equals_nocase(void* obj1, void* obj2) +{ + if (!obj1 || !obj2) + return FALSE; + + return _stricmp(obj1, obj2) == 0; +} + +static void string_free(void* obj1) +{ + if (!obj1) + return; + + free(obj1); +} + HttpContext* http_context_new() { return (HttpContext*) calloc(1, sizeof(HttpContext)); @@ -397,6 +442,13 @@ BOOL http_response_parse_header_field(HttpResponse* response, char* name, char* { response->ContentLength = atoi(value); } + else if (_stricmp(name, "Content-Type") == 0) + { + response->ContentType = _strdup(value); + + if (!response->ContentType) + return FALSE; + } else if (_stricmp(name, "WWW-Authenticate") == 0) { char* separator = NULL; @@ -440,6 +492,7 @@ BOOL http_response_parse_header_field(HttpResponse* response, char* name, char* BOOL http_response_parse_header(HttpResponse* response) { + char c; int count; char* line; char* name; @@ -447,7 +500,6 @@ BOOL http_response_parse_header(HttpResponse* response) char* colon_pos; char* end_of_header; char end_of_header_char; - char c; if (!response) return FALSE; @@ -522,22 +574,29 @@ void http_response_print(HttpResponse* response) HttpResponse* http_response_recv(rdpTls* tls) { - int nbytes; - int length; + wStream* s; + int size; + int count; int status; - BYTE* buffer; - char* content; - char* header_end; + int position; + char* line; + char* buffer; + char* header; + char* payload; + int bodyLength; + int payloadOffset; HttpResponse* response; - nbytes = 0; - length = 10000; - content = NULL; + size = 1024; + payload = NULL; + payloadOffset = 0; - buffer = calloc(length, 1); + s = Stream_New(NULL, size); - if (!buffer) - return NULL; + if (!s) + goto out_free; + + buffer = (char*) Stream_Buffer(s); response = http_response_new(); @@ -548,9 +607,9 @@ HttpResponse* http_response_recv(rdpTls* tls) while (TRUE) { - while (nbytes < 5) + while (!payloadOffset) { - status = BIO_read(tls->bio, &buffer[nbytes], length - nbytes); + status = BIO_read(tls->bio, Stream_Pointer(s), Stream_Capacity(s) - Stream_GetPosition(s)); if (status <= 0) { @@ -564,34 +623,40 @@ HttpResponse* http_response_recv(rdpTls* tls) #ifdef HAVE_VALGRIND_MEMCHECK_H VALGRIND_MAKE_MEM_DEFINED(p, status); #endif - nbytes += status; - } - header_end = strstr((char*) buffer, "\r\n\r\n"); + Stream_Seek(s, status); - if (!header_end) - { - WLog_ERR(TAG, "invalid response"); - winpr_HexDump(TAG, WLOG_ERROR, buffer, status); - goto out_error; - } - - header_end += 2; - - if (header_end) - { - int count; - char* line; - - header_end[0] = '\0'; - header_end[1] = '\0'; - content = header_end + 2; - count = 0; - line = (char*) buffer; - - while ((line = strstr(line, "\r\n")) != NULL) + if (Stream_GetRemainingLength(s) < 1024) { - line++; + Stream_EnsureRemainingCapacity(s, 1024); + buffer = (char*) Stream_Buffer(s); + payload = &buffer[payloadOffset]; + } + + position = Stream_GetPosition(s); + + if (position >= 4) + { + line = string_strnstr(buffer, "\r\n\r\n", position); + + if (line) + { + payloadOffset = (line - buffer) + 4; + payload = &buffer[payloadOffset]; + } + } + } + + if (payloadOffset) + { + count = 0; + line = buffer; + + position = Stream_GetPosition(s); + + while ((line = string_strnstr(line, "\r\n", payloadOffset - (line - buffer) - 2))) + { + line += 2; count++; } @@ -605,8 +670,17 @@ HttpResponse* http_response_recv(rdpTls* tls) goto out_error; } + header = (char*) malloc(payloadOffset); + + if (!header) + goto out_error; + + CopyMemory(header, buffer, payloadOffset); + header[payloadOffset - 1] = '\0'; + header[payloadOffset - 2] = '\0'; + count = 0; - line = strtok((char*) buffer, "\r\n"); + line = strtok(header, "\r\n"); while (line && response->lines) { @@ -619,10 +693,12 @@ HttpResponse* http_response_recv(rdpTls* tls) count++; } + free(header); + if (!http_response_parse_header(response)) goto out_error; - response->BodyLength = nbytes - (content - (char*) buffer); + response->BodyLength = Stream_GetPosition(s) - payloadOffset; if (response->BodyLength > 0) { @@ -631,44 +707,45 @@ HttpResponse* http_response_recv(rdpTls* tls) if (!response->BodyContent) goto out_error; - CopyMemory(response->BodyContent, content, response->BodyLength); + CopyMemory(response->BodyContent, payload, response->BodyLength); + } + + bodyLength = 0; /* expected body length */ + + if (response->ContentType) + { + if (_stricmp(response->ContentType, "text/plain") == 0) + { + bodyLength = response->ContentLength; + } + } + + if (bodyLength != response->BodyLength) + { + WLog_WARN(TAG, "http_response_recv: %s unexpected body length: actual: %d, expected: %d", + response->ContentType, response->ContentLength, response->BodyLength); } break; } - if ((length - nbytes) <= 0) + if (Stream_GetRemainingLength(s) < 1024) { - length *= 2; - buffer = realloc(buffer, length); + Stream_EnsureRemainingCapacity(s, 1024); + buffer = (char*) Stream_Buffer(s); + payload = &buffer[payloadOffset]; } } - free(buffer); + Stream_Free(s, TRUE); return response; out_error: http_response_free(response); out_free: - free(buffer); + Stream_Free(s, TRUE); return NULL; } -static BOOL strings_equals_nocase(void* obj1, void* obj2) -{ - if (!obj1 || !obj2) - return FALSE; - - return _stricmp(obj1, obj2) == 0; -} - -static void string_free(void* obj1) -{ - if (!obj1) - return; - - free(obj1); -} - HttpResponse* http_response_new() { HttpResponse* response = (HttpResponse*) calloc(1, sizeof(HttpResponse)); @@ -703,6 +780,8 @@ void http_response_free(HttpResponse* response) free(response->lines); free(response->ReasonPhrase); + free(response->ContentType); + ListDictionary_Free(response->Authenticates); if (response->ContentLength > 0) diff --git a/libfreerdp/core/gateway/http.h b/libfreerdp/core/gateway/http.h index 375503b76..d18327996 100644 --- a/libfreerdp/core/gateway/http.h +++ b/libfreerdp/core/gateway/http.h @@ -83,6 +83,7 @@ struct _http_response char* ReasonPhrase; int ContentLength; + char* ContentType; int BodyLength; BYTE* BodyContent; diff --git a/libfreerdp/core/gateway/ncacn_http.c b/libfreerdp/core/gateway/ncacn_http.c index 9d85aa2ee..8b9885e30 100644 --- a/libfreerdp/core/gateway/ncacn_http.c +++ b/libfreerdp/core/gateway/ncacn_http.c @@ -243,19 +243,19 @@ int rpc_ncacn_http_send_out_channel_request(rdpRpc* rpc) int rpc_ncacn_http_recv_out_channel_response(rdpRpc* rpc) { char* token64; + HttpResponse* response; int ntlm_token_length = 0; BYTE* ntlm_token_data = NULL; - HttpResponse* http_response; rdpNtlm* ntlm = rpc->NtlmHttpOut->ntlm; - http_response = http_response_recv(rpc->TlsOut); + response = http_response_recv(rpc->TlsOut); - if (!http_response) + if (!response) return -1; - if (ListDictionary_Contains(http_response->Authenticates, "NTLM")) + if (ListDictionary_Contains(response->Authenticates, "NTLM")) { - token64 = ListDictionary_GetItemValue(http_response->Authenticates, "NTLM"); + token64 = ListDictionary_GetItemValue(response->Authenticates, "NTLM"); if (!token64) goto out; @@ -266,7 +266,7 @@ int rpc_ncacn_http_recv_out_channel_response(rdpRpc* rpc) out: ntlm->inputBuffer[0].pvBuffer = ntlm_token_data; ntlm->inputBuffer[0].cbBuffer = ntlm_token_length; - http_response_free(http_response); + http_response_free(response); return 1; } @@ -297,15 +297,24 @@ BOOL rpc_ntlm_http_out_connect(rdpRpc* rpc) /* Send OUT Channel Request */ if (rpc_ncacn_http_send_out_channel_request(rpc) <= 0) + { + WLog_ERR(TAG, "rpc_ncacn_http_send_out_channel_request failure"); goto out; + } /* Receive OUT Channel Response */ if (rpc_ncacn_http_recv_out_channel_response(rpc) <= 0) + { + WLog_ERR(TAG, "rpc_ncacn_http_recv_out_channel_response failure"); goto out; + } /* Send OUT Channel Request */ if (rpc_ncacn_http_send_out_channel_request(rpc) <= 0) + { + WLog_ERR(TAG, "rpc_ncacn_http_send_out_channel_request failure"); goto out; + } status = TRUE; diff --git a/libfreerdp/core/gateway/rts.c b/libfreerdp/core/gateway/rts.c index 9296f206c..34dcf45c4 100644 --- a/libfreerdp/core/gateway/rts.c +++ b/libfreerdp/core/gateway/rts.c @@ -126,6 +126,11 @@ BOOL rts_connect(rdpRpc* rpc) return FALSE; } + WLog_DBG(TAG, "HTTP Body (%d):", response->BodyLength); + + if (response->BodyLength) + winpr_HexDump(TAG, WLOG_DEBUG, response->BodyContent, response->BodyLength); + http_response_free(response); rpc->VirtualConnection->State = VIRTUAL_CONNECTION_STATE_WAIT_A3W; diff --git a/libfreerdp/core/gateway/tsg.c b/libfreerdp/core/gateway/tsg.c index d1cff44f9..92eb80135 100644 --- a/libfreerdp/core/gateway/tsg.c +++ b/libfreerdp/core/gateway/tsg.c @@ -1367,7 +1367,7 @@ BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port) if (!rts_connect(rpc)) { WLog_ERR(TAG, "rts_connect error!"); - return -1; + return FALSE; } ReadEvent = NULL; diff --git a/libfreerdp/core/nego.c b/libfreerdp/core/nego.c index 2a2491a13..6655292d2 100644 --- a/libfreerdp/core/nego.c +++ b/libfreerdp/core/nego.c @@ -74,19 +74,19 @@ BOOL nego_connect(rdpNego* nego) if (nego->state == NEGO_STATE_INITIAL) { - if (nego->enabled_protocols[PROTOCOL_EXT]) + if (nego->EnabledProtocols[PROTOCOL_EXT]) { nego->state = NEGO_STATE_EXT; } - else if (nego->enabled_protocols[PROTOCOL_NLA]) + else if (nego->EnabledProtocols[PROTOCOL_NLA]) { nego->state = NEGO_STATE_NLA; } - else if (nego->enabled_protocols[PROTOCOL_TLS]) + else if (nego->EnabledProtocols[PROTOCOL_TLS]) { nego->state = NEGO_STATE_TLS; } - else if (nego->enabled_protocols[PROTOCOL_RDP]) + else if (nego->EnabledProtocols[PROTOCOL_RDP]) { nego->state = NEGO_STATE_RDP; } @@ -102,39 +102,42 @@ BOOL nego_connect(rdpNego* nego) WLog_DBG(TAG, "Security Layer Negotiation is disabled"); /* attempt only the highest enabled protocol (see nego_attempt_*) */ - nego->enabled_protocols[PROTOCOL_NLA] = FALSE; - nego->enabled_protocols[PROTOCOL_TLS] = FALSE; - nego->enabled_protocols[PROTOCOL_RDP] = FALSE; - nego->enabled_protocols[PROTOCOL_EXT] = FALSE; + nego->EnabledProtocols[PROTOCOL_NLA] = FALSE; + nego->EnabledProtocols[PROTOCOL_TLS] = FALSE; + nego->EnabledProtocols[PROTOCOL_RDP] = FALSE; + nego->EnabledProtocols[PROTOCOL_EXT] = FALSE; if (nego->state == NEGO_STATE_EXT) { - nego->enabled_protocols[PROTOCOL_EXT] = TRUE; - nego->enabled_protocols[PROTOCOL_NLA] = TRUE; - nego->selected_protocol = PROTOCOL_EXT; + nego->EnabledProtocols[PROTOCOL_EXT] = TRUE; + nego->EnabledProtocols[PROTOCOL_NLA] = TRUE; + nego->SelectedProtocol = PROTOCOL_EXT; } else if (nego->state == NEGO_STATE_NLA) { - nego->enabled_protocols[PROTOCOL_NLA] = TRUE; - nego->selected_protocol = PROTOCOL_NLA; + nego->EnabledProtocols[PROTOCOL_NLA] = TRUE; + nego->SelectedProtocol = PROTOCOL_NLA; } else if (nego->state == NEGO_STATE_TLS) { - nego->enabled_protocols[PROTOCOL_TLS] = TRUE; - nego->selected_protocol = PROTOCOL_TLS; + nego->EnabledProtocols[PROTOCOL_TLS] = TRUE; + nego->SelectedProtocol = PROTOCOL_TLS; } else if (nego->state == NEGO_STATE_RDP) { - nego->enabled_protocols[PROTOCOL_RDP] = TRUE; - nego->selected_protocol = PROTOCOL_RDP; + nego->EnabledProtocols[PROTOCOL_RDP] = TRUE; + nego->SelectedProtocol = PROTOCOL_RDP; } } - if (!nego_send_preconnection_pdu(nego)) + if (nego->SendPreconnectionPdu) { - WLog_ERR(TAG, "Failed to send preconnection pdu"); - nego->state = NEGO_STATE_FINAL; - return FALSE; + if (!nego_send_preconnection_pdu(nego)) + { + WLog_ERR(TAG, "Failed to send preconnection pdu"); + nego->state = NEGO_STATE_FINAL; + return FALSE; + } } } @@ -153,14 +156,14 @@ BOOL nego_connect(rdpNego* nego) } while (nego->state != NEGO_STATE_FINAL); - WLog_DBG(TAG, "Negotiated %s security", PROTOCOL_SECURITY_STRINGS[nego->selected_protocol]); + WLog_DBG(TAG, "Negotiated %s security", PROTOCOL_SECURITY_STRINGS[nego->SelectedProtocol]); /* update settings with negotiated protocol security */ - settings->RequestedProtocols = nego->requested_protocols; - settings->SelectedProtocol = nego->selected_protocol; + settings->RequestedProtocols = nego->RequestedProtocols; + settings->SelectedProtocol = nego->SelectedProtocol; settings->NegotiationFlags = nego->flags; - if (nego->selected_protocol == PROTOCOL_RDP) + if (nego->SelectedProtocol == PROTOCOL_RDP) { settings->UseRdpSecurityLayer = TRUE; @@ -177,7 +180,7 @@ BOOL nego_connect(rdpNego* nego) /* finally connect security layer (if not already done) */ if (!nego_security_connect(nego)) { - WLog_DBG(TAG, "Failed to connect with %s security", PROTOCOL_SECURITY_STRINGS[nego->selected_protocol]); + WLog_DBG(TAG, "Failed to connect with %s security", PROTOCOL_SECURITY_STRINGS[nego->SelectedProtocol]); return FALSE; } @@ -196,26 +199,26 @@ BOOL nego_disconnect(rdpNego* nego) /* connect to selected security layer */ BOOL nego_security_connect(rdpNego* nego) { - if (!nego->tcp_connected) + if (!nego->TcpConnected) { - nego->security_connected = FALSE; + nego->SecurityConnected = FALSE; } - else if (!nego->security_connected) + else if (!nego->SecurityConnected) { - if (nego->selected_protocol == PROTOCOL_NLA) + if (nego->SelectedProtocol == PROTOCOL_NLA) { WLog_DBG(TAG, "nego_security_connect with PROTOCOL_NLA"); - nego->security_connected = transport_connect_nla(nego->transport); + nego->SecurityConnected = transport_connect_nla(nego->transport); } - else if (nego->selected_protocol == PROTOCOL_TLS) + else if (nego->SelectedProtocol == PROTOCOL_TLS) { WLog_DBG(TAG, "nego_security_connect with PROTOCOL_TLS"); - nego->security_connected = transport_connect_tls(nego->transport); + nego->SecurityConnected = transport_connect_tls(nego->transport); } - else if (nego->selected_protocol == PROTOCOL_RDP) + else if (nego->SelectedProtocol == PROTOCOL_RDP) { WLog_DBG(TAG, "nego_security_connect with PROTOCOL_RDP"); - nego->security_connected = transport_connect_rdp(nego->transport); + nego->SecurityConnected = transport_connect_rdp(nego->transport); } else { @@ -223,7 +226,7 @@ BOOL nego_security_connect(rdpNego* nego) } } - return nego->security_connected; + return nego->SecurityConnected; } /** @@ -234,7 +237,7 @@ BOOL nego_security_connect(rdpNego* nego) BOOL nego_tcp_connect(rdpNego* nego) { - if (!nego->tcp_connected) + if (!nego->TcpConnected) { if (nego->GatewayEnabled) { @@ -244,22 +247,22 @@ BOOL nego_tcp_connect(rdpNego* nego) WLog_INFO(TAG, "Detecting if host can be reached locally. - This might take some time."); WLog_INFO(TAG, "To disable auto detection use /gateway-usage-method:direct"); transport_set_gateway_enabled(nego->transport, FALSE); - nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port, 1); + nego->TcpConnected = transport_connect(nego->transport, nego->hostname, nego->port, 1); } - if (!nego->tcp_connected) + if (!nego->TcpConnected) { transport_set_gateway_enabled(nego->transport, TRUE); - nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port, 15); + nego->TcpConnected = transport_connect(nego->transport, nego->hostname, nego->port, 15); } } else { - nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port, 15); + nego->TcpConnected = transport_connect(nego->transport, nego->hostname, nego->port, 15); } } - return nego->tcp_connected; + return nego->TcpConnected; } /** @@ -272,10 +275,10 @@ BOOL nego_transport_connect(rdpNego* nego) { nego_tcp_connect(nego); - if (nego->tcp_connected && !nego->NegotiateSecurityLayer) + if (nego->TcpConnected && !nego->NegotiateSecurityLayer) return nego_security_connect(nego); - return nego->tcp_connected; + return nego->TcpConnected; } /** @@ -286,11 +289,11 @@ BOOL nego_transport_connect(rdpNego* nego) BOOL nego_transport_disconnect(rdpNego* nego) { - if (nego->tcp_connected) + if (nego->TcpConnected) transport_disconnect(nego->transport); - nego->tcp_connected = FALSE; - nego->security_connected = FALSE; + nego->TcpConnected = FALSE; + nego->SecurityConnected = FALSE; return TRUE; } @@ -308,9 +311,6 @@ BOOL nego_send_preconnection_pdu(rdpNego* nego) UINT16 cchPCB = 0; WCHAR* wszPCB = NULL; - if (!nego->send_preconnection_pdu) - return TRUE; - WLog_DBG(TAG, "Sending preconnection PDU"); if (!nego_tcp_connect(nego)) @@ -319,9 +319,9 @@ BOOL nego_send_preconnection_pdu(rdpNego* nego) /* it's easier to always send the version 2 PDU, and it's just 2 bytes overhead */ cbSize = PRECONNECTION_PDU_V2_MIN_SIZE; - if (nego->preconnection_blob) + if (nego->PreconnectionBlob) { - cchPCB = (UINT16) ConvertToUnicode(CP_UTF8, 0, nego->preconnection_blob, -1, &wszPCB, 0); + cchPCB = (UINT16) ConvertToUnicode(CP_UTF8, 0, nego->PreconnectionBlob, -1, &wszPCB, 0); cchPCB += 1; /* zero-termination */ cbSize += cchPCB * 2; } @@ -331,7 +331,7 @@ BOOL nego_send_preconnection_pdu(rdpNego* nego) Stream_Write_UINT32(s, cbSize); /* cbSize */ Stream_Write_UINT32(s, 0); /* Flags */ Stream_Write_UINT32(s, PRECONNECTION_PDU_V2); /* Version */ - Stream_Write_UINT32(s, nego->preconnection_id); /* Id */ + Stream_Write_UINT32(s, nego->PreconnectionId); /* Id */ Stream_Write_UINT16(s, cchPCB); /* cchPCB */ if (wszPCB) @@ -360,7 +360,7 @@ BOOL nego_send_preconnection_pdu(rdpNego* nego) void nego_attempt_ext(rdpNego* nego) { - nego->requested_protocols = PROTOCOL_NLA | PROTOCOL_TLS | PROTOCOL_EXT; + nego->RequestedProtocols = PROTOCOL_NLA | PROTOCOL_TLS | PROTOCOL_EXT; WLog_DBG(TAG, "Attempting NLA extended security"); @@ -388,11 +388,11 @@ void nego_attempt_ext(rdpNego* nego) { nego_transport_disconnect(nego); - if (nego->enabled_protocols[PROTOCOL_NLA]) + if (nego->EnabledProtocols[PROTOCOL_NLA]) nego->state = NEGO_STATE_NLA; - else if (nego->enabled_protocols[PROTOCOL_TLS]) + else if (nego->EnabledProtocols[PROTOCOL_TLS]) nego->state = NEGO_STATE_TLS; - else if (nego->enabled_protocols[PROTOCOL_RDP]) + else if (nego->EnabledProtocols[PROTOCOL_RDP]) nego->state = NEGO_STATE_RDP; else nego->state = NEGO_STATE_FAIL; @@ -406,7 +406,7 @@ void nego_attempt_ext(rdpNego* nego) void nego_attempt_nla(rdpNego* nego) { - nego->requested_protocols = PROTOCOL_NLA | PROTOCOL_TLS; + nego->RequestedProtocols = PROTOCOL_NLA | PROTOCOL_TLS; WLog_DBG(TAG, "Attempting NLA security"); @@ -434,9 +434,9 @@ void nego_attempt_nla(rdpNego* nego) { nego_transport_disconnect(nego); - if (nego->enabled_protocols[PROTOCOL_TLS]) + if (nego->EnabledProtocols[PROTOCOL_TLS]) nego->state = NEGO_STATE_TLS; - else if (nego->enabled_protocols[PROTOCOL_RDP]) + else if (nego->EnabledProtocols[PROTOCOL_RDP]) nego->state = NEGO_STATE_RDP; else nego->state = NEGO_STATE_FAIL; @@ -450,7 +450,7 @@ void nego_attempt_nla(rdpNego* nego) void nego_attempt_tls(rdpNego* nego) { - nego->requested_protocols = PROTOCOL_TLS; + nego->RequestedProtocols = PROTOCOL_TLS; WLog_DBG(TAG, "Attempting TLS security"); @@ -476,7 +476,7 @@ void nego_attempt_tls(rdpNego* nego) { nego_transport_disconnect(nego); - if (nego->enabled_protocols[PROTOCOL_RDP]) + if (nego->EnabledProtocols[PROTOCOL_RDP]) nego->state = NEGO_STATE_RDP; else nego->state = NEGO_STATE_FAIL; @@ -490,7 +490,7 @@ void nego_attempt_tls(rdpNego* nego) void nego_attempt_rdp(rdpNego* nego) { - nego->requested_protocols = PROTOCOL_RDP; + nego->RequestedProtocols = PROTOCOL_RDP; WLog_DBG(TAG, "Attempting RDP security"); @@ -580,24 +580,24 @@ int nego_recv(rdpTransport* transport, wStream* s, void* extra) case TYPE_RDP_NEG_RSP: nego_process_negotiation_response(nego, s); - WLog_DBG(TAG, "selected_protocol: %d", nego->selected_protocol); + WLog_DBG(TAG, "selected_protocol: %d", nego->SelectedProtocol); /* enhanced security selected ? */ - if (nego->selected_protocol) + if (nego->SelectedProtocol) { - if ((nego->selected_protocol == PROTOCOL_NLA) && - (!nego->enabled_protocols[PROTOCOL_NLA])) + if ((nego->SelectedProtocol == PROTOCOL_NLA) && + (!nego->EnabledProtocols[PROTOCOL_NLA])) { nego->state = NEGO_STATE_FAIL; } - if ((nego->selected_protocol == PROTOCOL_TLS) && - (!nego->enabled_protocols[PROTOCOL_TLS])) + if ((nego->SelectedProtocol == PROTOCOL_TLS) && + (!nego->EnabledProtocols[PROTOCOL_TLS])) { nego->state = NEGO_STATE_FAIL; } } - else if (!nego->enabled_protocols[PROTOCOL_RDP]) + else if (!nego->EnabledProtocols[PROTOCOL_RDP]) { nego->state = NEGO_STATE_FAIL; } @@ -612,7 +612,7 @@ int nego_recv(rdpTransport* transport, wStream* s, void* extra) { WLog_DBG(TAG, "no rdpNegData"); - if (!nego->enabled_protocols[PROTOCOL_RDP]) + if (!nego->EnabledProtocols[PROTOCOL_RDP]) nego->state = NEGO_STATE_FAIL; else nego->state = NEGO_STATE_FINAL; @@ -645,7 +645,7 @@ BOOL nego_read_request(rdpNego* nego, wStream* s) if (li != Stream_GetRemainingLength(s) + 6) { - WLog_ERR(TAG, "Incorrect TPDU length indicator."); + WLog_ERR(TAG, "Incorrect TPDU length indicator."); return FALSE; } @@ -677,7 +677,7 @@ BOOL nego_read_request(rdpNego* nego, wStream* s) if (type != TYPE_RDP_NEG_REQ) { - WLog_ERR(TAG, "Incorrect negotiation request type %d", type); + WLog_ERR(TAG, "Incorrect negotiation request type %d", type); return FALSE; } @@ -730,8 +730,12 @@ BOOL nego_send_negotiation_request(rdpNego* nego) if (nego->RoutingToken) { Stream_Write(s, nego->RoutingToken, nego->RoutingTokenLength); + /* Ensure Routing Token is correctly terminated - may already be present in string */ - if (nego->RoutingTokenLength>2 && (nego->RoutingToken[nego->RoutingTokenLength-2]==0x0D && nego->RoutingToken[nego->RoutingTokenLength-1]==0x0A)) + + if ((nego->RoutingTokenLength > 2) && + (nego->RoutingToken[nego->RoutingTokenLength - 2] == 0x0D) && + (nego->RoutingToken[nego->RoutingTokenLength - 1] == 0x0A)) { WLog_DBG(TAG, "Routing token looks correctly terminated - use verbatim"); length +=nego->RoutingTokenLength; @@ -748,8 +752,8 @@ BOOL nego_send_negotiation_request(rdpNego* nego) { cookie_length = strlen(nego->cookie); - if (cookie_length > (int) nego->cookie_max_length) - cookie_length = nego->cookie_max_length; + if (cookie_length > (int) nego->CookieMaxLength) + cookie_length = nego->CookieMaxLength; Stream_Write(s, "Cookie: mstshash=", 17); Stream_Write(s, (BYTE*) nego->cookie, cookie_length); @@ -758,9 +762,9 @@ BOOL nego_send_negotiation_request(rdpNego* nego) length += cookie_length + 19; } - WLog_DBG(TAG, "RequestedProtocols: %d", nego->requested_protocols); + WLog_DBG(TAG, "RequestedProtocols: %d", nego->RequestedProtocols); - if ((nego->requested_protocols > PROTOCOL_RDP) || (nego->sendNegoData)) + if ((nego->RequestedProtocols > PROTOCOL_RDP) || (nego->sendNegoData)) { /* RDP_NEG_DATA must be present for TLS and NLA */ @@ -770,7 +774,7 @@ BOOL nego_send_negotiation_request(rdpNego* nego) Stream_Write_UINT8(s, TYPE_RDP_NEG_REQ); Stream_Write_UINT8(s, flags); Stream_Write_UINT16(s, 8); /* RDP_NEG_DATA length (8) */ - Stream_Write_UINT32(s, nego->requested_protocols); /* requestedProtocols */ + Stream_Write_UINT32(s, nego->RequestedProtocols); /* requestedProtocols */ length += 8; } @@ -806,9 +810,9 @@ void nego_process_negotiation_request(rdpNego* nego, wStream* s) Stream_Read_UINT8(s, flags); Stream_Read_UINT16(s, length); - Stream_Read_UINT32(s, nego->requested_protocols); + Stream_Read_UINT32(s, nego->RequestedProtocols); - WLog_DBG(TAG, "RDP_NEG_REQ: RequestedProtocol: 0x%04X", nego->requested_protocols); + WLog_DBG(TAG, "RDP_NEG_REQ: RequestedProtocol: 0x%04X", nego->RequestedProtocols); nego->state = NEGO_STATE_FINAL; } @@ -834,7 +838,7 @@ void nego_process_negotiation_response(rdpNego* nego, wStream* s) Stream_Read_UINT8(s, nego->flags); Stream_Read_UINT16(s, length); - Stream_Read_UINT32(s, nego->selected_protocol); + Stream_Read_UINT32(s, nego->SelectedProtocol); nego->state = NEGO_STATE_FINAL; } @@ -914,7 +918,7 @@ BOOL nego_send_negotiation_response(rdpNego* nego) bm = Stream_GetPosition(s); Stream_Seek(s, length); - if ((nego->selected_protocol == PROTOCOL_RDP) && !settings->RdpSecurity) + if ((nego->SelectedProtocol == PROTOCOL_RDP) && !settings->RdpSecurity) { flags = 0; @@ -926,7 +930,7 @@ BOOL nego_send_negotiation_response(rdpNego* nego) * TODO: Check for other possibilities, * like SSL_NOT_ALLOWED_BY_SERVER. */ - WLog_ERR(TAG, "client supports only Standard RDP Security"); + WLog_ERR(TAG, "client supports only Standard RDP Security"); Stream_Write_UINT32(s, SSL_REQUIRED_BY_SERVER); length += 8; status = FALSE; @@ -942,7 +946,7 @@ BOOL nego_send_negotiation_response(rdpNego* nego) Stream_Write_UINT8(s, TYPE_RDP_NEG_RSP); Stream_Write_UINT8(s, flags); /* flags */ Stream_Write_UINT16(s, 8); /* RDP_NEG_DATA length (8) */ - Stream_Write_UINT32(s, nego->selected_protocol); /* selectedProtocol */ + Stream_Write_UINT32(s, nego->SelectedProtocol); /* selectedProtocol */ length += 8; } @@ -965,8 +969,8 @@ BOOL nego_send_negotiation_response(rdpNego* nego) if (status) { /* update settings with negotiated protocol security */ - settings->RequestedProtocols = nego->requested_protocols; - settings->SelectedProtocol = nego->selected_protocol; + settings->RequestedProtocols = nego->RequestedProtocols; + settings->SelectedProtocol = nego->SelectedProtocol; if (settings->SelectedProtocol == PROTOCOL_RDP) { @@ -1032,10 +1036,10 @@ BOOL nego_send_negotiation_response(rdpNego* nego) void nego_init(rdpNego* nego) { nego->state = NEGO_STATE_INITIAL; - nego->requested_protocols = PROTOCOL_RDP; + nego->RequestedProtocols = PROTOCOL_RDP; nego->transport->ReceiveCallback = nego_recv; nego->transport->ReceiveExtra = (void*) nego; - nego->cookie_max_length = DEFAULT_COOKIE_MAX_LENGTH; + nego->CookieMaxLength = DEFAULT_COOKIE_MAX_LENGTH; nego->sendNegoData = FALSE; nego->flags = 0; } @@ -1127,7 +1131,7 @@ void nego_set_gateway_bypass_local(rdpNego* nego, BOOL GatewayBypassLocal) void nego_enable_rdp(rdpNego* nego, BOOL enable_rdp) { WLog_DBG(TAG, "Enabling RDP security: %s", enable_rdp ? "TRUE" : "FALSE"); - nego->enabled_protocols[PROTOCOL_RDP] = enable_rdp; + nego->EnabledProtocols[PROTOCOL_RDP] = enable_rdp; } /** @@ -1139,7 +1143,7 @@ void nego_enable_rdp(rdpNego* nego, BOOL enable_rdp) void nego_enable_tls(rdpNego* nego, BOOL enable_tls) { WLog_DBG(TAG, "Enabling TLS security: %s", enable_tls ? "TRUE" : "FALSE"); - nego->enabled_protocols[PROTOCOL_TLS] = enable_tls; + nego->EnabledProtocols[PROTOCOL_TLS] = enable_tls; } /** @@ -1151,7 +1155,7 @@ void nego_enable_tls(rdpNego* nego, BOOL enable_tls) void nego_enable_nla(rdpNego* nego, BOOL enable_nla) { WLog_DBG(TAG, "Enabling NLA security: %s", enable_nla ? "TRUE" : "FALSE"); - nego->enabled_protocols[PROTOCOL_NLA] = enable_nla; + nego->EnabledProtocols[PROTOCOL_NLA] = enable_nla; } /** @@ -1163,7 +1167,7 @@ void nego_enable_nla(rdpNego* nego, BOOL enable_nla) void nego_enable_ext(rdpNego* nego, BOOL enable_ext) { WLog_DBG(TAG, "Enabling NLA extended security: %s", enable_ext ? "TRUE" : "FALSE"); - nego->enabled_protocols[PROTOCOL_EXT] = enable_ext; + nego->EnabledProtocols[PROTOCOL_EXT] = enable_ext; } /** @@ -1210,12 +1214,12 @@ BOOL nego_set_cookie(rdpNego* nego, char* cookie) /** * Set cookie maximum length * @param nego - * @param cookie_max_length + * @param CookieMaxLength */ -void nego_set_cookie_max_length(rdpNego* nego, UINT32 cookie_max_length) +void nego_set_cookie_max_length(rdpNego* nego, UINT32 CookieMaxLength) { - nego->cookie_max_length = cookie_max_length; + nego->CookieMaxLength = CookieMaxLength; } /** @@ -1224,9 +1228,9 @@ void nego_set_cookie_max_length(rdpNego* nego, UINT32 cookie_max_length) * @param send_pcpdu */ -void nego_set_send_preconnection_pdu(rdpNego* nego, BOOL send_pcpdu) +void nego_set_send_preconnection_pdu(rdpNego* nego, BOOL SendPreconnectionPdu) { - nego->send_preconnection_pdu = send_pcpdu; + nego->SendPreconnectionPdu = SendPreconnectionPdu; } /** @@ -1235,9 +1239,9 @@ void nego_set_send_preconnection_pdu(rdpNego* nego, BOOL send_pcpdu) * @param id */ -void nego_set_preconnection_id(rdpNego* nego, UINT32 id) +void nego_set_preconnection_id(rdpNego* nego, UINT32 PreconnectionId) { - nego->preconnection_id = id; + nego->PreconnectionId = PreconnectionId; } /** @@ -1246,7 +1250,7 @@ void nego_set_preconnection_id(rdpNego* nego, UINT32 id) * @param blob */ -void nego_set_preconnection_blob(rdpNego* nego, char* blob) +void nego_set_preconnection_blob(rdpNego* nego, char* PreconnectionBlob) { - nego->preconnection_blob = blob; + nego->PreconnectionBlob = PreconnectionBlob; } diff --git a/libfreerdp/core/nego.h b/libfreerdp/core/nego.h index d41334406..30b082de5 100644 --- a/libfreerdp/core/nego.h +++ b/libfreerdp/core/nego.h @@ -95,20 +95,20 @@ struct rdp_nego char* cookie; BYTE* RoutingToken; DWORD RoutingTokenLength; - BOOL send_preconnection_pdu; - UINT32 preconnection_id; - char* preconnection_blob; + BOOL SendPreconnectionPdu; + UINT32 PreconnectionId; + char* PreconnectionBlob; NEGO_STATE state; - BOOL tcp_connected; - BOOL security_connected; - UINT32 cookie_max_length; + BOOL TcpConnected; + BOOL SecurityConnected; + UINT32 CookieMaxLength; BOOL sendNegoData; - UINT32 selected_protocol; - UINT32 requested_protocols; + UINT32 SelectedProtocol; + UINT32 RequestedProtocols; BOOL NegotiateSecurityLayer; - BYTE enabled_protocols[16]; + BYTE EnabledProtocols[16]; BOOL RestrictedAdminModeRequired; BOOL GatewayEnabled; BOOL GatewayBypassLocal; @@ -143,7 +143,7 @@ void nego_free(rdpNego* nego); void nego_init(rdpNego* nego); void nego_set_target(rdpNego* nego, char* hostname, int port); -void nego_set_negotiation_enabled(rdpNego* nego, BOOL NegotiateSecurityLayer_enabled); +void nego_set_negotiation_enabled(rdpNego* nego, BOOL NegotiateSecurityLayer); void nego_set_restricted_admin_mode_required(rdpNego* nego, BOOL RestrictedAdminModeRequired); void nego_set_gateway_enabled(rdpNego* nego, BOOL GatewayEnabled); void nego_set_gateway_bypass_local(rdpNego* nego, BOOL GatewayBypassLocal); @@ -153,9 +153,9 @@ void nego_enable_nla(rdpNego* nego, BOOL enable_nla); void nego_enable_ext(rdpNego* nego, BOOL enable_ext); BOOL nego_set_routing_token(rdpNego* nego, BYTE* RoutingToken, DWORD RoutingTokenLength); BOOL nego_set_cookie(rdpNego* nego, char* cookie); -void nego_set_cookie_max_length(rdpNego* nego, UINT32 cookie_max_length); -void nego_set_send_preconnection_pdu(rdpNego* nego, BOOL send_pcpdu); -void nego_set_preconnection_id(rdpNego* nego, UINT32 id); -void nego_set_preconnection_blob(rdpNego* nego, char* blob); +void nego_set_cookie_max_length(rdpNego* nego, UINT32 CookieMaxLength); +void nego_set_send_preconnection_pdu(rdpNego* nego, BOOL SendPreconnectionPdu); +void nego_set_preconnection_id(rdpNego* nego, UINT32 PreconnectionId); +void nego_set_preconnection_blob(rdpNego* nego, char* PreconnectionBlob); #endif /* __NEGO_H */ diff --git a/libfreerdp/core/nla.c b/libfreerdp/core/nla.c index ecbfc8b26..1829208f7 100644 --- a/libfreerdp/core/nla.c +++ b/libfreerdp/core/nla.c @@ -251,7 +251,6 @@ int credssp_client_authenticate(rdpCredssp* credssp) BOOL have_context; BOOL have_input_buffer; BOOL have_pub_key_auth; - sspi_GlobalInit(); if (credssp_ntlm_client_init(credssp) == 0) return 0; @@ -423,7 +422,6 @@ int credssp_server_authenticate(rdpCredssp* credssp) BOOL have_context; BOOL have_input_buffer; BOOL have_pub_key_auth; - sspi_GlobalInit(); if (credssp_ntlm_server_init(credssp) == 0) return 0; @@ -846,7 +844,9 @@ void credssp_read_ts_credentials(rdpCredssp* credssp, PSecBuffer ts_credentials) wStream* s; int length; int ts_password_creds_length; + s = Stream_New(ts_credentials->pvBuffer, ts_credentials->cbBuffer); + /* TSCredentials (SEQUENCE) */ ber_read_sequence_tag(s, &length); /* [0] credType (INTEGER) */ @@ -855,7 +855,9 @@ void credssp_read_ts_credentials(rdpCredssp* credssp, PSecBuffer ts_credentials) /* [1] credentials (OCTET STRING) */ ber_read_contextual_tag(s, 1, &length, TRUE); ber_read_octet_string_tag(s, &ts_password_creds_length); + credssp_read_ts_password_creds(credssp, s); + Stream_Free(s, FALSE); } @@ -889,6 +891,7 @@ void credssp_encode_ts_credentials(rdpCredssp* credssp) int DomainLength; int UserLength; int PasswordLength; + DomainLength = credssp->identity.DomainLength; UserLength = credssp->identity.UserLength; PasswordLength = credssp->identity.PasswordLength; @@ -920,7 +923,9 @@ SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp) SecBuffer Buffers[2]; SecBufferDesc Message; SECURITY_STATUS status; + credssp_encode_ts_credentials(credssp); + Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */ Buffers[1].BufferType = SECBUFFER_DATA; /* TSCredentials */ sspi_SecBufferAlloc(&credssp->authInfo, credssp->ContextSizes.cbMaxSignature + credssp->ts_credentials.cbBuffer); @@ -930,9 +935,11 @@ SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp) Buffers[1].cbBuffer = credssp->ts_credentials.cbBuffer; Buffers[1].pvBuffer = &((BYTE*) credssp->authInfo.pvBuffer)[Buffers[0].cbBuffer]; CopyMemory(Buffers[1].pvBuffer, credssp->ts_credentials.pvBuffer, Buffers[1].cbBuffer); + Message.cBuffers = 2; Message.ulVersion = SECBUFFER_VERSION; Message.pBuffers = (PSecBuffer) &Buffers; + status = credssp->table->EncryptMessage(&credssp->context, 0, &Message, credssp->send_seq_num++); if (status != SEC_E_OK) @@ -1084,7 +1091,9 @@ int credssp_recv(rdpCredssp* credssp) int length; int status; UINT32 version; + s = Stream_New(NULL, 4096); + status = transport_read_pdu(credssp->transport, s); if (status < 0) diff --git a/libfreerdp/core/peer.c b/libfreerdp/core/peer.c index 453a4679b..55b6180f0 100644 --- a/libfreerdp/core/peer.c +++ b/libfreerdp/core/peer.c @@ -451,7 +451,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) if (!rdp_server_accept_nego(rdp, s)) return -1; - if (rdp->nego->selected_protocol & PROTOCOL_NLA) + if (rdp->nego->SelectedProtocol & PROTOCOL_NLA) { sspi_CopyAuthIdentity(&client->identity, &(rdp->nego->transport->credssp->identity)); IFCALLRET(client->Logon, client->authenticated, client, &client->identity, TRUE);