libfreerdp-core: change client connection sequence using nonblocking.
[platform/upstream/freerdp.git] / libfreerdp-core / gcc.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Client
3  * T.124 Generic Conference Control (GCC)
4  *
5  * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #include "gcc.h"
21
22 /**
23  * T.124 GCC is defined in:
24  *
25  * http://www.itu.int/rec/T-REC-T.124-199802-S/en
26  * ITU-T T.124 (02/98): Generic Conference Control
27  */
28
29 /**
30  * ConnectData ::= SEQUENCE
31  * {
32  *      t124Identifier  Key,
33  *      connectPDU      OCTET_STRING
34  * }
35  *
36  * Key ::= CHOICE
37  * {
38  *      object                          OBJECT_IDENTIFIER,
39  *      h221NonStandard                 H221NonStandardIdentifier
40  * }
41  *
42  * ConnectGCCPDU ::= CHOICE
43  * {
44  *      conferenceCreateRequest         ConferenceCreateRequest,
45  *      conferenceCreateResponse        ConferenceCreateResponse,
46  *      conferenceQueryRequest          ConferenceQueryRequest,
47  *      conferenceQueryResponse         ConferenceQueryResponse,
48  *      conferenceJoinRequest           ConferenceJoinRequest,
49  *      conferenceJoinResponse          ConferenceJoinResponse,
50  *      conferenceInviteRequest         ConferenceInviteRequest,
51  *      conferenceInviteResponse        ConferenceInviteResponse,
52  *      ...
53  * }
54  *
55  * ConferenceCreateRequest ::= SEQUENCE
56  * {
57  *      conferenceName                  ConferenceName,
58  *      convenerPassword                Password OPTIONAL,
59  *      password                        Password OPTIONAL,
60  *      lockedConference                BOOLEAN,
61  *      listedConference                BOOLEAN,
62  *      conductibleConference           BOOLEAN,
63  *      terminationMethod               TerminationMethod,
64  *      conductorPrivileges             SET OF Privilege OPTIONAL,
65  *      conductedPrivileges             SET OF Privilege OPTIONAL,
66  *      nonConductedPrivileges          SET OF Privilege OPTIONAL,
67  *      conferenceDescription           TextString OPTIONAL,
68  *      callerIdentifier                TextString OPTIONAL,
69  *      userData                        UserData OPTIONAL,
70  *      ...,
71  *      conferencePriority              ConferencePriority OPTIONAL,
72  *      conferenceMode                  ConferenceMode OPTIONAL
73  * }
74  *
75  * ConferenceCreateResponse ::= SEQUENCE
76  * {
77  *      nodeID                          UserID,
78  *      tag                             INTEGER,
79  *      result                          ENUMERATED
80  *      {
81  *              success                         (0),
82  *              userRejected                    (1),
83  *              resourcesNotAvailable           (2),
84  *              rejectedForSymmetryBreaking     (3),
85  *              lockedConferenceNotSupported    (4)
86  *      },
87  *      userData                        UserData OPTIONAL,
88  *      ...
89  * }
90  *
91  * ConferenceName ::= SEQUENCE
92  * {
93  *      numeric                         SimpleNumericString
94  *      text                            SimpleTextString OPTIONAL,
95  *      ...
96  * }
97  *
98  * SimpleNumericString ::= NumericString (SIZE (1..255)) (FROM ("0123456789"))
99  *
100  * UserData ::= SET OF SEQUENCE
101  * {
102  *      key                             Key,
103  *      value                           OCTET_STRING OPTIONAL
104  * }
105  *
106  * H221NonStandardIdentifier ::= OCTET STRING (SIZE (4..255))
107  *
108  * UserID ::= DynamicChannelID
109  *
110  * ChannelID ::= INTEGER (1..65535)
111  * StaticChannelID ::= INTEGER (1..1000)
112  * DynamicChannelID ::= INTEGER (1001..65535)
113  *
114  */
115
116 /*
117  * OID = 0.0.20.124.0.1
118  * { itu-t(0) recommendation(0) t(20) t124(124) version(0) 1 }
119  * v.1 of ITU-T Recommendation T.124 (Feb 1998): "Generic Conference Control"
120  */
121 uint8 t124_02_98_oid[6] = { 0, 0, 20, 124, 0, 1 };
122
123 uint8 h221_cs_key[4] = "Duca";
124 uint8 h221_sc_key[4] = "McDn";
125
126 /**
127  * Read a GCC Conference Create Request.\n
128  * @msdn{cc240836}
129  * @param s stream
130  * @param settings rdp settings
131  */
132
133 boolean gcc_read_conference_create_request(STREAM* s, rdpSettings* settings)
134 {
135         uint16 length;
136         uint8 choice;
137         uint8 number;
138         uint8 selection;
139
140         /* ConnectData */
141         if (!per_read_choice(s, &choice))
142                 return False;
143         if (!per_read_object_identifier(s, t124_02_98_oid))
144                 return False;
145
146         /* ConnectData::connectPDU (OCTET_STRING) */
147         if (!per_read_length(s, &length))
148                 return False;
149
150         /* ConnectGCCPDU */
151         if (!per_read_choice(s, &choice))
152                 return False;
153         if (!per_read_selection(s, &selection))
154                 return False;
155
156         /* ConferenceCreateRequest::conferenceName */
157         if (!per_read_numeric_string(s, 1)) /* ConferenceName::numeric */
158                 return False;
159         if (!per_read_padding(s, 1)) /* padding */
160                 return False;
161
162         /* UserData (SET OF SEQUENCE) */
163         if (!per_read_number_of_sets(s, &number) || number != 1) /* one set of UserData */
164                 return False;
165         if (!per_read_choice(s, &choice) || choice != 0xC0) /* UserData::value present + select h221NonStandard (1) */
166                 return False;
167
168         /* h221NonStandard */
169         if (!per_read_octet_string(s, h221_cs_key, 4, 4)) /* h221NonStandard, client-to-server H.221 key, "Duca" */
170                 return False;
171
172         /* userData::value (OCTET_STRING) */
173         if (!per_read_length(s, &length))
174                 return False;
175         if (stream_get_left(s) < length)
176                 return False;
177         if (!gcc_read_client_data_blocks(s, settings, length))
178                 return False;
179
180         return True;
181 }
182
183 /**
184  * Write a GCC Conference Create Request.\n
185  * @msdn{cc240836}
186  * @param s stream
187  * @param user_data client data blocks
188  */
189
190 void gcc_write_conference_create_request(STREAM* s, STREAM* user_data)
191 {
192         /* ConnectData */
193         per_write_choice(s, 0); /* From Key select object (0) of type OBJECT_IDENTIFIER */
194         per_write_object_identifier(s, t124_02_98_oid); /* ITU-T T.124 (02/98) OBJECT_IDENTIFIER */
195
196         /* ConnectData::connectPDU (OCTET_STRING) */
197         per_write_length(s, stream_get_length(user_data) + 14); /* connectPDU length */
198
199         /* ConnectGCCPDU */
200         per_write_choice(s, 0); /* From ConnectGCCPDU select conferenceCreateRequest (0) of type ConferenceCreateRequest */
201         per_write_selection(s, 0x08); /* select optional userData from ConferenceCreateRequest */
202
203         /* ConferenceCreateRequest::conferenceName */
204         per_write_numeric_string(s, (uint8*)"1", 1, 1); /* ConferenceName::numeric */
205         per_write_padding(s, 1); /* padding */
206
207         /* UserData (SET OF SEQUENCE) */
208         per_write_number_of_sets(s, 1); /* one set of UserData */
209         per_write_choice(s, 0xC0); /* UserData::value present + select h221NonStandard (1) */
210
211         /* h221NonStandard */
212         per_write_octet_string(s, h221_cs_key, 4, 4); /* h221NonStandard, client-to-server H.221 key, "Duca" */
213
214         /* userData::value (OCTET_STRING) */
215         per_write_octet_string(s, user_data->data, stream_get_length(user_data), 0); /* array of client data blocks */
216 }
217
218 boolean gcc_read_conference_create_response(STREAM* s, rdpSettings* settings)
219 {
220         uint16 length;
221         uint32 tag;
222         uint16 nodeID;
223         uint8 result;
224         uint8 choice;
225         uint8 number;
226
227         /* ConnectData */
228         per_read_choice(s, &choice);
229         per_read_object_identifier(s, t124_02_98_oid);
230
231         /* ConnectData::connectPDU (OCTET_STRING) */
232         per_read_length(s, &length);
233
234         /* ConnectGCCPDU */
235         per_read_choice(s, &choice);
236
237         /* ConferenceCreateResponse::nodeID (UserID) */
238         per_read_integer16(s, &nodeID, 1001);
239
240         /* ConferenceCreateResponse::tag (INTEGER) */
241         per_read_integer(s, &tag);
242
243         /* ConferenceCreateResponse::result (ENUMERATED) */
244         per_read_enumerated(s, &result, MCS_Result_enum_length);
245
246         /* number of UserData sets */
247         per_read_number_of_sets(s, &number);
248
249         /* UserData::value present + select h221NonStandard (1) */
250         per_read_choice(s, &choice);
251
252         /* h221NonStandard */
253         per_read_octet_string(s, h221_sc_key, 4, 4); /* h221NonStandard, server-to-client H.221 key, "McDn" */
254
255         /* userData (OCTET_STRING) */
256         per_read_length(s, &length);
257         if (!gcc_read_server_data_blocks(s, settings, length))
258                 return False;
259
260         return True;
261 }
262
263 void gcc_write_conference_create_response(STREAM* s, STREAM* user_data)
264 {
265         /* ConnectData */
266         per_write_choice(s, 0);
267         per_write_object_identifier(s, t124_02_98_oid);
268
269         /* ConnectData::connectPDU (OCTET_STRING) */
270         per_write_length(s, stream_get_length(user_data) + 2);
271
272         /* ConnectGCCPDU */
273         per_write_choice(s, 0x14);
274
275         /* ConferenceCreateResponse::nodeID (UserID) */
276         per_write_integer16(s, 0x79F3, 1001);
277
278         /* ConferenceCreateResponse::tag (INTEGER) */
279         per_write_integer(s, 1);
280
281         /* ConferenceCreateResponse::result (ENUMERATED) */
282         per_write_enumerated(s, 0, MCS_Result_enum_length);
283
284         /* number of UserData sets */
285         per_write_number_of_sets(s, 1);
286
287         /* UserData::value present + select h221NonStandard (1) */
288         per_write_choice(s, 0xC0);
289
290         /* h221NonStandard */
291         per_write_octet_string(s, h221_sc_key, 4, 4); /* h221NonStandard, server-to-client H.221 key, "McDn" */
292
293         /* userData (OCTET_STRING) */
294         per_write_octet_string(s, user_data->data, stream_get_length(user_data), 0); /* array of server data blocks */
295 }
296
297 boolean gcc_read_client_data_blocks(STREAM* s, rdpSettings *settings, int length)
298 {
299         uint16 type;
300         uint16 blockLength;
301         int pos;
302
303         while (length > 0)
304         {
305                 pos = stream_get_pos(s);
306                 gcc_read_user_data_header(s, &type, &blockLength);
307
308                 switch (type)
309                 {
310                         case CS_CORE:
311                                 if (!gcc_read_client_core_data(s, settings, blockLength - 4))
312                                         return False;
313                                 break;
314
315                         case CS_SECURITY:
316                                 if (!gcc_read_client_security_data(s, settings, blockLength - 4))
317                                         return False;
318                                 break;
319
320                         case CS_NET:
321                                 if (!gcc_read_client_network_data(s, settings, blockLength - 4))
322                                         return False;
323                                 break;
324
325                         case CS_CLUSTER:
326                                 if (!gcc_read_client_cluster_data(s, settings, blockLength - 4))
327                                         return False;
328                                 break;
329
330                         case CS_MONITOR:
331                                 if (!gcc_read_client_monitor_data(s, settings, blockLength - 4))
332                                         return False;
333                                 break;
334
335                         default:
336                                 break;
337                 }
338
339                 length -= blockLength;
340                 stream_set_pos(s, pos + blockLength);
341         }
342
343         return True;
344 }
345
346 void gcc_write_client_data_blocks(STREAM* s, rdpSettings *settings)
347 {
348         gcc_write_client_core_data(s, settings);
349         gcc_write_client_cluster_data(s, settings);
350         gcc_write_client_security_data(s, settings);
351         gcc_write_client_network_data(s, settings);
352         gcc_write_client_monitor_data(s, settings);
353 }
354
355 boolean gcc_read_server_data_blocks(STREAM* s, rdpSettings *settings, int length)
356 {
357         uint16 type;
358         uint16 offset = 0;
359         uint16 blockLength;
360
361         while (offset < length)
362         {
363                 if (!gcc_read_user_data_header(s, &type, &blockLength))
364                         return False;
365
366                 switch (type)
367                 {
368                         case SC_CORE:
369                                 if (!gcc_read_server_core_data(s, settings))
370                                         return False;
371                                 break;
372
373                         case SC_SECURITY:
374                                 if (!gcc_read_server_security_data(s, settings))
375                                         return False;
376                                 break;
377
378                         case SC_NET:
379                                 if (!gcc_read_server_network_data(s, settings))
380                                         return False;
381                                 break;
382
383                         default:
384                                 break;
385                 }
386
387                 offset += blockLength;
388         }
389
390         return True;
391 }
392
393 void gcc_write_server_data_blocks(STREAM* s, rdpSettings *settings)
394 {
395         gcc_write_server_core_data(s, settings);
396         gcc_write_server_network_data(s, settings);
397         gcc_write_server_security_data(s, settings);
398 }
399
400 boolean gcc_read_user_data_header(STREAM* s, uint16* type, uint16* length)
401 {
402         stream_read_uint16(s, *type); /* type */
403         stream_read_uint16(s, *length); /* length */
404
405         if (stream_get_left(s) < *length - 4)
406                 return False;
407
408         return True;
409 }
410
411 /**
412  * Write a user data header (TS_UD_HEADER).\n
413  * @msdn{cc240509}
414  * @param s stream
415  * @param type data block type
416  * @param length data block length
417  */
418
419 void gcc_write_user_data_header(STREAM* s, uint16 type, uint16 length)
420 {
421         stream_write_uint16(s, type); /* type */
422         stream_write_uint16(s, length); /* length */
423 }
424
425 /**
426  * Read a client core data block (TS_UD_CS_CORE).\n
427  * @msdn{cc240510}
428  * @param s stream
429  * @param settings rdp settings
430  */
431
432 boolean gcc_read_client_core_data(STREAM* s, rdpSettings *settings, uint16 blockLength)
433 {
434         uint32 version;
435         uint16 colorDepth = 0;
436         uint16 postBeta2ColorDepth = 0;
437         uint16 highColorDepth = 0;
438         uint16 supportedColorDepths = 0;
439         uint16 earlyCapabilityFlags = 0;
440         uint32 serverSelectedProtocol = 0;
441         char* str;
442
443         /* Length of all required fields, until imeFileName */
444         if (blockLength < 128)
445                 return False;
446
447         stream_read_uint32(s, version); /* version */
448         settings->rdp_version = (version == RDP_VERSION_4 ? 4 : 7);
449
450         stream_read_uint16(s, settings->width); /* desktopWidth */
451         stream_read_uint16(s, settings->height); /* desktopHeight */
452         stream_read_uint16(s, colorDepth); /* colorDepth */
453         stream_seek_uint16(s); /* SASSequence (Secure Access Sequence) */
454         stream_read_uint32(s, settings->kbd_layout); /* keyboardLayout */
455         stream_read_uint32(s, settings->client_build); /* clientBuild */
456         
457         /* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */
458         str = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), 32);
459         stream_seek(s, 32);
460         snprintf(settings->client_hostname, sizeof(settings->client_hostname), "%s", str);
461         xfree(str);
462
463         stream_read_uint32(s, settings->kbd_type); /* keyboardType */
464         stream_read_uint32(s, settings->kbd_subtype); /* keyboardSubType */
465         stream_read_uint32(s, settings->kbd_fn_keys); /* keyboardFunctionKey */
466
467         stream_seek(s, 64); /* imeFileName */
468
469         blockLength -= 128;
470
471         /**
472          * The following fields are all optional. If one field is present, all of the preceding
473          * fields MUST also be present. If one field is not present, all of the subsequent fields
474          * MUST NOT be present.
475          * We must check the bytes left before reading each field.
476          */
477
478         do
479         {
480                 if (blockLength < 2)
481                         break;
482                 stream_read_uint16(s, postBeta2ColorDepth); /* postBeta2ColorDepth */
483                 blockLength -= 2;
484
485                 if (blockLength < 2)
486                         break;
487                 stream_seek_uint16(s); /* clientProductID */
488                 blockLength -= 2;
489
490                 if (blockLength < 4)
491                         break;
492                 stream_seek_uint32(s); /* serialNumber */
493                 blockLength -= 4;
494
495                 if (blockLength < 2)
496                         break;
497                 stream_read_uint16(s, highColorDepth); /* highColorDepth */
498                 blockLength -= 2;
499
500                 if (blockLength < 2)
501                         break;
502                 stream_read_uint16(s, supportedColorDepths); /* supportedColorDepths */
503                 blockLength -= 2;
504
505                 if (blockLength < 2)
506                         break;
507                 stream_read_uint16(s, earlyCapabilityFlags); /* earlyCapabilityFlags */
508                 blockLength -= 2;
509
510                 if (blockLength < 64)
511                         break;
512                 str = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), 64);
513                 stream_seek(s, 64);
514                 snprintf(settings->client_product_id, sizeof(settings->client_product_id), "%s", str);
515                 xfree(str);
516                 blockLength -= 64;
517
518                 if (blockLength < 1)
519                         break;
520                 stream_read_uint8(s, settings->performance_flags); /* connectionType */
521                 blockLength -= 1;
522
523                 if (blockLength < 1)
524                         break;
525                 stream_seek_uint8(s); /* pad1octet */
526                 blockLength -= 1;
527
528                 if (blockLength < 4)
529                         break;
530                 stream_read_uint32(s, serverSelectedProtocol); /* serverSelectedProtocol */
531                 blockLength -= 4;
532
533                 if (settings->selected_protocol != serverSelectedProtocol)
534                         return False;
535         } while (0);
536
537         if (highColorDepth > 0)
538                 settings->color_depth = highColorDepth;
539         else if (postBeta2ColorDepth > 0)
540         {
541                 switch (postBeta2ColorDepth)
542                 {
543                         case RNS_UD_COLOR_4BPP:
544                                 settings->color_depth = 4;
545                                 break;
546                         case RNS_UD_COLOR_8BPP:
547                                 settings->color_depth = 8;
548                                 break;
549                         case RNS_UD_COLOR_16BPP_555:
550                                 settings->color_depth = 15;
551                                 break;
552                         case RNS_UD_COLOR_16BPP_565:
553                                 settings->color_depth = 16;
554                                 break;
555                         case RNS_UD_COLOR_24BPP:
556                                 settings->color_depth = 24;
557                                 break;
558                         default:
559                                 return False;
560                 }
561         }
562         else
563         {
564                 switch (colorDepth)
565                 {
566                         case RNS_UD_COLOR_4BPP:
567                                 settings->color_depth = 4;
568                                 break;
569                         case RNS_UD_COLOR_8BPP:
570                                 settings->color_depth = 8;
571                                 break;
572                         default:
573                                 return False;
574                 }
575         }
576
577         return True;
578 }
579
580 /**
581  * Write a client core data block (TS_UD_CS_CORE).\n
582  * @msdn{cc240510}
583  * @param s stream
584  * @param settings rdp settings
585  */
586
587 void gcc_write_client_core_data(STREAM* s, rdpSettings *settings)
588 {
589         uint32 version;
590         char* clientName;
591         size_t clientNameLength;
592         uint8 connectionType;
593         uint16 highColorDepth;
594         uint16 supportedColorDepths;
595         uint16 earlyCapabilityFlags;
596         char* clientDigProductId;
597         size_t clientDigProductIdLength;
598
599         gcc_write_user_data_header(s, CS_CORE, 216);
600
601         version = settings->rdp_version >= 5 ? RDP_VERSION_5_PLUS : RDP_VERSION_4;
602         clientName = freerdp_uniconv_out(settings->uniconv, settings->client_hostname, &clientNameLength);
603         clientDigProductId = freerdp_uniconv_out(settings->uniconv, settings->client_product_id, &clientDigProductIdLength);
604
605         stream_write_uint32(s, version); /* version */
606         stream_write_uint16(s, settings->width); /* desktopWidth */
607         stream_write_uint16(s, settings->height); /* desktopHeight */
608         stream_write_uint16(s, RNS_UD_COLOR_8BPP); /* colorDepth, ignored because of postBeta2ColorDepth */
609         stream_write_uint16(s, RNS_UD_SAS_DEL); /* SASSequence (Secure Access Sequence) */
610         stream_write_uint32(s, settings->kbd_layout); /* keyboardLayout */
611         stream_write_uint32(s, settings->client_build); /* clientBuild */
612
613         /* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */
614         if (clientNameLength > 30)
615         {
616                 clientNameLength = 30;
617                 clientName[clientNameLength] = 0;
618                 clientName[clientNameLength + 1] = 0;
619         }
620         stream_write(s, clientName, clientNameLength + 2);
621         stream_write_zero(s, 32 - clientNameLength - 2);
622         xfree(clientName);
623
624         stream_write_uint32(s, settings->kbd_type); /* keyboardType */
625         stream_write_uint32(s, settings->kbd_subtype); /* keyboardSubType */
626         stream_write_uint32(s, settings->kbd_fn_keys); /* keyboardFunctionKey */
627
628         stream_write_zero(s, 64); /* imeFileName */
629
630         stream_write_uint16(s, RNS_UD_COLOR_8BPP); /* postBeta2ColorDepth */
631         stream_write_uint16(s, 1); /* clientProductID */
632         stream_write_uint32(s, 0); /* serialNumber (should be initialized to 0) */
633
634         highColorDepth = MIN(settings->color_depth, 24);
635
636         supportedColorDepths =
637                         RNS_UD_24BPP_SUPPORT |
638                         RNS_UD_16BPP_SUPPORT |
639                         RNS_UD_15BPP_SUPPORT;
640
641         connectionType = 0;
642         earlyCapabilityFlags = RNS_UD_CS_SUPPORT_ERRINFO_PDU;
643
644         if (settings->performance_flags == PERF_FLAG_NONE)
645         {
646                 earlyCapabilityFlags |= RNS_UD_CS_VALID_CONNECTION_TYPE;
647                 connectionType = CONNECTION_TYPE_LAN;
648         }
649
650         if (settings->color_depth == 32)
651         {
652                 supportedColorDepths |= RNS_UD_32BPP_SUPPORT;
653                 earlyCapabilityFlags |= RNS_UD_CS_WANT_32BPP_SESSION;
654         }
655
656         stream_write_uint16(s, highColorDepth); /* highColorDepth */
657         stream_write_uint16(s, supportedColorDepths); /* supportedColorDepths */
658
659         stream_write_uint16(s, earlyCapabilityFlags); /* earlyCapabilityFlags */
660
661         /* clientDigProductId (64 bytes, null-terminated unicode, truncated to 30 characters) */
662         if (clientDigProductIdLength > 62)
663         {
664                 clientDigProductIdLength = 62;
665                 clientDigProductId[clientDigProductIdLength] = 0;
666                 clientDigProductId[clientDigProductIdLength + 1] = 0;
667         }
668         stream_write(s, clientDigProductId, clientDigProductIdLength + 2);
669         stream_write_zero(s, 64 - clientDigProductIdLength - 2);
670         xfree(clientDigProductId);
671
672         stream_write_uint8(s, connectionType); /* connectionType */
673         stream_write_uint8(s, 0); /* pad1octet */
674
675         stream_write_uint32(s, settings->selected_protocol); /* serverSelectedProtocol */
676 }
677
678 boolean gcc_read_server_core_data(STREAM* s, rdpSettings *settings)
679 {
680         uint32 version;
681         uint32 clientRequestedProtocols;
682
683         stream_read_uint32(s, version); /* version */
684         stream_read_uint32(s, clientRequestedProtocols); /* clientRequestedProtocols */
685
686         if (version == RDP_VERSION_4 && settings->rdp_version > 4)
687                 settings->rdp_version = 4;
688         else if (version == RDP_VERSION_5_PLUS && settings->rdp_version < 5)
689                 settings->rdp_version = 7;
690
691         return True;
692 }
693
694 void gcc_write_server_core_data(STREAM* s, rdpSettings *settings)
695 {
696         gcc_write_user_data_header(s, SC_CORE, 12);
697
698         stream_write_uint32(s, settings->rdp_version == 4 ? RDP_VERSION_4 : RDP_VERSION_5_PLUS);
699         stream_write_uint32(s, settings->requested_protocols); /* clientRequestedProtocols */
700 }
701
702 /**
703  * Read a client security data block (TS_UD_CS_SEC).\n
704  * @msdn{cc240511}
705  * @param s stream
706  * @param settings rdp settings
707  */
708
709 boolean gcc_read_client_security_data(STREAM* s, rdpSettings *settings, uint16 blockLength)
710 {
711         if (blockLength < 8)
712                 return False;
713
714         stream_read_uint32(s, settings->encryption_method); /* encryptionMethods */
715         if (settings->encryption_method == 0)
716                 stream_read_uint32(s, settings->encryption_method); /* extEncryptionMethods */
717
718         return True;
719 }
720
721 /**
722  * Write a client security data block (TS_UD_CS_SEC).\n
723  * @msdn{cc240511}
724  * @param s stream
725  * @param settings rdp settings
726  */
727
728 void gcc_write_client_security_data(STREAM* s, rdpSettings *settings)
729 {
730         gcc_write_user_data_header(s, CS_SECURITY, 12);
731
732         if (settings->encryption > 0)
733         {
734                 stream_write_uint32(s, settings->encryption_method); /* encryptionMethods */
735                 stream_write_uint32(s, 0); /* extEncryptionMethods */
736         }
737         else
738         {
739                 /* French locale, disable encryption */
740                 stream_write_uint32(s, 0); /* encryptionMethods */
741                 stream_write_uint32(s, settings->encryption_method); /* extEncryptionMethods */
742         }
743 }
744
745 boolean gcc_read_server_security_data(STREAM* s, rdpSettings *settings)
746 {
747         uint32 encryptionMethod;
748         uint32 encryptionLevel;
749         uint32 serverRandomLen;
750         uint32 serverCertLen;
751
752         stream_read_uint32(s, encryptionMethod); /* encryptionMethod */
753         stream_read_uint32(s, encryptionLevel); /* encryptionLevel */
754
755         if (encryptionMethod == 0 && encryptionLevel == 0)
756         {
757                 /* serverRandom and serverRandom must not be present */
758                 return True;
759         }
760
761         stream_read_uint32(s, serverRandomLen); /* serverRandomLen */
762         stream_read_uint32(s, serverCertLen); /* serverCertLen */
763
764         if (serverRandomLen > 0)
765         {
766                 /* serverRandom */
767                 freerdp_blob_alloc(&settings->server_random, serverRandomLen);
768                 memcpy(settings->server_random.data, s->p, serverRandomLen);
769                 stream_seek(s, serverRandomLen);
770         }
771
772         if (serverCertLen > 0)
773         {
774                 /* serverCertificate */
775                 freerdp_blob_alloc(&settings->server_certificate, serverCertLen);
776                 memcpy(settings->server_certificate.data, s->p, serverCertLen);
777                 stream_seek(s, serverCertLen);
778         }
779
780         return True;
781 }
782
783 void gcc_write_server_security_data(STREAM* s, rdpSettings *settings)
784 {
785         gcc_write_user_data_header(s, SC_SECURITY, 12);
786
787         stream_write_uint32(s, ENCRYPTION_METHOD_NONE); /* encryptionMethod */
788         stream_write_uint32(s, ENCRYPTION_LEVEL_NONE); /* encryptionLevel */
789 #if 0
790         stream_write_uint32(s, 0); /* serverRandomLen */
791         stream_write_uint32(s, 0); /* serverCertLen */
792 #endif
793 }
794
795 /**
796  * Read a client network data block (TS_UD_CS_NET).\n
797  * @msdn{cc240512}
798  * @param s stream
799  * @param settings rdp settings
800  */
801
802 boolean gcc_read_client_network_data(STREAM* s, rdpSettings *settings, uint16 blockLength)
803 {
804         int i;
805
806         if (blockLength < 4)
807                 return False;
808
809         stream_read_uint32(s, settings->num_channels); /* channelCount */
810         if (blockLength < 4 + settings->num_channels * 12)
811                 return False;
812         if (settings->num_channels > 16)
813                 return False;
814
815         /* channelDefArray */
816         for (i = 0; i < settings->num_channels; i++)
817         {
818                 /* CHANNEL_DEF */
819                 stream_read(s, settings->channels[i].name, 8); /* name (8 bytes) */
820                 stream_read_uint32(s, settings->channels[i].options); /* options (4 bytes) */
821                 settings->channels[i].chan_id = MCS_GLOBAL_CHANNEL_ID + 1 + i;
822         }
823
824         return True;
825 }
826
827 /**
828  * Write a client network data block (TS_UD_CS_NET).\n
829  * @msdn{cc240512}
830  * @param s stream
831  * @param settings rdp settings
832  */
833
834 void gcc_write_client_network_data(STREAM* s, rdpSettings *settings)
835 {
836         int i;
837         uint16 length;
838
839         if (settings->num_channels > 0)
840         {
841                 length = settings->num_channels * 12 + 8;
842                 gcc_write_user_data_header(s, CS_NET, length);
843
844                 stream_write_uint32(s, settings->num_channels); /* channelCount */
845
846                 /* channelDefArray */
847                 for (i = 0; i < settings->num_channels; i++)
848                 {
849                         /* CHANNEL_DEF */
850                         stream_write(s, settings->channels[i].name, 8); /* name (8 bytes) */
851                         stream_write_uint32(s, settings->channels[i].options); /* options (4 bytes) */
852                 }
853         }
854 }
855
856 boolean gcc_read_server_network_data(STREAM* s, rdpSettings *settings)
857 {
858         int i;
859         uint16 MCSChannelId;
860         uint16 channelCount;
861         uint16 channelId;
862
863         stream_read_uint16(s, MCSChannelId); /* MCSChannelId */
864         stream_read_uint16(s, channelCount); /* channelCount */
865
866         if (channelCount != settings->num_channels)
867         {
868                 printf("requested %d channels, got %d instead\n",
869                                 settings->num_channels, channelCount);
870         }
871
872         for (i = 0; i < channelCount; i++)
873         {
874                 stream_read_uint16(s, channelId); /* channelId */
875                 settings->channels[i].chan_id = channelId;
876         }
877
878         if (channelCount % 2 == 1)
879                 stream_seek(s, 2); /* padding */
880
881         return True;
882 }
883
884 void gcc_write_server_network_data(STREAM* s, rdpSettings *settings)
885 {
886         int i;
887
888         gcc_write_user_data_header(s, SC_NET, 8 + settings->num_channels * 2 + (settings->num_channels % 2 == 1 ? 2 : 0));
889
890         stream_write_uint16(s, MCS_GLOBAL_CHANNEL_ID); /* MCSChannelId */
891         stream_write_uint16(s, settings->num_channels); /* channelCount */
892
893         for (i = 0; i < settings->num_channels; i++)
894         {
895                 stream_write_uint16(s, settings->channels[i].chan_id);
896         }
897
898         if (settings->num_channels % 2 == 1)
899                 stream_write_uint16(s, 0);
900 }
901
902 /**
903  * Read a client cluster data block (TS_UD_CS_CLUSTER).\n
904  * @msdn{cc240514}
905  * @param s stream
906  * @param settings rdp settings
907  */
908
909 boolean gcc_read_client_cluster_data(STREAM* s, rdpSettings *settings, uint16 blockLength)
910 {
911         uint32 flags;
912
913         if (blockLength < 8)
914                 return False;
915
916         stream_read_uint32(s, flags); /* flags */
917
918         if ((flags | REDIRECTED_SESSIONID_FIELD_VALID))
919                 stream_read_uint32(s, settings->redirected_session_id); /* redirectedSessionID */
920
921         return True;
922 }
923
924 /**
925  * Write a client cluster data block (TS_UD_CS_CLUSTER).\n
926  * @msdn{cc240514}
927  * @param s stream
928  * @param settings rdp settings
929  */
930
931 void gcc_write_client_cluster_data(STREAM* s, rdpSettings *settings)
932 {
933         uint32 flags;
934
935         gcc_write_user_data_header(s, CS_CLUSTER, 12);
936
937         flags = REDIRECTION_SUPPORTED | (REDIRECTION_VERSION4 << 2);
938
939         if (settings->console_session || settings->redirected_session_id)
940                 flags |= REDIRECTED_SESSIONID_FIELD_VALID;
941
942         stream_write_uint32(s, flags); /* flags */
943         stream_write_uint32(s, settings->redirected_session_id); /* redirectedSessionID */
944 }
945
946 /**
947  * Read a client monitor data block (TS_UD_CS_MONITOR).\n
948  * @msdn{dd305336}
949  * @param s stream
950  * @param settings rdp settings
951  */
952
953 boolean gcc_read_client_monitor_data(STREAM* s, rdpSettings *settings, uint16 blockLength)
954 {
955         printf("CS_MONITOR\n");
956         return True;
957 }
958
959 /**
960  * Write a client monitor data block (TS_UD_CS_MONITOR).\n
961  * @msdn{dd305336}
962  * @param s stream
963  * @param settings rdp settings
964  */
965
966 void gcc_write_client_monitor_data(STREAM* s, rdpSettings *settings)
967 {
968         int i;
969         uint16 length;
970         uint32 left, top, right, bottom, flags;
971
972         if (settings->num_monitors > 1)
973         {
974                 length = (20 * settings->num_monitors) + 12;
975                 gcc_write_user_data_header(s, CS_MONITOR, length);
976
977                 stream_write_uint32(s, 0); /* flags */
978                 stream_write_uint32(s, settings->num_monitors); /* monitorCount */
979
980                 for (i = 0; i < settings->num_monitors; i++)
981                 {
982                         left = settings->monitors[i].x;
983                         top = settings->monitors[i].y;
984                         right = settings->monitors[i].x + settings->monitors[i].width - 1;
985                         bottom = settings->monitors[i].y + settings->monitors[i].height - 1;
986                         flags = settings->monitors[i].is_primary ? MONITOR_PRIMARY : 0;
987
988                         stream_write_uint32(s, left); /* left */
989                         stream_write_uint32(s, top); /* top */
990                         stream_write_uint32(s, right); /* right */
991                         stream_write_uint32(s, bottom); /* bottom */
992                         stream_write_uint32(s, flags); /* flags */
993                 }
994         }
995 }
996