2 * FreeRDP: A Remote Desktop Protocol Client
3 * T.124 Generic Conference Control (GCC)
5 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 * T.124 GCC is defined in:
25 * http://www.itu.int/rec/T-REC-T.124-199802-S/en
26 * ITU-T T.124 (02/98): Generic Conference Control
30 * ConnectData ::= SEQUENCE
33 * connectPDU OCTET_STRING
38 * object OBJECT_IDENTIFIER,
39 * h221NonStandard H221NonStandardIdentifier
42 * ConnectGCCPDU ::= CHOICE
44 * conferenceCreateRequest ConferenceCreateRequest,
45 * conferenceCreateResponse ConferenceCreateResponse,
46 * conferenceQueryRequest ConferenceQueryRequest,
47 * conferenceQueryResponse ConferenceQueryResponse,
48 * conferenceJoinRequest ConferenceJoinRequest,
49 * conferenceJoinResponse ConferenceJoinResponse,
50 * conferenceInviteRequest ConferenceInviteRequest,
51 * conferenceInviteResponse ConferenceInviteResponse,
55 * ConferenceCreateRequest ::= SEQUENCE
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,
71 * conferencePriority ConferencePriority OPTIONAL,
72 * conferenceMode ConferenceMode OPTIONAL
75 * ConferenceCreateResponse ::= SEQUENCE
83 * resourcesNotAvailable (2),
84 * rejectedForSymmetryBreaking (3),
85 * lockedConferenceNotSupported (4)
87 * userData UserData OPTIONAL,
91 * ConferenceName ::= SEQUENCE
93 * numeric SimpleNumericString
94 * text SimpleTextString OPTIONAL,
98 * SimpleNumericString ::= NumericString (SIZE (1..255)) (FROM ("0123456789"))
100 * UserData ::= SET OF SEQUENCE
103 * value OCTET_STRING OPTIONAL
106 * H221NonStandardIdentifier ::= OCTET STRING (SIZE (4..255))
108 * UserID ::= DynamicChannelID
110 * ChannelID ::= INTEGER (1..65535)
111 * StaticChannelID ::= INTEGER (1..1000)
112 * DynamicChannelID ::= INTEGER (1001..65535)
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"
121 uint8 t124_02_98_oid[6] = { 0, 0, 20, 124, 0, 1 };
123 uint8 h221_cs_key[4] = "Duca";
124 uint8 h221_sc_key[4] = "McDn";
127 * Write a GCC Conference Create Request.\n
130 * @param user_data client data blocks
133 void gcc_write_conference_create_request(STREAM* s, STREAM* user_data)
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 */
139 /* ConnectData::connectPDU (OCTET_STRING) */
140 per_write_length(s, stream_get_length(user_data) + 14); /* connectPDU length */
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 */
146 /* ConferenceCreateRequest::conferenceName */
147 per_write_numeric_string(s, "1", 1, 1); /* ConferenceName::numeric */
148 per_write_padding(s, 1); /* padding */
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) */
154 /* h221NonStandard */
155 per_write_octet_string(s, h221_cs_key, 4, 4); /* h221NonStandard, client-to-server H.221 key, "Duca" */
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 */
161 void gcc_read_conference_create_response(STREAM* s, rdpSettings* settings)
172 per_read_choice(s, &choice);
173 per_read_object_identifier(s, t124_02_98_oid);
175 /* ConnectData::connectPDU (OCTET_STRING) */
176 per_read_length(s, &length);
179 per_read_choice(s, &choice);
181 /* ConferenceCreateResponse::nodeID (UserID) */
182 per_read_integer16(s, &nodeID, 1001);
184 /* ConferenceCreateResponse::tag (INTEGER) */
185 per_read_integer(s, &tag);
187 /* ConferenceCreateResponse::result (ENUMERATED) */
188 per_read_enumerated(s, &result);
190 /* number of UserData sets */
191 per_read_number_of_sets(s, &number);
193 /* UserData::value present + select h221NonStandard (1) */
194 per_read_choice(s, &choice);
196 /* h221NonStandard */
197 per_read_octet_string(s, h221_sc_key, 4, 4); /* h221NonStandard, server-to-client H.221 key, "McDn" */
199 /* userData (OCTET_STRING) */
200 per_read_length(s, &length);
202 printf("server core data, length:%d\n", length);
203 gcc_read_server_data_blocks(s, settings, length);
206 void gcc_read_server_data_blocks(STREAM* s, rdpSettings *settings, int length)
212 while (offset < length)
214 gcc_read_user_data_header(s, &type, &blockLength);
219 gcc_read_server_core_data(s, settings);
223 gcc_read_server_security_data(s, settings);
227 gcc_read_server_network_data(s, settings);
234 offset += blockLength;
238 void gcc_read_user_data_header(STREAM* s, uint16* type, uint16* length)
240 stream_read_uint16(s, *type); /* type */
241 stream_read_uint16(s, *length); /* length */
245 * Write a user data header (TS_UD_HEADER).\n
248 * @param type data block type
249 * @param length data block length
252 void gcc_write_user_data_header(STREAM* s, uint16 type, uint16 length)
254 stream_write_uint16(s, type); /* type */
255 stream_write_uint16(s, length); /* length */
259 * Write a client core data block (TS_UD_CS_CORE).\n
262 * @param settings rdp settings
265 void gcc_write_client_core_data(STREAM* s, rdpSettings *settings)
269 size_t clientNameLength;
270 uint8 connectionType;
271 uint16 highColorDepth;
272 uint16 supportedColorDepths;
273 uint16 earlyCapabilityFlags;
274 uint8* clientDigProductId;
275 size_t clientDigProductIdLength;
277 gcc_write_user_data_header(s, CS_CORE, 216);
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);
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 */
291 /* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */
292 if (clientNameLength > 30)
294 clientNameLength = 30;
295 clientName[clientNameLength] = 0;
296 clientName[clientNameLength + 1] = 0;
298 stream_write(s, clientName, clientNameLength + 2);
299 stream_write_zero(s, 32 - clientNameLength - 2);
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 */
306 stream_write_zero(s, 64); /* imeFileName */
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) */
312 highColorDepth = MIN(settings->color_depth, 24);
314 supportedColorDepths =
315 RNS_UD_32BPP_SUPPORT |
316 RNS_UD_24BPP_SUPPORT |
317 RNS_UD_16BPP_SUPPORT |
318 RNS_UD_15BPP_SUPPORT;
321 earlyCapabilityFlags = RNS_UD_CS_SUPPORT_ERRINFO_PDU;
323 if (settings->performance_flags == PERF_FLAG_NONE)
325 earlyCapabilityFlags |= RNS_UD_CS_VALID_CONNECTION_TYPE;
326 connectionType = CONNECTION_TYPE_LAN;
329 if (settings->color_depth == 32)
331 supportedColorDepths |= RNS_UD_32BPP_SUPPORT;
332 earlyCapabilityFlags |= RNS_UD_CS_WANT_32BPP_SESSION;
335 stream_write_uint16(s, highColorDepth); /* highColorDepth */
336 stream_write_uint16(s, supportedColorDepths); /* supportedColorDepths */
338 stream_write_uint16(s, earlyCapabilityFlags); /* earlyCapabilityFlags */
340 /* clientDigProductId (64 bytes, null-terminated unicode, truncated to 30 characters) */
341 if (clientDigProductIdLength > 62)
343 clientDigProductIdLength = 62;
344 clientDigProductId[clientDigProductIdLength] = 0;
345 clientDigProductId[clientDigProductIdLength + 1] = 0;
347 stream_write(s, clientDigProductId, clientDigProductIdLength + 2);
348 stream_write_zero(s, 64 - clientDigProductIdLength - 2);
349 xfree(clientDigProductId);
351 stream_write_uint8(s, connectionType); /* connectionType */
352 stream_write_uint8(s, 0); /* pad1octet */
354 stream_write_uint32(s, settings->selected_protocol); /* serverSelectedProtocol */
357 void gcc_read_server_core_data(STREAM* s, rdpSettings *settings)
360 uint32 clientRequestedProtocols;
362 stream_read_uint32(s, version); /* version */
363 stream_read_uint32(s, clientRequestedProtocols); /* clientRequestedProtocols */
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;
372 * Write a client security data block (TS_UD_CS_SEC).\n
375 * @param settings rdp settings
378 void gcc_write_client_security_data(STREAM* s, rdpSettings *settings)
380 gcc_write_user_data_header(s, CS_SECURITY, 12);
382 if (settings->encryption > 0)
384 stream_write_uint32(s, settings->encryption_methods); /* encryptionMethods */
385 stream_write_uint32(s, 0); /* extEncryptionMethods */
389 /* French locale, disable encryption */
390 stream_write_uint32(s, 0); /* encryptionMethods */
391 stream_write_uint32(s, settings->encryption_methods); /* extEncryptionMethods */
395 void gcc_read_server_security_data(STREAM* s, rdpSettings *settings)
397 uint32 encryptionMethod;
398 uint32 encryptionLevel;
399 uint32 serverRandomLen;
400 uint32 serverCertLen;
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 */
407 if (encryptionMethod == 0 && encryptionLevel == 0)
409 /* serverRandom and serverRandom must not be present */
413 if (serverRandomLen > 0)
416 freerdp_blob_alloc(&settings->server_random, serverRandomLen);
417 memcpy(settings->server_random.data, s->p, serverRandomLen);
418 stream_seek(s, serverRandomLen);
421 if (serverCertLen > 0)
423 /* serverCertificate */
424 freerdp_blob_alloc(&settings->server_certificate, serverCertLen);
425 memcpy(settings->server_certificate.data, s->p, serverCertLen);
426 stream_seek(s, serverCertLen);
431 * Write a client network data block (TS_UD_CS_NET).\n
434 * @param settings rdp settings
437 void gcc_write_client_network_data(STREAM* s, rdpSettings *settings)
442 if (settings->num_channels > 0)
444 length = settings->num_channels * 12 + 8;
445 gcc_write_user_data_header(s, CS_NET, length);
447 stream_write_uint32(s, settings->num_channels); /* channelCount */
449 /* channelDefArray */
450 for (i = 0; i < settings->num_channels; i++)
453 stream_write(s, settings->channels[i].name, 8); /* name (8 bytes) */
454 stream_write_uint32(s, settings->channels[i].options); /* options (4 bytes) */
459 void gcc_read_server_network_data(STREAM* s, rdpSettings *settings)
466 stream_read_uint16(s, MCSChannelId); /* MCSChannelId */
467 stream_read_uint16(s, channelCount); /* channelCount */
469 if (channelCount != settings->num_channels)
471 printf("requested %d channels, got %d instead\n",
472 settings->num_channels, channelCount);
475 for (i = 0; i < channelCount; i++)
477 stream_read_uint16(s, channelId); /* channelId */
479 if (channelId != settings->channels[i].chan_id)
481 printf("channel %d is %d, but %d was expected\n",
482 i, channelId, settings->channels[i].chan_id);
486 if (channelCount % 2 == 1)
487 stream_seek(s, 2); /* padding */
491 * Write a client cluster data block (TS_UD_CS_CLUSTER).\n
494 * @param settings rdp settings
497 void gcc_write_client_cluster_data(STREAM* s, rdpSettings *settings)
501 gcc_write_user_data_header(s, CS_CLUSTER, 12);
503 flags = REDIRECTION_SUPPORTED | (REDIRECTION_VERSION4 << 2);
505 if (settings->console_session || settings->redirected_session_id)
506 flags |= REDIRECTED_SESSIONID_FIELD_VALID;
508 stream_write_uint32(s, flags); /* flags */
509 stream_write_uint32(s, settings->redirected_session_id); /* redirectedSessionID */
513 * Write a client monitor data block (TS_UD_CS_MONITOR).\n
516 * @param settings rdp settings
519 void gcc_write_client_monitor_data(STREAM* s, rdpSettings *settings)
523 uint32 left, top, right, bottom, flags;
525 if (settings->num_monitors > 1)
527 length = (20 * settings->num_monitors) + 12;
528 gcc_write_user_data_header(s, CS_MONITOR, length);
530 stream_write_uint32(s, 0); /* flags */
531 stream_write_uint32(s, settings->num_monitors); /* monitorCount */
533 for (i = 0; i < settings->num_monitors; i++)
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;
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 */