diff --git a/freerdp-ui/test/freerdp.c b/freerdp-ui/test/freerdp.c index 368e701b9..b8a00caa0 100644 --- a/freerdp-ui/test/freerdp.c +++ b/freerdp-ui/test/freerdp.c @@ -80,7 +80,7 @@ int main(int argc, char* argv[]) mcs = mcs_new(transport); mcs_send_connect_initial(mcs); - mcs_recv(mcs); + mcs_recv_connect_response(mcs); return 0; } diff --git a/libfreerdp-core/ber.c b/libfreerdp-core/ber.c index b804fd0be..04c67713d 100644 --- a/libfreerdp-core/ber.c +++ b/libfreerdp-core/ber.c @@ -19,6 +19,25 @@ #include "ber.h" +void ber_read_length(STREAM* s, int* length) +{ + uint8 byte; + + stream_read_uint8(s, byte); + + if (byte & 0x80) + { + if (byte & ~(0x80) == 2) + { + stream_read_uint16_be(s, *length); + } + } + else + { + *length = byte; + } +} + /** * Write BER length. * @param s stream @@ -38,6 +57,18 @@ void ber_write_length(STREAM* s, int length) } } +boolean ber_read_universal_tag(STREAM* s, uint8 tag) +{ + uint8 byte; + + stream_read_uint8(s, byte); + + if (byte != (BER_CLASS_UNIV | BER_PRIMITIVE) | (BER_TAG_MASK & tag)) + return False; + + return True; +} + /** * Write BER Universal tag. * @param s stream @@ -71,6 +102,51 @@ void ber_write_application_tag(STREAM* s, uint8 tag, int length) } } +boolean ber_read_application_tag(STREAM* s, uint8 tag, int* length) +{ + uint8 byte; + + if (tag > 30) + { + stream_read_uint8(s, byte); + + if (byte != ((BER_CLASS_APPL | BER_CONSTRUCT) | BER_TAG_MASK)) + return False; + + stream_read_uint8(s, byte); + + if (byte != tag) + return False; + + ber_read_length(s, length); + } + else + { + stream_read_uint8(s, byte); + + if (byte != ((BER_CLASS_APPL | BER_CONSTRUCT) | (BER_TAG_MASK & tag))) + return False; + + ber_read_length(s, length); + } + + return True; +} + +boolean ber_read_sequence_of_tag(STREAM* s, int* length) +{ + uint8 byte; + + stream_read_uint8(s, byte); + + if (byte != ((BER_CLASS_UNIV | BER_CONSTRUCT) | (BER_TAG_SEQUENCE_OF))) + return False; + + ber_read_length(s, length); + + return True; +} + /** * Write BER SEQUENCE OF tag. * @param s stream @@ -83,6 +159,33 @@ 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) +{ + int length; + + ber_read_universal_tag(s, BER_TAG_ENUMERATED); + ber_read_length(s, &length); + + if (length == 1) + stream_read_uint8(s, *enumerated); + else + return False; + + /* check that enumerated value falls within expected range */ + if (*enumerated > max) + return False; + + return True; +} + +boolean ber_read_octet_string(STREAM* s, int* length) +{ + ber_read_universal_tag(s, BER_TAG_OCTET_STRING); + ber_read_length(s, length); + + return True; +} + /** * Write a BER OCTET_STRING * @param s stream @@ -110,6 +213,30 @@ void ber_write_boolean(STREAM* s, boolean value) stream_write_uint8(s, (value == True) ? 0xFF : 0); } +boolean ber_read_integer(STREAM* s, uint32* value) +{ + int length; + + ber_read_universal_tag(s, BER_TAG_INTEGER); + ber_read_length(s, &length); + + if (length == 1) + stream_read_uint8(s, *value); + else if (length == 2) + stream_read_uint16_be(s, *value); + else if (length == 3) + { + uint8 byte; + stream_read_uint8(s, byte); + stream_read_uint16_be(s, *value); + *value += (byte << 16); + } + else + return False; + + return True; +} + /** * Write a BER INTEGER * @param s diff --git a/libfreerdp-core/ber.h b/libfreerdp-core/ber.h index 79c72236f..2a373bf6b 100644 --- a/libfreerdp-core/ber.h +++ b/libfreerdp-core/ber.h @@ -42,14 +42,21 @@ #define BER_TAG_BOOLEAN 0x01 #define BER_TAG_INTEGER 0x02 #define BER_TAG_OCTET_STRING 0x04 +#define BER_TAG_ENUMERATED 0x0A #define BER_TAG_SEQUENCE_OF 0x10 +void ber_read_length(STREAM* s, int* length); 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_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); void ber_write_octet_string(STREAM* s, uint8* oct_str, int length); void ber_write_boolean(STREAM* s, boolean value); +boolean ber_read_integer(STREAM* s, uint32* value); void ber_write_integer(STREAM* s, uint32 value); #endif /* __BER_H */ diff --git a/libfreerdp-core/mcs.c b/libfreerdp-core/mcs.c index 48e2c7adf..afab69e7c 100644 --- a/libfreerdp-core/mcs.c +++ b/libfreerdp-core/mcs.c @@ -52,11 +52,59 @@ * protocolVersion INTEGER (0..MAX) * } * + * Connect-Response ::= [APPLICATION 102] IMPLICIT SEQUENCE + * { + * result Result, + * calledConnectId INTEGER (0..MAX), + * domainParameters DomainParameters, + * userData OCTET_STRING + * } + * + * Result ::= ENUMERATED + * { + * rt-successful (0), + * rt-domain-merging (1), + * rt-domain-not-hierarchical (2), + * rt-no-such-channel (3), + * rt-no-such-domain (4), + * rt-no-such-user (5), + * rt-not-admitted (6), + * rt-other-user-id (7), + * rt-parameters-unacceptable (8), + * rt-token-not-available (9), + * rt-token-not-possessed (10), + * rt-too-many-channels (11), + * rt-too-many-tokens (12), + * rt-too-many-users (13), + * rt-unspecified-failure (14), + * rt-user-rejected (15) + * } + * */ uint8 callingDomainSelector[1] = "\x01"; uint8 calledDomainSelector[1] = "\x01"; +uint8 mcs_result_enumerated[16][32] = +{ + "rt-successful", + "rt-domain-merging", + "rt-domain-not-hierarchical", + "rt-no-such-channel", + "rt-no-such-domain", + "rt-no-such-user", + "rt-not-admitted", + "rt-other-user-id", + "rt-parameters-unacceptable", + "rt-token-not-available", + "rt-token-not-possessed", + "rt-too-many-channels", + "rt-too-many-tokens", + "rt-too-many-users", + "rt-unspecified-failure", + "rt-user-rejected" +}; + /** * Initialize MCS Domain Parameters. * @param domainParameters domain parameters @@ -80,6 +128,20 @@ static void mcs_init_domain_parameters(DOMAIN_PARAMETERS* domainParameters, domainParameters->protocolVersion = 2; } +static void mcs_read_domain_parameters(STREAM* s, DOMAIN_PARAMETERS* domainParameters) +{ + int length; + ber_read_sequence_of_tag(s, &length); + ber_read_integer(s, &(domainParameters->maxChannelIds)); + ber_read_integer(s, &(domainParameters->maxUserIds)); + ber_read_integer(s, &(domainParameters->maxTokenIds)); + ber_read_integer(s, &(domainParameters->numPriorities)); + ber_read_integer(s, &(domainParameters->minThroughput)); + ber_read_integer(s, &(domainParameters->maxHeight)); + ber_read_integer(s, &(domainParameters->maxMCSPDUsize)); + ber_read_integer(s, &(domainParameters->protocolVersion)); +} + /** * Write MCS Domain Parameters. * @param s stream @@ -111,6 +173,20 @@ 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) +{ + printf("DomainParameters {\n"); + printf("\tmaxChannelIds:%d\n", domainParameters->maxChannelIds); + printf("\tmaxUserIds:%d\n", domainParameters->maxUserIds); + printf("\tmaxTokenIds:%d\n", domainParameters->maxTokenIds); + printf("\tnumPriorities:%d\n", domainParameters->numPriorities); + printf("\tminThroughput:%d\n", domainParameters->minThroughput); + printf("\tmaxHeight:%d\n", domainParameters->maxHeight); + printf("\tmaxMCSPDUsize:%d\n", domainParameters->maxMCSPDUsize); + printf("\tprotocolVersion:%d\n", domainParameters->protocolVersion); + printf("}\n"); +} + /** * Write an MCS Connect Initial PDU. * @param s stream @@ -158,18 +234,6 @@ void mcs_write_connect_initial(STREAM* s, rdpMcs* mcs, STREAM* user_data) stream_set_mark(s, em); } -int mcs_recv(rdpMcs* mcs) -{ - int bytes_read; - int size = 2048; - char *recv_buffer; - - recv_buffer = xmalloc(size); - bytes_read = tls_read(mcs->transport->tls, recv_buffer, size); - - return 0; -} - void mcs_send_connect_initial(rdpMcs* mcs) { STREAM* s; @@ -205,6 +269,33 @@ void mcs_send_connect_initial(rdpMcs* mcs) tls_write(mcs->transport->tls, s->data, stream_get_length(s)); } +void mcs_recv_connect_response(rdpMcs* mcs) +{ + STREAM* s; + int length; + uint8 result; + uint32 calledConnectId; + + s = stream_new(1024); + tls_read(mcs->transport->tls, s->data, s->size); + + tpkt_read_header(s); + tpdu_read_data(s); + + ber_read_application_tag(s, MCS_TYPE_CONNECT_RESPONSE, &length); + ber_read_enumerated(s, &result, 15); + 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); + + printf("userData, length:%d\n", length); +} + /** * Instantiate new MCS module. * @param transport transport diff --git a/libfreerdp-core/mcs.h b/libfreerdp-core/mcs.h index 8144055d5..e7604b4f7 100644 --- a/libfreerdp-core/mcs.h +++ b/libfreerdp-core/mcs.h @@ -28,19 +28,20 @@ typedef struct { - uint16 maxChannelIds; - uint16 maxUserIds; - uint16 maxTokenIds; - uint16 numPriorities; - uint16 minThroughput; - uint16 maxHeight; - uint16 maxMCSPDUsize; - uint16 protocolVersion; + uint32 maxChannelIds; + uint32 maxUserIds; + uint32 maxTokenIds; + uint32 numPriorities; + uint32 minThroughput; + uint32 maxHeight; + uint32 maxMCSPDUsize; + uint32 protocolVersion; } DOMAIN_PARAMETERS; struct rdp_mcs { struct rdp_transport* transport; + DOMAIN_PARAMETERS domainParameters; DOMAIN_PARAMETERS targetParameters; DOMAIN_PARAMETERS minimumParameters; DOMAIN_PARAMETERS maximumParameters; @@ -53,8 +54,7 @@ typedef struct rdp_mcs rdpMcs; void mcs_write_connect_initial(STREAM* s, rdpMcs* mcs, STREAM* user_data); void mcs_send_connect_initial(rdpMcs* mcs); - -int mcs_recv(rdpMcs* mcs); +void mcs_recv_connect_response(rdpMcs* mcs); rdpMcs* mcs_new(rdpTransport* transport); void mcs_free(rdpMcs* mcs); diff --git a/libfreerdp-core/tpdu.c b/libfreerdp-core/tpdu.c index e11d0c627..d66617bca 100644 --- a/libfreerdp-core/tpdu.c +++ b/libfreerdp-core/tpdu.c @@ -70,16 +70,18 @@ tpdu_read_header(STREAM* s, uint8* code) stream_read_uint8(s, li); /* LI */ stream_read_uint8(s, *code); /* Code */ - /* DST-REF (2 bytes) */ - /* SRC-REF (2 bytes) */ - /* Class 0 (1 byte) */ - stream_seek(s, 5); - if (*code == X224_TPDU_DATA) { /* EOT (1 byte) */ stream_seek(s, 1); } + else + { + /* DST-REF (2 bytes) */ + /* SRC-REF (2 bytes) */ + /* Class 0 (1 byte) */ + stream_seek(s, 5); + } return li; } @@ -166,3 +168,25 @@ tpdu_write_data(STREAM* s) { tpdu_write_header(s, 2, X224_TPDU_DATA); } + +/** + * Read Data TPDU. + * @param s stream + */ + +uint16 +tpdu_read_data(STREAM* s) +{ + uint8 code; + uint16 li; + + li = tpdu_read_header(s, &code); + + if (code != X224_TPDU_DATA) + { + printf("expected X224_TPDU_DATA\n"); + return 0; + } + + return li; +} diff --git a/libfreerdp-core/tpdu.h b/libfreerdp-core/tpdu.h index b756b4d98..106f11d50 100644 --- a/libfreerdp-core/tpdu.h +++ b/libfreerdp-core/tpdu.h @@ -35,17 +35,12 @@ enum X224_TPDU_TYPE #define TPDU_CONNECTION_CONFIRM_LENGTH 7 #define TPDU_DISCONNECT_REQUEST_LENGTH 7 -uint8 -tpdu_read_header(STREAM* s, uint8* code); -void -tpdu_write_header(STREAM* s, uint16 length, uint8 code); -void -tpdu_write_connection_request(STREAM* s, uint16 length); -uint8 -tpdu_read_connection_confirm(STREAM* s); -void -tpdu_write_disconnect_request(STREAM* s, uint16 length); -void -tpdu_write_data(STREAM* s); +uint8 tpdu_read_header(STREAM* s, uint8* code); +void tpdu_write_header(STREAM* s, uint16 length, uint8 code); +void tpdu_write_connection_request(STREAM* s, uint16 length); +uint8 tpdu_read_connection_confirm(STREAM* s); +void tpdu_write_disconnect_request(STREAM* s, uint16 length); +uint16 tpdu_read_data(STREAM* s); +void tpdu_write_data(STREAM* s); #endif /* __TPDU_H */