Merge pull request #32 from llyzs/svc
[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, (uint8*)"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         uint16 length;
164         uint32 tag;
165         uint16 nodeID;
166         uint8 result;
167         uint8 choice;
168         uint8 number;
169
170         /* ConnectData */
171         per_read_choice(s, &choice);
172         per_read_object_identifier(s, t124_02_98_oid);
173
174         /* ConnectData::connectPDU (OCTET_STRING) */
175         per_read_length(s, &length);
176
177         /* ConnectGCCPDU */
178         per_read_choice(s, &choice);
179
180         /* ConferenceCreateResponse::nodeID (UserID) */
181         per_read_integer16(s, &nodeID, 1001);
182
183         /* ConferenceCreateResponse::tag (INTEGER) */
184         per_read_integer(s, &tag);
185
186         /* ConferenceCreateResponse::result (ENUMERATED) */
187         per_read_enumerated(s, &result, MCS_Result_enum_length);
188
189         /* number of UserData sets */
190         per_read_number_of_sets(s, &number);
191
192         /* UserData::value present + select h221NonStandard (1) */
193         per_read_choice(s, &choice);
194
195         /* h221NonStandard */
196         per_read_octet_string(s, h221_sc_key, 4, 4); /* h221NonStandard, server-to-client H.221 key, "McDn" */
197
198         /* userData (OCTET_STRING) */
199         per_read_length(s, &length);
200         gcc_read_server_data_blocks(s, settings, length);
201 }
202
203 void gcc_write_client_data_blocks(STREAM* s, rdpSettings *settings)
204 {
205         gcc_write_client_core_data(s, settings);
206         gcc_write_client_cluster_data(s, settings);
207         gcc_write_client_security_data(s, settings);
208         gcc_write_client_network_data(s, settings);
209         gcc_write_client_monitor_data(s, settings);
210 }
211
212 void gcc_read_server_data_blocks(STREAM* s, rdpSettings *settings, int length)
213 {
214         uint16 type;
215         uint16 offset = 0;
216         uint16 blockLength;
217
218         while (offset < length)
219         {
220                 gcc_read_user_data_header(s, &type, &blockLength);
221
222                 switch (type)
223                 {
224                         case SC_CORE:
225                                 gcc_read_server_core_data(s, settings);
226                                 break;
227
228                         case SC_SECURITY:
229                                 gcc_read_server_security_data(s, settings);
230                                 break;
231
232                         case SC_NET:
233                                 gcc_read_server_network_data(s, settings);
234                                 break;
235
236                         default:
237                                 break;
238                 }
239
240                 offset += blockLength;
241         }
242 }
243
244 void gcc_read_user_data_header(STREAM* s, uint16* type, uint16* length)
245 {
246         stream_read_uint16(s, *type); /* type */
247         stream_read_uint16(s, *length); /* length */
248 }
249
250 /**
251  * Write a user data header (TS_UD_HEADER).\n
252  * @msdn{cc240509}
253  * @param s stream
254  * @param type data block type
255  * @param length data block length
256  */
257
258 void gcc_write_user_data_header(STREAM* s, uint16 type, uint16 length)
259 {
260         stream_write_uint16(s, type); /* type */
261         stream_write_uint16(s, length); /* length */
262 }
263
264 /**
265  * Write a client core data block (TS_UD_CS_CORE).\n
266  * @msdn{cc240510}
267  * @param s stream
268  * @param settings rdp settings
269  */
270
271 void gcc_write_client_core_data(STREAM* s, rdpSettings *settings)
272 {
273         uint32 version;
274         char* clientName;
275         size_t clientNameLength;
276         uint8 connectionType;
277         uint16 highColorDepth;
278         uint16 supportedColorDepths;
279         uint16 earlyCapabilityFlags;
280         char* clientDigProductId;
281         size_t clientDigProductIdLength;
282
283         gcc_write_user_data_header(s, CS_CORE, 216);
284
285         version = settings->rdp_version >= 5 ? RDP_VERSION_5_PLUS : RDP_VERSION_4;
286         clientName = freerdp_uniconv_out(settings->uniconv, settings->client_hostname, &clientNameLength);
287         clientDigProductId = freerdp_uniconv_out(settings->uniconv, settings->client_product_id, &clientDigProductIdLength);
288
289         stream_write_uint32(s, version); /* version */
290         stream_write_uint16(s, settings->width); /* desktopWidth */
291         stream_write_uint16(s, settings->height); /* desktopHeight */
292         stream_write_uint16(s, RNS_UD_COLOR_8BPP); /* colorDepth, ignored because of postBeta2ColorDepth */
293         stream_write_uint16(s, RNS_UD_SAS_DEL); /* SASSequence (Secure Access Sequence) */
294         stream_write_uint32(s, settings->kbd_layout); /* keyboardLayout */
295         stream_write_uint32(s, settings->client_build); /* clientBuild */
296
297         /* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */
298         if (clientNameLength > 30)
299         {
300                 clientNameLength = 30;
301                 clientName[clientNameLength] = 0;
302                 clientName[clientNameLength + 1] = 0;
303         }
304         stream_write(s, clientName, clientNameLength + 2);
305         stream_write_zero(s, 32 - clientNameLength - 2);
306         xfree(clientName);
307
308         stream_write_uint32(s, settings->kbd_type); /* keyboardType */
309         stream_write_uint32(s, settings->kbd_subtype); /* keyboardSubType */
310         stream_write_uint32(s, settings->kbd_fn_keys); /* keyboardFunctionKey */
311
312         stream_write_zero(s, 64); /* imeFileName */
313
314         stream_write_uint16(s, RNS_UD_COLOR_8BPP); /* postBeta2ColorDepth */
315         stream_write_uint16(s, 1); /* clientProductID */
316         stream_write_uint32(s, 0); /* serialNumber (should be initialized to 0) */
317
318         highColorDepth = MIN(settings->color_depth, 24);
319
320         supportedColorDepths =
321                         RNS_UD_24BPP_SUPPORT |
322                         RNS_UD_16BPP_SUPPORT |
323                         RNS_UD_15BPP_SUPPORT;
324
325         connectionType = 0;
326         earlyCapabilityFlags = RNS_UD_CS_SUPPORT_ERRINFO_PDU;
327
328         if (settings->performance_flags == PERF_FLAG_NONE)
329         {
330                 earlyCapabilityFlags |= RNS_UD_CS_VALID_CONNECTION_TYPE;
331                 connectionType = CONNECTION_TYPE_LAN;
332         }
333
334         if (settings->color_depth == 32)
335         {
336                 supportedColorDepths |= RNS_UD_32BPP_SUPPORT;
337                 earlyCapabilityFlags |= RNS_UD_CS_WANT_32BPP_SESSION;
338         }
339
340         stream_write_uint16(s, highColorDepth); /* highColorDepth */
341         stream_write_uint16(s, supportedColorDepths); /* supportedColorDepths */
342
343         stream_write_uint16(s, earlyCapabilityFlags); /* earlyCapabilityFlags */
344
345         /* clientDigProductId (64 bytes, null-terminated unicode, truncated to 30 characters) */
346         if (clientDigProductIdLength > 62)
347         {
348                 clientDigProductIdLength = 62;
349                 clientDigProductId[clientDigProductIdLength] = 0;
350                 clientDigProductId[clientDigProductIdLength + 1] = 0;
351         }
352         stream_write(s, clientDigProductId, clientDigProductIdLength + 2);
353         stream_write_zero(s, 64 - clientDigProductIdLength - 2);
354         xfree(clientDigProductId);
355
356         stream_write_uint8(s, connectionType); /* connectionType */
357         stream_write_uint8(s, 0); /* pad1octet */
358
359         stream_write_uint32(s, settings->selected_protocol); /* serverSelectedProtocol */
360 }
361
362 void gcc_read_server_core_data(STREAM* s, rdpSettings *settings)
363 {
364         uint32 version;
365         uint32 clientRequestedProtocols;
366
367         stream_read_uint32(s, version); /* version */
368         stream_read_uint32(s, clientRequestedProtocols); /* clientRequestedProtocols */
369
370         if (version == RDP_VERSION_4 && settings->rdp_version > 4)
371                 settings->rdp_version = 4;
372         else if (version == RDP_VERSION_5_PLUS && settings->rdp_version < 5)
373                 settings->rdp_version = 7;
374 }
375
376 /**
377  * Write a client security data block (TS_UD_CS_SEC).\n
378  * @msdn{cc240511}
379  * @param s stream
380  * @param settings rdp settings
381  */
382
383 void gcc_write_client_security_data(STREAM* s, rdpSettings *settings)
384 {
385         gcc_write_user_data_header(s, CS_SECURITY, 12);
386
387         if (settings->encryption > 0)
388         {
389                 stream_write_uint32(s, settings->encryption_method); /* encryptionMethods */
390                 stream_write_uint32(s, 0); /* extEncryptionMethods */
391         }
392         else
393         {
394                 /* French locale, disable encryption */
395                 stream_write_uint32(s, 0); /* encryptionMethods */
396                 stream_write_uint32(s, settings->encryption_method); /* extEncryptionMethods */
397         }
398 }
399
400 void gcc_read_server_security_data(STREAM* s, rdpSettings *settings)
401 {
402         uint32 encryptionMethod;
403         uint32 encryptionLevel;
404         uint32 serverRandomLen;
405         uint32 serverCertLen;
406
407         stream_read_uint32(s, encryptionMethod); /* encryptionMethod */
408         stream_read_uint32(s, encryptionLevel); /* encryptionLevel */
409         stream_read_uint32(s, serverRandomLen); /* serverRandomLen */
410         stream_read_uint32(s, serverCertLen); /* serverCertLen */
411
412         if (encryptionMethod == 0 && encryptionLevel == 0)
413         {
414                 /* serverRandom and serverRandom must not be present */
415                 return;
416         }
417
418         if (serverRandomLen > 0)
419         {
420                 /* serverRandom */
421                 freerdp_blob_alloc(&settings->server_random, serverRandomLen);
422                 memcpy(settings->server_random.data, s->p, serverRandomLen);
423                 stream_seek(s, serverRandomLen);
424         }
425
426         if (serverCertLen > 0)
427         {
428                 /* serverCertificate */
429                 freerdp_blob_alloc(&settings->server_certificate, serverCertLen);
430                 memcpy(settings->server_certificate.data, s->p, serverCertLen);
431                 stream_seek(s, serverCertLen);
432         }
433 }
434
435 /**
436  * Write a client network data block (TS_UD_CS_NET).\n
437  * @msdn{cc240512}
438  * @param s stream
439  * @param settings rdp settings
440  */
441
442 void gcc_write_client_network_data(STREAM* s, rdpSettings *settings)
443 {
444         int i;
445         uint16 length;
446
447         if (settings->num_channels > 0)
448         {
449                 length = settings->num_channels * 12 + 8;
450                 gcc_write_user_data_header(s, CS_NET, length);
451
452                 stream_write_uint32(s, settings->num_channels); /* channelCount */
453
454                 /* channelDefArray */
455                 for (i = 0; i < settings->num_channels; i++)
456                 {
457                         /* CHANNEL_DEF */
458                         stream_write(s, settings->channels[i].name, 8); /* name (8 bytes) */
459                         stream_write_uint32(s, settings->channels[i].options); /* options (4 bytes) */
460                 }
461         }
462 }
463
464 void gcc_read_server_network_data(STREAM* s, rdpSettings *settings)
465 {
466         int i;
467         uint16 MCSChannelId;
468         uint16 channelCount;
469         uint16 channelId;
470
471         stream_read_uint16(s, MCSChannelId); /* MCSChannelId */
472         stream_read_uint16(s, channelCount); /* channelCount */
473
474         if (channelCount != settings->num_channels)
475         {
476                 printf("requested %d channels, got %d instead\n",
477                                 settings->num_channels, channelCount);
478         }
479
480         for (i = 0; i < channelCount; i++)
481         {
482                 stream_read_uint16(s, channelId); /* channelId */
483                 settings->channels[i].chan_id = channelId;
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 }