/src/FreeRDP/libfreerdp/core/mcs.c
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /**  | 
2  |  |  * FreeRDP: A Remote Desktop Protocol Implementation  | 
3  |  |  * T.125 Multipoint Communication Service (MCS) Protocol  | 
4  |  |  *  | 
5  |  |  * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>  | 
6  |  |  * Copyright 2015 Thincast Technologies GmbH  | 
7  |  |  * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>  | 
8  |  |  * Copyright 2017 Armin Novak <armin.novak@thincast.com>  | 
9  |  |  * Copyright 2017 Thincast Technologies GmbH  | 
10  |  |  *  | 
11  |  |  * Licensed under the Apache License, Version 2.0 (the "License");  | 
12  |  |  * you may not use this file except in compliance with the License.  | 
13  |  |  * You may obtain a copy of the License at  | 
14  |  |  *  | 
15  |  |  *     http://www.apache.org/licenses/LICENSE-2.0  | 
16  |  |  *  | 
17  |  |  * Unless required by applicable law or agreed to in writing, software  | 
18  |  |  * distributed under the License is distributed on an "AS IS" BASIS,  | 
19  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  | 
20  |  |  * See the License for the specific language governing permissions and  | 
21  |  |  * limitations under the License.  | 
22  |  |  */  | 
23  |  |  | 
24  |  | #include <freerdp/config.h>  | 
25  |  |  | 
26  |  | #include <winpr/crt.h>  | 
27  |  | #include <winpr/assert.h>  | 
28  |  | #include <freerdp/log.h>  | 
29  |  |  | 
30  |  | #include "gcc.h"  | 
31  |  |  | 
32  |  | #include "mcs.h"  | 
33  |  | #include "tpdu.h"  | 
34  |  | #include "tpkt.h"  | 
35  |  | #include "client.h"  | 
36  |  | #include "connection.h"  | 
37  |  |  | 
38  |  | #define TAG FREERDP_TAG("core") | 
39  |  |  | 
40  |  | /**  | 
41  |  |  * T.125 MCS is defined in:  | 
42  |  |  *  | 
43  |  |  * http://www.itu.int/rec/T-REC-T.125-199802-I/  | 
44  |  |  * ITU-T T.125 Multipoint Communication Service Protocol Specification  | 
45  |  |  */  | 
46  |  |  | 
47  |  | /**  | 
48  |  |  * Connect-Initial ::= [APPLICATION 101] IMPLICIT SEQUENCE  | 
49  |  |  * { | 
50  |  |  *  callingDomainSelector   OCTET_STRING,  | 
51  |  |  *  calledDomainSelector    OCTET_STRING,  | 
52  |  |  *  upwardFlag      BOOLEAN,  | 
53  |  |  *  targetParameters    DomainParameters,  | 
54  |  |  *  minimumParameters   DomainParameters,  | 
55  |  |  *  maximumParameters   DomainParameters,  | 
56  |  |  *  userData      OCTET_STRING  | 
57  |  |  * }  | 
58  |  |  *  | 
59  |  |  * DomainParameters ::= SEQUENCE  | 
60  |  |  * { | 
61  |  |  *  maxChannelIds     INTEGER (0..MAX),  | 
62  |  |  *  maxUserIds      INTEGER (0..MAX),  | 
63  |  |  *  maxTokenIds     INTEGER (0..MAX),  | 
64  |  |  *  numPriorities     INTEGER (0..MAX),  | 
65  |  |  *  minThroughput     INTEGER (0..MAX),  | 
66  |  |  *  maxHeight     INTEGER (0..MAX),  | 
67  |  |  *  maxMCSPDUsize     INTEGER (0..MAX),  | 
68  |  |  *  protocolVersion     INTEGER (0..MAX)  | 
69  |  |  * }  | 
70  |  |  *  | 
71  |  |  * Connect-Response ::= [APPLICATION 102] IMPLICIT SEQUENCE  | 
72  |  |  * { | 
73  |  |  *  result        Result,  | 
74  |  |  *  calledConnectId     INTEGER (0..MAX),  | 
75  |  |  *  domainParameters    DomainParameters,  | 
76  |  |  *  userData      OCTET_STRING  | 
77  |  |  * }  | 
78  |  |  *  | 
79  |  |  * Result ::= ENUMERATED  | 
80  |  |  * { | 
81  |  |  *  rt-successful     (0),  | 
82  |  |  *  rt-domain-merging   (1),  | 
83  |  |  *  rt-domain-not-hierarchical  (2),  | 
84  |  |  *  rt-no-such-channel    (3),  | 
85  |  |  *  rt-no-such-domain   (4),  | 
86  |  |  *  rt-no-such-user     (5),  | 
87  |  |  *  rt-not-admitted     (6),  | 
88  |  |  *  rt-other-user-id    (7),  | 
89  |  |  *  rt-parameters-unacceptable  (8),  | 
90  |  |  *  rt-token-not-available    (9),  | 
91  |  |  *  rt-token-not-possessed    (10),  | 
92  |  |  *  rt-too-many-channels    (11),  | 
93  |  |  *  rt-too-many-tokens    (12),  | 
94  |  |  *  rt-too-many-users   (13),  | 
95  |  |  *  rt-unspecified-failure    (14),  | 
96  |  |  *  rt-user-rejected    (15)  | 
97  |  |  * }  | 
98  |  |  *  | 
99  |  |  * ErectDomainRequest ::= [APPLICATION 1] IMPLICIT SEQUENCE  | 
100  |  |  * { | 
101  |  |  *  subHeight     INTEGER (0..MAX),  | 
102  |  |  *  subInterval     INTEGER (0..MAX)  | 
103  |  |  * }  | 
104  |  |  *  | 
105  |  |  * AttachUserRequest ::= [APPPLICATION 10] IMPLICIT SEQUENCE  | 
106  |  |  * { | 
107  |  |  * }  | 
108  |  |  *  | 
109  |  |  * AttachUserConfirm ::= [APPLICATION 11] IMPLICIT SEQUENCE  | 
110  |  |  * { | 
111  |  |  *  result        Result,  | 
112  |  |  *  initiator     UserId OPTIONAL  | 
113  |  |  * }  | 
114  |  |  *  | 
115  |  |  * ChannelJoinRequest ::= [APPLICATION 14] IMPLICIT SEQUENCE  | 
116  |  |  * { | 
117  |  |  *  initiator     UserId,  | 
118  |  |  *  channelId     ChannelId  | 
119  |  |  * }  | 
120  |  |  *  | 
121  |  |  * ChannelJoinConfirm ::= [APPLICATION 15] IMPLICIT SEQUENCE  | 
122  |  |  * { | 
123  |  |  *  result        Result,  | 
124  |  |  *  initiator     UserId,  | 
125  |  |  *  requested     ChannelId,  | 
126  |  |  *  channelId     ChannelId OPTIONAL  | 
127  |  |  * }  | 
128  |  |  *  | 
129  |  |  * SendDataRequest ::= [APPLICATION 25] IMPLICIT SEQUENCE  | 
130  |  |  * { | 
131  |  |  *  initiator     UserId,  | 
132  |  |  *  channelId     ChannelId,  | 
133  |  |  *  dataPriority      DataPriority,  | 
134  |  |  *  segmentation      Segmentation,  | 
135  |  |  *  userData      OCTET_STRING  | 
136  |  |  * }  | 
137  |  |  *  | 
138  |  |  * DataPriority ::= CHOICE  | 
139  |  |  * { | 
140  |  |  *  top       NULL,  | 
141  |  |  *  high        NULL,  | 
142  |  |  *  medium        NULL,  | 
143  |  |  *  low       NULL,  | 
144  |  |  *  ...  | 
145  |  |  * }  | 
146  |  |  *  | 
147  |  |  * Segmentation ::= BIT_STRING  | 
148  |  |  * { | 
149  |  |  *  begin       (0),  | 
150  |  |  *  end       (1)  | 
151  |  |  * } (SIZE(2))  | 
152  |  |  *  | 
153  |  |  * SendDataIndication ::= SEQUENCE  | 
154  |  |  * { | 
155  |  |  *  initiator     UserId,  | 
156  |  |  *  channelId     ChannelId,  | 
157  |  |  *  reliability     BOOLEAN,  | 
158  |  |  *  domainReferenceID   INTEGER (0..65535) OPTIONAL,  | 
159  |  |  *  dataPriority      DataPriority,  | 
160  |  |  *  segmentation      Segmentation,  | 
161  |  |  *  userData      OCTET_STRING,  | 
162  |  |  *  totalDataSize     INTEGER OPTIONAL,  | 
163  |  |  *  nonStandard     SEQUENCE OF NonStandardParameter OPTIONAL,  | 
164  |  |  *  ...  | 
165  |  |  * }  | 
166  |  |  *  | 
167  |  |  */  | 
168  |  |  | 
169  |  | static const BYTE callingDomainSelector[1] = "\x01";  | 
170  |  | static const BYTE calledDomainSelector[1] = "\x01";  | 
171  |  |  | 
172  |  | /*  | 
173  |  | static const char* const mcs_result_enumerated[] =  | 
174  |  | { | 
175  |  |         "rt-successful",  | 
176  |  |         "rt-domain-merging",  | 
177  |  |         "rt-domain-not-hierarchical",  | 
178  |  |         "rt-no-such-channel",  | 
179  |  |         "rt-no-such-domain",  | 
180  |  |         "rt-no-such-user",  | 
181  |  |         "rt-not-admitted",  | 
182  |  |         "rt-other-user-id",  | 
183  |  |         "rt-parameters-unacceptable",  | 
184  |  |         "rt-token-not-available",  | 
185  |  |         "rt-token-not-possessed",  | 
186  |  |         "rt-too-many-channels",  | 
187  |  |         "rt-too-many-tokens",  | 
188  |  |         "rt-too-many-users",  | 
189  |  |         "rt-unspecified-failure",  | 
190  |  |         "rt-user-rejected"  | 
191  |  | };  | 
192  |  | */  | 
193  |  |  | 
194  |  | const char* mcs_domain_pdu_string(DomainMCSPDU pdu)  | 
195  | 114  | { | 
196  | 114  |   switch (pdu)  | 
197  | 114  |   { | 
198  | 7  |     case DomainMCSPDU_PlumbDomainIndication:  | 
199  | 7  |       return "DomainMCSPDU_PlumbDomainIndication";  | 
200  | 1  |     case DomainMCSPDU_ErectDomainRequest:  | 
201  | 1  |       return "DomainMCSPDU_ErectDomainRequest";  | 
202  | 0  |     case DomainMCSPDU_MergeChannelsRequest:  | 
203  | 0  |       return "DomainMCSPDU_MergeChannelsRequest";  | 
204  | 1  |     case DomainMCSPDU_MergeChannelsConfirm:  | 
205  | 1  |       return "DomainMCSPDU_MergeChannelsConfirm";  | 
206  | 0  |     case DomainMCSPDU_PurgeChannelsIndication:  | 
207  | 0  |       return "DomainMCSPDU_PurgeChannelsIndication";  | 
208  | 2  |     case DomainMCSPDU_MergeTokensRequest:  | 
209  | 2  |       return "DomainMCSPDU_MergeTokensRequest";  | 
210  | 1  |     case DomainMCSPDU_MergeTokensConfirm:  | 
211  | 1  |       return "DomainMCSPDU_MergeTokensConfirm";  | 
212  | 0  |     case DomainMCSPDU_PurgeTokensIndication:  | 
213  | 0  |       return "DomainMCSPDU_PurgeTokensIndication";  | 
214  | 0  |     case DomainMCSPDU_DisconnectProviderUltimatum:  | 
215  | 0  |       return "DomainMCSPDU_DisconnectProviderUltimatum";  | 
216  | 0  |     case DomainMCSPDU_RejectMCSPDUUltimatum:  | 
217  | 0  |       return "DomainMCSPDU_RejectMCSPDUUltimatum";  | 
218  | 0  |     case DomainMCSPDU_AttachUserRequest:  | 
219  | 0  |       return "DomainMCSPDU_AttachUserRequest";  | 
220  | 2  |     case DomainMCSPDU_AttachUserConfirm:  | 
221  | 2  |       return "DomainMCSPDU_AttachUserConfirm";  | 
222  | 1  |     case DomainMCSPDU_DetachUserRequest:  | 
223  | 1  |       return "DomainMCSPDU_DetachUserRequest";  | 
224  | 0  |     case DomainMCSPDU_DetachUserIndication:  | 
225  | 0  |       return "DomainMCSPDU_DetachUserIndication";  | 
226  | 0  |     case DomainMCSPDU_ChannelJoinRequest:  | 
227  | 0  |       return "DomainMCSPDU_ChannelJoinRequest";  | 
228  | 0  |     case DomainMCSPDU_ChannelJoinConfirm:  | 
229  | 0  |       return "DomainMCSPDU_ChannelJoinConfirm";  | 
230  | 1  |     case DomainMCSPDU_ChannelLeaveRequest:  | 
231  | 1  |       return "DomainMCSPDU_ChannelLeaveRequest";  | 
232  | 1  |     case DomainMCSPDU_ChannelConveneRequest:  | 
233  | 1  |       return "DomainMCSPDU_ChannelConveneRequest";  | 
234  | 1  |     case DomainMCSPDU_ChannelConveneConfirm:  | 
235  | 1  |       return "DomainMCSPDU_ChannelConveneConfirm";  | 
236  | 3  |     case DomainMCSPDU_ChannelDisbandRequest:  | 
237  | 3  |       return "DomainMCSPDU_ChannelDisbandRequest";  | 
238  | 0  |     case DomainMCSPDU_ChannelDisbandIndication:  | 
239  | 0  |       return "DomainMCSPDU_ChannelDisbandIndication";  | 
240  | 2  |     case DomainMCSPDU_ChannelAdmitRequest:  | 
241  | 2  |       return "DomainMCSPDU_ChannelAdmitRequest";  | 
242  | 0  |     case DomainMCSPDU_ChannelAdmitIndication:  | 
243  | 0  |       return "DomainMCSPDU_ChannelAdmitIndication";  | 
244  | 1  |     case DomainMCSPDU_ChannelExpelRequest:  | 
245  | 1  |       return "DomainMCSPDU_ChannelExpelRequest";  | 
246  | 1  |     case DomainMCSPDU_ChannelExpelIndication:  | 
247  | 1  |       return "DomainMCSPDU_ChannelExpelIndication";  | 
248  | 28  |     case DomainMCSPDU_SendDataRequest:  | 
249  | 28  |       return "DomainMCSPDU_SendDataRequest";  | 
250  | 31  |     case DomainMCSPDU_SendDataIndication:  | 
251  | 31  |       return "DomainMCSPDU_SendDataIndication";  | 
252  | 0  |     case DomainMCSPDU_UniformSendDataRequest:  | 
253  | 0  |       return "DomainMCSPDU_UniformSendDataRequest";  | 
254  | 0  |     case DomainMCSPDU_UniformSendDataIndication:  | 
255  | 0  |       return "DomainMCSPDU_UniformSendDataIndication";  | 
256  | 0  |     case DomainMCSPDU_TokenGrabRequest:  | 
257  | 0  |       return "DomainMCSPDU_TokenGrabRequest";  | 
258  | 1  |     case DomainMCSPDU_TokenGrabConfirm:  | 
259  | 1  |       return "DomainMCSPDU_TokenGrabConfirm";  | 
260  | 8  |     case DomainMCSPDU_TokenInhibitRequest:  | 
261  | 8  |       return "DomainMCSPDU_TokenInhibitRequest";  | 
262  | 0  |     case DomainMCSPDU_TokenInhibitConfirm:  | 
263  | 0  |       return "DomainMCSPDU_TokenInhibitConfirm";  | 
264  | 0  |     case DomainMCSPDU_TokenGiveRequest:  | 
265  | 0  |       return "DomainMCSPDU_TokenGiveRequest";  | 
266  | 1  |     case DomainMCSPDU_TokenGiveIndication:  | 
267  | 1  |       return "DomainMCSPDU_TokenGiveIndication";  | 
268  | 0  |     case DomainMCSPDU_TokenGiveResponse:  | 
269  | 0  |       return "DomainMCSPDU_TokenGiveResponse";  | 
270  | 0  |     case DomainMCSPDU_TokenGiveConfirm:  | 
271  | 0  |       return "DomainMCSPDU_TokenGiveConfirm";  | 
272  | 1  |     case DomainMCSPDU_TokenPleaseRequest:  | 
273  | 1  |       return "DomainMCSPDU_TokenPleaseRequest";  | 
274  | 1  |     case DomainMCSPDU_TokenPleaseConfirm:  | 
275  | 1  |       return "DomainMCSPDU_TokenPleaseConfirm";  | 
276  | 1  |     case DomainMCSPDU_TokenReleaseRequest:  | 
277  | 1  |       return "DomainMCSPDU_TokenReleaseRequest";  | 
278  | 0  |     case DomainMCSPDU_TokenReleaseConfirm:  | 
279  | 0  |       return "DomainMCSPDU_TokenReleaseConfirm";  | 
280  | 1  |     case DomainMCSPDU_TokenTestRequest:  | 
281  | 1  |       return "DomainMCSPDU_TokenTestRequest";  | 
282  | 1  |     case DomainMCSPDU_TokenTestConfirm:  | 
283  | 1  |       return "DomainMCSPDU_TokenTestConfirm";  | 
284  | 0  |     case DomainMCSPDU_enum_length:  | 
285  | 0  |       return "DomainMCSPDU_enum_length";  | 
286  | 15  |     default:  | 
287  | 15  |       return "DomainMCSPDU_UNKNOWN";  | 
288  | 114  |   }  | 
289  | 114  | }  | 
290  |  |  | 
291  |  | static BOOL mcs_merge_domain_parameters(DomainParameters* targetParameters,  | 
292  |  |                                         DomainParameters* minimumParameters,  | 
293  |  |                                         DomainParameters* maximumParameters,  | 
294  |  |                                         DomainParameters* pOutParameters);  | 
295  |  |  | 
296  |  | static BOOL mcs_write_connect_initial(wStream* s, rdpMcs* mcs, wStream* userData);  | 
297  |  | static BOOL mcs_write_connect_response(wStream* s, rdpMcs* mcs, wStream* userData);  | 
298  |  | static BOOL mcs_read_domain_mcspdu_header(wStream* s, DomainMCSPDU domainMCSPDU, UINT16* length,  | 
299  |  |                                           DomainMCSPDU* actual);  | 
300  |  |  | 
301  |  | static int mcs_initialize_client_channels(rdpMcs* mcs, const rdpSettings* settings)  | 
302  | 0  | { | 
303  | 0  |   if (!mcs || !settings)  | 
304  | 0  |     return -1;  | 
305  |  |  | 
306  | 0  |   mcs->channelCount = freerdp_settings_get_uint32(settings, FreeRDP_ChannelCount);  | 
307  |  | 
  | 
308  | 0  |   if (mcs->channelCount > mcs->channelMaxCount)  | 
309  | 0  |     mcs->channelCount = mcs->channelMaxCount;  | 
310  |  | 
  | 
311  | 0  |   ZeroMemory(mcs->channels, sizeof(rdpMcsChannel) * mcs->channelMaxCount);  | 
312  |  | 
  | 
313  | 0  |   for (UINT32 index = 0; index < mcs->channelCount; index++)  | 
314  | 0  |   { | 
315  | 0  |     const CHANNEL_DEF* defchannel =  | 
316  | 0  |         freerdp_settings_get_pointer_array(settings, FreeRDP_ChannelDefArray, index);  | 
317  | 0  |     rdpMcsChannel* cur = &mcs->channels[index];  | 
318  | 0  |     WINPR_ASSERT(defchannel);  | 
319  | 0  |     CopyMemory(cur->Name, defchannel->name, CHANNEL_NAME_LEN);  | 
320  | 0  |     cur->options = defchannel->options;  | 
321  | 0  |   }  | 
322  |  |  | 
323  | 0  |   return 0;  | 
324  | 0  | }  | 
325  |  |  | 
326  |  | /**  | 
327  |  |  * Read a DomainMCSPDU header.  | 
328  |  |  * @param s stream  | 
329  |  |  * @param domainMCSPDU DomainMCSPDU type  | 
330  |  |  * @param length TPKT length  | 
331  |  |  *  | 
332  |  |  * @return \b TRUE for success, \b FALSE otherwise  | 
333  |  |  */  | 
334  |  |  | 
335  |  | BOOL mcs_read_domain_mcspdu_header(wStream* s, DomainMCSPDU domainMCSPDU, UINT16* length,  | 
336  |  |                                    DomainMCSPDU* actual)  | 
337  | 0  | { | 
338  | 0  |   UINT16 li = 0;  | 
339  | 0  |   BYTE choice = 0;  | 
340  |  | 
  | 
341  | 0  |   if (actual)  | 
342  | 0  |     *actual = DomainMCSPDU_invalid;  | 
343  |  | 
  | 
344  | 0  |   WINPR_ASSERT(s);  | 
345  | 0  |   WINPR_ASSERT(domainMCSPDU);  | 
346  | 0  |   WINPR_ASSERT(length);  | 
347  |  |  | 
348  | 0  |   if (!tpkt_read_header(s, length))  | 
349  | 0  |     return FALSE;  | 
350  |  |  | 
351  | 0  |   if (!tpdu_read_data(s, &li, *length))  | 
352  | 0  |     return FALSE;  | 
353  |  |  | 
354  | 0  |   if (!per_read_choice(s, &choice))  | 
355  | 0  |     return FALSE;  | 
356  |  |  | 
357  | 0  |   const DomainMCSPDU MCSPDU = (choice >> 2);  | 
358  | 0  |   if (actual)  | 
359  | 0  |     *actual = MCSPDU;  | 
360  |  | 
  | 
361  | 0  |   if (domainMCSPDU != MCSPDU)  | 
362  | 0  |   { | 
363  | 0  |     WLog_ERR(TAG, "Expected MCS %s, got %s", mcs_domain_pdu_string(domainMCSPDU),  | 
364  | 0  |              mcs_domain_pdu_string(MCSPDU));  | 
365  | 0  |     return FALSE;  | 
366  | 0  |   }  | 
367  |  |  | 
368  | 0  |   return TRUE;  | 
369  | 0  | }  | 
370  |  |  | 
371  |  | /**  | 
372  |  |  * Write a DomainMCSPDU header.  | 
373  |  |  * @param s stream  | 
374  |  |  * @param domainMCSPDU DomainMCSPDU type  | 
375  |  |  * @param length TPKT length  | 
376  |  |  */  | 
377  |  |  | 
378  |  | BOOL mcs_write_domain_mcspdu_header(wStream* s, DomainMCSPDU domainMCSPDU, UINT16 length,  | 
379  |  |                                     BYTE options)  | 
380  | 2.54k  | { | 
381  | 2.54k  |   WINPR_ASSERT(s);  | 
382  | 2.54k  |   WINPR_ASSERT((options & ~0x03) == 0);  | 
383  | 2.54k  |   WINPR_ASSERT((domainMCSPDU & ~0x3F) == 0);  | 
384  |  |  | 
385  | 2.54k  |   if (!tpkt_write_header(s, length))  | 
386  | 0  |     return FALSE;  | 
387  | 2.54k  |   if (!tpdu_write_data(s))  | 
388  | 0  |     return FALSE;  | 
389  | 2.54k  |   return per_write_choice(s, (BYTE)((domainMCSPDU << 2) | options));  | 
390  | 2.54k  | }  | 
391  |  |  | 
392  |  | /**  | 
393  |  |  * Initialize MCS Domain Parameters.  | 
394  |  |  * @param domainParameters domain parameters  | 
395  |  |  * @param maxChannelIds max channel ids  | 
396  |  |  * @param maxUserIds max user ids  | 
397  |  |  * @param maxTokenIds max token ids  | 
398  |  |  * @param maxMCSPDUsize max MCS PDU size  | 
399  |  |  */  | 
400  |  |  | 
401  |  | static BOOL mcs_init_domain_parameters(DomainParameters* domainParameters, UINT32 maxChannelIds,  | 
402  |  |                                        UINT32 maxUserIds, UINT32 maxTokenIds, UINT32 maxMCSPDUsize)  | 
403  | 159k  | { | 
404  | 159k  |   if (!domainParameters)  | 
405  | 0  |     return FALSE;  | 
406  |  |  | 
407  | 159k  |   domainParameters->maxChannelIds = maxChannelIds;  | 
408  | 159k  |   domainParameters->maxUserIds = maxUserIds;  | 
409  | 159k  |   domainParameters->maxTokenIds = maxTokenIds;  | 
410  | 159k  |   domainParameters->maxMCSPDUsize = maxMCSPDUsize;  | 
411  | 159k  |   domainParameters->numPriorities = 1;  | 
412  | 159k  |   domainParameters->minThroughput = 0;  | 
413  | 159k  |   domainParameters->maxHeight = 1;  | 
414  | 159k  |   domainParameters->protocolVersion = 2;  | 
415  | 159k  |   return TRUE;  | 
416  | 159k  | }  | 
417  |  |  | 
418  |  | /**  | 
419  |  |  * Read MCS Domain Parameters.  | 
420  |  |  * @param s stream  | 
421  |  |  * @param domainParameters domain parameters  | 
422  |  |  */  | 
423  |  |  | 
424  |  | static BOOL mcs_read_domain_parameters(wStream* s, DomainParameters* domainParameters)  | 
425  | 3.39k  | { | 
426  | 3.39k  |   size_t length = 0;  | 
427  |  |  | 
428  | 3.39k  |   if (!s || !domainParameters)  | 
429  | 0  |     return FALSE;  | 
430  |  |  | 
431  | 3.39k  |   return ber_read_sequence_tag(s, &length) &&  | 
432  | 3.39k  |          ber_read_integer(s, &(domainParameters->maxChannelIds)) &&  | 
433  | 3.39k  |          ber_read_integer(s, &(domainParameters->maxUserIds)) &&  | 
434  | 3.39k  |          ber_read_integer(s, &(domainParameters->maxTokenIds)) &&  | 
435  | 3.39k  |          ber_read_integer(s, &(domainParameters->numPriorities)) &&  | 
436  | 3.39k  |          ber_read_integer(s, &(domainParameters->minThroughput)) &&  | 
437  | 3.39k  |          ber_read_integer(s, &(domainParameters->maxHeight)) &&  | 
438  | 3.39k  |          ber_read_integer(s, &(domainParameters->maxMCSPDUsize)) &&  | 
439  | 3.39k  |          ber_read_integer(s, &(domainParameters->protocolVersion));  | 
440  | 3.39k  | }  | 
441  |  |  | 
442  |  | /**  | 
443  |  |  * Write MCS Domain Parameters.  | 
444  |  |  * @param s stream  | 
445  |  |  * @param domainParameters domain parameters  | 
446  |  |  */  | 
447  |  |  | 
448  |  | static BOOL mcs_write_domain_parameters(wStream* s, DomainParameters* domainParameters)  | 
449  | 0  | { | 
450  | 0  |   size_t length = 0;  | 
451  | 0  |   wStream* tmps = NULL;  | 
452  |  | 
  | 
453  | 0  |   if (!s || !domainParameters)  | 
454  | 0  |     return FALSE;  | 
455  |  |  | 
456  | 0  |   tmps = Stream_New(NULL, Stream_Capacity(s));  | 
457  |  | 
  | 
458  | 0  |   if (!tmps)  | 
459  | 0  |   { | 
460  | 0  |     WLog_ERR(TAG, "Stream_New failed!");  | 
461  | 0  |     return FALSE;  | 
462  | 0  |   }  | 
463  |  |  | 
464  | 0  |   ber_write_integer(tmps, domainParameters->maxChannelIds);  | 
465  | 0  |   ber_write_integer(tmps, domainParameters->maxUserIds);  | 
466  | 0  |   ber_write_integer(tmps, domainParameters->maxTokenIds);  | 
467  | 0  |   ber_write_integer(tmps, domainParameters->numPriorities);  | 
468  | 0  |   ber_write_integer(tmps, domainParameters->minThroughput);  | 
469  | 0  |   ber_write_integer(tmps, domainParameters->maxHeight);  | 
470  | 0  |   ber_write_integer(tmps, domainParameters->maxMCSPDUsize);  | 
471  | 0  |   ber_write_integer(tmps, domainParameters->protocolVersion);  | 
472  | 0  |   length = Stream_GetPosition(tmps);  | 
473  | 0  |   ber_write_sequence_tag(s, length);  | 
474  | 0  |   Stream_Write(s, Stream_Buffer(tmps), length);  | 
475  | 0  |   Stream_Free(tmps, TRUE);  | 
476  | 0  |   return TRUE;  | 
477  | 0  | }  | 
478  |  |  | 
479  |  | #ifdef DEBUG_MCS  | 
480  |  | /**  | 
481  |  |  * Print MCS Domain Parameters.  | 
482  |  |  * @param domainParameters domain parameters  | 
483  |  |  */  | 
484  |  |  | 
485  |  | static void mcs_print_domain_parameters(DomainParameters* domainParameters)  | 
486  |  | { | 
487  |  |   WLog_INFO(TAG, "DomainParameters {"); | 
488  |  |  | 
489  |  |   if (domainParameters)  | 
490  |  |   { | 
491  |  |     WLog_INFO(TAG, "\tmaxChannelIds:%" PRIu32 "", domainParameters->maxChannelIds);  | 
492  |  |     WLog_INFO(TAG, "\tmaxUserIds:%" PRIu32 "", domainParameters->maxUserIds);  | 
493  |  |     WLog_INFO(TAG, "\tmaxTokenIds:%" PRIu32 "", domainParameters->maxTokenIds);  | 
494  |  |     WLog_INFO(TAG, "\tnumPriorities:%" PRIu32 "", domainParameters->numPriorities);  | 
495  |  |     WLog_INFO(TAG, "\tminThroughput:%" PRIu32 "", domainParameters->minThroughput);  | 
496  |  |     WLog_INFO(TAG, "\tmaxHeight:%" PRIu32 "", domainParameters->maxHeight);  | 
497  |  |     WLog_INFO(TAG, "\tmaxMCSPDUsize:%" PRIu32 "", domainParameters->maxMCSPDUsize);  | 
498  |  |     WLog_INFO(TAG, "\tprotocolVersion:%" PRIu32 "", domainParameters->protocolVersion);  | 
499  |  |   }  | 
500  |  |   else  | 
501  |  |     WLog_INFO(TAG, "\tdomainParameters=%p", domainParameters);  | 
502  |  |  | 
503  |  |   WLog_INFO(TAG, "}");  | 
504  |  | }  | 
505  |  | #endif  | 
506  |  |  | 
507  |  | /**  | 
508  |  |  * Merge MCS Domain Parameters.  | 
509  |  |  * @param targetParameters target parameters  | 
510  |  |  * @param minimumParameters minimum parameters  | 
511  |  |  * @param maximumParameters maximum parameters  | 
512  |  |  * @param pOutParameters output parameters  | 
513  |  |  *  | 
514  |  |  * @return \b TRUE for success, \b FALSE otherwise  | 
515  |  |  */  | 
516  |  |  | 
517  |  | BOOL mcs_merge_domain_parameters(DomainParameters* targetParameters,  | 
518  |  |                                  DomainParameters* minimumParameters,  | 
519  |  |                                  DomainParameters* maximumParameters,  | 
520  |  |                                  DomainParameters* pOutParameters)  | 
521  | 231  | { | 
522  |  |   /* maxChannelIds */  | 
523  | 231  |   if (!targetParameters || !minimumParameters || !maximumParameters || !pOutParameters)  | 
524  | 0  |     return FALSE;  | 
525  |  |  | 
526  | 231  |   if (targetParameters->maxChannelIds >= 4)  | 
527  | 181  |   { | 
528  | 181  |     pOutParameters->maxChannelIds = targetParameters->maxChannelIds;  | 
529  | 181  |   }  | 
530  | 50  |   else if (maximumParameters->maxChannelIds >= 4)  | 
531  | 49  |   { | 
532  | 49  |     pOutParameters->maxChannelIds = 4;  | 
533  | 49  |   }  | 
534  | 1  |   else  | 
535  | 1  |   { | 
536  | 1  |     WLog_ERR(TAG, "invalid maxChannelIds [%" PRIu32 ", %" PRIu32 "]",  | 
537  | 1  |              targetParameters->maxChannelIds, maximumParameters->maxChannelIds);  | 
538  | 1  |     return FALSE;  | 
539  | 1  |   }  | 
540  |  |  | 
541  |  |   /* maxUserIds */  | 
542  |  |  | 
543  | 230  |   if (targetParameters->maxUserIds >= 3)  | 
544  | 200  |   { | 
545  | 200  |     pOutParameters->maxUserIds = targetParameters->maxUserIds;  | 
546  | 200  |   }  | 
547  | 30  |   else if (maximumParameters->maxUserIds >= 3)  | 
548  | 29  |   { | 
549  | 29  |     pOutParameters->maxUserIds = 3;  | 
550  | 29  |   }  | 
551  | 1  |   else  | 
552  | 1  |   { | 
553  | 1  |     WLog_ERR(TAG, "invalid maxUserIds [%" PRIu32 ", %" PRIu32 "]", targetParameters->maxUserIds,  | 
554  | 1  |              maximumParameters->maxUserIds);  | 
555  | 1  |     return FALSE;  | 
556  | 1  |   }  | 
557  |  |  | 
558  |  |   /* maxTokenIds */  | 
559  | 229  |   pOutParameters->maxTokenIds = targetParameters->maxTokenIds;  | 
560  |  |  | 
561  |  |   /* numPriorities */  | 
562  |  |  | 
563  | 229  |   if (minimumParameters->numPriorities <= 1)  | 
564  | 58  |   { | 
565  | 58  |     pOutParameters->numPriorities = 1;  | 
566  | 58  |   }  | 
567  | 171  |   else  | 
568  | 171  |   { | 
569  | 171  |     WLog_ERR(TAG, "invalid numPriorities [%" PRIu32 "]", maximumParameters->numPriorities);  | 
570  | 171  |     return FALSE;  | 
571  | 171  |   }  | 
572  |  |  | 
573  |  |   /* minThroughput */  | 
574  | 58  |   pOutParameters->minThroughput = targetParameters->minThroughput;  | 
575  |  |  | 
576  |  |   /* maxHeight */  | 
577  |  |  | 
578  | 58  |   if ((targetParameters->maxHeight == 1) || (minimumParameters->maxHeight <= 1))  | 
579  | 40  |   { | 
580  | 40  |     pOutParameters->maxHeight = 1;  | 
581  | 40  |   }  | 
582  | 18  |   else  | 
583  | 18  |   { | 
584  | 18  |     WLog_ERR(TAG, "invalid maxHeight [%" PRIu32 ", %" PRIu32 "]", targetParameters->maxHeight,  | 
585  | 18  |              minimumParameters->maxHeight);  | 
586  | 18  |     return FALSE;  | 
587  | 18  |   }  | 
588  |  |  | 
589  |  |   /* maxMCSPDUsize */  | 
590  |  |  | 
591  | 40  |   if (targetParameters->maxMCSPDUsize >= 1024)  | 
592  | 29  |   { | 
593  | 29  |     if (targetParameters->maxMCSPDUsize <= 65528)  | 
594  | 7  |     { | 
595  | 7  |       pOutParameters->maxMCSPDUsize = targetParameters->maxMCSPDUsize;  | 
596  | 7  |     }  | 
597  | 22  |     else if ((minimumParameters->maxMCSPDUsize >= 124) &&  | 
598  | 22  |              (minimumParameters->maxMCSPDUsize <= 65528))  | 
599  | 2  |     { | 
600  | 2  |       pOutParameters->maxMCSPDUsize = 65528;  | 
601  | 2  |     }  | 
602  | 20  |     else  | 
603  | 20  |     { | 
604  | 20  |       WLog_ERR(TAG, "invalid maxMCSPDUsize [%" PRIu32 ", %" PRIu32 "]",  | 
605  | 20  |                targetParameters->maxMCSPDUsize, minimumParameters->maxMCSPDUsize);  | 
606  | 20  |       return FALSE;  | 
607  | 20  |     }  | 
608  | 29  |   }  | 
609  | 11  |   else  | 
610  | 11  |   { | 
611  | 11  |     if (maximumParameters->maxMCSPDUsize >= 124)  | 
612  | 9  |     { | 
613  | 9  |       pOutParameters->maxMCSPDUsize = maximumParameters->maxMCSPDUsize;  | 
614  | 9  |     }  | 
615  | 2  |     else  | 
616  | 2  |     { | 
617  | 2  |       WLog_ERR(TAG, "invalid maxMCSPDUsize [%" PRIu32 "]", maximumParameters->maxMCSPDUsize);  | 
618  | 2  |       return FALSE;  | 
619  | 2  |     }  | 
620  | 11  |   }  | 
621  |  |  | 
622  |  |   /* protocolVersion */  | 
623  |  |  | 
624  | 18  |   if ((targetParameters->protocolVersion == 2) ||  | 
625  | 18  |       ((minimumParameters->protocolVersion <= 2) && (maximumParameters->protocolVersion >= 2)))  | 
626  | 2  |   { | 
627  | 2  |     pOutParameters->protocolVersion = 2;  | 
628  | 2  |   }  | 
629  | 16  |   else  | 
630  | 16  |   { | 
631  | 16  |     WLog_ERR(TAG, "invalid protocolVersion [%" PRIu32 ", %" PRIu32 ", %" PRIu32 "]",  | 
632  | 16  |              targetParameters->protocolVersion, minimumParameters->protocolVersion,  | 
633  | 16  |              maximumParameters->protocolVersion);  | 
634  | 16  |     return FALSE;  | 
635  | 16  |   }  | 
636  |  |  | 
637  | 2  |   return TRUE;  | 
638  | 18  | }  | 
639  |  |  | 
640  |  | /**  | 
641  |  |  * Read an MCS Connect Initial PDU.  | 
642  |  |  * msdn{cc240508} | 
643  |  |  * @param mcs MCS module  | 
644  |  |  * @param s stream  | 
645  |  |  */  | 
646  |  |  | 
647  |  | BOOL mcs_recv_connect_initial(rdpMcs* mcs, wStream* s)  | 
648  | 13.2k  | { | 
649  | 13.2k  |   UINT16 li = 0;  | 
650  | 13.2k  |   size_t length = 0;  | 
651  | 13.2k  |   BOOL upwardFlag = FALSE;  | 
652  | 13.2k  |   UINT16 tlength = 0;  | 
653  |  |  | 
654  | 13.2k  |   WINPR_ASSERT(mcs);  | 
655  | 13.2k  |   WINPR_ASSERT(s);  | 
656  |  |  | 
657  | 13.2k  |   if (!tpkt_read_header(s, &tlength))  | 
658  | 329  |     return FALSE;  | 
659  |  |  | 
660  | 12.9k  |   if (!tpdu_read_data(s, &li, tlength))  | 
661  | 10.4k  |     return FALSE;  | 
662  |  |  | 
663  | 2.47k  |   if (!ber_read_application_tag(s, MCS_TYPE_CONNECT_INITIAL, &length))  | 
664  | 1.61k  |     return FALSE;  | 
665  |  |  | 
666  |  |   /* callingDomainSelector (OCTET_STRING) */  | 
667  | 858  |   if (!ber_read_octet_string_tag(s, &length) ||  | 
668  | 858  |       (!Stream_CheckAndLogRequiredLength(TAG, s, length)))  | 
669  | 34  |     return FALSE;  | 
670  |  |  | 
671  | 824  |   Stream_Seek(s, length);  | 
672  |  |  | 
673  |  |   /* calledDomainSelector (OCTET_STRING) */  | 
674  | 824  |   if (!ber_read_octet_string_tag(s, &length) ||  | 
675  | 824  |       (!Stream_CheckAndLogRequiredLength(TAG, s, length)))  | 
676  | 16  |     return FALSE;  | 
677  |  |  | 
678  | 808  |   Stream_Seek(s, length);  | 
679  |  |  | 
680  |  |   /* upwardFlag (BOOLEAN) */  | 
681  | 808  |   if (!ber_read_BOOL(s, &upwardFlag))  | 
682  | 57  |     return FALSE;  | 
683  |  |  | 
684  |  |   /* targetParameters (DomainParameters) */  | 
685  | 751  |   if (!mcs_read_domain_parameters(s, &mcs->targetParameters))  | 
686  | 148  |     return FALSE;  | 
687  |  |  | 
688  |  |   /* minimumParameters (DomainParameters) */  | 
689  | 603  |   if (!mcs_read_domain_parameters(s, &mcs->minimumParameters))  | 
690  | 20  |     return FALSE;  | 
691  |  |  | 
692  |  |   /* maximumParameters (DomainParameters) */  | 
693  | 583  |   if (!mcs_read_domain_parameters(s, &mcs->maximumParameters))  | 
694  | 18  |     return FALSE;  | 
695  |  |  | 
696  | 565  |   if (!ber_read_octet_string_tag(s, &length) ||  | 
697  | 565  |       (!Stream_CheckAndLogRequiredLength(TAG, s, length)))  | 
698  | 3  |     return FALSE;  | 
699  |  |  | 
700  | 562  |   if (!gcc_read_conference_create_request(s, mcs))  | 
701  | 331  |     return FALSE;  | 
702  |  |  | 
703  | 231  |   if (!mcs_merge_domain_parameters(&mcs->targetParameters, &mcs->minimumParameters,  | 
704  | 231  |                                    &mcs->maximumParameters, &mcs->domainParameters))  | 
705  | 229  |     return FALSE;  | 
706  |  |  | 
707  | 2  |   return tpkt_ensure_stream_consumed(s, tlength);  | 
708  | 231  | }  | 
709  |  |  | 
710  |  | /**  | 
711  |  |  * Write an MCS Connect Initial PDU.  | 
712  |  |  * msdn{cc240508} | 
713  |  |  * @param s stream  | 
714  |  |  * @param mcs MCS module  | 
715  |  |  * @param userData GCC Conference Create Request  | 
716  |  |  */  | 
717  |  |  | 
718  |  | BOOL mcs_write_connect_initial(wStream* s, rdpMcs* mcs, wStream* userData)  | 
719  | 0  | { | 
720  | 0  |   size_t length = 0;  | 
721  | 0  |   wStream* tmps = NULL;  | 
722  | 0  |   BOOL ret = FALSE;  | 
723  |  | 
  | 
724  | 0  |   if (!s || !mcs || !userData)  | 
725  | 0  |     return FALSE;  | 
726  |  |  | 
727  | 0  |   tmps = Stream_New(NULL, Stream_Capacity(s));  | 
728  |  | 
  | 
729  | 0  |   if (!tmps)  | 
730  | 0  |   { | 
731  | 0  |     WLog_ERR(TAG, "Stream_New failed!");  | 
732  | 0  |     return FALSE;  | 
733  | 0  |   }  | 
734  |  |  | 
735  |  |   /* callingDomainSelector (OCTET_STRING) */  | 
736  | 0  |   ber_write_octet_string(tmps, callingDomainSelector, sizeof(callingDomainSelector));  | 
737  |  |   /* calledDomainSelector (OCTET_STRING) */  | 
738  | 0  |   ber_write_octet_string(tmps, calledDomainSelector, sizeof(calledDomainSelector));  | 
739  |  |   /* upwardFlag (BOOLEAN) */  | 
740  | 0  |   ber_write_BOOL(tmps, TRUE);  | 
741  |  |  | 
742  |  |   /* targetParameters (DomainParameters) */  | 
743  | 0  |   if (!mcs_write_domain_parameters(tmps, &mcs->targetParameters))  | 
744  | 0  |     goto out;  | 
745  |  |  | 
746  |  |   /* minimumParameters (DomainParameters) */  | 
747  | 0  |   if (!mcs_write_domain_parameters(tmps, &mcs->minimumParameters))  | 
748  | 0  |     goto out;  | 
749  |  |  | 
750  |  |   /* maximumParameters (DomainParameters) */  | 
751  | 0  |   if (!mcs_write_domain_parameters(tmps, &mcs->maximumParameters))  | 
752  | 0  |     goto out;  | 
753  |  |  | 
754  |  |   /* userData (OCTET_STRING) */  | 
755  | 0  |   ber_write_octet_string(tmps, Stream_Buffer(userData), Stream_GetPosition(userData));  | 
756  | 0  |   length = Stream_GetPosition(tmps);  | 
757  |  |   /* Connect-Initial (APPLICATION 101, IMPLICIT SEQUENCE) */  | 
758  | 0  |   ber_write_application_tag(s, MCS_TYPE_CONNECT_INITIAL, length);  | 
759  | 0  |   Stream_Write(s, Stream_Buffer(tmps), length);  | 
760  | 0  |   ret = TRUE;  | 
761  | 0  | out:  | 
762  | 0  |   Stream_Free(tmps, TRUE);  | 
763  | 0  |   return ret;  | 
764  | 0  | }  | 
765  |  |  | 
766  |  | /**  | 
767  |  |  * Write an MCS Connect Response PDU.  | 
768  |  |  * msdn{cc240508} | 
769  |  |  * @param s stream  | 
770  |  |  * @param mcs MCS module  | 
771  |  |  * @param userData GCC Conference Create Response  | 
772  |  |  *  | 
773  |  |  * @return \b TRUE for success, \b FALSE otherwise  | 
774  |  |  */  | 
775  |  |  | 
776  |  | BOOL mcs_write_connect_response(wStream* s, rdpMcs* mcs, wStream* userData)  | 
777  | 0  | { | 
778  | 0  |   size_t length = 0;  | 
779  | 0  |   wStream* tmps = NULL;  | 
780  | 0  |   BOOL ret = FALSE;  | 
781  |  | 
  | 
782  | 0  |   if (!s || !mcs || !userData)  | 
783  | 0  |     return FALSE;  | 
784  |  |  | 
785  | 0  |   tmps = Stream_New(NULL, Stream_Capacity(s));  | 
786  |  | 
  | 
787  | 0  |   if (!tmps)  | 
788  | 0  |   { | 
789  | 0  |     WLog_ERR(TAG, "Stream_New failed!");  | 
790  | 0  |     return FALSE;  | 
791  | 0  |   }  | 
792  |  |  | 
793  | 0  |   ber_write_enumerated(tmps, 0, MCS_Result_enum_length);  | 
794  | 0  |   ber_write_integer(tmps, 0); /* calledConnectId */  | 
795  |  | 
  | 
796  | 0  |   if (!mcs_write_domain_parameters(tmps, &(mcs->domainParameters)))  | 
797  | 0  |     goto out;  | 
798  |  |  | 
799  |  |   /* userData (OCTET_STRING) */  | 
800  | 0  |   ber_write_octet_string(tmps, Stream_Buffer(userData), Stream_GetPosition(userData));  | 
801  | 0  |   length = Stream_GetPosition(tmps);  | 
802  | 0  |   ber_write_application_tag(s, MCS_TYPE_CONNECT_RESPONSE, length);  | 
803  | 0  |   Stream_Write(s, Stream_Buffer(tmps), length);  | 
804  | 0  |   ret = TRUE;  | 
805  | 0  | out:  | 
806  | 0  |   Stream_Free(tmps, TRUE);  | 
807  | 0  |   return ret;  | 
808  | 0  | }  | 
809  |  |  | 
810  |  | /**  | 
811  |  |  * Send MCS Connect Initial.  | 
812  |  |  * msdn{cc240508} | 
813  |  |  * @param mcs mcs module  | 
814  |  |  */  | 
815  |  |  | 
816  |  | static BOOL mcs_send_connect_initial(rdpMcs* mcs)  | 
817  | 0  | { | 
818  | 0  |   int status = -1;  | 
819  | 0  |   size_t length = 0;  | 
820  | 0  |   wStream* s = NULL;  | 
821  | 0  |   size_t bm = 0;  | 
822  | 0  |   size_t em = 0;  | 
823  | 0  |   wStream* gcc_CCrq = NULL;  | 
824  | 0  |   wStream* client_data = NULL;  | 
825  | 0  |   rdpContext* context = NULL;  | 
826  |  | 
  | 
827  | 0  |   if (!mcs)  | 
828  | 0  |     return FALSE;  | 
829  |  |  | 
830  | 0  |   context = transport_get_context(mcs->transport);  | 
831  | 0  |   WINPR_ASSERT(context);  | 
832  |  |  | 
833  | 0  |   mcs_initialize_client_channels(mcs, context->settings);  | 
834  | 0  |   client_data = Stream_New(NULL, 512);  | 
835  |  | 
  | 
836  | 0  |   if (!client_data)  | 
837  | 0  |   { | 
838  | 0  |     WLog_ERR(TAG, "Stream_New failed!");  | 
839  | 0  |     return FALSE;  | 
840  | 0  |   }  | 
841  |  |  | 
842  | 0  |   if (!gcc_write_client_data_blocks(client_data, mcs))  | 
843  | 0  |     goto out;  | 
844  | 0  |   gcc_CCrq = Stream_New(NULL, 1024);  | 
845  |  | 
  | 
846  | 0  |   if (!gcc_CCrq)  | 
847  | 0  |   { | 
848  | 0  |     WLog_ERR(TAG, "Stream_New failed!");  | 
849  | 0  |     goto out;  | 
850  | 0  |   }  | 
851  |  |  | 
852  | 0  |   if (!gcc_write_conference_create_request(gcc_CCrq, client_data))  | 
853  | 0  |     goto out;  | 
854  | 0  |   length = Stream_GetPosition(gcc_CCrq) + 7;  | 
855  | 0  |   s = Stream_New(NULL, 1024 + length);  | 
856  |  | 
  | 
857  | 0  |   if (!s)  | 
858  | 0  |   { | 
859  | 0  |     WLog_ERR(TAG, "Stream_New failed!");  | 
860  | 0  |     goto out;  | 
861  | 0  |   }  | 
862  |  |  | 
863  | 0  |   bm = Stream_GetPosition(s);  | 
864  | 0  |   Stream_Seek(s, 7);  | 
865  |  | 
  | 
866  | 0  |   if (!mcs_write_connect_initial(s, mcs, gcc_CCrq))  | 
867  | 0  |   { | 
868  | 0  |     WLog_ERR(TAG, "mcs_write_connect_initial failed!");  | 
869  | 0  |     goto out;  | 
870  | 0  |   }  | 
871  |  |  | 
872  | 0  |   em = Stream_GetPosition(s);  | 
873  | 0  |   length = (em - bm);  | 
874  | 0  |   if (length > UINT16_MAX)  | 
875  | 0  |     goto out;  | 
876  | 0  |   Stream_SetPosition(s, bm);  | 
877  | 0  |   if (!tpkt_write_header(s, (UINT16)length))  | 
878  | 0  |     goto out;  | 
879  | 0  |   if (!tpdu_write_data(s))  | 
880  | 0  |     goto out;  | 
881  | 0  |   Stream_SetPosition(s, em);  | 
882  | 0  |   Stream_SealLength(s);  | 
883  | 0  |   status = transport_write(mcs->transport, s);  | 
884  | 0  | out:  | 
885  | 0  |   Stream_Free(s, TRUE);  | 
886  | 0  |   Stream_Free(gcc_CCrq, TRUE);  | 
887  | 0  |   Stream_Free(client_data, TRUE);  | 
888  | 0  |   return (status < 0 ? FALSE : TRUE);  | 
889  | 0  | }  | 
890  |  |  | 
891  |  | /**  | 
892  |  |  * Read MCS Connect Response.  | 
893  |  |  * msdn{cc240501} | 
894  |  |  * @param mcs mcs module  | 
895  |  |  */  | 
896  |  |  | 
897  |  | BOOL mcs_recv_connect_response(rdpMcs* mcs, wStream* s)  | 
898  | 13.2k  | { | 
899  | 13.2k  |   size_t length = 0;  | 
900  | 13.2k  |   UINT16 tlength = 0;  | 
901  | 13.2k  |   BYTE result = 0;  | 
902  | 13.2k  |   UINT16 li = 0;  | 
903  | 13.2k  |   UINT32 calledConnectId = 0;  | 
904  |  |  | 
905  | 13.2k  |   if (!mcs || !s)  | 
906  | 0  |     return FALSE;  | 
907  |  |  | 
908  | 13.2k  |   if (!tpkt_read_header(s, &tlength))  | 
909  | 329  |     return FALSE;  | 
910  |  |  | 
911  | 12.9k  |   if (!tpdu_read_data(s, &li, tlength))  | 
912  | 10.4k  |     return FALSE;  | 
913  |  |  | 
914  | 2.47k  |   if (!ber_read_application_tag(s, MCS_TYPE_CONNECT_RESPONSE, &length) ||  | 
915  | 2.47k  |       !ber_read_enumerated(s, &result, MCS_Result_enum_length) ||  | 
916  | 2.47k  |       !ber_read_integer(s, &calledConnectId) ||  | 
917  | 2.47k  |       !mcs_read_domain_parameters(s, &(mcs->domainParameters)) ||  | 
918  | 2.47k  |       !ber_read_octet_string_tag(s, &length))  | 
919  | 1.20k  |   { | 
920  | 1.20k  |     return FALSE;  | 
921  | 1.20k  |   }  | 
922  |  |  | 
923  | 1.26k  |   if (!gcc_read_conference_create_response(s, mcs))  | 
924  | 1.06k  |   { | 
925  | 1.06k  |     WLog_ERR(TAG, "gcc_read_conference_create_response failed");  | 
926  | 1.06k  |     return FALSE;  | 
927  | 1.06k  |   }  | 
928  |  |  | 
929  | 205  |   return tpkt_ensure_stream_consumed(s, tlength);  | 
930  | 1.26k  | }  | 
931  |  |  | 
932  |  | /**  | 
933  |  |  * Send MCS Connect Response.  | 
934  |  |  * msdn{cc240501} | 
935  |  |  * @param mcs mcs module  | 
936  |  |  */  | 
937  |  |  | 
938  |  | BOOL mcs_send_connect_response(rdpMcs* mcs)  | 
939  | 0  | { | 
940  | 0  |   size_t length = 0;  | 
941  | 0  |   int status = -1;  | 
942  | 0  |   wStream* s = NULL;  | 
943  | 0  |   size_t bm = 0;  | 
944  | 0  |   size_t em = 0;  | 
945  | 0  |   wStream* gcc_CCrsp = NULL;  | 
946  | 0  |   wStream* server_data = NULL;  | 
947  |  | 
  | 
948  | 0  |   if (!mcs)  | 
949  | 0  |     return FALSE;  | 
950  |  |  | 
951  | 0  |   server_data = Stream_New(NULL, 512);  | 
952  |  | 
  | 
953  | 0  |   if (!server_data)  | 
954  | 0  |   { | 
955  | 0  |     WLog_ERR(TAG, "Stream_New failed!");  | 
956  | 0  |     return FALSE;  | 
957  | 0  |   }  | 
958  |  |  | 
959  | 0  |   if (!gcc_write_server_data_blocks(server_data, mcs))  | 
960  | 0  |     goto out;  | 
961  |  |  | 
962  | 0  |   gcc_CCrsp = Stream_New(NULL, 512 + Stream_Capacity(server_data));  | 
963  |  | 
  | 
964  | 0  |   if (!gcc_CCrsp)  | 
965  | 0  |   { | 
966  | 0  |     WLog_ERR(TAG, "Stream_New failed!");  | 
967  | 0  |     goto out;  | 
968  | 0  |   }  | 
969  |  |  | 
970  | 0  |   if (!gcc_write_conference_create_response(gcc_CCrsp, server_data))  | 
971  | 0  |     goto out;  | 
972  | 0  |   length = Stream_GetPosition(gcc_CCrsp) + 7;  | 
973  | 0  |   s = Stream_New(NULL, length + 1024);  | 
974  |  | 
  | 
975  | 0  |   if (!s)  | 
976  | 0  |   { | 
977  | 0  |     WLog_ERR(TAG, "Stream_New failed!");  | 
978  | 0  |     goto out;  | 
979  | 0  |   }  | 
980  |  |  | 
981  | 0  |   bm = Stream_GetPosition(s);  | 
982  | 0  |   Stream_Seek(s, 7);  | 
983  |  | 
  | 
984  | 0  |   if (!mcs_write_connect_response(s, mcs, gcc_CCrsp))  | 
985  | 0  |     goto out;  | 
986  |  |  | 
987  | 0  |   em = Stream_GetPosition(s);  | 
988  | 0  |   length = (em - bm);  | 
989  | 0  |   if (length > UINT16_MAX)  | 
990  | 0  |     goto out;  | 
991  | 0  |   Stream_SetPosition(s, bm);  | 
992  | 0  |   if (!tpkt_write_header(s, (UINT16)length))  | 
993  | 0  |     goto out;  | 
994  | 0  |   if (!tpdu_write_data(s))  | 
995  | 0  |     goto out;  | 
996  | 0  |   Stream_SetPosition(s, em);  | 
997  | 0  |   Stream_SealLength(s);  | 
998  | 0  |   status = transport_write(mcs->transport, s);  | 
999  | 0  | out:  | 
1000  | 0  |   Stream_Free(s, TRUE);  | 
1001  | 0  |   Stream_Free(gcc_CCrsp, TRUE);  | 
1002  | 0  |   Stream_Free(server_data, TRUE);  | 
1003  | 0  |   return (status < 0) ? FALSE : TRUE;  | 
1004  | 0  | }  | 
1005  |  |  | 
1006  |  | /**  | 
1007  |  |  * Read MCS Erect Domain Request.  | 
1008  |  |  * msdn{cc240523} | 
1009  |  |  * @param mcs MCS module to use  | 
1010  |  |  * @param s stream  | 
1011  |  |  */  | 
1012  |  |  | 
1013  |  | BOOL mcs_recv_erect_domain_request(rdpMcs* mcs, wStream* s)  | 
1014  | 0  | { | 
1015  | 0  |   UINT16 length = 0;  | 
1016  | 0  |   UINT32 subHeight = 0;  | 
1017  | 0  |   UINT32 subInterval = 0;  | 
1018  |  | 
  | 
1019  | 0  |   WINPR_ASSERT(mcs);  | 
1020  | 0  |   WINPR_ASSERT(s);  | 
1021  |  |  | 
1022  | 0  |   if (!mcs_read_domain_mcspdu_header(s, DomainMCSPDU_ErectDomainRequest, &length, NULL))  | 
1023  | 0  |     return FALSE;  | 
1024  |  |  | 
1025  | 0  |   if (!per_read_integer(s, &subHeight)) /* subHeight (INTEGER) */  | 
1026  | 0  |     return FALSE;  | 
1027  |  |  | 
1028  | 0  |   if (!per_read_integer(s, &subInterval)) /* subInterval (INTEGER) */  | 
1029  | 0  |     return FALSE;  | 
1030  |  |  | 
1031  | 0  |   return tpkt_ensure_stream_consumed(s, length);  | 
1032  | 0  | }  | 
1033  |  |  | 
1034  |  | /**  | 
1035  |  |  * Send MCS Erect Domain Request.  | 
1036  |  |  * msdn{cc240523} | 
1037  |  |  * @param mcs MCS module to use  | 
1038  |  |  */  | 
1039  |  |  | 
1040  |  | BOOL mcs_send_erect_domain_request(rdpMcs* mcs)  | 
1041  | 0  | { | 
1042  | 0  |   wStream* s = NULL;  | 
1043  | 0  |   int status = 0;  | 
1044  | 0  |   UINT16 length = 12;  | 
1045  |  | 
  | 
1046  | 0  |   if (!mcs)  | 
1047  | 0  |     return FALSE;  | 
1048  |  |  | 
1049  | 0  |   s = Stream_New(NULL, length);  | 
1050  |  | 
  | 
1051  | 0  |   if (!s)  | 
1052  | 0  |   { | 
1053  | 0  |     WLog_ERR(TAG, "Stream_New failed!");  | 
1054  | 0  |     return FALSE;  | 
1055  | 0  |   }  | 
1056  |  |  | 
1057  | 0  |   mcs_write_domain_mcspdu_header(s, DomainMCSPDU_ErectDomainRequest, length, 0);  | 
1058  | 0  |   per_write_integer(s, 0); /* subHeight (INTEGER) */  | 
1059  | 0  |   per_write_integer(s, 0); /* subInterval (INTEGER) */  | 
1060  | 0  |   Stream_SealLength(s);  | 
1061  | 0  |   status = transport_write(mcs->transport, s);  | 
1062  | 0  |   Stream_Free(s, TRUE);  | 
1063  | 0  |   return (status < 0) ? FALSE : TRUE;  | 
1064  | 0  | }  | 
1065  |  |  | 
1066  |  | /**  | 
1067  |  |  * Read MCS Attach User Request.  | 
1068  |  |  * msdn{cc240524} | 
1069  |  |  * @param mcs mcs module  | 
1070  |  |  * @param s stream  | 
1071  |  |  */  | 
1072  |  |  | 
1073  |  | BOOL mcs_recv_attach_user_request(rdpMcs* mcs, wStream* s)  | 
1074  | 0  | { | 
1075  | 0  |   UINT16 length = 0;  | 
1076  |  | 
  | 
1077  | 0  |   if (!mcs || !s)  | 
1078  | 0  |     return FALSE;  | 
1079  |  |  | 
1080  | 0  |   if (!mcs_read_domain_mcspdu_header(s, DomainMCSPDU_AttachUserRequest, &length, NULL))  | 
1081  | 0  |     return FALSE;  | 
1082  | 0  |   return tpkt_ensure_stream_consumed(s, length);  | 
1083  | 0  | }  | 
1084  |  |  | 
1085  |  | /**  | 
1086  |  |  * Send MCS Attach User Request.  | 
1087  |  |  * msdn{cc240524} | 
1088  |  |  * @param mcs mcs module  | 
1089  |  |  */  | 
1090  |  |  | 
1091  |  | BOOL mcs_send_attach_user_request(rdpMcs* mcs)  | 
1092  | 0  | { | 
1093  | 0  |   wStream* s = NULL;  | 
1094  | 0  |   int status = 0;  | 
1095  | 0  |   UINT16 length = 8;  | 
1096  |  | 
  | 
1097  | 0  |   if (!mcs)  | 
1098  | 0  |     return FALSE;  | 
1099  |  |  | 
1100  | 0  |   s = Stream_New(NULL, length);  | 
1101  |  | 
  | 
1102  | 0  |   if (!s)  | 
1103  | 0  |   { | 
1104  | 0  |     WLog_ERR(TAG, "Stream_New failed!");  | 
1105  | 0  |     return FALSE;  | 
1106  | 0  |   }  | 
1107  |  |  | 
1108  | 0  |   mcs_write_domain_mcspdu_header(s, DomainMCSPDU_AttachUserRequest, length, 0);  | 
1109  | 0  |   Stream_SealLength(s);  | 
1110  | 0  |   status = transport_write(mcs->transport, s);  | 
1111  | 0  |   Stream_Free(s, TRUE);  | 
1112  | 0  |   return (status < 0) ? FALSE : TRUE;  | 
1113  | 0  | }  | 
1114  |  |  | 
1115  |  | /**  | 
1116  |  |  * Read MCS Attach User Confirm.  | 
1117  |  |  * msdn{cc240525} | 
1118  |  |  * @param mcs mcs module  | 
1119  |  |  */  | 
1120  |  |  | 
1121  |  | BOOL mcs_recv_attach_user_confirm(rdpMcs* mcs, wStream* s)  | 
1122  | 0  | { | 
1123  | 0  |   BYTE result = 0;  | 
1124  | 0  |   UINT16 length = 0;  | 
1125  |  | 
  | 
1126  | 0  |   if (!mcs || !s)  | 
1127  | 0  |     return FALSE;  | 
1128  |  |  | 
1129  | 0  |   if (!mcs_read_domain_mcspdu_header(s, DomainMCSPDU_AttachUserConfirm, &length, NULL))  | 
1130  | 0  |     return FALSE;  | 
1131  | 0  |   if (!per_read_enumerated(s, &result, MCS_Result_enum_length)) /* result */  | 
1132  | 0  |     return FALSE;  | 
1133  | 0  |   if (!per_read_integer16(s, &(mcs->userId), MCS_BASE_CHANNEL_ID)) /* initiator (UserId) */  | 
1134  | 0  |     return FALSE;  | 
1135  | 0  |   return tpkt_ensure_stream_consumed(s, length);  | 
1136  | 0  | }  | 
1137  |  |  | 
1138  |  | /**  | 
1139  |  |  * Send MCS Attach User Confirm.  | 
1140  |  |  * msdn{cc240525} | 
1141  |  |  * @param mcs mcs module  | 
1142  |  |  */  | 
1143  |  |  | 
1144  |  | BOOL mcs_send_attach_user_confirm(rdpMcs* mcs)  | 
1145  | 0  | { | 
1146  | 0  |   wStream* s = NULL;  | 
1147  | 0  |   int status = 0;  | 
1148  | 0  |   UINT16 length = 11;  | 
1149  |  | 
  | 
1150  | 0  |   if (!mcs)  | 
1151  | 0  |     return FALSE;  | 
1152  |  |  | 
1153  | 0  |   s = Stream_New(NULL, length);  | 
1154  |  | 
  | 
1155  | 0  |   if (!s)  | 
1156  | 0  |   { | 
1157  | 0  |     WLog_ERR(TAG, "Stream_New failed!");  | 
1158  | 0  |     return FALSE;  | 
1159  | 0  |   }  | 
1160  |  |  | 
1161  | 0  |   mcs->userId = mcs->baseChannelId++;  | 
1162  | 0  |   mcs_write_domain_mcspdu_header(s, DomainMCSPDU_AttachUserConfirm, length, 2);  | 
1163  | 0  |   per_write_enumerated(s, 0, MCS_Result_enum_length);       /* result */  | 
1164  | 0  |   per_write_integer16(s, mcs->userId, MCS_BASE_CHANNEL_ID); /* initiator (UserId) */  | 
1165  | 0  |   Stream_SealLength(s);  | 
1166  | 0  |   status = transport_write(mcs->transport, s);  | 
1167  | 0  |   Stream_Free(s, TRUE);  | 
1168  | 0  |   return (status < 0) ? FALSE : TRUE;  | 
1169  | 0  | }  | 
1170  |  |  | 
1171  |  | /**  | 
1172  |  |  * Read MCS Channel Join Request.  | 
1173  |  |  * msdn{cc240526} | 
1174  |  |  * @param mcs mcs module  | 
1175  |  |  * @param s stream  | 
1176  |  |  */  | 
1177  |  |  | 
1178  |  | BOOL mcs_recv_channel_join_request(rdpMcs* mcs, const rdpSettings* settings, wStream* s,  | 
1179  |  |                                    UINT16* channelId)  | 
1180  | 0  | { | 
1181  | 0  |   UINT16 length = 0;  | 
1182  | 0  |   UINT16 userId = 0;  | 
1183  |  | 
  | 
1184  | 0  |   if (!mcs || !s || !channelId)  | 
1185  | 0  |     return FALSE;  | 
1186  |  |  | 
1187  | 0  |   if (!mcs_read_domain_mcspdu_header(s, DomainMCSPDU_ChannelJoinRequest, &length, NULL))  | 
1188  | 0  |     return FALSE;  | 
1189  |  |  | 
1190  | 0  |   if (!per_read_integer16(s, &userId, MCS_BASE_CHANNEL_ID))  | 
1191  | 0  |     return FALSE;  | 
1192  | 0  |   if (userId != mcs->userId)  | 
1193  | 0  |   { | 
1194  | 0  |     if (freerdp_settings_get_bool(settings, FreeRDP_TransportDumpReplay))  | 
1195  | 0  |       mcs->userId = userId;  | 
1196  | 0  |     else  | 
1197  | 0  |       return FALSE;  | 
1198  | 0  |   }  | 
1199  | 0  |   if (!per_read_integer16(s, channelId, 0))  | 
1200  | 0  |     return FALSE;  | 
1201  |  |  | 
1202  | 0  |   return tpkt_ensure_stream_consumed(s, length);  | 
1203  | 0  | }  | 
1204  |  |  | 
1205  |  | /**  | 
1206  |  |  * Send MCS Channel Join Request.  | 
1207  |  |  * msdn{cc240526} | 
1208  |  |  *  | 
1209  |  |  * @param mcs mcs module  | 
1210  |  |  * @param channelId channel id  | 
1211  |  |  *  | 
1212  |  |  * @return \b TRUE for success, \b FALSE otherwise  | 
1213  |  |  */  | 
1214  |  |  | 
1215  |  | BOOL mcs_send_channel_join_request(rdpMcs* mcs, UINT16 channelId)  | 
1216  | 0  | { | 
1217  | 0  |   wStream* s = NULL;  | 
1218  | 0  |   int status = 0;  | 
1219  | 0  |   UINT16 length = 12;  | 
1220  |  | 
  | 
1221  | 0  |   WINPR_ASSERT(mcs);  | 
1222  |  |  | 
1223  | 0  |   s = Stream_New(NULL, length);  | 
1224  |  | 
  | 
1225  | 0  |   if (!s)  | 
1226  | 0  |   { | 
1227  | 0  |     WLog_ERR(TAG, "Stream_New failed!");  | 
1228  | 0  |     return FALSE;  | 
1229  | 0  |   }  | 
1230  |  |  | 
1231  | 0  |   mcs_write_domain_mcspdu_header(s, DomainMCSPDU_ChannelJoinRequest, length, 0);  | 
1232  | 0  |   per_write_integer16(s, mcs->userId, MCS_BASE_CHANNEL_ID);  | 
1233  | 0  |   per_write_integer16(s, channelId, 0);  | 
1234  | 0  |   Stream_SealLength(s);  | 
1235  | 0  |   status = transport_write(mcs->transport, s);  | 
1236  | 0  |   Stream_Free(s, TRUE);  | 
1237  | 0  |   return (status < 0) ? FALSE : TRUE;  | 
1238  | 0  | }  | 
1239  |  |  | 
1240  |  | /**  | 
1241  |  |  * Read MCS Channel Join Confirm.  | 
1242  |  |  * msdn{cc240527} | 
1243  |  |  * @param mcs mcs module  | 
1244  |  |  */  | 
1245  |  |  | 
1246  |  | BOOL mcs_recv_channel_join_confirm(rdpMcs* mcs, wStream* s, UINT16* channelId)  | 
1247  | 0  | { | 
1248  | 0  |   UINT16 length = 0;  | 
1249  | 0  |   BYTE result = 0;  | 
1250  | 0  |   UINT16 initiator = 0;  | 
1251  | 0  |   UINT16 requested = 0;  | 
1252  |  | 
  | 
1253  | 0  |   WINPR_ASSERT(mcs);  | 
1254  | 0  |   WINPR_ASSERT(channelId);  | 
1255  |  |  | 
1256  | 0  |   if (!mcs_read_domain_mcspdu_header(s, DomainMCSPDU_ChannelJoinConfirm, &length, NULL))  | 
1257  | 0  |     return FALSE;  | 
1258  |  |  | 
1259  | 0  |   if (!per_read_enumerated(s, &result, MCS_Result_enum_length)) /* result */  | 
1260  | 0  |     return FALSE;  | 
1261  | 0  |   if (!per_read_integer16(s, &initiator, MCS_BASE_CHANNEL_ID)) /* initiator (UserId) */  | 
1262  | 0  |     return FALSE;  | 
1263  | 0  |   if (!per_read_integer16(s, &requested, 0)) /* requested (ChannelId) */  | 
1264  | 0  |     return FALSE;  | 
1265  | 0  |   if (!per_read_integer16(s, channelId, 0)) /* channelId */  | 
1266  | 0  |     return FALSE;  | 
1267  | 0  |   return tpkt_ensure_stream_consumed(s, length);  | 
1268  | 0  | }  | 
1269  |  |  | 
1270  |  | /**  | 
1271  |  |  * Send MCS Channel Join Confirm.  | 
1272  |  |  * msdn{cc240527} | 
1273  |  |  * @param mcs mcs module  | 
1274  |  |  */  | 
1275  |  |  | 
1276  |  | BOOL mcs_send_channel_join_confirm(rdpMcs* mcs, UINT16 channelId)  | 
1277  | 0  | { | 
1278  | 0  |   wStream* s = NULL;  | 
1279  | 0  |   int status = -1;  | 
1280  | 0  |   UINT16 length = 15;  | 
1281  |  | 
  | 
1282  | 0  |   if (!mcs)  | 
1283  | 0  |     return FALSE;  | 
1284  |  |  | 
1285  | 0  |   s = Stream_New(NULL, length);  | 
1286  |  | 
  | 
1287  | 0  |   if (!s)  | 
1288  | 0  |   { | 
1289  | 0  |     WLog_ERR(TAG, "Stream_New failed!");  | 
1290  | 0  |     return FALSE;  | 
1291  | 0  |   }  | 
1292  |  |  | 
1293  | 0  |   if (!mcs_write_domain_mcspdu_header(s, DomainMCSPDU_ChannelJoinConfirm, length, 2))  | 
1294  | 0  |     goto fail;  | 
1295  | 0  |   if (!per_write_enumerated(s, 0, MCS_Result_enum_length)) /* result */  | 
1296  | 0  |     goto fail;  | 
1297  | 0  |   if (!per_write_integer16(s, mcs->userId, MCS_BASE_CHANNEL_ID)) /* initiator (UserId) */  | 
1298  | 0  |     goto fail;  | 
1299  | 0  |   if (!per_write_integer16(s, channelId, 0)) /* requested (ChannelId) */  | 
1300  | 0  |     goto fail;  | 
1301  | 0  |   if (!per_write_integer16(s, channelId, 0)) /* channelId */  | 
1302  | 0  |     goto fail;  | 
1303  | 0  |   Stream_SealLength(s);  | 
1304  | 0  |   status = transport_write(mcs->transport, s);  | 
1305  | 0  | fail:  | 
1306  | 0  |   Stream_Free(s, TRUE);  | 
1307  | 0  |   return (status < 0) ? FALSE : TRUE;  | 
1308  | 0  | }  | 
1309  |  |  | 
1310  |  | /**  | 
1311  |  |  * Receive MCS Disconnect Provider Ultimatum PDU.  | 
1312  |  |  * @param mcs mcs module  | 
1313  |  |  */  | 
1314  |  |  | 
1315  |  | BOOL mcs_recv_disconnect_provider_ultimatum(rdpMcs* mcs, wStream* s, int* reason)  | 
1316  | 532  | { | 
1317  | 532  |   BYTE b1 = 0;  | 
1318  | 532  |   BYTE b2 = 0;  | 
1319  |  |  | 
1320  | 532  |   WINPR_ASSERT(mcs);  | 
1321  | 532  |   WINPR_ASSERT(s);  | 
1322  | 532  |   WINPR_ASSERT(reason);  | 
1323  |  |  | 
1324  |  |   /*  | 
1325  |  |    * http://msdn.microsoft.com/en-us/library/cc240872.aspx:  | 
1326  |  |    *  | 
1327  |  |    * PER encoded (ALIGNED variant of BASIC-PER) PDU contents:  | 
1328  |  |    * 21 80  | 
1329  |  |    *  | 
1330  |  |    * 0x21:  | 
1331  |  |    * 0 - --\  | 
1332  |  |    * 0 -   |  | 
1333  |  |    * 1 -   | CHOICE: From DomainMCSPDU select disconnectProviderUltimatum (8)  | 
1334  |  |    * 0 -   | of type DisconnectProviderUltimatum  | 
1335  |  |    * 0 -   |  | 
1336  |  |    * 0 - --/  | 
1337  |  |    * 0 - --\  | 
1338  |  |    * 1 -   |  | 
1339  |  |    *       | DisconnectProviderUltimatum::reason = rn-user-requested (3)  | 
1340  |  |    * 0x80: |  | 
1341  |  |    * 1 - --/  | 
1342  |  |    * 0 - padding  | 
1343  |  |    * 0 - padding  | 
1344  |  |    * 0 - padding  | 
1345  |  |    * 0 - padding  | 
1346  |  |    * 0 - padding  | 
1347  |  |    * 0 - padding  | 
1348  |  |    * 0 - padding  | 
1349  |  |    */  | 
1350  |  |  | 
1351  | 532  |   if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))  | 
1352  | 2  |     return FALSE;  | 
1353  |  |  | 
1354  | 530  |   Stream_Rewind_UINT8(s);  | 
1355  | 530  |   Stream_Read_UINT8(s, b1);  | 
1356  | 530  |   Stream_Read_UINT8(s, b2);  | 
1357  | 530  |   *reason = ((b1 & 0x01) << 1) | (b2 >> 7);  | 
1358  | 530  |   return TRUE;  | 
1359  | 532  | }  | 
1360  |  |  | 
1361  |  | /**  | 
1362  |  |  * Send MCS Disconnect Provider Ultimatum PDU.  | 
1363  |  |  * @param mcs mcs module  | 
1364  |  |  */  | 
1365  |  |  | 
1366  |  | BOOL mcs_send_disconnect_provider_ultimatum(rdpMcs* mcs)  | 
1367  | 0  | { | 
1368  | 0  |   wStream* s = NULL;  | 
1369  | 0  |   int status = -1;  | 
1370  | 0  |   UINT16 length = 9;  | 
1371  |  | 
  | 
1372  | 0  |   WINPR_ASSERT(mcs);  | 
1373  |  |  | 
1374  | 0  |   s = Stream_New(NULL, length);  | 
1375  |  | 
  | 
1376  | 0  |   if (!s)  | 
1377  | 0  |     goto fail;  | 
1378  |  |  | 
1379  | 0  |   if (!mcs_write_domain_mcspdu_header(s, DomainMCSPDU_DisconnectProviderUltimatum, length, 1))  | 
1380  | 0  |     goto fail;  | 
1381  |  |  | 
1382  | 0  |   if (!per_write_enumerated(s, 0x80, 0))  | 
1383  | 0  |     goto fail;  | 
1384  | 0  |   status = transport_write(mcs->transport, s);  | 
1385  | 0  | fail:  | 
1386  | 0  |   Stream_Free(s, TRUE);  | 
1387  | 0  |   return (status < 0) ? FALSE : TRUE;  | 
1388  | 0  | }  | 
1389  |  |  | 
1390  |  | BOOL mcs_client_begin(rdpMcs* mcs)  | 
1391  | 0  | { | 
1392  | 0  |   rdpContext* context = NULL;  | 
1393  |  | 
  | 
1394  | 0  |   if (!mcs || !mcs->transport)  | 
1395  | 0  |     return FALSE;  | 
1396  |  |  | 
1397  | 0  |   context = transport_get_context(mcs->transport);  | 
1398  |  | 
  | 
1399  | 0  |   if (!context)  | 
1400  | 0  |     return FALSE;  | 
1401  |  |  | 
1402  |  |   /* First transition state, we need this to trigger session recording */  | 
1403  | 0  |   if (!mcs_send_connect_initial(mcs))  | 
1404  | 0  |   { | 
1405  | 0  |     freerdp_set_last_error_if_not(context, FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR);  | 
1406  |  | 
  | 
1407  | 0  |     WLog_ERR(TAG, "Error: unable to send MCS Connect Initial");  | 
1408  | 0  |     return FALSE;  | 
1409  | 0  |   }  | 
1410  |  |  | 
1411  | 0  |   return TRUE;  | 
1412  | 0  | }  | 
1413  |  |  | 
1414  |  | /**  | 
1415  |  |  * Instantiate new MCS module.  | 
1416  |  |  * @param transport transport  | 
1417  |  |  * @return new MCS module  | 
1418  |  |  */  | 
1419  |  |  | 
1420  |  | rdpMcs* mcs_new(rdpTransport* transport)  | 
1421  | 39.8k  | { | 
1422  | 39.8k  |   rdpMcs* mcs = NULL;  | 
1423  |  |  | 
1424  | 39.8k  |   mcs = (rdpMcs*)calloc(1, sizeof(rdpMcs));  | 
1425  |  |  | 
1426  | 39.8k  |   if (!mcs)  | 
1427  | 0  |     return NULL;  | 
1428  |  |  | 
1429  | 39.8k  |   mcs->transport = transport;  | 
1430  | 39.8k  |   mcs_init_domain_parameters(&mcs->targetParameters, 34, 2, 0, 0xFFFF);  | 
1431  | 39.8k  |   mcs_init_domain_parameters(&mcs->minimumParameters, 1, 1, 1, 0x420);  | 
1432  | 39.8k  |   mcs_init_domain_parameters(&mcs->maximumParameters, 0xFFFF, 0xFC17, 0xFFFF, 0xFFFF);  | 
1433  | 39.8k  |   mcs_init_domain_parameters(&mcs->domainParameters, 0, 0, 0, 0xFFFF);  | 
1434  | 39.8k  |   mcs->channelCount = 0;  | 
1435  | 39.8k  |   mcs->channelMaxCount = CHANNEL_MAX_COUNT;  | 
1436  | 39.8k  |   mcs->baseChannelId = MCS_GLOBAL_CHANNEL_ID + 1;  | 
1437  | 39.8k  |   mcs->channels = (rdpMcsChannel*)calloc(mcs->channelMaxCount, sizeof(rdpMcsChannel));  | 
1438  |  |  | 
1439  | 39.8k  |   if (!mcs->channels)  | 
1440  | 0  |     goto out_free;  | 
1441  |  |  | 
1442  | 39.8k  |   return mcs;  | 
1443  | 0  | out_free:  | 
1444  | 0  |   free(mcs);  | 
1445  | 0  |   return NULL;  | 
1446  | 39.8k  | }  | 
1447  |  |  | 
1448  |  | /**  | 
1449  |  |  * Free MCS module.  | 
1450  |  |  * @param mcs MCS module to be freed  | 
1451  |  |  */  | 
1452  |  |  | 
1453  |  | void mcs_free(rdpMcs* mcs)  | 
1454  | 39.8k  | { | 
1455  | 39.8k  |   if (mcs)  | 
1456  | 39.8k  |   { | 
1457  | 39.8k  |     free(mcs->channels);  | 
1458  | 39.8k  |     free(mcs);  | 
1459  | 39.8k  |   }  | 
1460  | 39.8k  | }  | 
1461  |  |  | 
1462  |  | BOOL mcs_server_apply_to_settings(const rdpMcs* mcs, rdpSettings* settings)  | 
1463  | 0  | { | 
1464  | 0  |   BOOL rc = FALSE;  | 
1465  |  | 
  | 
1466  | 0  |   WINPR_ASSERT(mcs);  | 
1467  | 0  |   WINPR_ASSERT(settings);  | 
1468  |  |  | 
1469  | 0  |   if (!freerdp_settings_set_uint32(settings, FreeRDP_ChannelCount, mcs->channelCount))  | 
1470  | 0  |     goto fail;  | 
1471  |  |  | 
1472  | 0  |   for (UINT32 x = 0; x < mcs->channelCount; x++)  | 
1473  | 0  |   { | 
1474  | 0  |     const rdpMcsChannel* current = &mcs->channels[x];  | 
1475  | 0  |     CHANNEL_DEF def = { 0 }; | 
1476  | 0  |     def.options = current->options;  | 
1477  | 0  |     memcpy(def.name, current->Name, sizeof(def.name));  | 
1478  | 0  |     if (!freerdp_settings_set_pointer_array(settings, FreeRDP_ChannelDefArray, x, &def))  | 
1479  | 0  |       goto fail;  | 
1480  | 0  |   }  | 
1481  |  |  | 
1482  | 0  |   rc = TRUE;  | 
1483  | 0  | fail:  | 
1484  | 0  |   if (!rc)  | 
1485  | 0  |     WLog_WARN(TAG, "failed to apply settings");  | 
1486  |  | 
  | 
1487  | 0  |   return rc;  | 
1488  | 0  | }  |