BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) { UINT16 flags; UINT16 length; rdpRedirection* redirection = rdp->redirection; if (Stream_GetRemainingLength(s) < 12) return -1; Stream_Read_UINT16(s, flags); /* flags (2 bytes) */ Stream_Read_UINT16(s, length); /* length (2 bytes) */ Stream_Read_UINT32(s, redirection->sessionID); /* sessionID (4 bytes) */ Stream_Read_UINT32(s, redirection->flags); /* redirFlags (4 bytes) */ WLog_Print(redirection->log, WLOG_DEBUG, "flags: 0x%04X, redirFlags: 0x%04X length: %d, sessionID: 0x%08X", flags, redirection->flags, length, redirection->sessionID); #ifdef WITH_DEBUG_REDIR rdp_print_redirection_flags(redirection->flags); #endif if (redirection->flags & LB_TARGET_NET_ADDRESS) { if (!rdp_redirection_read_string(s, &(redirection->TargetNetAddress))) return -1; } if (redirection->flags & LB_LOAD_BALANCE_INFO) { if (Stream_GetRemainingLength(s) < 4) return -1; Stream_Read_UINT32(s, redirection->LoadBalanceInfoLength); if (Stream_GetRemainingLength(s) < redirection->LoadBalanceInfoLength) return -1; redirection->LoadBalanceInfo = (BYTE*) malloc(redirection->LoadBalanceInfoLength); Stream_Read(s, redirection->LoadBalanceInfo, redirection->LoadBalanceInfoLength); #ifdef WITH_DEBUG_REDIR DEBUG_REDIR("loadBalanceInfo:"); winpr_HexDump(redirection->LoadBalanceInfo, redirection->LoadBalanceInfoLength); #endif } if (redirection->flags & LB_USERNAME) { if (!rdp_redirection_read_string(s, &(redirection->Username))) return -1; WLog_Print(redirection->log, WLOG_DEBUG, "Username: %s", redirection->Username); } if (redirection->flags & LB_DOMAIN) { if (!rdp_redirection_read_string(s, &(redirection->Domain))) return FALSE; WLog_Print(redirection->log, WLOG_DEBUG, "Domain: %s", redirection->Domain); } if (redirection->flags & LB_PASSWORD) { /* Note: length (hopefully) includes double zero termination */ if (Stream_GetRemainingLength(s) < 4) return -1; Stream_Read_UINT32(s, redirection->PasswordLength); redirection->Password = (BYTE*) malloc(redirection->PasswordLength); Stream_Read(s, redirection->Password, redirection->PasswordLength); #ifdef WITH_DEBUG_REDIR DEBUG_REDIR("PasswordCookie:"); winpr_HexDump(redirection->Password, redirection->PasswordLength); #endif } if (redirection->flags & LB_TARGET_FQDN) { if (!rdp_redirection_read_string(s, &(redirection->TargetFQDN))) return -1; WLog_Print(redirection->log, WLOG_DEBUG, "TargetFQDN: %s", redirection->TargetFQDN); } if (redirection->flags & LB_TARGET_NETBIOS_NAME) { if (!rdp_redirection_read_string(s, &(redirection->TargetNetBiosName))) return -1; WLog_Print(redirection->log, WLOG_DEBUG, "TargetNetBiosName: %s", redirection->TargetNetBiosName); } if (redirection->flags & LB_CLIENT_TSV_URL) { if (Stream_GetRemainingLength(s) < 4) return -1; Stream_Read_UINT32(s, redirection->TsvUrlLength); if (Stream_GetRemainingLength(s) < redirection->TsvUrlLength) return -1; redirection->TsvUrl = (BYTE*) malloc(redirection->TsvUrlLength); Stream_Read(s, redirection->TsvUrl, redirection->TsvUrlLength); #ifdef WITH_DEBUG_REDIR DEBUG_REDIR("TsvUrl:"); winpr_HexDump(redirection->TsvUrl, redirection->TsvUrlLength); #endif } if (redirection->flags & LB_TARGET_NET_ADDRESSES) { int i; UINT32 count; UINT32 targetNetAddressesLength; if (Stream_GetRemainingLength(s) < 8) return -1; Stream_Read_UINT32(s, targetNetAddressesLength); Stream_Read_UINT32(s, redirection->TargetNetAddressesCount); count = redirection->TargetNetAddressesCount; redirection->TargetNetAddresses = (char**) malloc(count * sizeof(char*)); ZeroMemory(redirection->TargetNetAddresses, count * sizeof(char*)); WLog_Print(redirection->log, WLOG_DEBUG, "TargetNetAddressesCount: %d", redirection->TargetNetAddressesCount); for (i = 0; i < (int) count; i++) { if (!rdp_redirection_read_string(s, &(redirection->TargetNetAddresses[i]))) return FALSE; WLog_Print(redirection->log, WLOG_DEBUG, "TargetNetAddresses[%d]: %s", i, redirection->TargetNetAddresses[i]); } } if (!Stream_SafeSeek(s, 8)) /* pad (8 bytes) */ return -1; if (redirection->flags & LB_NOREDIRECT) return 0; return 1; }
static BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) { UINT16 flags; UINT16 length; rdpRedirection* redirection = rdp->redirection; if (Stream_GetRemainingLength(s) < 12) return -1; Stream_Read_UINT16(s, flags); /* flags (2 bytes) */ Stream_Read_UINT16(s, length); /* length (2 bytes) */ Stream_Read_UINT32(s, redirection->sessionID); /* sessionID (4 bytes) */ Stream_Read_UINT32(s, redirection->flags); /* redirFlags (4 bytes) */ WLog_DBG(TAG, "flags: 0x%04"PRIX16", redirFlags: 0x%08"PRIX32" length: %"PRIu16", sessionID: 0x%08"PRIX32"", flags, redirection->flags, length, redirection->sessionID); rdp_print_redirection_flags(redirection->flags); /* Although MS-RDPBCGR does not mention any length constraints limits for the * variable length null-terminated unicode strings in the RDP_SERVER_REDIRECTION_PACKET * structure we will use the following limits in bytes including the null terminator: * * TargetNetAddress: 80 bytes * UserName: 512 bytes * Domain: 52 bytes * Password(Cookie): 512 bytes * TargetFQDN: 512 bytes * TargetNetBiosName: 32 bytes */ if (redirection->flags & LB_TARGET_NET_ADDRESS) { if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetNetAddress), 80)) return -1; } if (redirection->flags & LB_LOAD_BALANCE_INFO) { /* See [MSFT-SDLBTS] (a.k.a. TS_Session_Directory.doc) * load balance info example data: * 0000 43 6f 6f 6b 69 65 3a 20 6d 73 74 73 3d 32 31 33 Cookie: msts=213 * 0010 34 30 32 36 34 33 32 2e 31 35 36 32 39 2e 30 30 4026432.15629.00 * 0020 30 30 0d 0a 00.. */ if (Stream_GetRemainingLength(s) < 4) return -1; Stream_Read_UINT32(s, redirection->LoadBalanceInfoLength); if (Stream_GetRemainingLength(s) < redirection->LoadBalanceInfoLength) return -1; redirection->LoadBalanceInfo = (BYTE*) malloc(redirection->LoadBalanceInfoLength); if (!redirection->LoadBalanceInfo) return -1; Stream_Read(s, redirection->LoadBalanceInfo, redirection->LoadBalanceInfoLength); WLog_DBG(TAG, "loadBalanceInfo:"); winpr_HexDump(TAG, WLOG_DEBUG, redirection->LoadBalanceInfo, redirection->LoadBalanceInfoLength); } if (redirection->flags & LB_USERNAME) { if (!rdp_redirection_read_unicode_string(s, &(redirection->Username), 512)) return -1; WLog_DBG(TAG, "Username: %s", redirection->Username); } if (redirection->flags & LB_DOMAIN) { if (!rdp_redirection_read_unicode_string(s, &(redirection->Domain), 52)) return FALSE; WLog_DBG(TAG, "Domain: %s", redirection->Domain); } if (redirection->flags & LB_PASSWORD) { /* Note: Password is a variable-length array of bytes containing the * password used by the user in Unicode format, including a null-terminator * or (!) or a cookie value that MUST be passed to the target server on * successful connection. * Since the format of the password cookie (probably some salted hash) is * currently unknown we'll treat it as opaque data. All cookies seen so far * are 120 bytes including \0\0 termination. * Here is an observed example of a redirection password cookie: * * 0000 02 00 00 80 44 53 48 4c 60 ab 69 2f 07 d6 9e 2d ....DSHL`.i/...- * 0010 f0 3a 97 3b a9 c5 ec 7e 66 bd b3 84 6c b1 ef b9 .:.;...~f...l... * 0020 b6 82 4e cc 3a df 64 b7 7b 25 04 54 c2 58 98 f8 ..N.:.d.{%.T.X.. * 0030 97 87 d4 93 c7 c1 e1 5b c2 85 f8 22 49 1f 81 88 .......[..."I... * 0040 43 44 83 f6 9a 72 40 24 dc 4d 43 cb d9 92 3c 8f CD...r@$.MC...<. * 0050 3a 37 5c 77 13 a0 72 3c 72 08 64 2a 29 fb dc eb :7\w..r<r.d*)... * 0060 0d 2b 06 b4 c6 08 b4 73 34 16 93 62 6d 24 e9 93 .+.....s4..bm$.. * 0070 97 27 7b dd 9a 72 00 00 .'{..r.. * * Notwithstanding the above, we'll allocated an additional zero WCHAR at the * end of the buffer which won't get counted in PasswordLength. */ if (Stream_GetRemainingLength(s) < 4) return -1; Stream_Read_UINT32(s, redirection->PasswordLength); /* [MS-RDPBCGR] specifies 512 bytes as the upper limit for the password length * including the null terminatior(s). This should also be enough for the unknown * password cookie format (see previous comment). */ if (Stream_GetRemainingLength(s) < redirection->PasswordLength) return -1; if (redirection->PasswordLength > 512) return -1; redirection->Password = (BYTE*) calloc(1, redirection->PasswordLength + sizeof(WCHAR)); if (!redirection->Password) return -1; Stream_Read(s, redirection->Password, redirection->PasswordLength); WLog_DBG(TAG, "PasswordCookie:"); winpr_HexDump(TAG, WLOG_DEBUG, redirection->Password, redirection->PasswordLength); } if (redirection->flags & LB_TARGET_FQDN) { if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetFQDN), 512)) return -1; WLog_DBG(TAG, "TargetFQDN: %s", redirection->TargetFQDN); } if (redirection->flags & LB_TARGET_NETBIOS_NAME) { if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetNetBiosName), 32)) return -1; WLog_DBG(TAG, "TargetNetBiosName: %s", redirection->TargetNetBiosName); } if (redirection->flags & LB_CLIENT_TSV_URL) { if (Stream_GetRemainingLength(s) < 4) return -1; Stream_Read_UINT32(s, redirection->TsvUrlLength); if (Stream_GetRemainingLength(s) < redirection->TsvUrlLength) return -1; redirection->TsvUrl = (BYTE*) malloc(redirection->TsvUrlLength); if (!redirection->TsvUrl) return -1; Stream_Read(s, redirection->TsvUrl, redirection->TsvUrlLength); WLog_DBG(TAG, "TsvUrl:"); winpr_HexDump(TAG, WLOG_DEBUG, redirection->TsvUrl, redirection->TsvUrlLength); } if (redirection->flags & LB_TARGET_NET_ADDRESSES) { int i; UINT32 count; UINT32 targetNetAddressesLength; if (Stream_GetRemainingLength(s) < 8) return -1; Stream_Read_UINT32(s, targetNetAddressesLength); Stream_Read_UINT32(s, redirection->TargetNetAddressesCount); count = redirection->TargetNetAddressesCount; redirection->TargetNetAddresses = (char**) calloc(count, sizeof(char*)); if (!redirection->TargetNetAddresses) return FALSE; WLog_DBG(TAG, "TargetNetAddressesCount: %"PRIu32"", redirection->TargetNetAddressesCount); for (i = 0; i < (int) count; i++) { if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetNetAddresses[i]), 80)) return FALSE; WLog_DBG(TAG, "TargetNetAddresses[%d]: %s", i, redirection->TargetNetAddresses[i]); } } if (Stream_GetRemainingLength(s) >= 8) { /* some versions of windows don't included this padding before closing the connection */ Stream_Seek(s, 8); /* pad (8 bytes) */ } if (redirection->flags & LB_NOREDIRECT) return 0; return 1; }
BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, STREAM* s) { UINT16 flags; UINT16 length; rdpRedirection* redirection = rdp->redirection; if(stream_get_left(s) < 12) return FALSE; stream_read_UINT16(s, flags); /* flags (2 bytes) */ stream_read_UINT16(s, length); /* length (2 bytes) */ stream_read_UINT32(s, redirection->sessionID); /* sessionID (4 bytes) */ stream_read_UINT32(s, redirection->flags); /* redirFlags (4 bytes) */ DEBUG_REDIR("flags: 0x%04X, length:%d, sessionID:0x%08X", flags, length, redirection->sessionID); #ifdef WITH_DEBUG_REDIR rdp_print_redirection_flags(redirection->flags); #endif if (redirection->flags & LB_TARGET_NET_ADDRESS) { if(!freerdp_string_read_length32(s, &redirection->targetNetAddress)) return FALSE; DEBUG_REDIR("targetNetAddress: %s", redirection->targetNetAddress.ascii); } if (redirection->flags & LB_LOAD_BALANCE_INFO) { if(stream_get_left(s) < 4) return FALSE; stream_read_UINT32(s, redirection->LoadBalanceInfoLength); if(stream_get_left(s) < redirection->LoadBalanceInfoLength) return FALSE; redirection->LoadBalanceInfo = (BYTE*) malloc(redirection->LoadBalanceInfoLength); stream_read(s, redirection->LoadBalanceInfo, redirection->LoadBalanceInfoLength); #ifdef WITH_DEBUG_REDIR DEBUG_REDIR("loadBalanceInfo:"); winpr_HexDump(redirection->LoadBalanceInfo, redirection->LoadBalanceInfoLength); #endif } if (redirection->flags & LB_USERNAME) { if(!freerdp_string_read_length32(s, &redirection->username)) return FALSE; DEBUG_REDIR("username: %s", redirection->username.ascii); } if (redirection->flags & LB_DOMAIN) { if(!freerdp_string_read_length32(s, &redirection->domain)) return FALSE; DEBUG_REDIR("domain: %s", redirection->domain.ascii); } if (redirection->flags & LB_PASSWORD) { /* Note: length (hopefully) includes double zero termination */ if(stream_get_left(s) < 4) return FALSE; stream_read_UINT32(s, redirection->PasswordCookieLength); redirection->PasswordCookie = (BYTE*) malloc(redirection->PasswordCookieLength); stream_read(s, redirection->PasswordCookie, redirection->PasswordCookieLength); #ifdef WITH_DEBUG_REDIR DEBUG_REDIR("password_cookie:"); winpr_HexDump(redirection->PasswordCookie, redirection->PasswordCookieLength); #endif } if (redirection->flags & LB_TARGET_FQDN) { if(!freerdp_string_read_length32(s, &redirection->targetFQDN)) return FALSE; DEBUG_REDIR("targetFQDN: %s", redirection->targetFQDN.ascii); } if (redirection->flags & LB_TARGET_NETBIOS_NAME) { if(!freerdp_string_read_length32(s, &redirection->targetNetBiosName)) return FALSE; DEBUG_REDIR("targetNetBiosName: %s", redirection->targetNetBiosName.ascii); } if (redirection->flags & LB_CLIENT_TSV_URL) { if(!freerdp_string_read_length32(s, &redirection->tsvUrl)) return FALSE; DEBUG_REDIR("tsvUrl: %s", redirection->tsvUrl.ascii); } if (redirection->flags & LB_TARGET_NET_ADDRESSES) { int i; UINT32 count; UINT32 targetNetAddressesLength; if(stream_get_left(s) < 8) return FALSE; stream_read_UINT32(s, targetNetAddressesLength); stream_read_UINT32(s, redirection->targetNetAddressesCount); count = redirection->targetNetAddressesCount; redirection->targetNetAddresses = (rdpString*) malloc(count * sizeof(rdpString)); ZeroMemory(redirection->targetNetAddresses, count * sizeof(rdpString)); for (i = 0; i < (int) count; i++) { if(!freerdp_string_read_length32(s, &redirection->targetNetAddresses[i])) return FALSE; DEBUG_REDIR("targetNetAddresses: %s", (&redirection->targetNetAddresses[i])->ascii); } } if (!stream_skip(s, 8)) /* pad (8 bytes) */ return FALSE; if (redirection->flags & LB_NOREDIRECT) return TRUE; else return rdp_client_redirect(rdp); }
tbool rdp_recv_server_redirection_pdu(rdpRdp* rdp, STREAM* s) { uint16 flags; uint16 length; rdpRedirection* redirection = rdp->redirection; stream_read_uint16(s, flags); /* flags (2 bytes) */ stream_read_uint16(s, length); /* length (2 bytes) */ stream_read_uint32(s, redirection->sessionID); /* sessionID (4 bytes) */ stream_read_uint32(s, redirection->flags); /* redirFlags (4 bytes) */ DEBUG_REDIR("flags: 0x%04X, length:%d, sessionID:0x%08X", flags, length, redirection->sessionID); #ifdef WITH_DEBUG_REDIR rdp_print_redirection_flags(redirection->flags); #endif if (redirection->flags & LB_TARGET_NET_ADDRESS) { freerdp_string_read_length32(s, &redirection->targetNetAddress, rdp->settings->uniconv); DEBUG_REDIR("targetNetAddress: %s", redirection->targetNetAddress.ascii); } if (redirection->flags & LB_LOAD_BALANCE_INFO) { uint32 loadBalanceInfoLength; stream_read_uint32(s, loadBalanceInfoLength); freerdp_blob_alloc(&redirection->loadBalanceInfo, loadBalanceInfoLength); stream_read(s, redirection->loadBalanceInfo.data, loadBalanceInfoLength); #ifdef WITH_DEBUG_REDIR DEBUG_REDIR("loadBalanceInfo:"); freerdp_hexdump(redirection->loadBalanceInfo.data, redirection->loadBalanceInfo.length); #endif } if (redirection->flags & LB_USERNAME) { freerdp_string_read_length32(s, &redirection->username, rdp->settings->uniconv); DEBUG_REDIR("username: %s", redirection->username.ascii); } if (redirection->flags & LB_DOMAIN) { freerdp_string_read_length32(s, &redirection->domain, rdp->settings->uniconv); DEBUG_REDIR("domain: %s", redirection->domain.ascii); } if (redirection->flags & LB_PASSWORD) { uint32 passwordLength; stream_read_uint32(s, passwordLength); freerdp_blob_alloc(&redirection->password_cookie, passwordLength); stream_read(s, redirection->password_cookie.data, passwordLength); #ifdef WITH_DEBUG_REDIR DEBUG_REDIR("password_cookie:"); freerdp_hexdump(redirection->password_cookie.data, redirection->password_cookie.length); #endif } if (redirection->flags & LB_TARGET_FQDN) { freerdp_string_read_length32(s, &redirection->targetFQDN, rdp->settings->uniconv); DEBUG_REDIR("targetFQDN: %s", redirection->targetFQDN.ascii); } if (redirection->flags & LB_TARGET_NETBIOS_NAME) { freerdp_string_read_length32(s, &redirection->targetNetBiosName, rdp->settings->uniconv); DEBUG_REDIR("targetNetBiosName: %s", redirection->targetNetBiosName.ascii); } if (redirection->flags & LB_CLIENT_TSV_URL) { freerdp_string_read_length32(s, &redirection->tsvUrl, rdp->settings->uniconv); DEBUG_REDIR("tsvUrl: %s", redirection->tsvUrl.ascii); } if (redirection->flags & LB_TARGET_NET_ADDRESSES) { int i; uint32 count; uint32 targetNetAddressesLength; stream_read_uint32(s, targetNetAddressesLength); stream_read_uint32(s, redirection->targetNetAddressesCount); count = redirection->targetNetAddressesCount; redirection->targetNetAddresses = (rdpString*) xzalloc(count * sizeof(rdpString)); for (i = 0; i < (int) count; i++) { freerdp_string_read_length32(s, &redirection->targetNetAddresses[i], rdp->settings->uniconv); DEBUG_REDIR("targetNetAddresses: %s", (&redirection->targetNetAddresses[i])->ascii); } } stream_seek(s, 8); /* pad (8 bytes) */ if (redirection->flags & LB_NOREDIRECT) return true; else return rdp_client_redirect(rdp); }