diff --git a/freerdp-ui/test/freerdp.c b/freerdp-ui/test/freerdp.c index b8a00caa0..7a24739e1 100644 --- a/freerdp-ui/test/freerdp.c +++ b/freerdp-ui/test/freerdp.c @@ -78,9 +78,15 @@ int main(int argc, char* argv[]) transport_connect_nla(transport); mcs = mcs_new(transport); + mcs_send_connect_initial(mcs); mcs_recv_connect_response(mcs); + mcs_send_erect_domain_request(mcs); + mcs_send_attach_user_request(mcs); + + mcs_recv_attach_user_confirm(mcs); + return 0; } diff --git a/libfreerdp-core/ber.c b/libfreerdp-core/ber.c index 04c67713d..36cb4cb70 100644 --- a/libfreerdp-core/ber.c +++ b/libfreerdp-core/ber.c @@ -159,7 +159,7 @@ void ber_write_sequence_of_tag(STREAM* s, int length) ber_write_length(s, length); } -boolean ber_read_enumerated(STREAM* s, uint8* enumerated, uint8 max) +boolean ber_read_enumerated(STREAM* s, uint8* enumerated, uint8 count) { int length; @@ -172,7 +172,7 @@ boolean ber_read_enumerated(STREAM* s, uint8* enumerated, uint8 max) return False; /* check that enumerated value falls within expected range */ - if (*enumerated > max) + if (*enumerated + 1 > count) return False; return True; diff --git a/libfreerdp-core/ber.h b/libfreerdp-core/ber.h index 2a373bf6b..052b7daaa 100644 --- a/libfreerdp-core/ber.h +++ b/libfreerdp-core/ber.h @@ -50,7 +50,7 @@ void ber_write_length(STREAM* s, int length); void ber_write_universal_tag(STREAM* s, uint8 tag); void ber_write_application_tag(STREAM* s, uint8 tag, int length); boolean ber_read_application_tag(STREAM* s, uint8 tag, int* length); -boolean ber_read_enumerated(STREAM* s, uint8* enumerated, uint8 max); +boolean ber_read_enumerated(STREAM* s, uint8* enumerated, uint8 count); boolean ber_read_sequence_of_tag(STREAM* s, int* length); void ber_write_sequence_of_tag(STREAM* s, int length); boolean ber_read_octet_string(STREAM* s, int* length); diff --git a/libfreerdp-core/gcc.c b/libfreerdp-core/gcc.c index eef2e2313..eab01178d 100644 --- a/libfreerdp-core/gcc.c +++ b/libfreerdp-core/gcc.c @@ -185,7 +185,7 @@ void gcc_read_conference_create_response(STREAM* s, rdpSettings* settings) per_read_integer(s, &tag); /* ConferenceCreateResponse::result (ENUMERATED) */ - per_read_enumerated(s, &result); + per_read_enumerated(s, &result, MCS_Result_enum_length); /* number of UserData sets */ per_read_number_of_sets(s, &number); @@ -198,11 +198,18 @@ void gcc_read_conference_create_response(STREAM* s, rdpSettings* settings) /* userData (OCTET_STRING) */ per_read_length(s, &length); - - printf("server core data, length:%d\n", length); gcc_read_server_data_blocks(s, settings, length); } +void gcc_write_client_data_blocks(STREAM* s, rdpSettings *settings) +{ + gcc_write_client_core_data(s, settings); + gcc_write_client_cluster_data(s, settings); + gcc_write_client_security_data(s, settings); + gcc_write_client_network_data(s, settings); + gcc_write_client_monitor_data(s, settings); +} + void gcc_read_server_data_blocks(STREAM* s, rdpSettings *settings, int length) { uint16 type; diff --git a/libfreerdp-core/gcc.h b/libfreerdp-core/gcc.h index 4fe12de8e..cbfa17292 100644 --- a/libfreerdp-core/gcc.h +++ b/libfreerdp-core/gcc.h @@ -21,6 +21,7 @@ #define __GCC_H #include "per.h" +#include "mcs.h" #include #include @@ -101,6 +102,7 @@ void gcc_write_conference_create_request(STREAM* s, STREAM* user_data); void gcc_read_conference_create_response(STREAM* s, rdpSettings* settings); +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); diff --git a/libfreerdp-core/mcs.c b/libfreerdp-core/mcs.c index 1a458c64f..6d53dca22 100644 --- a/libfreerdp-core/mcs.c +++ b/libfreerdp-core/mcs.c @@ -80,6 +80,36 @@ * rt-user-rejected (15) * } * + * ErectDomainRequest ::= [APPLICATION 1] IMPLICIT SEQUENCE + * { + * subHeight INTEGER (0..MAX), + * subInterval INTEGER (0..MAX) + * } + * + * AttachUserRequest ::= [APPPLICATION 10] IMPLICIT SEQUENCE + * { + * } + * + * AttachUserConfirm ::= [APPLICATION 11] IMPLICIT SEQUENCE + * { + * result Result, + * initiator UserId OPTIONAL + * } + * + * ChannelJoinRequest ::= [APPLICATION 14] IMPLICIT SEQUENCE + * { + * initiator UserId, + * channelId ChannelId + * } + * + * ChannelJoinConfirm ::= [APPLICATION 15] IMPLICIT SEQUENCE + * { + * result Result, + * initiator UserId, + * requested ChannelId, + * channelId ChannelId OPTIONAL + * } + * */ uint8 callingDomainSelector[1] = "\x01"; @@ -114,7 +144,7 @@ uint8 mcs_result_enumerated[16][32] = * @param maxMCSPDUsize max MCS PDU size */ -static void mcs_init_domain_parameters(DOMAIN_PARAMETERS* domainParameters, +static void mcs_init_domain_parameters(DomainParameters* domainParameters, uint32 maxChannelIds, uint32 maxUserIds, uint32 maxTokenIds, uint32 maxMCSPDUsize) { domainParameters->maxChannelIds = maxChannelIds; @@ -128,7 +158,7 @@ static void mcs_init_domain_parameters(DOMAIN_PARAMETERS* domainParameters, domainParameters->protocolVersion = 2; } -static void mcs_read_domain_parameters(STREAM* s, DOMAIN_PARAMETERS* domainParameters) +static void mcs_read_domain_parameters(STREAM* s, DomainParameters* domainParameters) { int length; ber_read_sequence_of_tag(s, &length); @@ -148,7 +178,7 @@ static void mcs_read_domain_parameters(STREAM* s, DOMAIN_PARAMETERS* domainParam * @param domainParameters domain parameters */ -static void mcs_write_domain_parameters(STREAM* s, DOMAIN_PARAMETERS* domainParameters) +static void mcs_write_domain_parameters(STREAM* s, DomainParameters* domainParameters) { int length; uint8 *bm, *em; @@ -173,7 +203,7 @@ static void mcs_write_domain_parameters(STREAM* s, DOMAIN_PARAMETERS* domainPara stream_set_mark(s, em); } -static void mcs_print_domain_parameters(DOMAIN_PARAMETERS* domainParameters) +void mcs_print_domain_parameters(DomainParameters* domainParameters) { printf("DomainParameters {\n"); printf("\tmaxChannelIds:%d\n", domainParameters->maxChannelIds); @@ -243,11 +273,7 @@ void mcs_send_connect_initial(rdpMcs* mcs) STREAM* client_data; client_data = stream_new(512); - gcc_write_client_core_data(client_data, mcs->transport->settings); - gcc_write_client_cluster_data(client_data, mcs->transport->settings); - gcc_write_client_security_data(client_data, mcs->transport->settings); - gcc_write_client_network_data(client_data, mcs->transport->settings); - gcc_write_client_monitor_data(client_data, mcs->transport->settings); + gcc_write_client_data_blocks(client_data, mcs->transport->settings); gcc_CCrq = stream_new(512); gcc_write_conference_create_request(gcc_CCrq, client_data); @@ -283,19 +309,106 @@ void mcs_recv_connect_response(rdpMcs* mcs) tpdu_read_data(s); ber_read_application_tag(s, MCS_TYPE_CONNECT_RESPONSE, &length); - ber_read_enumerated(s, &result, 15); + ber_read_enumerated(s, &result, MCS_Result_enum_length); ber_read_integer(s, &calledConnectId); - printf("MCS Connect-Response Result: %s\n", mcs_result_enumerated[result]); - mcs_read_domain_parameters(s, &(mcs->domainParameters)); - mcs_print_domain_parameters(&(mcs->domainParameters)); ber_read_octet_string(s, &length); gcc_read_conference_create_response(s, mcs->transport->settings); } +void mcs_send_erect_domain_request(rdpMcs* mcs) +{ + STREAM* s; + int length = 12; + s = stream_new(length); + + tpkt_write_header(s, length); + tpdu_write_data(s, length - 5); + + /* DomainMCSPDU, ErectDomainRequest */ + per_write_choice(s, DomainMCSPDU_ErectDomainRequest << 2); + per_write_integer(s, 0); /* subHeight (INTEGER) */ + per_write_integer(s, 0); /* subInterval (INTEGER) */ + + tls_write(mcs->transport->tls, s->data, stream_get_length(s)); +} + +void mcs_send_attach_user_request(rdpMcs* mcs) +{ + STREAM* s; + int length = 8; + s = stream_new(length); + + tpkt_write_header(s, length); + tpdu_write_data(s, length - 5); + + /* DomainMCSPDU, AttachUserRequest */ + per_write_choice(s, DomainMCSPDU_AttachUserRequest << 2); + + tls_write(mcs->transport->tls, s->data, stream_get_length(s)); +} + +void mcs_recv_attach_user_confirm(rdpMcs* mcs) +{ + STREAM* s; + int length; + uint8 result; + uint8 choice; + + s = stream_new(32); + tls_read(mcs->transport->tls, s->data, s->size); + + tpkt_read_header(s); + tpdu_read_data(s); + + per_read_choice(s, &choice); + per_read_enumerated(s, &result, MCS_Result_enum_length); /* result */ + per_read_integer16(s, &(mcs->user_id), MCS_BASE_CHANNEL_ID); /* initiator (UserId) */ +} + +void mcs_send_channel_join_request(rdpMcs* mcs, uint16 channel_id) +{ + STREAM* s; + int length = 8; + s = stream_new(length); + + tpkt_write_header(s, length); + tpdu_write_data(s, length - 5); + + /* DomainMCSPDU, ChannelJoinRequest*/ + per_write_choice(s, DomainMCSPDU_ChannelJoinRequest << 2); + per_write_integer16(s, mcs->user_id, MCS_BASE_CHANNEL_ID); + per_write_integer16(s, channel_id + MCS_BASE_CHANNEL_ID, 0); + + tls_write(mcs->transport->tls, s->data, stream_get_length(s)); +} + +void mcs_recv_channel_join_confirm(rdpMcs* mcs) +{ + STREAM* s; + int length; + uint8 choice; + uint8 result; + uint16 initiator; + uint16 requested; + uint16 channelId; + + s = stream_new(32); + tls_read(mcs->transport->tls, s->data, s->size); + + tpkt_read_header(s); + tpdu_read_data(s); + + per_read_choice(s, &choice); + per_read_enumerated(s, &result, MCS_Result_enum_length); /* result */ + per_read_integer16(s, &initiator, MCS_BASE_CHANNEL_ID); /* initiator (UserId) */ + per_read_integer16(s, &requested, 0); /* requested (ChannelId) */ + per_read_integer16(s, &channelId, 0); /* channelId */ +} + /** * Instantiate new MCS module. * @param transport transport diff --git a/libfreerdp-core/mcs.h b/libfreerdp-core/mcs.h index e7604b4f7..a9a636d66 100644 --- a/libfreerdp-core/mcs.h +++ b/libfreerdp-core/mcs.h @@ -26,6 +26,77 @@ #include #include +#define MCS_BASE_CHANNEL_ID 1001 + +enum MCS_Result +{ + MCS_Result_successful = 0, + MCS_Result_domain_merging = 1, + MCS_Result_domain_not_hierarchical = 2, + MCS_Result_no_such_channel = 3, + MCS_Result_no_such_domain = 4, + MCS_Result_no_such_user = 5, + MCS_Result_not_admitted = 6, + MCS_Result_other_user_id = 7, + MCS_Result_parameters_unacceptable = 8, + MCS_Result_token_not_available = 9, + MCS_Result_token_not_possessed = 10, + MCS_Result_too_many_channels = 11, + MCS_Result_too_many_tokens = 12, + MCS_Result_too_many_users = 13, + MCS_Result_unspecified_failure = 14, + MCS_Result_user_rejected = 15, + MCS_Result_enum_length = 16 +}; + +enum DomainMCSPDU +{ + DomainMCSPDU_PlumbDomainIndication = 0, + DomainMCSPDU_ErectDomainRequest = 1, + DomainMCSPDU_MergeChannelsRequest = 2, + DomainMCSPDU_MergeChannelsConfirm = 3, + DomainMCSPDU_PurgeChannelsIndication = 4, + DomainMCSPDU_MergeTokensRequest = 5, + DomainMCSPDU_MergeTokensConfirm = 6, + DomainMCSPDU_PurgeTokensIndication = 7, + DomainMCSPDU_DisconnectProviderUltimatum = 8, + DomainMCSPDU_RejectMCSPDUUltimatum = 9, + DomainMCSPDU_AttachUserRequest = 10, + DomainMCSPDU_AttachUserConfirm = 11, + DomainMCSPDU_DetachUserRequest = 12, + DomainMCSPDU_DetachUserIndication = 13, + DomainMCSPDU_ChannelJoinRequest = 14, + DomainMCSPDU_ChannelJoinConfirm = 15, + DomainMCSPDU_ChannelLeaveRequest = 16, + DomainMCSPDU_ChannelConveneRequest = 17, + DomainMCSPDU_ChannelConveneConfirm = 18, + DomainMCSPDU_ChannelDisbandRequest = 19, + DomainMCSPDU_ChannelDisbandIndication = 20, + DomainMCSPDU_ChannelAdmitRequest = 21, + DomainMCSPDU_ChannelAdmitIndication = 22, + DomainMCSPDU_ChannelExpelRequest = 23, + DomainMCSPDU_ChannelExpelIndication = 24, + DomainMCSPDU_SendDataRequest = 25, + DomainMCSPDU_SendDataIndication = 26, + DomainMCSPDU_UniformSendDataRequest = 27, + DomainMCSPDU_UniformSendDataIndication = 28, + DomainMCSPDU_TokenGrabRequest = 29, + DomainMCSPDU_TokenGrabConfirm = 30, + DomainMCSPDU_TokenInhibitRequest = 31, + DomainMCSPDU_TokenInhibitConfirm = 32, + DomainMCSPDU_TokenGiveRequest = 33, + DomainMCSPDU_TokenGiveIndication = 34, + DomainMCSPDU_TokenGiveResponse = 35, + DomainMCSPDU_TokenGiveConfirm = 36, + DomainMCSPDU_TokenPleaseRequest = 37, + DomainMCSPDU_TokenPleaseConfirm = 38, + DomainMCSPDU_TokenReleaseRequest = 39, + DomainMCSPDU_TokenReleaseConfirm = 40, + DomainMCSPDU_TokenTestRequest = 41, + DomainMCSPDU_TokenTestConfirm = 42, + DomainMCSPDU_enum_length = 43 +}; + typedef struct { uint32 maxChannelIds; @@ -36,15 +107,16 @@ typedef struct uint32 maxHeight; uint32 maxMCSPDUsize; uint32 protocolVersion; -} DOMAIN_PARAMETERS; +} DomainParameters; struct rdp_mcs { + uint16 user_id; struct rdp_transport* transport; - DOMAIN_PARAMETERS domainParameters; - DOMAIN_PARAMETERS targetParameters; - DOMAIN_PARAMETERS minimumParameters; - DOMAIN_PARAMETERS maximumParameters; + DomainParameters domainParameters; + DomainParameters targetParameters; + DomainParameters minimumParameters; + DomainParameters maximumParameters; }; typedef struct rdp_mcs rdpMcs; @@ -55,6 +127,10 @@ void mcs_write_connect_initial(STREAM* s, rdpMcs* mcs, STREAM* user_data); void mcs_send_connect_initial(rdpMcs* mcs); void mcs_recv_connect_response(rdpMcs* mcs); +void mcs_send_erect_domain_request(rdpMcs* mcs); +void mcs_recv_attach_user_confirm(rdpMcs* mcs); +void mcs_send_channel_join_request(rdpMcs* mcs, uint16 channel_id); +void mcs_recv_channel_join_confirm(rdpMcs* mcs); rdpMcs* mcs_new(rdpTransport* transport); void mcs_free(rdpMcs* mcs); diff --git a/libfreerdp-core/per.c b/libfreerdp-core/per.c index 058cf88cd..831894f92 100644 --- a/libfreerdp-core/per.c +++ b/libfreerdp-core/per.c @@ -146,9 +146,40 @@ boolean per_read_integer16(STREAM* s, uint16* integer, uint16 min) return True; } -boolean per_read_enumerated(STREAM* s, uint8* enumerated) +void per_write_integer(STREAM* s, uint32 integer) +{ + int length; + + if (integer <= 0xFF) + { + per_write_length(s, 1); + stream_write_uint8(s, integer); + } + else if (integer <= 0xFFFF) + { + per_write_length(s, 2); + stream_write_uint16_be(s, integer); + } + else if (integer <= 0xFFFFFFFF) + { + per_write_length(s, 4); + stream_write_uint32_be(s, integer); + } +} + +void per_write_integer16(STREAM* s, uint16 integer, uint16 min) +{ + stream_write_uint16_be(s, integer - min); +} + +boolean per_read_enumerated(STREAM* s, uint8* enumerated, uint8 count) { stream_read_uint8(s, *enumerated); + + /* check that enumerated value falls within expected range */ + if (*enumerated + 1 > count) + return False; + return True; } diff --git a/libfreerdp-core/per.h b/libfreerdp-core/per.h index 8c9cb5085..21d2f6ecb 100644 --- a/libfreerdp-core/per.h +++ b/libfreerdp-core/per.h @@ -33,7 +33,9 @@ void per_write_number_of_sets(STREAM* s, uint8 number); 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); -boolean per_read_enumerated(STREAM* s, uint8* enumerated); +void per_write_integer(STREAM* s, uint32 integer); +void per_write_integer16(STREAM* s, uint16 integer, uint16 min); +boolean per_read_enumerated(STREAM* s, uint8* enumerated, uint8 count); 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);