diff --git a/libfreerdp-core/connection.c b/libfreerdp-core/connection.c index 23d16a776..47140887a 100644 --- a/libfreerdp-core/connection.c +++ b/libfreerdp-core/connection.c @@ -213,3 +213,35 @@ boolean rdp_server_accept_mcs_attach_user_request(rdpRdp* rdp, STREAM* s) return True; } +boolean rdp_server_accept_mcs_channel_join_request(rdpRdp* rdp, STREAM* s) +{ + int i; + uint16 channel_id; + boolean all_joined = True; + + if (!mcs_read_channel_join_request(rdp->mcs, s, &channel_id)) + return False; + + if (!mcs_send_channel_join_confirm(rdp->mcs, channel_id)) + return False; + + if (channel_id == rdp->mcs->user_id) + rdp->mcs->user_channel_joined = True; + else if (channel_id == MCS_GLOBAL_CHANNEL_ID) + rdp->mcs->global_channel_joined = True; + + for (i = 0; i < rdp->settings->num_channels; i++) + { + if (rdp->settings->channels[i].chan_id == channel_id) + rdp->settings->channels[i].joined = True; + + if (!rdp->settings->channels[i].joined) + all_joined = False; + } + + if (rdp->mcs->user_channel_joined && rdp->mcs->global_channel_joined && all_joined) + rdp->state = CONNECTION_STATE_CHANNEL_JOIN; + + return True; +} + diff --git a/libfreerdp-core/connection.h b/libfreerdp-core/connection.h index a38a1680b..5473eba39 100644 --- a/libfreerdp-core/connection.h +++ b/libfreerdp-core/connection.h @@ -37,7 +37,8 @@ enum CONNECTION_STATE CONNECTION_STATE_NEGO, CONNECTION_STATE_MCS_CONNECT, CONNECTION_STATE_MCS_ERECT_DOMAIN, - CONNECTION_STATE_MCS_ATTACH_USER + CONNECTION_STATE_MCS_ATTACH_USER, + CONNECTION_STATE_CHANNEL_JOIN }; boolean rdp_client_connect(rdpRdp* rdp); @@ -46,5 +47,6 @@ boolean rdp_server_accept_nego(rdpRdp* rdp, STREAM* s); boolean rdp_server_accept_mcs_connect_initial(rdpRdp* rdp, STREAM* s); boolean rdp_server_accept_mcs_erect_domain_request(rdpRdp* rdp, STREAM* s); boolean rdp_server_accept_mcs_attach_user_request(rdpRdp* rdp, STREAM* s); +boolean rdp_server_accept_mcs_channel_join_request(rdpRdp* rdp, STREAM* s); #endif /* __CONNECTION_H */ diff --git a/libfreerdp-core/mcs.c b/libfreerdp-core/mcs.c index 39ef0102d..58c66644f 100644 --- a/libfreerdp-core/mcs.c +++ b/libfreerdp-core/mcs.c @@ -718,6 +718,33 @@ boolean mcs_send_attach_user_confirm(rdpMcs* mcs) return True; } +/** + * Read MCS Channel Join Request.\n + * @msdn{cc240526} + * @param mcs mcs module + * @param s stream + */ + +boolean mcs_read_channel_join_request(rdpMcs* mcs, STREAM* s, uint16* channel_id) +{ + int length; + enum DomainMCSPDU MCSPDU; + uint16 user_id; + + MCSPDU = DomainMCSPDU_ChannelJoinRequest; + if (!mcs_read_domain_mcspdu_header(s, &MCSPDU, &length)) + return False; + + if (!per_read_integer16(s, &user_id, MCS_BASE_CHANNEL_ID)) + return False; + if (user_id != mcs->user_id) + return False; + if (!per_read_integer16(s, channel_id, 0)) + return False; + + return True; +} + /** * Send MCS Channel Join Request.\n * @msdn{cc240526} @@ -767,6 +794,30 @@ void mcs_recv_channel_join_confirm(rdpMcs* mcs) per_read_integer16(s, &channelId, 0); /* channelId */ } +/** + * Send MCS Channel Join Confirm.\n + * @msdn{cc240527} + * @param mcs mcs module + */ + +boolean mcs_send_channel_join_confirm(rdpMcs* mcs, uint16 channel_id) +{ + STREAM* s; + int length = 15; + s = transport_send_stream_init(mcs->transport, 15); + + mcs_write_domain_mcspdu_header(s, DomainMCSPDU_ChannelJoinConfirm, length, 2); + + per_write_enumerated(s, 0, MCS_Result_enum_length); /* result */ + per_write_integer16(s, mcs->user_id, MCS_BASE_CHANNEL_ID); /* initiator (UserId) */ + per_write_integer16(s, channel_id, 0); /* requested (ChannelId) */ + per_write_integer16(s, channel_id, 0); /* channelId */ + + transport_write(mcs->transport, s); + + return True; +} + /** * Instantiate new MCS module. * @param transport transport diff --git a/libfreerdp-core/mcs.h b/libfreerdp-core/mcs.h index 61141f314..dfd2cb825 100644 --- a/libfreerdp-core/mcs.h +++ b/libfreerdp-core/mcs.h @@ -118,6 +118,9 @@ struct rdp_mcs DomainParameters targetParameters; DomainParameters minimumParameters; DomainParameters maximumParameters; + + boolean user_channel_joined; + boolean global_channel_joined; }; typedef struct rdp_mcs rdpMcs; @@ -141,8 +144,10 @@ boolean mcs_read_attach_user_request(rdpMcs* mcs, STREAM* s); void mcs_send_attach_user_request(rdpMcs* mcs); void mcs_recv_attach_user_confirm(rdpMcs* mcs); boolean mcs_send_attach_user_confirm(rdpMcs* mcs); +boolean mcs_read_channel_join_request(rdpMcs* mcs, STREAM* s, uint16* channel_id); void mcs_send_channel_join_request(rdpMcs* mcs, uint16 channel_id); void mcs_recv_channel_join_confirm(rdpMcs* mcs); +boolean mcs_send_channel_join_confirm(rdpMcs* mcs, uint16 channel_id); boolean mcs_read_domain_mcspdu_header(STREAM* s, enum DomainMCSPDU* domainMCSPDU, int* length); void mcs_write_domain_mcspdu_header(STREAM* s, enum DomainMCSPDU domainMCSPDU, int length, uint8 options); diff --git a/libfreerdp-core/peer.c b/libfreerdp-core/peer.c index 3f6cfb1b7..d225ef634 100644 --- a/libfreerdp-core/peer.c +++ b/libfreerdp-core/peer.c @@ -79,6 +79,11 @@ static int peer_recv_callback(rdpTransport* transport, STREAM* s, void* extra) return -1; break; + case CONNECTION_STATE_MCS_ATTACH_USER: + if (!rdp_server_accept_mcs_channel_join_request(peer->rdp, s)) + return -1; + break; + default: printf("Invalid state %d\n", peer->rdp->state); return -1;