server: send MCS Connect Response PDU.
[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 void 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         gcc_read_server_data_blocks(s, settings, length);
258 }
259
260 void gcc_write_conference_create_response(STREAM* s, STREAM* user_data)
261 {
262         /* ConnectData */
263         per_write_choice(s, 0);
264         per_write_object_identifier(s, t124_02_98_oid);
265
266         /* ConnectData::connectPDU (OCTET_STRING) */
267         per_write_length(s, stream_get_length(user_data) + 2);
268
269         /* ConnectGCCPDU */
270         per_write_choice(s, 0x14);
271
272         /* ConferenceCreateResponse::nodeID (UserID) */
273         per_write_integer16(s, 0x79F3, 1001);
274
275         /* ConferenceCreateResponse::tag (INTEGER) */
276         per_write_integer(s, 1);
277
278         /* ConferenceCreateResponse::result (ENUMERATED) */
279         per_write_enumerated(s, 0, MCS_Result_enum_length);
280
281         /* number of UserData sets */
282         per_write_number_of_sets(s, 1);
283
284         /* UserData::value present + select h221NonStandard (1) */
285         per_write_choice(s, 0xC0);
286
287         /* h221NonStandard */
288         per_write_octet_string(s, h221_sc_key, 4, 4); /* h221NonStandard, server-to-client H.221 key, "McDn" */
289
290         /* userData (OCTET_STRING) */
291         per_write_octet_string(s, user_data->data, stream_get_length(user_data), 0); /* array of server data blocks */
292 }
293
294 boolean gcc_read_client_data_blocks(STREAM* s, rdpSettings *settings, int length)
295 {
296         uint16 type;
297         uint16 blockLength;
298         int pos;
299
300         while (length > 0)
301         {
302                 pos = stream_get_pos(s);
303                 gcc_read_user_data_header(s, &type, &blockLength);
304
305                 switch (type)
306                 {
307                         case CS_CORE:
308                                 if (!gcc_read_client_core_data(s, settings, blockLength - 4))
309                                         return False;
310                                 break;
311
312                         case CS_SECURITY:
313                                 if (!gcc_read_client_security_data(s, settings, blockLength - 4))
314                                         return False;
315                                 break;
316
317                         case CS_NET:
318                                 if (!gcc_read_client_network_data(s, settings, blockLength - 4))
319                                         return False;
320                                 break;
321
322                         case CS_CLUSTER:
323                                 if (!gcc_read_client_cluster_data(s, settings, blockLength - 4))
324                                         return False;
325                                 break;
326
327                         case CS_MONITOR:
328                                 if (!gcc_read_client_monitor_data(s, settings, blockLength - 4))
329                                         return False;
330                                 break;
331
332                         default:
333                                 break;
334                 }
335
336                 length -= blockLength;
337                 stream_set_pos(s, pos + blockLength);
338         }
339
340         return True;
341 }
342
343 void gcc_write_client_data_blocks(STREAM* s, rdpSettings *settings)
344 {
345         gcc_write_client_core_data(s, settings);
346         gcc_write_client_cluster_data(s, settings);
347         gcc_write_client_security_data(s, settings);
348         gcc_write_client_network_data(s, settings);
349         gcc_write_client_monitor_data(s, settings);
350 }
351
352 void gcc_read_server_data_blocks(STREAM* s, rdpSettings *settings, int length)
353 {
354         uint16 type;
355         uint16 offset = 0;
356         uint16 blockLength;
357
358         while (offset < length)
359         {
360                 gcc_read_user_data_header(s, &type, &blockLength);
361
362                 switch (type)
363                 {
364                         case SC_CORE:
365                                 gcc_read_server_core_data(s, settings);
366                                 break;
367
368                         case SC_SECURITY:
369                                 gcc_read_server_security_data(s, settings);
370                                 break;
371
372                         case SC_NET:
373                                 gcc_read_server_network_data(s, settings);
374                                 break;
375
376                         default:
377                                 break;
378                 }
379
380                 offset += blockLength;
381         }
382 }
383
384 void gcc_write_server_data_blocks(STREAM* s, rdpSettings *settings)
385 {
386         gcc_write_server_core_data(s, settings);
387         gcc_write_server_network_data(s, settings);
388         gcc_write_server_security_data(s, settings);
389 }
390
391 void gcc_read_user_data_header(STREAM* s, uint16* type, uint16* length)
392 {
393         stream_read_uint16(s, *type); /* type */
394         stream_read_uint16(s, *length); /* length */
395 }
396
397 /**
398  * Write a user data header (TS_UD_HEADER).\n
399  * @msdn{cc240509}
400  * @param s stream
401  * @param type data block type
402  * @param length data block length
403  */
404
405 void gcc_write_user_data_header(STREAM* s, uint16 type, uint16 length)
406 {
407         stream_write_uint16(s, type); /* type */
408         stream_write_uint16(s, length); /* length */
409 }
410
411 /**
412  * Read a client core data block (TS_UD_CS_CORE).\n
413  * @msdn{cc240510}
414  * @param s stream
415  * @param settings rdp settings
416  */
417
418 boolean gcc_read_client_core_data(STREAM* s, rdpSettings *settings, uint16 blockLength)
419 {
420         uint32 version;
421         uint16 colorDepth = 0;
422         uint16 postBeta2ColorDepth = 0;
423         uint16 highColorDepth = 0;
424         uint16 supportedColorDepths = 0;
425         uint16 earlyCapabilityFlags = 0;
426         uint32 serverSelectedProtocol = 0;
427         char* str;
428
429         /* Length of all required fields, until imeFileName */
430         if (blockLength < 128)
431                 return False;
432
433         stream_read_uint32(s, version); /* version */
434         settings->rdp_version = (version == RDP_VERSION_4 ? 4 : 7);
435
436         stream_read_uint16(s, settings->width); /* desktopWidth */
437         stream_read_uint16(s, settings->height); /* desktopHeight */
438         stream_read_uint16(s, colorDepth); /* colorDepth */
439         stream_seek_uint16(s); /* SASSequence (Secure Access Sequence) */
440         stream_read_uint32(s, settings->kbd_layout); /* keyboardLayout */
441         stream_read_uint32(s, settings->client_build); /* clientBuild */
442         
443         /* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */
444         str = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), 32);
445         stream_seek(s, 32);
446         snprintf(settings->client_hostname, sizeof(settings->client_hostname), "%s", str);
447         xfree(str);
448
449         stream_read_uint32(s, settings->kbd_type); /* keyboardType */
450         stream_read_uint32(s, settings->kbd_subtype); /* keyboardSubType */
451         stream_read_uint32(s, settings->kbd_fn_keys); /* keyboardFunctionKey */
452
453         stream_seek(s, 64); /* imeFileName */
454
455         blockLength -= 128;
456
457         /**
458          * The following fields are all optional. If one field is present, all of the preceding
459          * fields MUST also be present. If one field is not present, all of the subsequent fields
460          * MUST NOT be present.
461          * We must check the bytes left before reading each field.
462          */
463
464         do
465         {
466                 if (blockLength < 2)
467                         break;
468                 stream_read_uint16(s, postBeta2ColorDepth); /* postBeta2ColorDepth */
469                 blockLength -= 2;
470
471                 if (blockLength < 2)
472                         break;
473                 stream_seek_uint16(s); /* clientProductID */
474                 blockLength -= 2;
475
476                 if (blockLength < 4)
477                         break;
478                 stream_seek_uint32(s); /* serialNumber */
479                 blockLength -= 4;
480
481                 if (blockLength < 2)
482                         break;
483                 stream_read_uint16(s, highColorDepth); /* highColorDepth */
484                 blockLength -= 2;
485
486                 if (blockLength < 2)
487                         break;
488                 stream_read_uint16(s, supportedColorDepths); /* supportedColorDepths */
489                 blockLength -= 2;
490
491                 if (blockLength < 2)
492                         break;
493                 stream_read_uint16(s, earlyCapabilityFlags); /* earlyCapabilityFlags */
494                 blockLength -= 2;
495
496                 if (blockLength < 64)
497                         break;
498                 str = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), 64);
499                 stream_seek(s, 64);
500                 snprintf(settings->client_product_id, sizeof(settings->client_product_id), "%s", str);
501                 xfree(str);
502                 blockLength -= 64;
503
504                 if (blockLength < 1)
505                         break;
506                 stream_read_uint8(s, settings->performance_flags); /* connectionType */
507                 blockLength -= 1;
508
509                 if (blockLength < 1)
510                         break;
511                 stream_seek_uint8(s); /* pad1octet */
512                 blockLength -= 1;
513
514                 if (blockLength < 4)
515                         break;
516                 stream_read_uint32(s, serverSelectedProtocol); /* serverSelectedProtocol */
517                 blockLength -= 4;
518
519                 if (settings->selected_protocol != serverSelectedProtocol)
520                         return False;
521         } while (0);
522
523         if (highColorDepth > 0)
524                 settings->color_depth = highColorDepth;
525         else if (postBeta2ColorDepth > 0)
526         {
527                 switch (postBeta2ColorDepth)
528                 {
529                         case RNS_UD_COLOR_4BPP:
530                                 settings->color_depth = 4;
531                                 break;
532                         case RNS_UD_COLOR_8BPP:
533                                 settings->color_depth = 8;
534                                 break;
535                         case RNS_UD_COLOR_16BPP_555:
536                                 settings->color_depth = 15;
537                                 break;
538                         case RNS_UD_COLOR_16BPP_565:
539                                 settings->color_depth = 16;
540                                 break;
541                         case RNS_UD_COLOR_24BPP:
542                                 settings->color_depth = 24;
543                                 break;
544                         default:
545                                 return False;
546                 }
547         }
548         else
549         {
550                 switch (colorDepth)
551                 {
552                         case RNS_UD_COLOR_4BPP:
553                                 settings->color_depth = 4;
554                                 break;
555                         case RNS_UD_COLOR_8BPP:
556                                 settings->color_depth = 8;
557                                 break;
558                         default:
559                                 return False;
560                 }
561         }
562
563         return True;
564 }
565
566 /**
567  * Write a client core data block (TS_UD_CS_CORE).\n
568  * @msdn{cc240510}
569  * @param s stream
570  * @param settings rdp settings
571  */
572
573 void gcc_write_client_core_data(STREAM* s, rdpSettings *settings)
574 {
575         uint32 version;
576         char* clientName;
577         size_t clientNameLength;
578         uint8 connectionType;
579         uint16 highColorDepth;
580         uint16 supportedColorDepths;
581         uint16 earlyCapabilityFlags;
582         char* clientDigProductId;
583         size_t clientDigProductIdLength;
584
585         gcc_write_user_data_header(s, CS_CORE, 216);
586
587         version = settings->rdp_version >= 5 ? RDP_VERSION_5_PLUS : RDP_VERSION_4;
588         clientName = freerdp_uniconv_out(settings->uniconv, settings->client_hostname, &clientNameLength);
589         clientDigProductId = freerdp_uniconv_out(settings->uniconv, settings->client_product_id, &clientDigProductIdLength);
590
591         stream_write_uint32(s, version); /* version */
592         stream_write_uint16(s, settings->width); /* desktopWidth */
593         stream_write_uint16(s, settings->height); /* desktopHeight */
594         stream_write_uint16(s, RNS_UD_COLOR_8BPP); /* colorDepth, ignored because of postBeta2ColorDepth */
595         stream_write_uint16(s, RNS_UD_SAS_DEL); /* SASSequence (Secure Access Sequence) */
596         stream_write_uint32(s, settings->kbd_layout); /* keyboardLayout */
597         stream_write_uint32(s, settings->client_build); /* clientBuild */
598
599         /* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */
600         if (clientNameLength > 30)
601         {
602                 clientNameLength = 30;
603                 clientName[clientNameLength] = 0;
604                 clientName[clientNameLength + 1] = 0;
605         }
606         stream_write(s, clientName, clientNameLength + 2);
607         stream_write_zero(s, 32 - clientNameLength - 2);
608         xfree(clientName);
609
610         stream_write_uint32(s, settings->kbd_type); /* keyboardType */
611         stream_write_uint32(s, settings->kbd_subtype); /* keyboardSubType */
612         stream_write_uint32(s, settings->kbd_fn_keys); /* keyboardFunctionKey */
613
614         stream_write_zero(s, 64); /* imeFileName */
615
616         stream_write_uint16(s, RNS_UD_COLOR_8BPP); /* postBeta2ColorDepth */
617         stream_write_uint16(s, 1); /* clientProductID */
618         stream_write_uint32(s, 0); /* serialNumber (should be initialized to 0) */
619
620         highColorDepth = MIN(settings->color_depth, 24);
621
622         supportedColorDepths =
623                         RNS_UD_24BPP_SUPPORT |
624                         RNS_UD_16BPP_SUPPORT |
625                         RNS_UD_15BPP_SUPPORT;
626
627         connectionType = 0;
628         earlyCapabilityFlags = RNS_UD_CS_SUPPORT_ERRINFO_PDU;
629
630         if (settings->performance_flags == PERF_FLAG_NONE)
631         {
632                 earlyCapabilityFlags |= RNS_UD_CS_VALID_CONNECTION_TYPE;
633                 connectionType = CONNECTION_TYPE_LAN;
634         }
635
636         if (settings->color_depth == 32)
637         {
638                 supportedColorDepths |= RNS_UD_32BPP_SUPPORT;
639                 earlyCapabilityFlags |= RNS_UD_CS_WANT_32BPP_SESSION;
640         }
641
642         stream_write_uint16(s, highColorDepth); /* highColorDepth */
643         stream_write_uint16(s, supportedColorDepths); /* supportedColorDepths */
644
645         stream_write_uint16(s, earlyCapabilityFlags); /* earlyCapabilityFlags */
646
647         /* clientDigProductId (64 bytes, null-terminated unicode, truncated to 30 characters) */
648         if (clientDigProductIdLength > 62)
649         {
650                 clientDigProductIdLength = 62;
651                 clientDigProductId[clientDigProductIdLength] = 0;
652                 clientDigProductId[clientDigProductIdLength + 1] = 0;
653         }
654         stream_write(s, clientDigProductId, clientDigProductIdLength + 2);
655         stream_write_zero(s, 64 - clientDigProductIdLength - 2);
656         xfree(clientDigProductId);
657
658         stream_write_uint8(s, connectionType); /* connectionType */
659         stream_write_uint8(s, 0); /* pad1octet */
660
661         stream_write_uint32(s, settings->selected_protocol); /* serverSelectedProtocol */
662 }
663
664 void gcc_read_server_core_data(STREAM* s, rdpSettings *settings)
665 {
666         uint32 version;
667         uint32 clientRequestedProtocols;
668
669         stream_read_uint32(s, version); /* version */
670         stream_read_uint32(s, clientRequestedProtocols); /* clientRequestedProtocols */
671
672         if (version == RDP_VERSION_4 && settings->rdp_version > 4)
673                 settings->rdp_version = 4;
674         else if (version == RDP_VERSION_5_PLUS && settings->rdp_version < 5)
675                 settings->rdp_version = 7;
676 }
677
678 void gcc_write_server_core_data(STREAM* s, rdpSettings *settings)
679 {
680         gcc_write_user_data_header(s, SC_CORE, 12);
681
682         stream_write_uint32(s, settings->rdp_version == 4 ? RDP_VERSION_4 : RDP_VERSION_5_PLUS);
683         stream_write_uint32(s, settings->requested_protocols); /* clientRequestedProtocols */
684 }
685
686 /**
687  * Read a client security data block (TS_UD_CS_SEC).\n
688  * @msdn{cc240511}
689  * @param s stream
690  * @param settings rdp settings
691  */
692
693 boolean gcc_read_client_security_data(STREAM* s, rdpSettings *settings, uint16 blockLength)
694 {
695         if (blockLength < 8)
696                 return False;
697
698         stream_read_uint32(s, settings->encryption_method); /* encryptionMethods */
699         if (settings->encryption_method == 0)
700                 stream_read_uint32(s, settings->encryption_method); /* extEncryptionMethods */
701
702         return True;
703 }
704
705 /**
706  * Write a client security data block (TS_UD_CS_SEC).\n
707  * @msdn{cc240511}
708  * @param s stream
709  * @param settings rdp settings
710  */
711
712 void gcc_write_client_security_data(STREAM* s, rdpSettings *settings)
713 {
714         gcc_write_user_data_header(s, CS_SECURITY, 12);
715
716         if (settings->encryption > 0)
717         {
718                 stream_write_uint32(s, settings->encryption_method); /* encryptionMethods */
719                 stream_write_uint32(s, 0); /* extEncryptionMethods */
720         }
721         else
722         {
723                 /* French locale, disable encryption */
724                 stream_write_uint32(s, 0); /* encryptionMethods */
725                 stream_write_uint32(s, settings->encryption_method); /* extEncryptionMethods */
726         }
727 }
728
729 void gcc_read_server_security_data(STREAM* s, rdpSettings *settings)
730 {
731         uint32 encryptionMethod;
732         uint32 encryptionLevel;
733         uint32 serverRandomLen;
734         uint32 serverCertLen;
735
736         stream_read_uint32(s, encryptionMethod); /* encryptionMethod */
737         stream_read_uint32(s, encryptionLevel); /* encryptionLevel */
738         stream_read_uint32(s, serverRandomLen); /* serverRandomLen */
739         stream_read_uint32(s, serverCertLen); /* serverCertLen */
740
741         if (encryptionMethod == 0 && encryptionLevel == 0)
742         {
743                 /* serverRandom and serverRandom must not be present */
744                 return;
745         }
746
747         if (serverRandomLen > 0)
748         {
749                 /* serverRandom */
750                 freerdp_blob_alloc(&settings->server_random, serverRandomLen);
751                 memcpy(settings->server_random.data, s->p, serverRandomLen);
752                 stream_seek(s, serverRandomLen);
753         }
754
755         if (serverCertLen > 0)
756         {
757                 /* serverCertificate */
758                 freerdp_blob_alloc(&settings->server_certificate, serverCertLen);
759                 memcpy(settings->server_certificate.data, s->p, serverCertLen);
760                 stream_seek(s, serverCertLen);
761         }
762 }
763
764 void gcc_write_server_security_data(STREAM* s, rdpSettings *settings)
765 {
766         gcc_write_user_data_header(s, SC_SECURITY, 12);
767
768         stream_write_uint32(s, ENCRYPTION_METHOD_NONE); /* encryptionMethod */
769         stream_write_uint32(s, ENCRYPTION_LEVEL_NONE); /* encryptionLevel */
770 #if 0
771         stream_write_uint32(s, 0); /* serverRandomLen */
772         stream_write_uint32(s, 0); /* serverCertLen */
773 #endif
774 }
775
776 /**
777  * Read a client network data block (TS_UD_CS_NET).\n
778  * @msdn{cc240512}
779  * @param s stream
780  * @param settings rdp settings
781  */
782
783 boolean gcc_read_client_network_data(STREAM* s, rdpSettings *settings, uint16 blockLength)
784 {
785         int i;
786
787         if (blockLength < 4)
788                 return False;
789
790         stream_read_uint32(s, settings->num_channels); /* channelCount */
791         if (blockLength < 4 + settings->num_channels * 12)
792                 return False;
793         if (settings->num_channels > 16)
794                 return False;
795
796         /* channelDefArray */
797         for (i = 0; i < settings->num_channels; i++)
798         {
799                 /* CHANNEL_DEF */
800                 stream_read(s, settings->channels[i].name, 8); /* name (8 bytes) */
801                 stream_read_uint32(s, settings->channels[i].options); /* options (4 bytes) */
802                 settings->channels[i].chan_id = MCS_GLOBAL_CHANNEL_ID + 1 + i;
803         }
804
805         return True;
806 }
807
808 /**
809  * Write a client network data block (TS_UD_CS_NET).\n
810  * @msdn{cc240512}
811  * @param s stream
812  * @param settings rdp settings
813  */
814
815 void gcc_write_client_network_data(STREAM* s, rdpSettings *settings)
816 {
817         int i;
818         uint16 length;
819
820         if (settings->num_channels > 0)
821         {
822                 length = settings->num_channels * 12 + 8;
823                 gcc_write_user_data_header(s, CS_NET, length);
824
825                 stream_write_uint32(s, settings->num_channels); /* channelCount */
826
827                 /* channelDefArray */
828                 for (i = 0; i < settings->num_channels; i++)
829                 {
830                         /* CHANNEL_DEF */
831                         stream_write(s, settings->channels[i].name, 8); /* name (8 bytes) */
832                         stream_write_uint32(s, settings->channels[i].options); /* options (4 bytes) */
833                 }
834         }
835 }
836
837 void gcc_read_server_network_data(STREAM* s, rdpSettings *settings)
838 {
839         int i;
840         uint16 MCSChannelId;
841         uint16 channelCount;
842         uint16 channelId;
843
844         stream_read_uint16(s, MCSChannelId); /* MCSChannelId */
845         stream_read_uint16(s, channelCount); /* channelCount */
846
847         if (channelCount != settings->num_channels)
848         {
849                 printf("requested %d channels, got %d instead\n",
850                                 settings->num_channels, channelCount);
851         }
852
853         for (i = 0; i < channelCount; i++)
854         {
855                 stream_read_uint16(s, channelId); /* channelId */
856                 settings->channels[i].chan_id = channelId;
857         }
858
859         if (channelCount % 2 == 1)
860                 stream_seek(s, 2); /* padding */
861 }
862
863 void gcc_write_server_network_data(STREAM* s, rdpSettings *settings)
864 {
865         int i;
866
867         gcc_write_user_data_header(s, SC_NET, 8 + settings->num_channels * 2 + (settings->num_channels % 2 == 1 ? 2 : 0));
868
869         stream_write_uint16(s, MCS_GLOBAL_CHANNEL_ID); /* MCSChannelId */
870         stream_write_uint16(s, settings->num_channels); /* channelCount */
871
872         for (i = 0; i < settings->num_channels; i++)
873         {
874                 stream_write_uint16(s, settings->channels[i].chan_id);
875         }
876
877         if (settings->num_channels % 2 == 1)
878                 stream_write_uint16(s, 0);
879 }
880
881 /**
882  * Read a client cluster data block (TS_UD_CS_CLUSTER).\n
883  * @msdn{cc240514}
884  * @param s stream
885  * @param settings rdp settings
886  */
887
888 boolean gcc_read_client_cluster_data(STREAM* s, rdpSettings *settings, uint16 blockLength)
889 {
890         uint32 flags;
891
892         if (blockLength < 8)
893                 return False;
894
895         stream_read_uint32(s, flags); /* flags */
896
897         if ((flags | REDIRECTED_SESSIONID_FIELD_VALID))
898                 stream_read_uint32(s, settings->redirected_session_id); /* redirectedSessionID */
899
900         return True;
901 }
902
903 /**
904  * Write a client cluster data block (TS_UD_CS_CLUSTER).\n
905  * @msdn{cc240514}
906  * @param s stream
907  * @param settings rdp settings
908  */
909
910 void gcc_write_client_cluster_data(STREAM* s, rdpSettings *settings)
911 {
912         uint32 flags;
913
914         gcc_write_user_data_header(s, CS_CLUSTER, 12);
915
916         flags = REDIRECTION_SUPPORTED | (REDIRECTION_VERSION4 << 2);
917
918         if (settings->console_session || settings->redirected_session_id)
919                 flags |= REDIRECTED_SESSIONID_FIELD_VALID;
920
921         stream_write_uint32(s, flags); /* flags */
922         stream_write_uint32(s, settings->redirected_session_id); /* redirectedSessionID */
923 }
924
925 /**
926  * Read a client monitor data block (TS_UD_CS_MONITOR).\n
927  * @msdn{dd305336}
928  * @param s stream
929  * @param settings rdp settings
930  */
931
932 boolean gcc_read_client_monitor_data(STREAM* s, rdpSettings *settings, uint16 blockLength)
933 {
934         printf("CS_MONITOR\n");
935         return True;
936 }
937
938 /**
939  * Write a client monitor data block (TS_UD_CS_MONITOR).\n
940  * @msdn{dd305336}
941  * @param s stream
942  * @param settings rdp settings
943  */
944
945 void gcc_write_client_monitor_data(STREAM* s, rdpSettings *settings)
946 {
947         int i;
948         uint16 length;
949         uint32 left, top, right, bottom, flags;
950
951         if (settings->num_monitors > 1)
952         {
953                 length = (20 * settings->num_monitors) + 12;
954                 gcc_write_user_data_header(s, CS_MONITOR, length);
955
956                 stream_write_uint32(s, 0); /* flags */
957                 stream_write_uint32(s, settings->num_monitors); /* monitorCount */
958
959                 for (i = 0; i < settings->num_monitors; i++)
960                 {
961                         left = settings->monitors[i].x;
962                         top = settings->monitors[i].y;
963                         right = settings->monitors[i].x + settings->monitors[i].width - 1;
964                         bottom = settings->monitors[i].y + settings->monitors[i].height - 1;
965                         flags = settings->monitors[i].is_primary ? MONITOR_PRIMARY : 0;
966
967                         stream_write_uint32(s, left); /* left */
968                         stream_write_uint32(s, top); /* top */
969                         stream_write_uint32(s, right); /* right */
970                         stream_write_uint32(s, bottom); /* bottom */
971                         stream_write_uint32(s, flags); /* flags */
972                 }
973         }
974 }
975