2 * FreeRDP: A Remote Desktop Protocol Client
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.
22 #define INFO_TYPE_LOGON 0x00000000
23 #define INFO_TYPE_LOGON_LONG 0x00000001
24 #define INFO_TYPE_LOGON_PLAIN_NOTIFY 0x00000002
25 #define INFO_TYPE_LOGON_EXTENDED_INF 0x00000003
28 static const char* const INFO_TYPE_LOGON_STRINGS[] =
38 * Read SYSTEM_TIME structure (TS_SYSTEMTIME).\n
41 * @param system_time system time structure
44 void rdp_read_system_time(STREAM* s, SYSTEM_TIME* system_time)
46 stream_read_uint16(s, system_time->wYear); /* wYear, must be set to 0 */
47 stream_read_uint16(s, system_time->wMonth); /* wMonth */
48 stream_read_uint16(s, system_time->wDayOfWeek); /* wDayOfWeek */
49 stream_read_uint16(s, system_time->wDay); /* wDay */
50 stream_read_uint16(s, system_time->wHour); /* wHour */
51 stream_read_uint16(s, system_time->wMinute); /* wMinute */
52 stream_read_uint16(s, system_time->wSecond); /* wSecond */
53 stream_read_uint16(s, system_time->wMilliseconds); /* wMilliseconds */
57 * Write SYSTEM_TIME structure (TS_SYSTEMTIME).\n
60 * @param system_time system time structure
63 void rdp_write_system_time(STREAM* s, SYSTEM_TIME* system_time)
65 stream_write_uint16(s, system_time->wYear); /* wYear, must be set to 0 */
66 stream_write_uint16(s, system_time->wMonth); /* wMonth */
67 stream_write_uint16(s, system_time->wDayOfWeek); /* wDayOfWeek */
68 stream_write_uint16(s, system_time->wDay); /* wDay */
69 stream_write_uint16(s, system_time->wHour); /* wHour */
70 stream_write_uint16(s, system_time->wMinute); /* wMinute */
71 stream_write_uint16(s, system_time->wSecond); /* wSecond */
72 stream_write_uint16(s, system_time->wMilliseconds); /* wMilliseconds */
76 * Get client time zone information.\n
78 * @param settings settings
81 void rdp_get_client_time_zone(STREAM* s, rdpSettings* settings)
84 struct tm* local_time;
85 TIME_ZONE_INFO* clientTimeZone;
88 local_time = localtime(&t);
89 clientTimeZone = settings->client_time_zone;
92 if(local_time->tm_isdst > 0)
93 clientTimeZone->bias = (uint32) (altzone / 3600);
95 clientTimeZone->bias = (uint32) (timezone / 3600);
96 #elif defined(HAVE_TM_GMTOFF)
97 if(local_time->tm_gmtoff >= 0)
98 clientTimeZone->bias = (uint32) (local_time->tm_gmtoff / 60);
100 clientTimeZone->bias = (uint32) ((-1 * local_time->tm_gmtoff) / 60 + 720);
102 clientTimeZone->bias = 0;
105 if(local_time->tm_isdst > 0)
107 clientTimeZone->standardBias = clientTimeZone->bias - 60;
108 clientTimeZone->daylightBias = clientTimeZone->bias;
112 clientTimeZone->standardBias = clientTimeZone->bias;
113 clientTimeZone->daylightBias = clientTimeZone->bias + 60;
116 strftime(clientTimeZone->standardName, 32, "%Z, Standard Time", local_time);
117 clientTimeZone->standardName[31] = 0;
118 strftime(clientTimeZone->daylightName, 32, "%Z, Summer Time", local_time);
119 clientTimeZone->daylightName[31] = 0;
123 * Read client time zone information (TS_TIME_ZONE_INFORMATION).\n
126 * @param settings settings
129 boolean rdp_read_client_time_zone(STREAM* s, rdpSettings* settings)
132 TIME_ZONE_INFO* clientTimeZone;
134 if (stream_get_left(s) < 172)
137 clientTimeZone = settings->client_time_zone;
139 stream_read_uint32(s, clientTimeZone->bias); /* Bias */
141 /* standardName (64 bytes) */
142 str = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), 64);
144 strncpy(clientTimeZone->standardName, str, sizeof(clientTimeZone->standardName));
147 rdp_read_system_time(s, &clientTimeZone->standardDate); /* StandardDate */
148 stream_read_uint32(s, clientTimeZone->standardBias); /* StandardBias */
150 /* daylightName (64 bytes) */
151 str = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), 64);
153 strncpy(clientTimeZone->daylightName, str, sizeof(clientTimeZone->daylightName));
156 rdp_read_system_time(s, &clientTimeZone->daylightDate); /* DaylightDate */
157 stream_read_uint32(s, clientTimeZone->daylightBias); /* DaylightBias */
163 * Write client time zone information (TS_TIME_ZONE_INFORMATION).\n
166 * @param settings settings
169 void rdp_write_client_time_zone(STREAM* s, rdpSettings* settings)
174 size_t standardNameLength;
175 size_t daylightNameLength;
176 TIME_ZONE_INFO* clientTimeZone;
178 rdp_get_client_time_zone(s, settings);
179 clientTimeZone = settings->client_time_zone;
181 standardName = (uint8*) freerdp_uniconv_out(settings->uniconv, clientTimeZone->standardName, &length);
182 standardNameLength = length;
184 daylightName = (uint8*) freerdp_uniconv_out(settings->uniconv, clientTimeZone->daylightName, &length);
185 daylightNameLength = length;
187 if (standardNameLength > 62)
188 standardNameLength = 62;
190 if (daylightNameLength > 62)
191 daylightNameLength = 62;
193 stream_write_uint32(s, clientTimeZone->bias); /* Bias */
195 /* standardName (64 bytes) */
196 stream_write(s, standardName, standardNameLength);
197 stream_write_zero(s, 64 - standardNameLength);
199 rdp_write_system_time(s, &clientTimeZone->standardDate); /* StandardDate */
200 stream_write_uint32(s, clientTimeZone->standardBias); /* StandardBias */
202 /* daylightName (64 bytes) */
203 stream_write(s, daylightName, daylightNameLength);
204 stream_write_zero(s, 64 - daylightNameLength);
206 rdp_write_system_time(s, &clientTimeZone->daylightDate); /* DaylightDate */
207 stream_write_uint32(s, clientTimeZone->daylightBias); /* DaylightBias */
214 * Read Server Auto Reconnect Cookie (ARC_SC_PRIVATE_PACKET).\n
217 * @param settings settings
220 void rdp_read_server_auto_reconnect_cookie(STREAM* s, rdpSettings* settings)
222 ARC_SC_PRIVATE_PACKET* autoReconnectCookie;
223 autoReconnectCookie = settings->server_auto_reconnect_cookie;
225 stream_read_uint32(s, autoReconnectCookie->cbLen); /* cbLen (4 bytes) */
226 stream_read_uint32(s, autoReconnectCookie->version); /* version (4 bytes) */
227 stream_read_uint32(s, autoReconnectCookie->logonId); /* LogonId (4 bytes) */
228 stream_read(s, autoReconnectCookie->arcRandomBits, 16); /* arcRandomBits (16 bytes) */
232 * Read Client Auto Reconnect Cookie (ARC_CS_PRIVATE_PACKET).\n
235 * @param settings settings
238 boolean rdp_read_client_auto_reconnect_cookie(STREAM* s, rdpSettings* settings)
240 ARC_CS_PRIVATE_PACKET* autoReconnectCookie;
241 autoReconnectCookie = settings->client_auto_reconnect_cookie;
243 if (stream_get_left(s) < 28)
246 stream_write_uint32(s, autoReconnectCookie->cbLen); /* cbLen (4 bytes) */
247 stream_write_uint32(s, autoReconnectCookie->version); /* version (4 bytes) */
248 stream_write_uint32(s, autoReconnectCookie->logonId); /* LogonId (4 bytes) */
249 stream_write(s, autoReconnectCookie->securityVerifier, 16); /* SecurityVerifier */
255 * Write Client Auto Reconnect Cookie (ARC_CS_PRIVATE_PACKET).\n
258 * @param settings settings
261 void rdp_write_client_auto_reconnect_cookie(STREAM* s, rdpSettings* settings)
263 ARC_CS_PRIVATE_PACKET* autoReconnectCookie;
264 autoReconnectCookie = settings->client_auto_reconnect_cookie;
266 stream_write_uint32(s, autoReconnectCookie->cbLen); /* cbLen (4 bytes) */
267 stream_write_uint32(s, autoReconnectCookie->version); /* version (4 bytes) */
268 stream_write_uint32(s, autoReconnectCookie->logonId); /* LogonId (4 bytes) */
269 stream_write(s, autoReconnectCookie->securityVerifier, 16); /* SecurityVerifier */
273 * Read Extended Info Packet (TS_EXTENDED_INFO_PACKET).\n
276 * @param settings settings
279 boolean rdp_read_extended_info_packet(STREAM* s, rdpSettings* settings)
281 uint16 clientAddressFamily;
282 uint16 cbClientAddress;
284 uint16 cbAutoReconnectLen;
286 stream_read_uint16(s, clientAddressFamily); /* clientAddressFamily */
287 stream_read_uint16(s, cbClientAddress); /* cbClientAddress */
289 settings->ipv6 = (clientAddressFamily == ADDRESS_FAMILY_INET6 ? true : false);
290 if (stream_get_left(s) < cbClientAddress)
292 settings->ip_address = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), cbClientAddress);
293 stream_seek(s, cbClientAddress);
295 stream_read_uint16(s, cbClientDir); /* cbClientDir */
296 if (stream_get_left(s) < cbClientDir)
298 if (settings->client_dir)
299 xfree(settings->client_dir);
300 settings->client_dir = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), cbClientDir);
301 stream_seek(s, cbClientDir);
303 if (!rdp_read_client_time_zone(s, settings))
306 stream_seek_uint32(s); /* clientSessionId, should be set to 0 */
307 stream_read_uint32(s, settings->performance_flags); /* performanceFlags */
309 stream_read_uint16(s, cbAutoReconnectLen); /* cbAutoReconnectLen */
311 if (cbAutoReconnectLen > 0)
312 return rdp_read_client_auto_reconnect_cookie(s, settings); /* autoReconnectCookie */
314 /* reserved1 (2 bytes) */
315 /* reserved2 (2 bytes) */
321 * Write Extended Info Packet (TS_EXTENDED_INFO_PACKET).\n
324 * @param settings settings
327 void rdp_write_extended_info_packet(STREAM* s, rdpSettings* settings)
330 uint16 clientAddressFamily;
331 uint8* clientAddress;
332 uint16 cbClientAddress;
335 uint16 cbAutoReconnectLen;
337 clientAddressFamily = settings->ipv6 ? ADDRESS_FAMILY_INET6 : ADDRESS_FAMILY_INET;
339 clientAddress = (uint8*) freerdp_uniconv_out(settings->uniconv, settings->ip_address, &length);
340 cbClientAddress = length;
342 clientDir = (uint8*) freerdp_uniconv_out(settings->uniconv, settings->client_dir, &length);
343 cbClientDir = length;
345 cbAutoReconnectLen = settings->client_auto_reconnect_cookie->cbLen;
347 stream_write_uint16(s, clientAddressFamily); /* clientAddressFamily */
349 stream_write_uint16(s, cbClientAddress + 2); /* cbClientAddress */
351 if (cbClientAddress > 0)
352 stream_write(s, clientAddress, cbClientAddress); /* clientAddress */
353 stream_write_uint16(s, 0);
355 stream_write_uint16(s, cbClientDir + 2); /* cbClientDir */
358 stream_write(s, clientDir, cbClientDir); /* clientDir */
359 stream_write_uint16(s, 0);
361 rdp_write_client_time_zone(s, settings); /* clientTimeZone */
363 stream_write_uint32(s, 0); /* clientSessionId, should be set to 0 */
364 stream_write_uint32(s, settings->performance_flags); /* performanceFlags */
366 stream_write_uint16(s, cbAutoReconnectLen); /* cbAutoReconnectLen */
368 if (cbAutoReconnectLen > 0)
369 rdp_write_client_auto_reconnect_cookie(s, settings); /* autoReconnectCookie */
371 /* reserved1 (2 bytes) */
372 /* reserved2 (2 bytes) */
374 xfree(clientAddress);
379 * Read Info Packet (TS_INFO_PACKET).\n
382 * @param settings settings
385 boolean rdp_read_info_packet(STREAM* s, rdpSettings* settings)
391 uint16 cbAlternateShell;
394 stream_seek_uint32(s); /* CodePage */
395 stream_read_uint32(s, flags); /* flags */
397 settings->autologon = ((flags & INFO_AUTOLOGON) ? true : false);
398 settings->remote_app = ((flags & INFO_RAIL) ? true : false);
399 settings->console_audio = ((flags & INFO_REMOTECONSOLEAUDIO) ? true : false);
400 settings->compression = ((flags & INFO_COMPRESSION) ? true : false);
402 stream_read_uint16(s, cbDomain); /* cbDomain */
403 stream_read_uint16(s, cbUserName); /* cbUserName */
404 stream_read_uint16(s, cbPassword); /* cbPassword */
405 stream_read_uint16(s, cbAlternateShell); /* cbAlternateShell */
406 stream_read_uint16(s, cbWorkingDir); /* cbWorkingDir */
408 if (stream_get_left(s) < cbDomain + 2)
412 settings->domain = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), cbDomain);
413 stream_seek(s, cbDomain);
417 if (stream_get_left(s) < cbUserName + 2)
421 settings->username = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), cbUserName);
422 stream_seek(s, cbUserName);
426 if (stream_get_left(s) < cbPassword + 2)
430 settings->password = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), cbPassword);
431 stream_seek(s, cbPassword);
435 if (stream_get_left(s) < cbAlternateShell + 2)
437 if (cbAlternateShell > 0)
439 settings->shell = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), cbAlternateShell);
440 stream_seek(s, cbAlternateShell);
444 if (stream_get_left(s) < cbWorkingDir + 2)
446 if (cbWorkingDir > 0)
448 settings->directory = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), cbWorkingDir);
449 stream_seek(s, cbWorkingDir);
453 if (settings->rdp_version >= 5)
454 return rdp_read_extended_info_packet(s, settings); /* extraInfo */
460 * Write Info Packet (TS_INFO_PACKET).\n
463 * @param settings settings
466 void rdp_write_info_packet(STREAM* s, rdpSettings* settings)
476 size_t passwordLength;
477 uint8* alternateShell;
478 uint16 cbAlternateShell;
481 boolean usedPasswordCookie = false;
488 INFO_ENABLEWINDOWSKEY |
489 INFO_DISABLECTRLALTDEL |
490 RNS_INFO_AUDIOCAPTURE;
492 if (settings->autologon)
493 flags |= INFO_AUTOLOGON;
495 if (settings->remote_app)
498 if (settings->console_audio)
499 flags |= INFO_REMOTECONSOLEAUDIO;
501 if (settings->compression)
502 flags |= INFO_COMPRESSION | INFO_PACKET_COMPR_TYPE_64K;
504 domain = (uint8*)freerdp_uniconv_out(settings->uniconv, settings->domain, &length);
507 userName = (uint8*)freerdp_uniconv_out(settings->uniconv, settings->username, &length);
510 if (settings->password_cookie && settings->password_cookie->length > 0)
512 usedPasswordCookie = true;
513 password = (uint8*)settings->password_cookie->data;
514 passwordLength = settings->password_cookie->length;
515 cbPassword = passwordLength - 2;
519 password = (uint8*)freerdp_uniconv_out(settings->uniconv, settings->password, &passwordLength);
520 cbPassword = passwordLength;
523 alternateShell = (uint8*)freerdp_uniconv_out(settings->uniconv, settings->shell, &length);
524 cbAlternateShell = length;
526 workingDir = (uint8*)freerdp_uniconv_out(settings->uniconv, settings->directory, &length);
527 cbWorkingDir = length;
529 stream_write_uint32(s, 0); /* CodePage */
530 stream_write_uint32(s, flags); /* flags */
532 stream_write_uint16(s, cbDomain); /* cbDomain */
533 stream_write_uint16(s, cbUserName); /* cbUserName */
534 stream_write_uint16(s, cbPassword); /* cbPassword */
535 stream_write_uint16(s, cbAlternateShell); /* cbAlternateShell */
536 stream_write_uint16(s, cbWorkingDir); /* cbWorkingDir */
539 stream_write(s, domain, cbDomain);
540 stream_write_uint16(s, 0);
543 stream_write(s, userName, cbUserName);
544 stream_write_uint16(s, 0);
547 stream_write(s, password, passwordLength);
548 stream_write_uint16(s, 0);
550 if (cbAlternateShell > 0)
551 stream_write(s, alternateShell, cbAlternateShell);
552 stream_write_uint16(s, 0);
554 if (cbWorkingDir > 0)
555 stream_write(s, workingDir, cbWorkingDir);
556 stream_write_uint16(s, 0);
560 xfree(alternateShell);
563 if (!usedPasswordCookie)
566 if (settings->rdp_version >= 5)
567 rdp_write_extended_info_packet(s, settings); /* extraInfo */
571 * Read Client Info PDU (CLIENT_INFO_PDU).\n
573 * @param rdp RDP module
577 boolean rdp_recv_client_info(rdpRdp* rdp, STREAM* s)
581 uint16 securityFlags;
583 if (!rdp_read_header(rdp, s, &length, &channelId))
586 rdp_read_security_header(s, &securityFlags);
587 if ((securityFlags & SEC_INFO_PKT) == 0)
590 if (rdp->settings->encryption)
592 if (securityFlags & SEC_REDIRECTION_PKT)
594 printf("Error: SEC_REDIRECTION_PKT unsupported\n");
597 if (securityFlags & SEC_ENCRYPT)
599 if (!rdp_decrypt(rdp, s, length - 4, securityFlags))
601 printf("rdp_decrypt failed\n");
607 return rdp_read_info_packet(s, rdp->settings);
611 * Send Client Info PDU (CLIENT_INFO_PDU).\n
613 * @param rdp RDP module
616 boolean rdp_send_client_info(rdpRdp* rdp)
620 //rdp->settings->crypt_flags |= SEC_INFO_PKT;
621 rdp->sec_flags |= SEC_INFO_PKT;
622 s = rdp_send_stream_init(rdp);
623 rdp_write_info_packet(s, rdp->settings);
624 return rdp_send(rdp, s, MCS_GLOBAL_CHANNEL_ID);
627 void rdp_recv_logon_info_v1(rdpRdp* rdp, STREAM* s)
632 stream_read_uint32(s, cbDomain); /* cbDomain (4 bytes) */
633 stream_seek(s, 52); /* domain (52 bytes) */
634 stream_read_uint32(s, cbUserName); /* cbUserName (4 bytes) */
635 stream_seek(s, 512); /* userName (512 bytes) */
636 stream_seek_uint32(s); /* sessionId (4 bytes) */
639 void rdp_recv_logon_info_v2(rdpRdp* rdp, STREAM* s)
644 stream_seek_uint16(s); /* version (2 bytes) */
645 stream_seek_uint32(s); /* size (4 bytes) */
646 stream_seek_uint32(s); /* sessionId (4 bytes) */
647 stream_read_uint32(s, cbDomain); /* cbDomain (4 bytes) */
648 stream_read_uint32(s, cbUserName); /* cbUserName (4 bytes) */
649 stream_seek(s, 558); /* pad */
650 stream_seek(s, cbDomain); /* domain */
651 stream_seek(s, cbUserName); /* userName */
654 void rdp_recv_logon_plain_notify(rdpRdp* rdp, STREAM* s)
656 stream_seek(s, 576); /* pad */
659 void rdp_recv_logon_error_info(rdpRdp* rdp, STREAM* s)
661 uint32 errorNotificationType;
662 uint32 errorNotificationData;
664 stream_read_uint32(s, errorNotificationType); /* errorNotificationType (4 bytes) */
665 stream_read_uint32(s, errorNotificationData); /* errorNotificationData (4 bytes) */
668 void rdp_recv_logon_info_extended(rdpRdp* rdp, STREAM* s)
671 uint32 fieldsPresent;
674 stream_read_uint16(s, Length); /* The total size in bytes of this structure */
675 stream_read_uint32(s, fieldsPresent); /* fieldsPresent (4 bytes) */
679 if (fieldsPresent & LOGON_EX_AUTORECONNECTCOOKIE)
681 stream_read_uint32(s, cbFieldData); /* cbFieldData (4 bytes) */
682 rdp_read_server_auto_reconnect_cookie(s, rdp->settings);
685 if (fieldsPresent & LOGON_EX_LOGONERRORS)
687 stream_read_uint32(s, cbFieldData); /* cbFieldData (4 bytes) */
688 rdp_recv_logon_error_info(rdp, s);
691 stream_seek(s, 570); /* pad */
694 boolean rdp_recv_save_session_info(rdpRdp* rdp, STREAM* s)
698 stream_read_uint32(s, infoType); /* infoType (4 bytes) */
700 //printf("%s\n", INFO_TYPE_LOGON_STRINGS[infoType]);
704 case INFO_TYPE_LOGON:
705 rdp_recv_logon_info_v1(rdp, s);
708 case INFO_TYPE_LOGON_LONG:
709 rdp_recv_logon_info_v2(rdp, s);
712 case INFO_TYPE_LOGON_PLAIN_NOTIFY:
713 rdp_recv_logon_plain_notify(rdp, s);
716 case INFO_TYPE_LOGON_EXTENDED_INF:
717 rdp_recv_logon_info_extended(rdp, s);