From b7f62964a4ae10fe33425792fc7cea463f1adf32 Mon Sep 17 00:00:00 2001 From: Vic Lee Date: Fri, 19 Aug 2011 17:39:37 +0800 Subject: [PATCH] server: start reading MCS Connect Initial PDU and Client Core Data. --- libfreerdp-core/ber.c | 21 ++++ libfreerdp-core/ber.h | 1 + libfreerdp-core/connection.c | 8 ++ libfreerdp-core/connection.h | 1 + libfreerdp-core/gcc.c | 274 +++++++++++++++++++++++++++++++++++++++++++ libfreerdp-core/gcc.h | 7 ++ libfreerdp-core/mcs.c | 63 ++++++++++ libfreerdp-core/mcs.h | 2 + libfreerdp-core/nego.c | 3 + libfreerdp-core/peer.c | 5 + libfreerdp-core/per.c | 39 ++++++ libfreerdp-core/per.h | 4 +- 12 files changed, 426 insertions(+), 2 deletions(-) diff --git a/libfreerdp-core/ber.c b/libfreerdp-core/ber.c index 3e42889..127cbdc 100644 --- a/libfreerdp-core/ber.c +++ b/libfreerdp-core/ber.c @@ -295,6 +295,27 @@ int ber_skip_octet_string(int length) } /** + * Read a BER BOOLEAN + * @param s + * @param value + */ + +boolean ber_read_boolean(STREAM* s, boolean* value) +{ + int length; + uint8 v; + + if (!ber_read_universal_tag(s, BER_TAG_BOOLEAN, False)) + return False; + ber_read_length(s, &length); + if (length != 1) + return False; + stream_read_uint8(s, v); + *value = (v ? True : False); + return True; +} + +/** * Write a BER BOOLEAN * @param s * @param value diff --git a/libfreerdp-core/ber.h b/libfreerdp-core/ber.h index 6b86ad8..6da53d6 100644 --- a/libfreerdp-core/ber.h +++ b/libfreerdp-core/ber.h @@ -72,6 +72,7 @@ boolean ber_read_octet_string(STREAM* s, int* length); void ber_write_octet_string(STREAM* s, uint8* oct_str, int length); int ber_write_octet_string_tag(STREAM* s, int length); int ber_skip_octet_string(int length); +boolean ber_read_boolean(STREAM* s, boolean* value); void ber_write_boolean(STREAM* s, boolean value); boolean ber_read_integer(STREAM* s, uint32* value); int ber_write_integer(STREAM* s, uint32 value); diff --git a/libfreerdp-core/connection.c b/libfreerdp-core/connection.c index bd56fd1..a27e5ea 100644 --- a/libfreerdp-core/connection.c +++ b/libfreerdp-core/connection.c @@ -167,3 +167,11 @@ boolean rdp_server_accept_nego(rdpRdp* rdp, STREAM* s) return True; } +boolean rdp_server_accept_mcs_connect_initial(rdpRdp* rdp, STREAM* s) +{ + if (!mcs_read_connect_initial(rdp->mcs, s)) + return False; + + return True; +} + diff --git a/libfreerdp-core/connection.h b/libfreerdp-core/connection.h index 4265a2b..6684cee 100644 --- a/libfreerdp-core/connection.h +++ b/libfreerdp-core/connection.h @@ -40,5 +40,6 @@ enum CONNECTION_STATE boolean rdp_client_connect(rdpRdp* rdp); boolean rdp_server_accept_nego(rdpRdp* rdp, STREAM* s); +boolean rdp_server_accept_mcs_connect_initial(rdpRdp* rdp, STREAM* s); #endif /* __CONNECTION_H */ diff --git a/libfreerdp-core/gcc.c b/libfreerdp-core/gcc.c index f65fe66..6b4f455 100644 --- a/libfreerdp-core/gcc.c +++ b/libfreerdp-core/gcc.c @@ -124,6 +124,63 @@ uint8 h221_cs_key[4] = "Duca"; uint8 h221_sc_key[4] = "McDn"; /** + * Read a GCC Conference Create Request.\n + * @msdn{cc240836} + * @param s stream + * @param settings rdp settings + */ + +boolean gcc_read_conference_create_request(STREAM* s, rdpSettings* settings) +{ + uint16 length; + uint8 choice; + uint8 number; + uint8 selection; + + /* ConnectData */ + if (!per_read_choice(s, &choice)) + return False; + if (!per_read_object_identifier(s, t124_02_98_oid)) + return False; + + /* ConnectData::connectPDU (OCTET_STRING) */ + if (!per_read_length(s, &length)) + return False; + + /* ConnectGCCPDU */ + if (!per_read_choice(s, &choice)) + return False; + if (!per_read_selection(s, &selection)) + return False; + + /* ConferenceCreateRequest::conferenceName */ + if (!per_read_numeric_string(s, 1)) /* ConferenceName::numeric */ + return False; + if (!per_read_padding(s, 1)) /* padding */ + return False; + + /* UserData (SET OF SEQUENCE) */ + if (!per_read_number_of_sets(s, &number) || number != 1) /* one set of UserData */ + return False; + if (!per_read_choice(s, &choice) || choice != 0xC0) /* UserData::value present + select h221NonStandard (1) */ + return False; + + /* h221NonStandard */ + if (!per_read_octet_string(s, h221_cs_key, 4, 4)) /* h221NonStandard, client-to-server H.221 key, "Duca" */ + return False; + + /* userData::value (OCTET_STRING) */ + if (!per_read_length(s, &length)) + return False; + if (stream_get_left(s) < length) + return False; + if (!gcc_read_client_data_blocks(s, settings, length)) + return False; + + return True; +} + +/** * Write a GCC Conference Create Request.\n * @msdn{cc240836} * @param s stream @@ -200,6 +257,55 @@ void gcc_read_conference_create_response(STREAM* s, rdpSettings* settings) gcc_read_server_data_blocks(s, settings, length); } +boolean gcc_read_client_data_blocks(STREAM* s, rdpSettings *settings, int length) +{ + uint16 type; + uint16 blockLength; + int pos; + + while (length > 0) + { + pos = stream_get_pos(s); + gcc_read_user_data_header(s, &type, &blockLength); + + switch (type) + { + case CS_CORE: + if (!gcc_read_client_core_data(s, settings, blockLength - 4)) + return False; + break; + + case CS_SECURITY: + if (!gcc_read_client_security_data(s, settings)) + return False; + break; + + case CS_NET: + if (!gcc_read_client_network_data(s, settings)) + return False; + break; + + case CS_CLUSTER: + if (!gcc_read_client_cluster_data(s, settings)) + return False; + break; + + case CS_MONITOR: + if (!gcc_read_client_monitor_data(s, settings)) + return False; + break; + + default: + break; + } + + length -= blockLength; + stream_set_pos(s, pos + blockLength); + } + + return True; +} + void gcc_write_client_data_blocks(STREAM* s, rdpSettings *settings) { gcc_write_client_core_data(s, settings); @@ -262,6 +368,121 @@ void gcc_write_user_data_header(STREAM* s, uint16 type, uint16 length) } /** + * Read a client core data block (TS_UD_CS_CORE).\n + * @msdn{cc240510} + * @param s stream + * @param settings rdp settings + */ + +boolean gcc_read_client_core_data(STREAM* s, rdpSettings *settings, uint16 blockLength) +{ + uint32 version; + uint16 colorDepth = 0; + uint16 postBeta2ColorDepth = 0; + uint16 highColorDepth = 0; + uint16 supportedColorDepths = 0; + uint16 earlyCapabilityFlags = 0; + uint32 serverSelectedProtocol = 0; + char* str; + + /* Length of all required fields, until imeFileName */ + if (blockLength < 128) + return False; + + stream_read_uint32(s, version); /* version */ + settings->rdp_version = (version == RDP_VERSION_4 ? 5 : 4); + + stream_read_uint16(s, settings->width); /* desktopWidth */ + stream_read_uint16(s, settings->height); /* desktopHeight */ + stream_read_uint16(s, colorDepth); /* colorDepth */ + stream_seek_uint16(s); /* SASSequence (Secure Access Sequence) */ + stream_read_uint32(s, settings->kbd_layout); /* keyboardLayout */ + stream_read_uint32(s, settings->client_build); /* clientBuild */ + + /* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */ + str = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), 32); + stream_seek(s, 32); + snprintf(settings->client_hostname, sizeof(settings->client_hostname), "%s", str); + xfree(str); + + stream_read_uint32(s, settings->kbd_type); /* keyboardType */ + stream_read_uint32(s, settings->kbd_subtype); /* keyboardSubType */ + stream_read_uint32(s, settings->kbd_fn_keys); /* keyboardFunctionKey */ + + stream_seek(s, 64); /* imeFileName */ + + blockLength -= 128; + + /** + * The following fields are all optional. If one field is present, all of the preceding + * fields MUST also be present. If one field is not present, all of the subsequent fields + * MUST NOT be present. + * We must check the bytes left before reading each field. + */ + + do + { + if (blockLength < 2) + break; + stream_read_uint16(s, postBeta2ColorDepth); /* postBeta2ColorDepth */ + blockLength -= 2; + + if (blockLength < 2) + break; + stream_seek_uint16(s); /* clientProductID */ + blockLength -= 2; + + if (blockLength < 4) + break; + stream_seek_uint32(s); /* serialNumber */ + blockLength -= 4; + + if (blockLength < 2) + break; + stream_read_uint16(s, highColorDepth); /* highColorDepth */ + blockLength -= 2; + + if (blockLength < 2) + break; + stream_read_uint16(s, supportedColorDepths); /* supportedColorDepths */ + blockLength -= 2; + + if (blockLength < 2) + break; + stream_read_uint16(s, earlyCapabilityFlags); /* earlyCapabilityFlags */ + blockLength -= 2; + + if (blockLength < 64) + break; + str = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), 64); + stream_seek(s, 64); + snprintf(settings->client_product_id, sizeof(settings->client_product_id), "%s", str); + xfree(str); + blockLength -= 64; + + if (blockLength < 1) + break; + stream_read_uint8(s, settings->performance_flags); /* connectionType */ + blockLength -= 1; + + if (blockLength < 1) + break; + stream_seek_uint8(s); /* pad1octet */ + blockLength -= 1; + + if (blockLength < 4) + break; + stream_read_uint32(s, serverSelectedProtocol); /* serverSelectedProtocol */ + blockLength -= 4; + + if (settings->selected_protocol != serverSelectedProtocol) + return False; + } while (0); + + return True; +} + +/** * Write a client core data block (TS_UD_CS_CORE).\n * @msdn{cc240510} * @param s stream @@ -374,6 +595,19 @@ void gcc_read_server_core_data(STREAM* s, rdpSettings *settings) } /** + * Read a client security data block (TS_UD_CS_SEC).\n + * @msdn{cc240511} + * @param s stream + * @param settings rdp settings + */ + +boolean gcc_read_client_security_data(STREAM* s, rdpSettings *settings) +{ + printf("CS_SECURITY\n"); + return True; +} + +/** * Write a client security data block (TS_UD_CS_SEC).\n * @msdn{cc240511} * @param s stream @@ -433,6 +667,19 @@ void gcc_read_server_security_data(STREAM* s, rdpSettings *settings) } /** + * Read a client network data block (TS_UD_CS_NET).\n + * @msdn{cc240512} + * @param s stream + * @param settings rdp settings + */ + +boolean gcc_read_client_network_data(STREAM* s, rdpSettings *settings) +{ + printf("CS_NETWORK\n"); + return True; +} + +/** * Write a client network data block (TS_UD_CS_NET).\n * @msdn{cc240512} * @param s stream @@ -488,6 +735,19 @@ void gcc_read_server_network_data(STREAM* s, rdpSettings *settings) } /** + * Read a client cluster data block (TS_UD_CS_CLUSTER).\n + * @msdn{cc240514} + * @param s stream + * @param settings rdp settings + */ + +boolean gcc_read_client_cluster_data(STREAM* s, rdpSettings *settings) +{ + printf("CS_CLUSTER\n"); + return True; +} + +/** * Write a client cluster data block (TS_UD_CS_CLUSTER).\n * @msdn{cc240514} * @param s stream @@ -510,6 +770,19 @@ void gcc_write_client_cluster_data(STREAM* s, rdpSettings *settings) } /** + * Read a client monitor data block (TS_UD_CS_MONITOR).\n + * @msdn{dd305336} + * @param s stream + * @param settings rdp settings + */ + +boolean gcc_read_client_monitor_data(STREAM* s, rdpSettings *settings) +{ + printf("CS_MONITOR\n"); + return True; +} + +/** * Write a client monitor data block (TS_UD_CS_MONITOR).\n * @msdn{dd305336} * @param s stream @@ -546,3 +819,4 @@ void gcc_write_client_monitor_data(STREAM* s, rdpSettings *settings) } } } + diff --git a/libfreerdp-core/gcc.h b/libfreerdp-core/gcc.h index cbfa172..551284c 100644 --- a/libfreerdp-core/gcc.h +++ b/libfreerdp-core/gcc.h @@ -100,19 +100,26 @@ /* Monitor Flags */ #define MONITOR_PRIMARY 0x00000001 +boolean gcc_read_conference_create_request(STREAM* s, rdpSettings* settings); void gcc_write_conference_create_request(STREAM* s, STREAM* user_data); void gcc_read_conference_create_response(STREAM* s, rdpSettings* settings); +boolean gcc_read_client_data_blocks(STREAM* s, rdpSettings *settings, int length); void gcc_write_client_data_blocks(STREAM* s, rdpSettings *settings); void gcc_read_server_data_blocks(STREAM* s, rdpSettings *settings, int length); void gcc_read_user_data_header(STREAM* s, uint16* type, uint16* length); void gcc_write_user_data_header(STREAM* s, uint16 type, uint16 length); +boolean gcc_read_client_core_data(STREAM* s, rdpSettings *settings, uint16 blockLength); void gcc_write_client_core_data(STREAM* s, rdpSettings *settings); void gcc_read_server_core_data(STREAM* s, rdpSettings *settings); +boolean gcc_read_client_security_data(STREAM* s, rdpSettings *settings); void gcc_write_client_security_data(STREAM* s, rdpSettings *settings); void gcc_read_server_security_data(STREAM* s, rdpSettings *settings); +boolean gcc_read_client_network_data(STREAM* s, rdpSettings *settings); void gcc_write_client_network_data(STREAM* s, rdpSettings *settings); void gcc_read_server_network_data(STREAM* s, rdpSettings *settings); +boolean gcc_read_client_cluster_data(STREAM* s, rdpSettings *settings); void gcc_write_client_cluster_data(STREAM* s, rdpSettings *settings); +boolean gcc_read_client_monitor_data(STREAM* s, rdpSettings *settings); void gcc_write_client_monitor_data(STREAM* s, rdpSettings *settings); #endif /* __GCC_H */ diff --git a/libfreerdp-core/mcs.c b/libfreerdp-core/mcs.c index 8c0df1f..438c17d 100644 --- a/libfreerdp-core/mcs.c +++ b/libfreerdp-core/mcs.c @@ -348,6 +348,58 @@ void mcs_print_domain_parameters(DomainParameters* domainParameters) } /** + * Read an MCS Connect Initial PDU.\n + * @msdn{cc240508} + * @param mcs MCS module + * @param s stream + */ + +boolean mcs_read_connect_initial(rdpMcs* mcs, STREAM* s) +{ + int length; + boolean upwardFlag; + + tpkt_read_header(s); + + if (tpdu_read_data(s) == 0) + return False; + + if (!ber_read_application_tag(s, MCS_TYPE_CONNECT_INITIAL, &length)) + return False; + + /* callingDomainSelector (OCTET_STRING) */ + if (!ber_read_octet_string(s, &length)) + return False; + stream_seek(s, length); + + /* calledDomainSelector (OCTET_STRING) */ + if (!ber_read_octet_string(s, &length)) + return False; + stream_seek(s, length); + + /* upwardFlag (BOOLEAN) */ + if (!ber_read_boolean(s, &upwardFlag)) + return False; + + /* targetParameters (DomainParameters) */ + mcs_read_domain_parameters(s, &mcs->targetParameters); + + /* minimumParameters (DomainParameters) */ + mcs_read_domain_parameters(s, &mcs->minimumParameters); + + /* maximumParameters (DomainParameters) */ + mcs_read_domain_parameters(s, &mcs->maximumParameters); + + if (!ber_read_octet_string(s, &length)) + return False; + + if (!gcc_read_conference_create_request(s, mcs->transport->settings)) + return False; + + return True; +} + +/** * Write an MCS Connect Initial PDU.\n * @msdn{cc240508} * @param s stream @@ -468,6 +520,17 @@ void mcs_recv_connect_response(rdpMcs* mcs) } /** + * Send MCS Connect Response.\n + * @msdn{cc240501} + * @param mcs mcs module + */ + +boolean mcs_send_connect_response(rdpMcs* mcs) +{ + return True; +} + +/** * Send MCS Erect Domain Request.\n * @msdn{cc240523} * @param mcs diff --git a/libfreerdp-core/mcs.h b/libfreerdp-core/mcs.h index 306f673..f4e85e3 100644 --- a/libfreerdp-core/mcs.h +++ b/libfreerdp-core/mcs.h @@ -130,8 +130,10 @@ boolean mcs_connect(rdpMcs* mcs); void mcs_write_connect_initial(STREAM* s, rdpMcs* mcs, STREAM* user_data); +boolean mcs_read_connect_initial(rdpMcs* mcs, STREAM* s); void mcs_send_connect_initial(rdpMcs* mcs); void mcs_recv_connect_response(rdpMcs* mcs); +boolean mcs_send_connect_response(rdpMcs* mcs); void mcs_send_erect_domain_request(rdpMcs* mcs); void mcs_send_attach_user_request(rdpMcs* mcs); void mcs_recv_attach_user_confirm(rdpMcs* mcs); diff --git a/libfreerdp-core/nego.c b/libfreerdp-core/nego.c index 0f48cff..8181a7e 100644 --- a/libfreerdp-core/nego.c +++ b/libfreerdp-core/nego.c @@ -508,6 +508,9 @@ void nego_send_negotiation_response(rdpNego* nego) stream_set_mark(s, em); transport_write(nego->transport, s); + + /* update settings with negotiated protocol security */ + nego->transport->settings->selected_protocol = nego->selected_protocol; } /** diff --git a/libfreerdp-core/peer.c b/libfreerdp-core/peer.c index 628448c..99022ba 100644 --- a/libfreerdp-core/peer.c +++ b/libfreerdp-core/peer.c @@ -64,6 +64,11 @@ static int peer_recv_callback(rdpTransport* transport, STREAM* s, void* extra) return -1; break; + case CONNECTION_STATE_NEGO: + if (!rdp_server_accept_mcs_connect_initial(peer->rdp, s)) + return -1; + break; + default: printf("Invalid state %d\n", peer->rdp->state); return -1; diff --git a/libfreerdp-core/per.c b/libfreerdp-core/per.c index 77125fc..1ea2477 100644 --- a/libfreerdp-core/per.c +++ b/libfreerdp-core/per.c @@ -134,6 +134,19 @@ void per_write_number_of_sets(STREAM* s, uint8 number) } /** + * Read PER padding with zeros. + * @param s stream + * @param length + */ + +boolean per_read_padding(STREAM* s, int length) +{ + stream_seek(s, length); + + return True; +} + +/** * Write PER padding with zeros. * @param s stream * @param length @@ -372,6 +385,32 @@ void per_write_octet_string(STREAM* s, uint8* oct_str, int length, int min) } /** + * Read PER NumericString. + * @param s stream + * @param num_str numeric string + * @param length string length + * @param min minimum string length + */ + +boolean per_read_numeric_string(STREAM* s, int min) +{ + int i; + int length; + uint16 mlength; + + per_read_length(s, &mlength); + + length = mlength + min; + + for (i = 0; i < length; i += 2) + { + stream_seek(s, 1); + } + + return True; +} + +/** * Write PER NumericString. * @param s stream * @param num_str numeric string diff --git a/libfreerdp-core/per.h b/libfreerdp-core/per.h index 0c5dc03..19821ab 100644 --- a/libfreerdp-core/per.h +++ b/libfreerdp-core/per.h @@ -30,6 +30,7 @@ boolean per_read_selection(STREAM* s, uint8* selection); void per_write_selection(STREAM* s, uint8 selection); boolean per_read_number_of_sets(STREAM* s, uint8* number); void per_write_number_of_sets(STREAM* s, uint8 number); +boolean per_read_padding(STREAM* s, int length); void per_write_padding(STREAM* s, int length); boolean per_read_integer(STREAM* s, uint32* integer); boolean per_read_integer16(STREAM* s, uint16* integer, uint16 min); @@ -40,8 +41,7 @@ void per_write_object_identifier(STREAM* s, uint8 oid[6]); boolean per_read_object_identifier(STREAM* s, uint8 oid[6]); boolean per_read_octet_string(STREAM* s, uint8* oct_str, int length, int min); void per_write_octet_string(STREAM* s, uint8* oct_str, int length, int min); +boolean per_read_numeric_string(STREAM* s, int min); void per_write_numeric_string(STREAM* s, uint8* num_str, int length, int min); -boolean per_read_integer16(STREAM* s, uint16* integer, uint16 min); -void per_write_integer16(STREAM* s, uint16 integer, uint16 min); #endif /* __PER_H */ -- 2.7.4