BOOL http_proxy_connect(BIO* bufferedBio, const char* hostname, UINT16 port) { int status; wStream* s; char port_str[10], recv_buf[256], *eol; int resultsize; _itoa_s(port, port_str, sizeof(port_str), 10); s = Stream_New(NULL, 200); Stream_Write(s, "CONNECT ", 8); Stream_Write(s, hostname, strlen(hostname)); Stream_Write_UINT8(s, ':'); Stream_Write(s, port_str, strlen(port_str)); Stream_Write(s, " HTTP/1.1" CRLF "Host: ", 17); Stream_Write(s, hostname, strlen(hostname)); Stream_Write_UINT8(s, ':'); Stream_Write(s, port_str, strlen(port_str)); Stream_Write(s, CRLF CRLF, 4); status = BIO_write(bufferedBio, Stream_Buffer(s), Stream_GetPosition(s)); if (status != Stream_GetPosition(s)) { WLog_ERR(TAG, "HTTP proxy: failed to write CONNECT request"); return FALSE; } Stream_Free(s, TRUE); s = NULL; /* Read result until CR-LF-CR-LF. * Keep recv_buf a null-terminated string. */ memset(recv_buf, '\0', sizeof(recv_buf)); resultsize = 0; while (strstr(recv_buf, CRLF CRLF) == NULL) { if (resultsize >= sizeof(recv_buf) - 1) { WLog_ERR(TAG, "HTTP Reply headers too long."); return FALSE; } status = BIO_read(bufferedBio, (BYTE*)recv_buf + resultsize, sizeof(recv_buf) - resultsize - 1); if (status < 0) { /* Error? */ if (BIO_should_retry(bufferedBio)) { USleep(100); continue; } WLog_ERR(TAG, "Failed reading reply from HTTP proxy (Status %d)", status); return FALSE; } else if (status == 0) { /* Error? */ WLog_ERR(TAG, "Failed reading reply from HTTP proxy (BIO_read returned zero)"); return FALSE; } resultsize += status; } /* Extract HTTP status line */ eol = strchr(recv_buf, '\r'); if (!eol) { /* should never happen */ return FALSE; } *eol = '\0'; WLog_INFO(TAG, "HTTP Proxy: %s", recv_buf); if (strlen(recv_buf) < 12) { return FALSE; } recv_buf[7] = 'X'; if (strncmp(recv_buf, "HTTP/1.X 200", 12)) return FALSE; return TRUE; }
BOOL WINAPI FreeRDP_WTSVirtualChannelWrite(HANDLE hChannelHandle, PCHAR Buffer, ULONG Length, PULONG pBytesWritten) { wStream* s; int cbLen; int cbChId; int first; BYTE* buffer; UINT32 length; UINT32 written; rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle; BOOL ret = TRUE; if (!channel) return FALSE; if (channel->channelType == RDP_PEER_CHANNEL_TYPE_SVC) { length = Length; buffer = (BYTE *)malloc(length); if (!buffer) { SetLastError(E_OUTOFMEMORY); return FALSE; } CopyMemory(buffer, Buffer, length); ret = wts_queue_send_item(channel, buffer, length); } else if (!channel->vcm->drdynvc_channel || (channel->vcm->drdynvc_state != DRDYNVC_STATE_READY)) { DEBUG_DVC("drdynvc not ready"); return FALSE; } else { first = TRUE; while (Length > 0) { s = Stream_New(NULL, channel->client->settings->VirtualChannelChunkSize); if (!s) { WLog_ERR(TAG, "Stream_New failed!"); SetLastError(E_OUTOFMEMORY); return FALSE; } buffer = Stream_Buffer(s); Stream_Seek_UINT8(s); cbChId = wts_write_variable_uint(s, channel->channelId); if (first && (Length > (UINT32) Stream_GetRemainingLength(s))) { cbLen = wts_write_variable_uint(s, Length); buffer[0] = (DATA_FIRST_PDU << 4) | (cbLen << 2) | cbChId; } else { buffer[0] = (DATA_PDU << 4) | cbChId; } first = FALSE; written = Stream_GetRemainingLength(s); if (written > Length) written = Length; Stream_Write(s, Buffer, written); length = Stream_GetPosition(s); Stream_Free(s, FALSE); Length -= written; Buffer += written; ret = wts_queue_send_item(channel->vcm->drdynvc_channel, buffer, length); } } if (pBytesWritten) *pBytesWritten = Length; return ret; }
/** * Function description * * @return 0 on success, otherwise a Win32 error code */ static UINT remdesk_send_ctl_authenticate_pdu(remdeskPlugin* remdesk) { int status; UINT error; wStream* s = NULL; int cbExpertBlobW = 0; WCHAR* expertBlobW = NULL; int cbRaConnectionStringW = 0; WCHAR* raConnectionStringW = NULL; REMDESK_CTL_AUTHENTICATE_PDU pdu; if ((error = remdesk_generate_expert_blob(remdesk))) { WLog_ERR(TAG, "remdesk_generate_expert_blob failed with error %lu", error); return error; } pdu.expertBlob = remdesk->ExpertBlob; pdu.raConnectionString = remdesk->settings->RemoteAssistanceRCTicket; status = ConvertToUnicode(CP_UTF8, 0, pdu.raConnectionString, -1, &raConnectionStringW, 0); if (status <= 0) { WLog_ERR(TAG, "ConvertToUnicode failed!"); return ERROR_INTERNAL_ERROR; } cbRaConnectionStringW = status * 2; status = ConvertToUnicode(CP_UTF8, 0, pdu.expertBlob, -1, &expertBlobW, 0); if (status <= 0) { WLog_ERR(TAG, "ConvertToUnicode failed!"); error = ERROR_INTERNAL_ERROR; goto out; } cbExpertBlobW = status * 2; remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_AUTHENTICATE, cbRaConnectionStringW + cbExpertBlobW); s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.DataLength); if (!s) { WLog_ERR(TAG, "Stream_New failed!"); error = CHANNEL_RC_NO_MEMORY; goto out; } remdesk_write_ctl_header(s, &(pdu.ctlHeader)); Stream_Write(s, (BYTE*) raConnectionStringW, cbRaConnectionStringW); Stream_Write(s, (BYTE*) expertBlobW, cbExpertBlobW); Stream_SealLength(s); if ((error = remdesk_virtual_channel_write(remdesk, s))) WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %lu!", error); out: free(raConnectionStringW); free(expertBlobW); if (error != CHANNEL_RC_OK) Stream_Free(s, TRUE); return error; }
static BOOL rdp_client_establish_keys(rdpRdp* rdp) { BYTE* mod; BYTE* exp; wStream* s; UINT32 length; UINT32 key_len; BYTE *crypt_client_random = NULL; BOOL ret = FALSE; int status = 0; if (!rdp->settings->DisableEncryption) { /* no RDP encryption */ return TRUE; } /* encrypt client random */ if (rdp->settings->ClientRandom) free(rdp->settings->ClientRandom); rdp->settings->ClientRandom = malloc(CLIENT_RANDOM_LENGTH); if (!rdp->settings->ClientRandom) return FALSE; crypto_nonce(rdp->settings->ClientRandom, CLIENT_RANDOM_LENGTH); key_len = rdp->settings->RdpServerCertificate->cert_info.ModulusLength; mod = rdp->settings->RdpServerCertificate->cert_info.Modulus; exp = rdp->settings->RdpServerCertificate->cert_info.exponent; /* * client random must be (bitlen / 8) + 8 - see [MS-RDPBCGR] 5.3.4.1 * for details */ crypt_client_random = calloc(1,key_len+8); if (!crypt_client_random) return FALSE; crypto_rsa_public_encrypt(rdp->settings->ClientRandom, CLIENT_RANDOM_LENGTH, key_len, mod, exp, crypt_client_random); /* send crypt client random to server */ length = RDP_PACKET_HEADER_MAX_LENGTH + RDP_SECURITY_HEADER_LENGTH + 4 + key_len + 8; s = Stream_New(NULL, length); rdp_write_header(rdp, s, length, MCS_GLOBAL_CHANNEL_ID); rdp_write_security_header(s, SEC_EXCHANGE_PKT | SEC_LICENSE_ENCRYPT_SC); length = key_len + 8; Stream_Write_UINT32(s, length); Stream_Write(s, crypt_client_random, length); Stream_SealLength(s); status = transport_write(rdp->mcs->transport, s); Stream_Free(s, TRUE); if (status < 0) goto end; /* now calculate encrypt / decrypt and update keys */ if (!security_establish_keys(rdp->settings->ClientRandom, rdp)) goto end; rdp->do_crypt = TRUE; if (rdp->settings->SaltedChecksum) rdp->do_secure_checksum = TRUE; if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS) { rdp->fips_encrypt = crypto_des3_encrypt_init(rdp->fips_encrypt_key, fips_ivec); if (!rdp->fips_encrypt) { DEBUG_WARN( "%s: unable to allocate des3 encrypt key\n", __FUNCTION__); goto end; } rdp->fips_decrypt = crypto_des3_decrypt_init(rdp->fips_decrypt_key, fips_ivec); if (!rdp->fips_decrypt) { DEBUG_WARN( "%s: unable to allocate des3 decrypt key\n", __FUNCTION__); goto end; } rdp->fips_hmac = crypto_hmac_new(); if (!rdp->fips_hmac) { DEBUG_WARN( "%s: unable to allocate fips hmac\n", __FUNCTION__); goto end; } ret = TRUE; goto end; } rdp->rc4_decrypt_key = crypto_rc4_init(rdp->decrypt_key, rdp->rc4_key_len); if (!rdp->rc4_decrypt_key) { DEBUG_WARN( "%s: unable to allocate rc4 decrypt key\n", __FUNCTION__); goto end; } rdp->rc4_encrypt_key = crypto_rc4_init(rdp->encrypt_key, rdp->rc4_key_len); if (!rdp->rc4_encrypt_key) { DEBUG_WARN( "%s: unable to allocate rc4 encrypt key\n", __FUNCTION__); goto end; } ret = TRUE; end: if (crypt_client_random) free(crypt_client_random); return ret; }
static DWORD WINAPI drdynvc_virtual_channel_client_thread(LPVOID arg) { wStream* data; wMessage message; UINT error = CHANNEL_RC_OK; drdynvcPlugin* drdynvc = (drdynvcPlugin*) arg; if (!drdynvc) { ExitThread((DWORD) CHANNEL_RC_BAD_CHANNEL_HANDLE); return CHANNEL_RC_BAD_CHANNEL_HANDLE; } while (1) { if (!MessageQueue_Wait(drdynvc->queue)) { WLog_Print(drdynvc->log, WLOG_ERROR, "MessageQueue_Wait failed!"); error = ERROR_INTERNAL_ERROR; break; } if (!MessageQueue_Peek(drdynvc->queue, &message, TRUE)) { WLog_Print(drdynvc->log, WLOG_ERROR, "MessageQueue_Peek failed!"); error = ERROR_INTERNAL_ERROR; break; } if (message.id == WMQ_QUIT) break; if (message.id == 0) { data = (wStream*) message.wParam; if ((error = drdynvc_order_recv(drdynvc, data))) { Stream_Free(data, TRUE); WLog_Print(drdynvc->log, WLOG_ERROR, "drdynvc_order_recv failed with error %"PRIu32"!", error); break; } Stream_Free(data, TRUE); } } { /* Disconnect remaining dynamic channels that the server did not. * This is required to properly shut down channels by calling the appropriate * event handlers. */ DVCMAN* drdynvcMgr = (DVCMAN*)drdynvc->channel_mgr; while (ArrayList_Count(drdynvcMgr->channels) > 0) { IWTSVirtualChannel* channel = (IWTSVirtualChannel*) ArrayList_GetItem(drdynvcMgr->channels, 0); const UINT32 ChannelId = drdynvc->channel_mgr->GetChannelId(channel); dvcman_close_channel(drdynvc->channel_mgr, ChannelId); } } if (error && drdynvc->rdpcontext) setChannelError(drdynvc->rdpcontext, error, "drdynvc_virtual_channel_client_thread reported an error"); ExitThread((DWORD) error); return error; }
RFX_MESSAGE* rfx_process_message(RFX_CONTEXT* context, BYTE* data, UINT32 length) { int pos; UINT32 blockLen; UINT32 blockType; RFX_MESSAGE* message = NULL; wStream* s = NULL; BOOL ok = TRUE; UINT16 expectedDataBlockType = WBT_FRAME_BEGIN; if (!context || !data || !length) goto fail; if (!(s = Stream_New(data, length))) goto fail; if (!(message = (RFX_MESSAGE*) calloc(1, sizeof(RFX_MESSAGE)))) goto fail; message->freeRects = TRUE; while (ok && Stream_GetRemainingLength(s) > 6) { /* RFX_BLOCKT */ Stream_Read_UINT16(s, blockType); /* blockType (2 bytes) */ Stream_Read_UINT32(s, blockLen); /* blockLen (4 bytes) */ WLog_Print(context->priv->log, WLOG_DEBUG, "blockType 0x%X blockLen %d", blockType, blockLen); if (blockLen == 0) { WLog_ERR(TAG, "zero blockLen"); goto fail; } if (Stream_GetRemainingLength(s) < blockLen - 6) { WLog_ERR(TAG, "%s: packet too small for blocklen=%d", __FUNCTION__, blockLen); goto fail; } pos = Stream_GetPosition(s) - 6 + blockLen; if (blockType > WBT_CONTEXT && context->decodedHeaderBlocks != _RFX_DECODED_HEADERS) { WLog_ERR(TAG, "%s: incomplete header blocks processing", __FUNCTION__); goto fail; } if (blockType >= WBT_CONTEXT && blockType <= WBT_EXTENSION) { /* RFX_CODEC_CHANNELT */ UINT8 codecId; UINT8 channelId; if (Stream_GetRemainingLength(s) < 2) goto fail; Stream_Read_UINT8(s, codecId); /* codecId (1 byte) must be set to 0x01 */ Stream_Read_UINT8(s, channelId); /* channelId (1 byte) 0xFF or 0x00, see below */ if (codecId != 0x01) { WLog_ERR(TAG, "%s: invalid codecId 0x%02X", __FUNCTION__, codecId); goto fail; } if (blockType == WBT_CONTEXT) { /* If the blockType is set to WBT_CONTEXT, then channelId MUST be set to 0xFF.*/ if (channelId != 0xFF) { WLog_ERR(TAG, "%s: invalid channelId 0x%02X for blockType 0x%04X", __FUNCTION__, channelId, blockType); goto fail; } } else { /* For all other values of blockType, channelId MUST be set to 0x00. */ if (channelId != 0x00) { WLog_ERR(TAG, "%s: invalid channelId 0x%02X for blockType WBT_CONTEXT", __FUNCTION__, channelId); goto fail; } } } switch (blockType) { /* Header messages: * The stream MUST start with the header messages and any of these headers can appear * in the stream at a later stage. The header messages can be repeated. */ case WBT_SYNC: ok = rfx_process_message_sync(context, s); break; case WBT_CONTEXT: ok = rfx_process_message_context(context, s); break; case WBT_CODEC_VERSIONS: ok = rfx_process_message_codec_versions(context, s); break; case WBT_CHANNELS: ok = rfx_process_message_channels(context, s); break; /* Data messages: * The data associated with each encoded frame or image is always bracketed by the * TS_RFX_FRAME_BEGIN (section 2.2.2.3.1) and TS_RFX_FRAME_END (section 2.2.2.3.2) messages. * There MUST only be one TS_RFX_REGION (section 2.2.2.3.3) message per frame and one TS_RFX_TILESET * (section 2.2.2.3.4) message per TS_RFX_REGION. */ case WBT_FRAME_BEGIN: ok = rfx_process_message_frame_begin(context, message, s, &expectedDataBlockType); break; case WBT_REGION: ok = rfx_process_message_region(context, message, s, &expectedDataBlockType); break; case WBT_EXTENSION: ok = rfx_process_message_tileset(context, message, s, &expectedDataBlockType); break; case WBT_FRAME_END: ok = rfx_process_message_frame_end(context, message, s, &expectedDataBlockType); break; default: WLog_ERR(TAG, "%s: unknown blockType 0x%X", __FUNCTION__, blockType); goto fail; } Stream_SetPosition(s, pos); } if (ok) { Stream_Free(s, FALSE); return message; } fail: Stream_Free(s, FALSE); rfx_message_free(context, message); return NULL; }
static void rpc_pdu_free(RPC_PDU* pdu) { Stream_Free(pdu->s, TRUE); free(pdu); }
static void* echo_server_thread_func(void* arg) { wStream* s; void* buffer; DWORD nCount; HANDLE events[8]; BOOL ready = FALSE; HANDLE ChannelEvent; DWORD BytesReturned = 0; echo_server* echo = (echo_server*) arg; UINT error; DWORD status; if ((error = echo_server_open_channel(echo))) { IFCALLRET(echo->context.OpenResult, error, &echo->context, ECHO_SERVER_OPEN_RESULT_NOTSUPPORTED); WLog_ERR(TAG, "echo_server_open_channel failed with error %lu!", error); goto out; } buffer = NULL; BytesReturned = 0; ChannelEvent = NULL; if (WTSVirtualChannelQuery(echo->echo_channel, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE) { if (BytesReturned == sizeof(HANDLE)) CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); WTSFreeMemory(buffer); } nCount = 0; events[nCount++] = echo->stopEvent; events[nCount++] = ChannelEvent; /* Wait for the client to confirm that the Graphics Pipeline dynamic channel is ready */ while (1) { status = WaitForMultipleObjects(nCount, events, FALSE, 100); if (status == WAIT_FAILED) { error = GetLastError(); WLog_ERR(TAG, "WaitForMultipleObjects failed with error %lu", error); break; } if (status == WAIT_OBJECT_0) { IFCALLRET(echo->context.OpenResult, error, &echo->context, ECHO_SERVER_OPEN_RESULT_CLOSED); if (error) WLog_ERR(TAG, "OpenResult failed with error %lu!", error); break; } if (WTSVirtualChannelQuery(echo->echo_channel, WTSVirtualChannelReady, &buffer, &BytesReturned) == FALSE) { IFCALLRET(echo->context.OpenResult, error, &echo->context, ECHO_SERVER_OPEN_RESULT_ERROR); if (error) WLog_ERR(TAG, "OpenResult failed with error %lu!", error); break; } ready = *((BOOL*) buffer); WTSFreeMemory(buffer); if (ready) { IFCALLRET(echo->context.OpenResult, error, &echo->context, ECHO_SERVER_OPEN_RESULT_OK); if (error) WLog_ERR(TAG, "OpenResult failed with error %lu!", error); break; } } s = Stream_New(NULL, 4096); if (!s) { WLog_ERR(TAG, "Stream_New failed!"); WTSVirtualChannelClose(echo->echo_channel); ExitThread((DWORD)ERROR_NOT_ENOUGH_MEMORY); return NULL; } while (ready) { status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); if (status == WAIT_FAILED) { error = GetLastError(); WLog_ERR(TAG, "WaitForMultipleObjects failed with error %lu", error); break; } if (status == WAIT_OBJECT_0) break; Stream_SetPosition(s, 0); WTSVirtualChannelRead(echo->echo_channel, 0, NULL, 0, &BytesReturned); if (BytesReturned < 1) continue; if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) { WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); error = CHANNEL_RC_NO_MEMORY; break; } if (WTSVirtualChannelRead(echo->echo_channel, 0, (PCHAR) Stream_Buffer(s), (ULONG) Stream_Capacity(s), &BytesReturned) == FALSE) { WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); error = ERROR_INTERNAL_ERROR; break; } IFCALLRET(echo->context.Response, error, &echo->context, (BYTE *) Stream_Buffer(s), BytesReturned); if (error) { WLog_ERR(TAG, "Response failed with error %lu!", error); break; } } Stream_Free(s, TRUE); WTSVirtualChannelClose(echo->echo_channel); echo->echo_channel = NULL; out: if (error && echo->context.rdpcontext) setChannelError(echo->context.rdpcontext, error, "echo_server_thread_func reported an error"); ExitThread((DWORD)error); return NULL; }
/** * Function description * * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback) { UINT error; wStream* s; UINT16 index; RDPGFX_PLUGIN* gfx; RDPGFX_HEADER header; RDPGFX_CAPSET* capsSet; RDPGFX_CAPSET capsSets[RDPGFX_NUMBER_CAPSETS]; RDPGFX_CAPS_ADVERTISE_PDU pdu; gfx = (RDPGFX_PLUGIN*) callback->plugin; header.flags = 0; header.cmdId = RDPGFX_CMDID_CAPSADVERTISE; pdu.capsSetCount = 0; pdu.capsSets = (RDPGFX_CAPSET*) capsSets; capsSet = &capsSets[pdu.capsSetCount++]; capsSet->version = RDPGFX_CAPVERSION_8; capsSet->flags = 0; if (gfx->ThinClient) capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT; /* in CAPVERSION_8 the spec says that we should not have both * thinclient and smallcache (and thinclient implies a small cache) */ if (gfx->SmallCache && !gfx->ThinClient) capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE; capsSet = &capsSets[pdu.capsSetCount++]; capsSet->version = RDPGFX_CAPVERSION_81; capsSet->flags = 0; if (gfx->ThinClient) capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT; if (gfx->SmallCache) capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE; #ifdef WITH_GFX_H264 if (gfx->H264) capsSet->flags |= RDPGFX_CAPS_FLAG_AVC420_ENABLED; #endif if (!gfx->H264 || gfx->AVC444) { capsSet = &capsSets[pdu.capsSetCount++]; capsSet->version = RDPGFX_CAPVERSION_10; capsSet->flags = 0; if (gfx->SmallCache) capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE; #ifdef WITH_GFX_H264 if (!gfx->AVC444) capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED; #else capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED; #endif capsSets[pdu.capsSetCount] = *capsSet; capsSets[pdu.capsSetCount++].version = RDPGFX_CAPVERSION_102; capsSets[pdu.capsSetCount] = *capsSet; capsSets[pdu.capsSetCount++].version = RDPGFX_CAPVERSION_103; } header.pduLength = RDPGFX_HEADER_SIZE + 2 + (pdu.capsSetCount * RDPGFX_CAPSET_SIZE); WLog_Print(gfx->log, WLOG_DEBUG, "SendCapsAdvertisePdu %"PRIu16"", pdu.capsSetCount); s = Stream_New(NULL, header.pduLength); if (!s) { WLog_ERR(TAG, "Stream_New failed!"); return CHANNEL_RC_NO_MEMORY; } if ((error = rdpgfx_write_header(s, &header))) goto fail; /* RDPGFX_CAPS_ADVERTISE_PDU */ Stream_Write_UINT16(s, pdu.capsSetCount); /* capsSetCount (2 bytes) */ for (index = 0; index < pdu.capsSetCount; index++) { capsSet = &(pdu.capsSets[index]); Stream_Write_UINT32(s, capsSet->version); /* version (4 bytes) */ Stream_Write_UINT32(s, 4); /* capsDataLength (4 bytes) */ Stream_Write_UINT32(s, capsSet->flags); /* capsData (4 bytes) */ } Stream_SealLength(s); error = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s), Stream_Buffer(s), NULL); fail: Stream_Free(s, TRUE); return error; }
static UINT remmina_rdp_cliprdr_server_format_data_response(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse) { TRACE_CALL(__func__); UINT8* data; size_t size; rfContext* rfi; RemminaProtocolWidget* gp; rfClipboard* clipboard; GdkPixbufLoader *pixbuf; gpointer output = NULL; RemminaPluginRdpUiObject *ui; clipboard = (rfClipboard*)context->custom; gp = clipboard->rfi->protocol_widget; rfi = GET_PLUGIN_DATA(gp); data = formatDataResponse->requestedFormatData; size = formatDataResponse->dataLen; // formatDataResponse->requestedFormatData is allocated // by freerdp and freed after returning from this callback function. // So we must make a copy if we need to preserve it if (size > 0) { switch (rfi->clipboard.format) { case CF_UNICODETEXT: { size = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)data, size / 2, (CHAR**)&output, 0, NULL, NULL); crlf2lf(output, &size); break; } case CF_TEXT: case CB_FORMAT_HTML: { output = (gpointer)calloc(1, size + 1); if (output) { memcpy(output, data, size); crlf2lf(output, &size); } break; } case CF_DIBV5: case CF_DIB: { wStream* s; UINT32 offset; GError *perr; BITMAPINFOHEADER* pbi; BITMAPV5HEADER* pbi5; pbi = (BITMAPINFOHEADER*)data; // offset calculation inspired by http://downloads.poolelan.com/MSDN/MSDNLibrary6/Disk1/Samples/VC/OS/WindowsXP/GetImage/BitmapUtil.cpp offset = 14 + pbi->biSize; if (pbi->biClrUsed != 0) offset += sizeof(RGBQUAD) * pbi->biClrUsed; else if (pbi->biBitCount <= 8) offset += sizeof(RGBQUAD) * (1 << pbi->biBitCount); if (pbi->biSize == sizeof(BITMAPINFOHEADER)) { if (pbi->biCompression == 3) // BI_BITFIELDS is 3 offset += 12; } else if (pbi->biSize >= sizeof(BITMAPV5HEADER)) { pbi5 = (BITMAPV5HEADER*)pbi; if (pbi5->bV5ProfileData <= offset) offset += pbi5->bV5ProfileSize; } s = Stream_New(NULL, 14 + size); Stream_Write_UINT8(s, 'B'); Stream_Write_UINT8(s, 'M'); Stream_Write_UINT32(s, 14 + size); Stream_Write_UINT32(s, 0); Stream_Write_UINT32(s, offset); Stream_Write(s, data, size); data = Stream_Buffer(s); size = Stream_Length(s); pixbuf = gdk_pixbuf_loader_new(); perr = NULL; if ( !gdk_pixbuf_loader_write(pixbuf, data, size, &perr) ) { remmina_plugin_service->log_printf("[RDP] rdp_cliprdr: gdk_pixbuf_loader_write() returned error %s\n", perr->message); }else { if ( !gdk_pixbuf_loader_close(pixbuf, &perr) ) { remmina_plugin_service->log_printf("[RDP] rdp_cliprdr: gdk_pixbuf_loader_close() returned error %s\n", perr->message); perr = NULL; } Stream_Free(s, TRUE); output = g_object_ref(gdk_pixbuf_loader_get_pixbuf(pixbuf)); } g_object_unref(pixbuf); break; } case CB_FORMAT_PNG: case CB_FORMAT_JPEG: { pixbuf = gdk_pixbuf_loader_new(); gdk_pixbuf_loader_write(pixbuf, data, size, NULL); output = g_object_ref(gdk_pixbuf_loader_get_pixbuf(pixbuf)); gdk_pixbuf_loader_close(pixbuf, NULL); g_object_unref(pixbuf); break; } } } pthread_mutex_lock(&clipboard->transfer_clip_mutex); pthread_cond_signal(&clipboard->transfer_clip_cond); if ( clipboard->srv_clip_data_wait == SCDW_BUSY_WAIT ) { clipboard->srv_data = output; }else { // Clipboard data arrived from server when we are not busywaiting. // Just put it on the local clipboard ui = g_new0(RemminaPluginRdpUiObject, 1); ui->type = REMMINA_RDP_UI_CLIPBOARD; ui->clipboard.clipboard = clipboard; ui->clipboard.type = REMMINA_RDP_UI_CLIPBOARD_SET_CONTENT; ui->clipboard.data = output; ui->clipboard.format = clipboard->format; remmina_rdp_event_queue_ui_sync_retint(gp, ui); clipboard->srv_clip_data_wait = SCDW_NONE; } pthread_mutex_unlock(&clipboard->transfer_clip_mutex); return CHANNEL_RC_OK; }
wStream* http_request_write(HttpContext* context, HttpRequest* request) { wStream* s; if (!context || !request) return NULL; s = Stream_New(NULL, 1024); if (!s) return NULL; if (!http_encode_header_line(s, request->Method, request->URI) || !http_encode_body_line(s, "Cache-Control", context->CacheControl) || !http_encode_body_line(s, "Connection", context->Connection) || !http_encode_body_line(s, "Pragma", context->Pragma) || !http_encode_body_line(s, "Accept", context->Accept) || !http_encode_body_line(s, "User-Agent", context->UserAgent) || !http_encode_body_line(s, "Host", context->Host)) goto fail; if (context->RdgConnectionId) { if (!http_encode_body_line(s, "RDG-Connection-Id", context->RdgConnectionId)) goto fail; } if (context->RdgAuthScheme) { if (!http_encode_body_line(s, "RDG-Auth-Scheme", context->RdgAuthScheme)) goto fail; } if (request->TransferEncoding) { if (!http_encode_body_line(s, "Transfer-Encoding", request->TransferEncoding)) goto fail; } else { if (!http_encode_content_length_line(s, request->ContentLength)) goto fail; } if (request->Authorization) { if (!http_encode_body_line(s, "Authorization", request->Authorization)) goto fail; } else if (request->AuthScheme && request->AuthParam) { if (!http_encode_authorization_line(s, request->AuthScheme, request->AuthParam)) goto fail; } Stream_Write(s, "\r\n", 2); Stream_SealLength(s); return s; fail: Stream_Free(s, TRUE); return NULL; }
/** * Function description * * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback) { UINT error; wStream* s; UINT16 index; RDPGFX_PLUGIN* gfx; RDPGFX_HEADER header; RDPGFX_CAPSET* capsSet; RDPGFX_CAPSET capsSets[RDPGFX_NUMBER_CAPSETS]; RDPGFX_CAPS_ADVERTISE_PDU pdu; gfx = (RDPGFX_PLUGIN*) callback->plugin; header.flags = 0; header.cmdId = RDPGFX_CMDID_CAPSADVERTISE; pdu.capsSetCount = 0; pdu.capsSets = (RDPGFX_CAPSET*) capsSets; capsSet = &capsSets[pdu.capsSetCount++]; capsSet->version = RDPGFX_CAPVERSION_8; capsSet->flags = 0; if (gfx->ThinClient) capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT; if (gfx->SmallCache) capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE; capsSet = &capsSets[pdu.capsSetCount++]; capsSet->version = RDPGFX_CAPVERSION_81; capsSet->flags = 0; if (gfx->ThinClient) capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT; if (gfx->SmallCache) capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE; if (gfx->H264) capsSet->flags |= RDPGFX_CAPS_FLAG_AVC420_ENABLED; if (gfx->AVC444) { capsSet = &capsSets[pdu.capsSetCount++]; capsSet->version = RDPGFX_CAPVERSION_10; capsSet->flags = 0; if (gfx->SmallCache) capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE; if (!gfx->H264) capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED; capsSets[pdu.capsSetCount] = *capsSet; capsSets[pdu.capsSetCount++].version = RDPGFX_CAPVERSION_102; } header.pduLength = RDPGFX_HEADER_SIZE + 2 + (pdu.capsSetCount * RDPGFX_CAPSET_SIZE); WLog_DBG(TAG, "SendCapsAdvertisePdu %d", pdu.capsSetCount); s = Stream_New(NULL, header.pduLength); if (!s) { WLog_ERR(TAG, "Stream_New failed!"); return CHANNEL_RC_NO_MEMORY; } if ((error = rdpgfx_write_header(s, &header))) { WLog_ERR(TAG, "rdpgfx_write_header failed with error %u!", error); return error; } /* RDPGFX_CAPS_ADVERTISE_PDU */ Stream_Write_UINT16(s, pdu.capsSetCount); /* capsSetCount (2 bytes) */ for (index = 0; index < pdu.capsSetCount; index++) { capsSet = &(pdu.capsSets[index]); Stream_Write_UINT32(s, capsSet->version); /* version (4 bytes) */ Stream_Write_UINT32(s, 4); /* capsDataLength (4 bytes) */ Stream_Write_UINT32(s, capsSet->flags); /* capsData (4 bytes) */ } Stream_SealLength(s); error = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s), Stream_Buffer(s), NULL); Stream_Free(s, TRUE); return error; }
static void* remdesk_server_thread(void* arg) { wStream* s; DWORD status; DWORD nCount; void* buffer; UINT32* pHeader; UINT32 PduLength; HANDLE events[8]; HANDLE ChannelEvent; DWORD BytesReturned; RemdeskServerContext* context; UINT error; context = (RemdeskServerContext*) arg; buffer = NULL; BytesReturned = 0; ChannelEvent = NULL; s = Stream_New(NULL, 4096); if (!s) { WLog_ERR(TAG, "Stream_New failed!"); error = CHANNEL_RC_NO_MEMORY; goto out; } if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE) { if (BytesReturned == sizeof(HANDLE)) CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); WTSFreeMemory(buffer); } else { WLog_ERR(TAG, "WTSVirtualChannelQuery failed!"); error = ERROR_INTERNAL_ERROR; goto out; } nCount = 0; events[nCount++] = ChannelEvent; events[nCount++] = context->priv->StopEvent; if ((error = remdesk_send_ctl_version_info_pdu(context))) { WLog_ERR(TAG, "remdesk_send_ctl_version_info_pdu failed with error %"PRIu32"!", error); goto out; } while (1) { status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); if (status == WAIT_FAILED) { error = GetLastError(); WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"", error); break; } status = WaitForSingleObject(context->priv->StopEvent, 0); if (status == WAIT_FAILED) { error = GetLastError(); WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error); break; } if (status == WAIT_OBJECT_0) { break; } if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) { if (BytesReturned) Stream_Seek(s, BytesReturned); } else { if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) { WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); error = CHANNEL_RC_NO_MEMORY; break; } } if (Stream_GetPosition(s) >= 8) { pHeader = (UINT32*) Stream_Buffer(s); PduLength = pHeader[0] + pHeader[1] + 8; if (PduLength >= Stream_GetPosition(s)) { Stream_SealLength(s); Stream_SetPosition(s, 0); if ((error = remdesk_server_receive_pdu(context, s))) { WLog_ERR(TAG, "remdesk_server_receive_pdu failed with error %"PRIu32"!", error); break; } Stream_SetPosition(s, 0); } } } Stream_Free(s, TRUE); out: if (error && context->rdpcontext) setChannelError(context->rdpcontext, error, "remdesk_server_thread reported an error"); ExitThread((DWORD)error); return NULL; }
static CLIPRDR_FORMAT* xf_cliprdr_parse_server_format_list(BYTE* data, size_t length, UINT32* numFormats) { UINT32 i; wStream* s = NULL; CLIPRDR_FORMAT* formats = NULL; if (!(s = Stream_New(data, length))) { WLog_ERR(TAG, "failed to allocate stream for parsing serialized format list"); goto error; } if (Stream_GetRemainingLength(s) < sizeof(UINT32)) { WLog_ERR(TAG, "too short serialized format list"); goto error; } Stream_Read_UINT32(s, *numFormats); if (*numFormats > MAX_CLIPBOARD_FORMATS) { WLog_ERR(TAG, "unexpectedly large number of formats: %"PRIu32"", *numFormats); goto error; } if (!(formats = (CLIPRDR_FORMAT*) calloc(*numFormats, sizeof(CLIPRDR_FORMAT)))) { WLog_ERR(TAG, "failed to allocate format list"); goto error; } for (i = 0; i < *numFormats; i++) { const char* formatName = NULL; size_t formatNameLength = 0; if (Stream_GetRemainingLength(s) < sizeof(UINT32)) { WLog_ERR(TAG, "unexpected end of serialized format list"); goto error; } Stream_Read_UINT32(s, formats[i].formatId); formatName = (const char*) Stream_Pointer(s); formatNameLength = strnlen(formatName, Stream_GetRemainingLength(s)); if (formatNameLength == Stream_GetRemainingLength(s)) { WLog_ERR(TAG, "missing terminating null byte, %"PRIuz" bytes left to read", formatNameLength); goto error; } formats[i].formatName = strndup(formatName, formatNameLength); Stream_Seek(s, formatNameLength + 1); } Stream_Free(s, FALSE); return formats; error: Stream_Free(s, FALSE); free(formats); *numFormats = 0; return NULL; }
BOOL nego_send_negotiation_response(rdpNego* nego) { int length; int bm, em; BOOL status; wStream* s; BYTE flags; rdpSettings* settings; status = TRUE; settings = nego->transport->settings; s = Stream_New(NULL, 512); if (!s) return FALSE; length = TPDU_CONNECTION_CONFIRM_LENGTH; bm = Stream_GetPosition(s); Stream_Seek(s, length); if (nego->SelectedProtocol & PROTOCOL_FAILED_NEGO) { UINT32 errorCode = (nego->SelectedProtocol & ~PROTOCOL_FAILED_NEGO); flags = 0; Stream_Write_UINT8(s, TYPE_RDP_NEG_FAILURE); Stream_Write_UINT8(s, flags); /* flags */ Stream_Write_UINT16(s, 8); /* RDP_NEG_DATA length (8) */ Stream_Write_UINT32(s, errorCode); length += 8; status = FALSE; } else { flags = EXTENDED_CLIENT_DATA_SUPPORTED; if (settings->SupportGraphicsPipeline) flags |= DYNVC_GFX_PROTOCOL_SUPPORTED; /* RDP_NEG_DATA must be present for TLS, NLA, and RDP */ Stream_Write_UINT8(s, TYPE_RDP_NEG_RSP); Stream_Write_UINT8(s, flags); /* flags */ Stream_Write_UINT16(s, 8); /* RDP_NEG_DATA length (8) */ Stream_Write_UINT32(s, nego->SelectedProtocol); /* selectedProtocol */ length += 8; } em = Stream_GetPosition(s); Stream_SetPosition(s, bm); tpkt_write_header(s, length); tpdu_write_connection_confirm(s, length - 5); Stream_SetPosition(s, em); Stream_SealLength(s); if (transport_write(nego->transport, s) < 0) { Stream_Free(s, TRUE); return FALSE; } Stream_Free(s, TRUE); if (status) { /* update settings with negotiated protocol security */ settings->RequestedProtocols = nego->RequestedProtocols; settings->SelectedProtocol = nego->SelectedProtocol; if (settings->SelectedProtocol == PROTOCOL_RDP) { settings->TlsSecurity = FALSE; settings->NlaSecurity = FALSE; settings->RdpSecurity = TRUE; settings->UseRdpSecurityLayer = TRUE; if (settings->EncryptionLevel == ENCRYPTION_LEVEL_NONE) { /** * If the server implementation did not explicitely set a * encryption level we default to client compatible */ settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE; } if (settings->LocalConnection) { /** * Note: This hack was firstly introduced in commit 95f5e115 to * disable the unnecessary encryption with peers connecting to * 127.0.0.1 or local unix sockets. * This also affects connections via port tunnels! (e.g. ssh -L) */ WLog_INFO(TAG, "Turning off encryption for local peer with standard rdp security"); settings->UseRdpSecurityLayer = FALSE; settings->EncryptionLevel = ENCRYPTION_LEVEL_NONE; } if (!settings->RdpServerRsaKey && !settings->RdpKeyFile) { WLog_ERR(TAG, "Missing server certificate"); return FALSE; } } else if (settings->SelectedProtocol == PROTOCOL_TLS) { settings->TlsSecurity = TRUE; settings->NlaSecurity = FALSE; settings->RdpSecurity = FALSE; settings->UseRdpSecurityLayer = FALSE; settings->EncryptionLevel = ENCRYPTION_LEVEL_NONE; } else if (settings->SelectedProtocol == PROTOCOL_NLA) { settings->TlsSecurity = TRUE; settings->NlaSecurity = TRUE; settings->RdpSecurity = FALSE; settings->UseRdpSecurityLayer = FALSE; settings->EncryptionLevel = ENCRYPTION_LEVEL_NONE; } } return status; }
/** * Function description * * @return 0 on success, otherwise a Win32 error code */ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) { char* name; char* path; int i; size_t length; RDPDR_PARALLEL* device; PARALLEL_DEVICE* parallel; UINT error; device = (RDPDR_PARALLEL*) pEntryPoints->device; name = device->Name; path = device->Path; if (!name || (name[0] == '*')) { /* TODO: implement auto detection of parallel ports */ return CHANNEL_RC_OK; } if (name[0] && path[0]) { parallel = (PARALLEL_DEVICE*) calloc(1, sizeof(PARALLEL_DEVICE)); if (!parallel) { WLog_ERR(TAG, "calloc failed!"); return CHANNEL_RC_NO_MEMORY; } parallel->device.type = RDPDR_DTYP_PARALLEL; parallel->device.name = name; parallel->device.IRPRequest = parallel_irp_request; parallel->device.Free = parallel_free; parallel->rdpcontext = pEntryPoints->rdpcontext; length = strlen(name); parallel->device.data = Stream_New(NULL, length + 1); if (!parallel->device.data) { WLog_ERR(TAG, "Stream_New failed!"); error = CHANNEL_RC_NO_MEMORY; goto error_out; } for (i = 0; i <= length; i++) Stream_Write_UINT8(parallel->device.data, name[i] < 0 ? '_' : name[i]); parallel->path = path; parallel->queue = MessageQueue_New(NULL); if (!parallel->queue) { WLog_ERR(TAG, "MessageQueue_New failed!"); error = CHANNEL_RC_NO_MEMORY; goto error_out; } if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) parallel))) { WLog_ERR(TAG, "RegisterDevice failed with error %u!", error); goto error_out; } if (!(parallel->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) parallel_thread_func, (void*) parallel, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); error = ERROR_INTERNAL_ERROR; goto error_out; } } return CHANNEL_RC_OK; error_out: MessageQueue_Free(parallel->queue); Stream_Free(parallel->device.data, TRUE); free(parallel); return error; }
static void rail_process_receive(rdpSvcPlugin* plugin, wStream* s) { railPlugin* rail = (railPlugin*) plugin; rail_order_recv(rail->rail_order, s); Stream_Free(s, TRUE); }
static DWORD WINAPI audin_server_thread_func(LPVOID arg) { wStream* s; void* buffer; DWORD nCount; BYTE MessageId; HANDLE events[8]; BOOL ready = FALSE; HANDLE ChannelEvent; DWORD BytesReturned = 0; audin_server* audin = (audin_server*) arg; UINT error = CHANNEL_RC_OK; DWORD status; buffer = NULL; BytesReturned = 0; ChannelEvent = NULL; if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE) { if (BytesReturned == sizeof(HANDLE)) CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); WTSFreeMemory(buffer); } else { WLog_ERR(TAG, "WTSVirtualChannelQuery failed"); error = ERROR_INTERNAL_ERROR; goto out; } nCount = 0; events[nCount++] = audin->stopEvent; events[nCount++] = ChannelEvent; /* Wait for the client to confirm that the Audio Input dynamic channel is ready */ while (1) { if ((status = WaitForMultipleObjects(nCount, events, FALSE, 100)) == WAIT_OBJECT_0) goto out; if (status == WAIT_FAILED) { error = GetLastError(); WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"", error); goto out; } if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualChannelReady, &buffer, &BytesReturned) == FALSE) { WLog_ERR(TAG, "WTSVirtualChannelQuery failed"); error = ERROR_INTERNAL_ERROR; goto out; } ready = *((BOOL*) buffer); WTSFreeMemory(buffer); if (ready) break; } s = Stream_New(NULL, 4096); if (!s) { WLog_ERR(TAG, "Stream_New failed!"); error = CHANNEL_RC_NO_MEMORY; goto out; } if (ready) { if ((error = audin_server_send_version(audin, s))) { WLog_ERR(TAG, "audin_server_send_version failed with error %"PRIu32"!", error); goto out_capacity; } } while (ready) { if ((status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE)) == WAIT_OBJECT_0) break; if (status == WAIT_FAILED) { error = GetLastError(); WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"", error); goto out; } Stream_SetPosition(s, 0); if (!WTSVirtualChannelRead(audin->audin_channel, 0, NULL, 0, &BytesReturned)) { WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); error = ERROR_INTERNAL_ERROR; break; } if (BytesReturned < 1) continue; if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) break; if (WTSVirtualChannelRead(audin->audin_channel, 0, (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned) == FALSE) { WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); error = ERROR_INTERNAL_ERROR; break; } Stream_Read_UINT8(s, MessageId); BytesReturned--; switch (MessageId) { case MSG_SNDIN_VERSION: if ((error = audin_server_recv_version(audin, s, BytesReturned))) { WLog_ERR(TAG, "audin_server_recv_version failed with error %"PRIu32"!", error); goto out_capacity; } if ((error = audin_server_send_formats(audin, s))) { WLog_ERR(TAG, "audin_server_send_formats failed with error %"PRIu32"!", error); goto out_capacity; } break; case MSG_SNDIN_FORMATS: if ((error = audin_server_recv_formats(audin, s, BytesReturned))) { WLog_ERR(TAG, "audin_server_recv_formats failed with error %"PRIu32"!", error); goto out_capacity; } if ((error = audin_server_send_open(audin, s))) { WLog_ERR(TAG, "audin_server_send_open failed with error %"PRIu32"!", error); goto out_capacity; } break; case MSG_SNDIN_OPEN_REPLY: if ((error = audin_server_recv_open_reply(audin, s, BytesReturned))) { WLog_ERR(TAG, "audin_server_recv_open_reply failed with error %"PRIu32"!", error); goto out_capacity; } break; case MSG_SNDIN_DATA_INCOMING: break; case MSG_SNDIN_DATA: if ((error = audin_server_recv_data(audin, s, BytesReturned))) { WLog_ERR(TAG, "audin_server_recv_data failed with error %"PRIu32"!", error); goto out_capacity; }; break; case MSG_SNDIN_FORMATCHANGE: break; default: WLog_ERR(TAG, "audin_server_thread_func: unknown MessageId %"PRIu8"", MessageId); break; } } out_capacity: Stream_Free(s, TRUE); out: WTSVirtualChannelClose(audin->audin_channel); audin->audin_channel = NULL; if (error && audin->context.rdpcontext) setChannelError(audin->context.rdpcontext, error, "audin_server_thread_func reported an error"); ExitThread(error); return error; }
static void* encomsp_server_thread(void* arg) { wStream* s; DWORD nCount; void* buffer; HANDLE events[8]; HANDLE ChannelEvent; DWORD BytesReturned; ENCOMSP_ORDER_HEADER* header; EncomspServerContext* context; UINT error = CHANNEL_RC_OK; DWORD status; context = (EncomspServerContext*) arg; freerdp_channel_init_thread_context(context->rdpcontext); buffer = NULL; BytesReturned = 0; ChannelEvent = NULL; s = Stream_New(NULL, 4096); if (!s) { WLog_ERR(TAG, "Stream_New failed!"); error = CHANNEL_RC_NO_MEMORY; goto out; } if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE) { if (BytesReturned == sizeof(HANDLE)) CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); WTSFreeMemory(buffer); } nCount = 0; events[nCount++] = ChannelEvent; events[nCount++] = context->priv->StopEvent; while (1) { status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); if (status == WAIT_FAILED) { error = GetLastError(); WLog_ERR(TAG, "WaitForMultipleObjects failed with error %lu", error); break; } status = WaitForSingleObject(context->priv->StopEvent, 0); if (status == WAIT_FAILED) { error = GetLastError(); WLog_ERR(TAG, "WaitForSingleObject failed with error %lu", error); break; } if (status == WAIT_OBJECT_0) { break; } WTSVirtualChannelRead(context->priv->ChannelHandle, 0, NULL, 0, &BytesReturned); if (BytesReturned < 1) continue; if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) { WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); error = CHANNEL_RC_NO_MEMORY; break; } if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) { WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); error = ERROR_INTERNAL_ERROR; break; } if (Stream_GetPosition(s) >= ENCOMSP_ORDER_HEADER_SIZE) { header = (ENCOMSP_ORDER_HEADER*) Stream_Buffer(s); if (header->Length >= Stream_GetPosition(s)) { Stream_SealLength(s); Stream_SetPosition(s, 0); if ((error = encomsp_server_receive_pdu(context, s))) { WLog_ERR(TAG, "encomsp_server_receive_pdu failed with error %lu!", error); break; } Stream_SetPosition(s, 0); } } } Stream_Free(s, TRUE); out: if (error && context->rdpcontext) setChannelError(context->rdpcontext, error, "encomsp_server_thread reported an error"); ExitThread((DWORD)error); return NULL; }
int disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callback, UINT32 NumMonitors, DISPLAY_CONTROL_MONITOR_LAYOUT* Monitors) { int status; wStream* s; UINT32 type; UINT32 index; UINT32 length; DISP_PLUGIN* disp; UINT32 MonitorLayoutSize; disp = (DISP_PLUGIN*) callback->plugin; MonitorLayoutSize = 40; length = 8 + 8 + (NumMonitors * MonitorLayoutSize); type = DISPLAY_CONTROL_PDU_TYPE_MONITOR_LAYOUT; s = Stream_New(NULL, length); Stream_Write_UINT32(s, type); /* Type (4 bytes) */ Stream_Write_UINT32(s, length); /* Length (4 bytes) */ if (NumMonitors > disp->MaxNumMonitors) NumMonitors = disp->MaxNumMonitors; Stream_Write_UINT32(s, MonitorLayoutSize); /* MonitorLayoutSize (4 bytes) */ Stream_Write_UINT32(s, NumMonitors); /* NumMonitors (4 bytes) */ //WLog_ERR(TAG, "NumMonitors: %d\n", NumMonitors); for (index = 0; index < NumMonitors; index++) { Monitors[index].Width -= (Monitors[index].Width % 2); if (Monitors[index].Width < 200) Monitors[index].Width = 200; if (Monitors[index].Width > 8192) Monitors[index].Width = 8192; if (Monitors[index].Width % 2) Monitors[index].Width++; if (Monitors[index].Height < 200) Monitors[index].Height = 200; if (Monitors[index].Height > 8192) Monitors[index].Height = 8192; Stream_Write_UINT32(s, Monitors[index].Flags); /* Flags (4 bytes) */ Stream_Write_UINT32(s, Monitors[index].Left); /* Left (4 bytes) */ Stream_Write_UINT32(s, Monitors[index].Top); /* Top (4 bytes) */ Stream_Write_UINT32(s, Monitors[index].Width); /* Width (4 bytes) */ Stream_Write_UINT32(s, Monitors[index].Height); /* Height (4 bytes) */ Stream_Write_UINT32(s, Monitors[index].PhysicalWidth); /* PhysicalWidth (4 bytes) */ Stream_Write_UINT32(s, Monitors[index].PhysicalHeight); /* PhysicalHeight (4 bytes) */ Stream_Write_UINT32(s, Monitors[index].Orientation); /* Orientation (4 bytes) */ Stream_Write_UINT32(s, Monitors[index].DesktopScaleFactor); /* DesktopScaleFactor (4 bytes) */ Stream_Write_UINT32(s, Monitors[index].DeviceScaleFactor); /* DeviceScaleFactor (4 bytes) */ #if 0 WLog_DBG(TAG, "\t: Flags: 0x%04X\n", Monitors[index].Flags); WLog_DBG(TAG, "\t: Left: %d\n", Monitors[index].Left); WLog_DBG(TAG, "\t: Top: %d\n", Monitors[index].Top); WLog_DBG(TAG, "\t: Width: %d\n", Monitors[index].Width); WLog_DBG(TAG, "\t: Height: %d\n", Monitors[index].Height); WLog_DBG(TAG, "\t: PhysicalWidth: %d\n", Monitors[index].PhysicalWidth); WLog_DBG(TAG, "\t: PhysicalHeight: %d\n", Monitors[index].PhysicalHeight); WLog_DBG(TAG, "\t: Orientation: %d\n", Monitors[index].Orientation); #endif } Stream_SealLength(s); status = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s), Stream_Buffer(s), NULL); Stream_Free(s, TRUE); return status; }int disp_recv_display_control_caps_pdu(DISP_CHANNEL_CALLBACK* callback, wStream* s)
static void rpc_fragment_free(wStream* fragment) { Stream_Free(fragment, TRUE); }
/** * Function description * * @return 0 on success, otherwise a Win32 error code */ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) { char* name; char* path; char* driver; RDPDR_SERIAL* device; #if defined __linux__ && !defined ANDROID int i, len; SERIAL_DEVICE* serial; #endif /* __linux__ */ UINT error = CHANNEL_RC_OK; device = (RDPDR_SERIAL*) pEntryPoints->device; name = device->Name; path = device->Path; driver = device->Driver; if (!name || (name[0] == '*')) { /* TODO: implement auto detection of serial ports */ return CHANNEL_RC_OK; } if ((name && name[0]) && (path && path[0])) { wLog* log; log = WLog_Get("com.freerdp.channel.serial.client"); WLog_Print(log, WLOG_DEBUG, "initializing"); #ifndef __linux__ /* to be removed */ WLog_Print(log, WLOG_WARN, "Serial ports redirection not supported on this platform."); return CHANNEL_RC_INITIALIZATION_ERROR; #else /* __linux __ */ WLog_Print(log, WLOG_DEBUG, "Defining %s as %s", name, path); if (!DefineCommDevice(name /* eg: COM1 */, path /* eg: /dev/ttyS0 */)) { DWORD status = GetLastError(); WLog_ERR(TAG, "DefineCommDevice failed with %08"PRIx32, status); return ERROR_INTERNAL_ERROR; } serial = (SERIAL_DEVICE*) calloc(1, sizeof(SERIAL_DEVICE)); if (!serial) { WLog_ERR(TAG, "calloc failed!"); return CHANNEL_RC_NO_MEMORY; } serial->log = log; serial->device.type = RDPDR_DTYP_SERIAL; serial->device.name = name; serial->device.IRPRequest = serial_irp_request; serial->device.Free = serial_free; serial->rdpcontext = pEntryPoints->rdpcontext; len = strlen(name); serial->device.data = Stream_New(NULL, len + 1); if (!serial->device.data) { WLog_ERR(TAG, "calloc failed!"); error = CHANNEL_RC_NO_MEMORY; goto error_out; } for (i = 0; i <= len; i++) Stream_Write_UINT8(serial->device.data, name[i] < 0 ? '_' : name[i]); if (driver != NULL) { if (_stricmp(driver, "Serial") == 0) serial->ServerSerialDriverId = SerialDriverSerialSys; else if (_stricmp(driver, "SerCx") == 0) serial->ServerSerialDriverId = SerialDriverSerCxSys; else if (_stricmp(driver, "SerCx2") == 0) serial->ServerSerialDriverId = SerialDriverSerCx2Sys; else { assert(FALSE); WLog_Print(serial->log, WLOG_DEBUG, "Unknown server's serial driver: %s. SerCx2 will be used", driver); serial->ServerSerialDriverId = SerialDriverSerialSys; } } else { /* default driver */ serial->ServerSerialDriverId = SerialDriverSerialSys; } if (device->Permissive != NULL) { if (_stricmp(device->Permissive, "permissive") == 0) { serial->permissive = TRUE; } else { WLog_Print(serial->log, WLOG_DEBUG, "Unknown flag: %s", device->Permissive); assert(FALSE); } } WLog_Print(serial->log, WLOG_DEBUG, "Server's serial driver: %s (id: %d)", driver, serial->ServerSerialDriverId); /* TODO: implement auto detection of the server's serial driver */ serial->MainIrpQueue = MessageQueue_New(NULL); if (!serial->MainIrpQueue) { WLog_ERR(TAG, "MessageQueue_New failed!"); error = CHANNEL_RC_NO_MEMORY; goto error_out; } /* IrpThreads content only modified by create_irp_thread() */ serial->IrpThreads = ListDictionary_New(FALSE); if (!serial->IrpThreads) { WLog_ERR(TAG, "ListDictionary_New failed!"); error = CHANNEL_RC_NO_MEMORY; goto error_out; } serial->IrpThreadToBeTerminatedCount = 0; InitializeCriticalSection(&serial->TerminatingIrpThreadsLock); if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) serial))) { WLog_ERR(TAG, "EntryPoints->RegisterDevice failed with error %"PRIu32"!", error); goto error_out; } if (!(serial->MainThread = CreateThread(NULL, 0, serial_thread_func, (void*) serial, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); error = ERROR_INTERNAL_ERROR; goto error_out; } #endif /* __linux __ */ } return error; error_out: #ifdef __linux__ /* to be removed */ ListDictionary_Free(serial->IrpThreads); MessageQueue_Free(serial->MainIrpQueue); Stream_Free(serial->device.data, TRUE); free(serial); #endif /* __linux __ */ return error; }
static void* audin_server_thread_func(void* arg) { wStream* s; void* buffer; DWORD nCount; BYTE MessageId; HANDLE events[8]; BOOL ready = FALSE; HANDLE ChannelEvent; DWORD BytesReturned = 0; audin_server* audin = (audin_server*) arg; buffer = NULL; BytesReturned = 0; ChannelEvent = NULL; if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE) { if (BytesReturned == sizeof(HANDLE)) CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); WTSFreeMemory(buffer); } nCount = 0; events[nCount++] = audin->stopEvent; events[nCount++] = ChannelEvent; /* Wait for the client to confirm that the Audio Input dynamic channel is ready */ while (1) { if (WaitForMultipleObjects(nCount, events, FALSE, 100) == WAIT_OBJECT_0) break; if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualChannelReady, &buffer, &BytesReturned) == FALSE) break; ready = *((BOOL*) buffer); WTSFreeMemory(buffer); if (ready) break; } s = Stream_New(NULL, 4096); if (!s) goto out; if (ready) { audin_server_send_version(audin, s); } while (ready) { if (WaitForMultipleObjects(nCount, events, FALSE, INFINITE) == WAIT_OBJECT_0) break; Stream_SetPosition(s, 0); if (WTSVirtualChannelRead(audin->audin_channel, 0, (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned) == FALSE) { if (BytesReturned == 0) break; Stream_EnsureRemainingCapacity(s, BytesReturned); if (WTSVirtualChannelRead(audin->audin_channel, 0, (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned) == FALSE) { break; } } if (BytesReturned < 1) continue; Stream_Read_UINT8(s, MessageId); BytesReturned--; switch (MessageId) { case MSG_SNDIN_VERSION: if (audin_server_recv_version(audin, s, BytesReturned)) audin_server_send_formats(audin, s); break; case MSG_SNDIN_FORMATS: if (audin_server_recv_formats(audin, s, BytesReturned)) audin_server_send_open(audin, s); break; case MSG_SNDIN_OPEN_REPLY: audin_server_recv_open_reply(audin, s, BytesReturned); break; case MSG_SNDIN_DATA_INCOMING: break; case MSG_SNDIN_DATA: audin_server_recv_data(audin, s, BytesReturned); break; case MSG_SNDIN_FORMATCHANGE: break; default: fprintf(stderr, "audin_server_thread_func: unknown MessageId %d\n", MessageId); break; } } Stream_Free(s, TRUE); out: WTSVirtualChannelClose(audin->audin_channel); audin->audin_channel = NULL; return NULL; }
DWORD TsProxySendToServer(handle_t IDL_handle, byte pRpcMessage[], UINT32 count, UINT32* lengths) { wStream* s; int status; rdpTsg* tsg; BYTE* buffer; UINT32 length; byte* buffer1 = NULL; byte* buffer2 = NULL; byte* buffer3 = NULL; UINT32 buffer1Length; UINT32 buffer2Length; UINT32 buffer3Length; UINT32 numBuffers = 0; UINT32 totalDataBytes = 0; tsg = (rdpTsg*) IDL_handle; buffer1Length = buffer2Length = buffer3Length = 0; if (count > 0) { numBuffers++; buffer1 = &pRpcMessage[0]; buffer1Length = lengths[0]; totalDataBytes += lengths[0] + 4; } if (count > 1) { numBuffers++; buffer2 = &pRpcMessage[1]; buffer2Length = lengths[1]; totalDataBytes += lengths[1] + 4; } if (count > 2) { numBuffers++; buffer3 = &pRpcMessage[2]; buffer3Length = lengths[2]; totalDataBytes += lengths[2] + 4; } length = 28 + totalDataBytes; buffer = (BYTE*) malloc(length); s = Stream_New(buffer, length); /* PCHANNEL_CONTEXT_HANDLE_NOSERIALIZE_NR (20 bytes) */ Stream_Write(s, &tsg->ChannelContext.ContextType, 4); /* ContextType (4 bytes) */ Stream_Write(s, tsg->ChannelContext.ContextUuid, 16); /* ContextUuid (16 bytes) */ Stream_Write_UINT32_BE(s, totalDataBytes); /* totalDataBytes (4 bytes) */ Stream_Write_UINT32_BE(s, numBuffers); /* numBuffers (4 bytes) */ if (buffer1Length > 0) Stream_Write_UINT32_BE(s, buffer1Length); /* buffer1Length (4 bytes) */ if (buffer2Length > 0) Stream_Write_UINT32_BE(s, buffer2Length); /* buffer2Length (4 bytes) */ if (buffer3Length > 0) Stream_Write_UINT32_BE(s, buffer3Length); /* buffer3Length (4 bytes) */ if (buffer1Length > 0) Stream_Write(s, buffer1, buffer1Length); /* buffer1 (variable) */ if (buffer2Length > 0) Stream_Write(s, buffer2, buffer2Length); /* buffer2 (variable) */ if (buffer3Length > 0) Stream_Write(s, buffer3, buffer3Length); /* buffer3 (variable) */ Stream_Length(s) = Stream_GetPosition(s); status = rpc_write(tsg->rpc, Stream_Buffer(s), Stream_Length(s), TsProxySendToServerOpnum); Stream_Free(s, TRUE); if (status <= 0) { fprintf(stderr, "rpc_write failed!\n"); return -1; } return length; }
HANDLE WINAPI FreeRDP_WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualName, DWORD flags) { UINT32 index; wStream* s; rdpMcs* mcs; BOOL joined = FALSE; freerdp_peer* client; rdpPeerChannel* channel; ULONG written; WTSVirtualChannelManager* vcm; if (SessionId == WTS_CURRENT_SESSION) return NULL; vcm = (WTSVirtualChannelManager*) HashTable_GetItemValue(g_ServerHandles, (void*) (UINT_PTR) SessionId); if (!vcm) return NULL; if (!(flags & WTS_CHANNEL_OPTION_DYNAMIC)) { return FreeRDP_WTSVirtualChannelOpen((HANDLE) vcm, SessionId, pVirtualName); } client = vcm->client; mcs = client->context->rdp->mcs; for (index = 0; index < mcs->channelCount; index++) { if (mcs->channels[index].joined && (strncmp(mcs->channels[index].Name, "drdynvc", 7) == 0)) { joined = TRUE; break; } } if (!joined) { SetLastError(ERROR_NOT_FOUND); return NULL; } if (!vcm->drdynvc_channel || (vcm->drdynvc_state != DRDYNVC_STATE_READY)) { SetLastError(ERROR_NOT_READY); return NULL; } channel = (rdpPeerChannel*) calloc(1, sizeof(rdpPeerChannel)); if (!channel) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; } channel->vcm = vcm; channel->client = client; channel->channelType = RDP_PEER_CHANNEL_TYPE_DVC; channel->receiveData = Stream_New(NULL, client->settings->VirtualChannelChunkSize); if (!channel->receiveData) { WLog_ERR(TAG, "Stream_New failed!"); goto error_receiveData; } channel->queue = MessageQueue_New(NULL); if (!channel->queue) goto error_queue; channel->channelId = InterlockedIncrement(&vcm->dvc_channel_id_seq); if (ArrayList_Add(vcm->dynamicVirtualChannels, channel) < 0) goto error_add; s = Stream_New(NULL, 64); if (!s) goto error_s; if (!wts_write_drdynvc_create_request(s, channel->channelId, pVirtualName)) goto error_create; if (!WTSVirtualChannelWrite(vcm->drdynvc_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written)) goto error_create; Stream_Free(s, TRUE); return channel; error_create: Stream_Free(s, TRUE); error_s: ArrayList_Remove(vcm->dynamicVirtualChannels, channel); error_add: MessageQueue_Free(channel->queue); error_queue: Stream_Free(channel->receiveData, TRUE); error_receiveData: free(channel); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; }
int rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback) { int status; wStream* s; UINT16 index; RDPGFX_PLUGIN* gfx; RDPGFX_HEADER header; RDPGFX_CAPSET* capsSet; RDPGFX_CAPSET capsSets[2]; RDPGFX_CAPS_ADVERTISE_PDU pdu; gfx = (RDPGFX_PLUGIN*) callback->plugin; header.flags = 0; header.cmdId = RDPGFX_CMDID_CAPSADVERTISE; pdu.capsSetCount = 0; pdu.capsSets = (RDPGFX_CAPSET*) capsSets; capsSet = &capsSets[pdu.capsSetCount++]; capsSet->version = RDPGFX_CAPVERSION_8; capsSet->flags = 0; if (gfx->ThinClient) capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT; if (gfx->SmallCache) capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE; capsSet = &capsSets[pdu.capsSetCount++]; capsSet->version = RDPGFX_CAPVERSION_81; capsSet->flags = 0; if (gfx->ThinClient) capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT; if (gfx->SmallCache) capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE; if (gfx->H264) capsSet->flags |= RDPGFX_CAPS_FLAG_H264ENABLED; header.pduLength = RDPGFX_HEADER_SIZE + 2 + (pdu.capsSetCount * RDPGFX_CAPSET_SIZE); WLog_Print(gfx->log, WLOG_DEBUG, "SendCapsAdvertisePdu"); s = Stream_New(NULL, header.pduLength); rdpgfx_write_header(s, &header); /* RDPGFX_CAPS_ADVERTISE_PDU */ Stream_Write_UINT16(s, pdu.capsSetCount); /* capsSetCount (2 bytes) */ for (index = 0; index < pdu.capsSetCount; index++) { capsSet = &(pdu.capsSets[index]); Stream_Write_UINT32(s, capsSet->version); /* version (4 bytes) */ Stream_Write_UINT32(s, 4); /* capsDataLength (4 bytes) */ Stream_Write_UINT32(s, capsSet->flags); /* capsData (4 bytes) */ } Stream_SealLength(s); status = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s), Stream_Buffer(s), NULL); Stream_Free(s, TRUE); return status; }
HANDLE WINAPI FreeRDP_WTSVirtualChannelOpen(HANDLE hServer, DWORD SessionId, LPSTR pVirtualName) { int length; UINT32 index; rdpMcs* mcs; BOOL joined = FALSE; freerdp_peer* client; rdpPeerChannel* channel; WTSVirtualChannelManager* vcm; HANDLE hChannelHandle = NULL; vcm = (WTSVirtualChannelManager*) hServer; if (!vcm) { SetLastError(ERROR_INVALID_DATA); return NULL; } client = vcm->client; mcs = client->context->rdp->mcs; length = strlen(pVirtualName); if (length > 8) { SetLastError(ERROR_NOT_FOUND); return NULL; } for (index = 0; index < mcs->channelCount; index++) { if (mcs->channels[index].joined && (strncmp(mcs->channels[index].Name, pVirtualName, length) == 0)) { joined = TRUE; break; } } if (!joined) { SetLastError(ERROR_NOT_FOUND); return NULL; } channel = (rdpPeerChannel*) mcs->channels[index].handle; if (!channel) { channel = (rdpPeerChannel*) calloc(1, sizeof(rdpPeerChannel)); if (!channel) goto error_channel_alloc; channel->vcm = vcm; channel->client = client; channel->channelId = mcs->channels[index].ChannelId; channel->index = index; channel->channelType = RDP_PEER_CHANNEL_TYPE_SVC; channel->receiveData = Stream_New(NULL, client->settings->VirtualChannelChunkSize); if (!channel->receiveData) { WLog_ERR(TAG, "Stream_New failed!"); goto error_receiveData; } channel->queue = MessageQueue_New(NULL); if (!channel->queue) goto error_queue; mcs->channels[index].handle = channel; } hChannelHandle = (HANDLE) channel; return hChannelHandle; error_queue: Stream_Free(channel->receiveData, TRUE); error_receiveData: free(channel); error_channel_alloc: SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; }
BOOL nego_send_negotiation_request(rdpNego* nego) { wStream* s; int length; int bm, em; BYTE flags = 0; int cookie_length; s = Stream_New(NULL, 512); length = TPDU_CONNECTION_REQUEST_LENGTH; bm = Stream_GetPosition(s); Stream_Seek(s, length); if (nego->RoutingToken) { Stream_Write(s, nego->RoutingToken, nego->RoutingTokenLength); /* Ensure Routing Token is correctly terminated - may already be present in string */ if ((nego->RoutingTokenLength > 2) && (nego->RoutingToken[nego->RoutingTokenLength - 2] == 0x0D) && (nego->RoutingToken[nego->RoutingTokenLength - 1] == 0x0A)) { WLog_DBG(TAG, "Routing token looks correctly terminated - use verbatim"); length +=nego->RoutingTokenLength; } else { WLog_DBG(TAG, "Adding terminating CRLF to routing token"); Stream_Write_UINT8(s, 0x0D); /* CR */ Stream_Write_UINT8(s, 0x0A); /* LF */ length += nego->RoutingTokenLength + 2; } } else if (nego->cookie) { cookie_length = strlen(nego->cookie); if (cookie_length > (int) nego->CookieMaxLength) cookie_length = nego->CookieMaxLength; Stream_Write(s, "Cookie: mstshash=", 17); Stream_Write(s, (BYTE*) nego->cookie, cookie_length); Stream_Write_UINT8(s, 0x0D); /* CR */ Stream_Write_UINT8(s, 0x0A); /* LF */ length += cookie_length + 19; } WLog_DBG(TAG, "RequestedProtocols: %d", nego->RequestedProtocols); if ((nego->RequestedProtocols > PROTOCOL_RDP) || (nego->sendNegoData)) { /* RDP_NEG_DATA must be present for TLS and NLA */ if (nego->RestrictedAdminModeRequired) flags |= RESTRICTED_ADMIN_MODE_REQUIRED; Stream_Write_UINT8(s, TYPE_RDP_NEG_REQ); Stream_Write_UINT8(s, flags); Stream_Write_UINT16(s, 8); /* RDP_NEG_DATA length (8) */ Stream_Write_UINT32(s, nego->RequestedProtocols); /* requestedProtocols */ length += 8; } em = Stream_GetPosition(s); Stream_SetPosition(s, bm); tpkt_write_header(s, length); tpdu_write_connection_request(s, length - 5); Stream_SetPosition(s, em); Stream_SealLength(s); if (transport_write(nego->transport, s) < 0) { Stream_Free(s, TRUE); return FALSE; } Stream_Free(s, TRUE); return TRUE; }
static BOOL TestStream_Create(int count, BOOL selfAlloc) { int i, len, cap, pos; wStream *s = NULL; void* buffer = NULL; for (i = 0; i < count; i++) { len = cap = i+1; pos = 0; if (selfAlloc) { if (!(buffer = malloc(cap))) { printf("%s: failed to allocate buffer of size %d\n", __FUNCTION__, cap); goto fail; } } if (!(s = Stream_New(selfAlloc ? buffer : NULL, len))) { printf("%s: Stream_New failed for stream #%d\n", __FUNCTION__, i); goto fail; } if (!TestStream_Verify(s, cap, len, pos)) { goto fail; } for (pos = 0; pos < len; pos++) { Stream_SetPosition(s, pos); Stream_SealLength(s); if (!TestStream_Verify(s, cap, pos, pos)) { goto fail; } } if (selfAlloc) { memset(buffer, i%256, cap); if (memcmp(buffer, Stream_Buffer(s), cap)) { printf("%s: buffer memory corruption\n", __FUNCTION__); goto fail; } } Stream_Free(s, buffer ? FALSE : TRUE); free(buffer); } return TRUE; fail: free(buffer); if (s) { Stream_Free(s, buffer ? FALSE : TRUE); } return FALSE; }
static BOOL rdp_client_establish_keys(rdpRdp* rdp) { BYTE* mod; BYTE* exp; wStream* s; UINT32 length; UINT32 key_len; int status = 0; BOOL ret = FALSE; rdpSettings* settings; BYTE* crypt_client_random = NULL; settings = rdp->settings; if (!settings->UseRdpSecurityLayer) { /* no RDP encryption */ return TRUE; } /* encrypt client random */ free(settings->ClientRandom); settings->ClientRandomLength = CLIENT_RANDOM_LENGTH; settings->ClientRandom = malloc(settings->ClientRandomLength); if (!settings->ClientRandom) return FALSE; winpr_RAND(settings->ClientRandom, settings->ClientRandomLength); key_len = settings->RdpServerCertificate->cert_info.ModulusLength; mod = settings->RdpServerCertificate->cert_info.Modulus; exp = settings->RdpServerCertificate->cert_info.exponent; /* * client random must be (bitlen / 8) + 8 - see [MS-RDPBCGR] 5.3.4.1 * for details */ crypt_client_random = calloc(key_len + 8, 1); if (!crypt_client_random) return FALSE; crypto_rsa_public_encrypt(settings->ClientRandom, settings->ClientRandomLength, key_len, mod, exp, crypt_client_random); /* send crypt client random to server */ length = RDP_PACKET_HEADER_MAX_LENGTH + RDP_SECURITY_HEADER_LENGTH + 4 + key_len + 8; s = Stream_New(NULL, length); if (!s) { WLog_ERR(TAG, "Stream_New failed!"); goto end; } rdp_write_header(rdp, s, length, MCS_GLOBAL_CHANNEL_ID); rdp_write_security_header(s, SEC_EXCHANGE_PKT | SEC_LICENSE_ENCRYPT_SC); length = key_len + 8; Stream_Write_UINT32(s, length); Stream_Write(s, crypt_client_random, length); Stream_SealLength(s); status = transport_write(rdp->mcs->transport, s); Stream_Free(s, TRUE); if (status < 0) goto end; rdp->do_crypt_license = TRUE; /* now calculate encrypt / decrypt and update keys */ if (!security_establish_keys(settings->ClientRandom, rdp)) goto end; rdp->do_crypt = TRUE; if (settings->SaltedChecksum) rdp->do_secure_checksum = TRUE; if (settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS) { rdp->fips_encrypt = winpr_Cipher_New(WINPR_CIPHER_DES_EDE3_CBC, WINPR_ENCRYPT, rdp->fips_encrypt_key, fips_ivec); if (!rdp->fips_encrypt) { WLog_ERR(TAG, "unable to allocate des3 encrypt key"); goto end; } rdp->fips_decrypt = winpr_Cipher_New(WINPR_CIPHER_DES_EDE3_CBC, WINPR_DECRYPT, rdp->fips_decrypt_key, fips_ivec); if (!rdp->fips_decrypt) { WLog_ERR(TAG, "unable to allocate des3 decrypt key"); goto end; } ret = TRUE; goto end; } rdp->rc4_decrypt_key = winpr_RC4_New(rdp->decrypt_key, rdp->rc4_key_len); rdp->rc4_encrypt_key = winpr_RC4_New(rdp->encrypt_key, rdp->rc4_key_len); if (!rdp->rc4_decrypt_key || !rdp->rc4_encrypt_key) goto end; ret = TRUE; end: free(crypt_client_random); if (!ret) { winpr_Cipher_Free(rdp->fips_decrypt); winpr_Cipher_Free(rdp->fips_encrypt); winpr_RC4_Free(rdp->rc4_decrypt_key); winpr_RC4_Free(rdp->rc4_encrypt_key); rdp->fips_decrypt = NULL; rdp->fips_encrypt = NULL; rdp->rc4_decrypt_key = NULL; rdp->rc4_encrypt_key = NULL; } return ret; }