libfreerdp-core: parsing of server data blocks
[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  * Write a GCC Conference Create Request.\n
128  * @msdn{cc240836}
129  * @param s stream
130  * @param user_data client data blocks
131  */
132
133 void gcc_write_conference_create_request(STREAM* s, STREAM* user_data)
134 {
135         /* ConnectData */
136         per_write_choice(s, 0); /* From Key select object (0) of type OBJECT_IDENTIFIER */
137         per_write_object_identifier(s, t124_02_98_oid); /* ITU-T T.124 (02/98) OBJECT_IDENTIFIER */
138
139         /* ConnectData::connectPDU (OCTET_STRING) */
140         per_write_length(s, stream_get_length(user_data) + 14); /* connectPDU length */
141
142         /* ConnectGCCPDU */
143         per_write_choice(s, 0); /* From ConnectGCCPDU select conferenceCreateRequest (0) of type ConferenceCreateRequest */
144         per_write_selection(s, 0x08); /* select optional userData from ConferenceCreateRequest */
145
146         /* ConferenceCreateRequest::conferenceName */
147         per_write_numeric_string(s, "1", 1, 1); /* ConferenceName::numeric */
148         per_write_padding(s, 1); /* padding */
149
150         /* UserData (SET OF SEQUENCE) */
151         per_write_number_of_sets(s, 1); /* one set of UserData */
152         per_write_choice(s, 0xC0); /* UserData::value present + select h221NonStandard (1) */
153
154         /* h221NonStandard */
155         per_write_octet_string(s, h221_cs_key, 4, 4); /* h221NonStandard, client-to-server H.221 key, "Duca" */
156
157         /* userData::value (OCTET_STRING) */
158         per_write_octet_string(s, user_data->data, stream_get_length(user_data), 0); /* array of client data blocks */
159 }
160
161 void gcc_read_conference_create_response(STREAM* s, rdpSettings* settings)
162 {
163         int length;
164         uint32 tag;
165         uint16 nodeID;
166         uint8 result;
167         uint8 choice;
168         uint8 selection;
169         uint8 number;
170
171         /* ConnectData */
172         per_read_choice(s, &choice);
173         per_read_object_identifier(s, t124_02_98_oid);
174
175         /* ConnectData::connectPDU (OCTET_STRING) */
176         per_read_length(s, &length);
177
178         /* ConnectGCCPDU */
179         per_read_choice(s, &choice);
180
181         /* ConferenceCreateResponse::nodeID (UserID) */
182         per_read_integer16(s, &nodeID, 1001);
183
184         /* ConferenceCreateResponse::tag (INTEGER) */
185         per_read_integer(s, &tag);
186
187         /* ConferenceCreateResponse::result (ENUMERATED) */
188         per_read_enumerated(s, &result);
189
190         /* number of UserData sets */
191         per_read_number_of_sets(s, &number);
192
193         /* UserData::value present + select h221NonStandard (1) */
194         per_read_choice(s, &choice);
195
196         /* h221NonStandard */
197         per_read_octet_string(s, h221_sc_key, 4, 4); /* h221NonStandard, server-to-client H.221 key, "McDn" */
198
199         /* userData (OCTET_STRING) */
200         per_read_length(s, &length);
201
202         printf("server core data, length:%d\n", length);
203         gcc_read_server_data_blocks(s, settings, length);
204 }
205
206 void gcc_read_server_data_blocks(STREAM* s, rdpSettings *settings, int length)
207 {
208         uint16 type;
209         uint16 offset = 0;
210         uint16 blockLength;
211
212         while (offset < length)
213         {
214                 gcc_read_user_data_header(s, &type, &blockLength);
215
216                 switch (type)
217                 {
218                         case SC_CORE:
219                                 gcc_read_server_core_data(s, settings);
220                                 break;
221
222                         case SC_SECURITY:
223                                 gcc_read_server_security_data(s, settings);
224                                 break;
225
226                         case SC_NET:
227                                 gcc_read_server_network_data(s, settings);
228                                 break;
229
230                         default:
231                                 break;
232                 }
233
234                 offset += blockLength;
235         }
236 }
237
238 void gcc_read_user_data_header(STREAM* s, uint16* type, uint16* length)
239 {
240         stream_read_uint16(s, *type); /* type */
241         stream_read_uint16(s, *length); /* length */
242 }
243
244 /**
245  * Write a user data header (TS_UD_HEADER).\n
246  * @msdn{cc240509}
247  * @param s stream
248  * @param type data block type
249  * @param length data block length
250  */
251
252 void gcc_write_user_data_header(STREAM* s, uint16 type, uint16 length)
253 {
254         stream_write_uint16(s, type); /* type */
255         stream_write_uint16(s, length); /* length */
256 }
257
258 /**
259  * Write a client core data block (TS_UD_CS_CORE).\n
260  * @msdn{cc240510}
261  * @param s stream
262  * @param settings rdp settings
263  */
264
265 void gcc_write_client_core_data(STREAM* s, rdpSettings *settings)
266 {
267         uint32 version;
268         uint8* clientName;
269         size_t clientNameLength;
270         uint8 connectionType;
271         uint16 highColorDepth;
272         uint16 supportedColorDepths;
273         uint16 earlyCapabilityFlags;
274         uint8* clientDigProductId;
275         size_t clientDigProductIdLength;
276
277         gcc_write_user_data_header(s, CS_CORE, 216);
278
279         version = settings->rdp_version >= 5 ? RDP_VERSION_5_PLUS : RDP_VERSION_4;
280         clientName = freerdp_uniconv_out(settings->uniconv, settings->client_hostname, &clientNameLength);
281         clientDigProductId = freerdp_uniconv_out(settings->uniconv, settings->client_product_id, &clientDigProductIdLength);
282
283         stream_write_uint32(s, version); /* version */
284         stream_write_uint16(s, settings->width); /* desktopWidth */
285         stream_write_uint16(s, settings->height); /* desktopHeight */
286         stream_write_uint16(s, RNS_UD_COLOR_8BPP); /* colorDepth, ignored because of postBeta2ColorDepth */
287         stream_write_uint16(s, RNS_UD_SAS_DEL); /* SASSequence (Secure Access Sequence) */
288         stream_write_uint32(s, settings->kbd_layout); /* keyboardLayout */
289         stream_write_uint32(s, settings->client_build); /* clientBuild */
290
291         /* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */
292         if (clientNameLength > 30)
293         {
294                 clientNameLength = 30;
295                 clientName[clientNameLength] = 0;
296                 clientName[clientNameLength + 1] = 0;
297         }
298         stream_write(s, clientName, clientNameLength + 2);
299         stream_write_zero(s, 32 - clientNameLength - 2);
300         xfree(clientName);
301
302         stream_write_uint32(s, settings->kbd_type); /* keyboardType */
303         stream_write_uint32(s, settings->kbd_subtype); /* keyboardSubType */
304         stream_write_uint32(s, settings->kbd_fn_keys); /* keyboardFunctionKey */
305
306         stream_write_zero(s, 64); /* imeFileName */
307
308         stream_write_uint16(s, RNS_UD_COLOR_8BPP); /* postBeta2ColorDepth */
309         stream_write_uint16(s, 1); /* clientProductID */
310         stream_write_uint32(s, 0); /* serialNumber (should be initialized to 0) */
311
312         highColorDepth = MIN(settings->color_depth, 24);
313
314         supportedColorDepths =
315                         RNS_UD_32BPP_SUPPORT |
316                         RNS_UD_24BPP_SUPPORT |
317                         RNS_UD_16BPP_SUPPORT |
318                         RNS_UD_15BPP_SUPPORT;
319
320         connectionType = 0;
321         earlyCapabilityFlags = RNS_UD_CS_SUPPORT_ERRINFO_PDU;
322
323         if (settings->performance_flags == PERF_FLAG_NONE)
324         {
325                 earlyCapabilityFlags |= RNS_UD_CS_VALID_CONNECTION_TYPE;
326                 connectionType = CONNECTION_TYPE_LAN;
327         }
328
329         if (settings->color_depth == 32)
330         {
331                 supportedColorDepths |= RNS_UD_32BPP_SUPPORT;
332                 earlyCapabilityFlags |= RNS_UD_CS_WANT_32BPP_SESSION;
333         }
334
335         stream_write_uint16(s, highColorDepth); /* highColorDepth */
336         stream_write_uint16(s, supportedColorDepths); /* supportedColorDepths */
337
338         stream_write_uint16(s, earlyCapabilityFlags); /* earlyCapabilityFlags */
339
340         /* clientDigProductId (64 bytes, null-terminated unicode, truncated to 30 characters) */
341         if (clientDigProductIdLength > 62)
342         {
343                 clientDigProductIdLength = 62;
344                 clientDigProductId[clientDigProductIdLength] = 0;
345                 clientDigProductId[clientDigProductIdLength + 1] = 0;
346         }
347         stream_write(s, clientDigProductId, clientDigProductIdLength + 2);
348         stream_write_zero(s, 64 - clientDigProductIdLength - 2);
349         xfree(clientDigProductId);
350
351         stream_write_uint8(s, connectionType); /* connectionType */
352         stream_write_uint8(s, 0); /* pad1octet */
353
354         stream_write_uint32(s, settings->selected_protocol); /* serverSelectedProtocol */
355 }
356
357 void gcc_read_server_core_data(STREAM* s, rdpSettings *settings)
358 {
359         uint32 version;
360         uint32 clientRequestedProtocols;
361
362         stream_read_uint32(s, version); /* version */
363         stream_read_uint32(s, clientRequestedProtocols); /* clientRequestedProtocols */
364
365         if (version == RDP_VERSION_4 && settings->rdp_version > 4)
366                 settings->rdp_version = 4;
367         else if (version == RDP_VERSION_5_PLUS && settings->rdp_version < 5)
368                 settings->rdp_version = 7;
369 }
370
371 /**
372  * Write a client security data block (TS_UD_CS_SEC).\n
373  * @msdn{cc240511}
374  * @param s stream
375  * @param settings rdp settings
376  */
377
378 void gcc_write_client_security_data(STREAM* s, rdpSettings *settings)
379 {
380         gcc_write_user_data_header(s, CS_SECURITY, 12);
381
382         if (settings->encryption > 0)
383         {
384                 stream_write_uint32(s, settings->encryption_methods); /* encryptionMethods */
385                 stream_write_uint32(s, 0); /* extEncryptionMethods */
386         }
387         else
388         {
389                 /* French locale, disable encryption */
390                 stream_write_uint32(s, 0); /* encryptionMethods */
391                 stream_write_uint32(s, settings->encryption_methods); /* extEncryptionMethods */
392         }
393 }
394
395 void gcc_read_server_security_data(STREAM* s, rdpSettings *settings)
396 {
397         uint32 encryptionMethod;
398         uint32 encryptionLevel;
399         uint32 serverRandomLen;
400         uint32 serverCertLen;
401
402         stream_read_uint32(s, encryptionMethod); /* encryptionMethod */
403         stream_read_uint32(s, encryptionLevel); /* encryptionLevel */
404         stream_read_uint32(s, serverRandomLen); /* serverRandomLen */
405         stream_read_uint32(s, serverCertLen); /* serverCertLen */
406
407         if (encryptionMethod == 0 && encryptionLevel == 0)
408         {
409                 /* serverRandom and serverRandom must not be present */
410                 return;
411         }
412
413         if (serverRandomLen > 0)
414         {
415                 /* serverRandom */
416                 freerdp_blob_alloc(&settings->server_random, serverRandomLen);
417                 memcpy(settings->server_random.data, s->p, serverRandomLen);
418                 stream_seek(s, serverRandomLen);
419         }
420
421         if (serverCertLen > 0)
422         {
423                 /* serverCertificate */
424                 freerdp_blob_alloc(&settings->server_certificate, serverCertLen);
425                 memcpy(settings->server_certificate.data, s->p, serverCertLen);
426                 stream_seek(s, serverCertLen);
427         }
428 }
429
430 /**
431  * Write a client network data block (TS_UD_CS_NET).\n
432  * @msdn{cc240512}
433  * @param s stream
434  * @param settings rdp settings
435  */
436
437 void gcc_write_client_network_data(STREAM* s, rdpSettings *settings)
438 {
439         int i;
440         uint16 length;
441
442         if (settings->num_channels > 0)
443         {
444                 length = settings->num_channels * 12 + 8;
445                 gcc_write_user_data_header(s, CS_NET, length);
446
447                 stream_write_uint32(s, settings->num_channels); /* channelCount */
448
449                 /* channelDefArray */
450                 for (i = 0; i < settings->num_channels; i++)
451                 {
452                         /* CHANNEL_DEF */
453                         stream_write(s, settings->channels[i].name, 8); /* name (8 bytes) */
454                         stream_write_uint32(s, settings->channels[i].options); /* options (4 bytes) */
455                 }
456         }
457 }
458
459 void gcc_read_server_network_data(STREAM* s, rdpSettings *settings)
460 {
461         int i;
462         uint16 MCSChannelId;
463         uint16 channelCount;
464         uint16 channelId;
465
466         stream_read_uint16(s, MCSChannelId); /* MCSChannelId */
467         stream_read_uint16(s, channelCount); /* channelCount */
468
469         if (channelCount != settings->num_channels)
470         {
471                 printf("requested %d channels, got %d instead\n",
472                                 settings->num_channels, channelCount);
473         }
474
475         for (i = 0; i < channelCount; i++)
476         {
477                 stream_read_uint16(s, channelId); /* channelId */
478
479                 if (channelId != settings->channels[i].chan_id)
480                 {
481                         printf("channel %d is %d, but %d was expected\n",
482                                         i, channelId, settings->channels[i].chan_id);
483                 }
484         }
485
486         if (channelCount % 2 == 1)
487                 stream_seek(s, 2); /* padding */
488 }
489
490 /**
491  * Write a client cluster data block (TS_UD_CS_CLUSTER).\n
492  * @msdn{cc240514}
493  * @param s stream
494  * @param settings rdp settings
495  */
496
497 void gcc_write_client_cluster_data(STREAM* s, rdpSettings *settings)
498 {
499         uint32 flags;
500
501         gcc_write_user_data_header(s, CS_CLUSTER, 12);
502
503         flags = REDIRECTION_SUPPORTED | (REDIRECTION_VERSION4 << 2);
504
505         if (settings->console_session || settings->redirected_session_id)
506                 flags |= REDIRECTED_SESSIONID_FIELD_VALID;
507
508         stream_write_uint32(s, flags); /* flags */
509         stream_write_uint32(s, settings->redirected_session_id); /* redirectedSessionID */
510 }
511
512 /**
513  * Write a client monitor data block (TS_UD_CS_MONITOR).\n
514  * @msdn{dd305336}
515  * @param s stream
516  * @param settings rdp settings
517  */
518
519 void gcc_write_client_monitor_data(STREAM* s, rdpSettings *settings)
520 {
521         int i;
522         uint16 length;
523         uint32 left, top, right, bottom, flags;
524
525         if (settings->num_monitors > 1)
526         {
527                 length = (20 * settings->num_monitors) + 12;
528                 gcc_write_user_data_header(s, CS_MONITOR, length);
529
530                 stream_write_uint32(s, 0); /* flags */
531                 stream_write_uint32(s, settings->num_monitors); /* monitorCount */
532
533                 for (i = 0; i < settings->num_monitors; i++)
534                 {
535                         left = settings->monitors[i].x;
536                         top = settings->monitors[i].y;
537                         right = settings->monitors[i].x + settings->monitors[i].width - 1;
538                         bottom = settings->monitors[i].y + settings->monitors[i].height - 1;
539                         flags = settings->monitors[i].is_primary ? MONITOR_PRIMARY : 0;
540
541                         stream_write_uint32(s, left); /* left */
542                         stream_write_uint32(s, top); /* top */
543                         stream_write_uint32(s, right); /* right */
544                         stream_write_uint32(s, bottom); /* bottom */
545                         stream_write_uint32(s, flags); /* flags */
546                 }
547         }
548 }