diff --git a/constants.h b/constants.h index 753a250..267522b 100644 --- a/constants.h +++ b/constants.h @@ -126,6 +126,17 @@ enum MCS_PDU_TYPE #define MCS_GLOBAL_CHANNEL 1003 #define MCS_USERCHANNEL_BASE 1001 +/* ITU-T Rec. T.125, Reason enumeration used with Disconnect Provider + Ultimatum, see mcs_send_dpu(reason) */ +enum MCS_DPU_REASON +{ + RN_DOMAIN_DISCONNECTED = 0, + RN_PROVIDER_INITIATED, + RN_TOKEN_PURGED, + RN_USER_REQUESTED, + RN_CHANNEL_PURGED, +}; + /* RDP secure transport constants */ #define SEC_RANDOM_SIZE 32 #define SEC_MODULUS_SIZE 64 diff --git a/mcs.c b/mcs.c index 8ddf1d0..615aa61 100644 --- a/mcs.c +++ b/mcs.c @@ -237,6 +237,32 @@ mcs_recv_cjcf(void) return s_check_end(s); } + +/* Send MCS Disconnect provider ultimatum PDU */ +void +mcs_send_dpu(unsigned short reason) +{ + STREAM s, contents; + + logger(Protocol, Debug, "mcs_send_dpu(), reason=%d", reason); + + contents = malloc(sizeof(struct stream)); + memset(contents, 0, sizeof(struct stream)); + s_realloc(contents, 6); + s_reset(contents); + ber_out_integer(contents, reason); /* Reason */ + ber_out_sequence(contents, NULL); /* SEQUENCE OF NonStandradParameters OPTIONAL */ + s_mark_end(contents); + + s = iso_init(8); + ber_out_sequence(s, contents); + s_free(contents); + + s_mark_end(s); + + iso_send(s); +} + /* Initialise an MCS transport data packet */ STREAM mcs_init(int length) @@ -353,8 +379,9 @@ mcs_connect_finalize(STREAM mcs_data) /* Disconnect from the MCS layer */ void -mcs_disconnect(void) +mcs_disconnect(int reason) { + mcs_send_dpu(reason); iso_disconnect(); } diff --git a/proto.h b/proto.h index 54ed81b..a5aa2f5 100644 --- a/proto.h +++ b/proto.h @@ -99,7 +99,7 @@ STREAM mcs_recv(uint16 * channel, uint8 * rdpver); RD_BOOL mcs_connect_start(char *server, char *username, char *domain, char *password, RD_BOOL reconnect, uint32 * selected_protocol); RD_BOOL mcs_connect_finalize(STREAM s); -void mcs_disconnect(void); +void mcs_disconnect(int reason); void mcs_reset_state(void); /* orders.c */ void process_orders(STREAM s, uint16 num_orders); diff --git a/secure.c b/secure.c index f416aba..679f4a0 100644 --- a/secure.c +++ b/secure.c @@ -958,7 +958,9 @@ sec_connect(char *server, char *username, char *domain, char *password, RD_BOOL void sec_disconnect(void) { - mcs_disconnect(); + /* Perform a User-initiated disconnect sequence, see + [MS-RDPBCGR] 1.3.1.4 Disconnect Sequences */ + mcs_disconnect(RN_USER_REQUESTED); } /* reset the state of the sec layer */ diff --git a/tests/mcs_test.c b/tests/mcs_test.c index 5799602..37d6ff5 100644 --- a/tests/mcs_test.c +++ b/tests/mcs_test.c @@ -81,3 +81,21 @@ Ensure(MCS, should_produce_valid_packet_for_McsSendCJrq) mcs_send_cjrq(chan_id); s_free(s); } + +/* Test function */ +Ensure(MCS, should_produce_valid_packet_for_McsSendDPU) +{ + int reason = 1; + struct stream *s; + uint8_t content[] = {0x30, 0x06, 0x02, 0x02, 0x00, reason, 0x30, 0x00}; + + s = stream_new(8); + + expect(logger); + expect(iso_init, will_return(s)); + + expect(iso_send, when(stream->data, is_equal_to_contents_of(content, sizeof(content)))); + + mcs_send_dpu(reason); + s_free(s); +}