/** * Function description * * @return 0 on success, otherwise a Win32 error code */ static UINT cliprdr_server_receive_format_list(CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header) { UINT32 index; UINT32 dataLen; UINT32 position; BOOL asciiNames; int formatNameLength; char* szFormatName; WCHAR* wszFormatName; CLIPRDR_FORMAT* formats = NULL; CLIPRDR_FORMAT_LIST formatList; CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; UINT error = CHANNEL_RC_OK; dataLen = header->dataLen; asciiNames = (header->msgFlags & CB_ASCII_NAMES) ? TRUE : FALSE; formatList.msgType = CB_FORMAT_LIST; formatList.msgFlags = header->msgFlags; formatList.dataLen = header->dataLen; index = 0; formatList.numFormats = 0; position = Stream_GetPosition(s); if (!header->dataLen) { /* empty format list */ formatList.formats = NULL; formatList.numFormats = 0; } else if (!cliprdr->useLongFormatNames) { formatList.numFormats = (dataLen / 36); if ((formatList.numFormats * 36) != dataLen) { WLog_ERR(TAG, "Invalid short format list length: %d", dataLen); return ERROR_INVALID_PARAMETER; } if (formatList.numFormats) formats = (CLIPRDR_FORMAT*) calloc(formatList.numFormats, sizeof(CLIPRDR_FORMAT)); if (!formats) { WLog_ERR(TAG, "calloc failed!"); return CHANNEL_RC_NO_MEMORY; } formatList.formats = formats; while (dataLen) { Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */ dataLen -= 4; formats[index].formatName = NULL; if (asciiNames) { szFormatName = (char*) Stream_Pointer(s); if (szFormatName[0]) { formats[index].formatName = (char*) malloc(32 + 1); CopyMemory(formats[index].formatName, szFormatName, 32); formats[index].formatName[32] = '\0'; } } else { wszFormatName = (WCHAR*) Stream_Pointer(s); if (wszFormatName[0]) { ConvertFromUnicode(CP_UTF8, 0, wszFormatName, 16, &(formats[index].formatName), 0, NULL, NULL); } } Stream_Seek(s, 32); dataLen -= 32; index++; } } else { while (dataLen) { Stream_Seek(s, 4); /* formatId (4 bytes) */ dataLen -= 4; wszFormatName = (WCHAR*) Stream_Pointer(s); if (!wszFormatName[0]) formatNameLength = 0; else formatNameLength = _wcslen(wszFormatName); Stream_Seek(s, (formatNameLength + 1) * 2); dataLen -= ((formatNameLength + 1) * 2); formatList.numFormats++; } dataLen = formatList.dataLen; Stream_SetPosition(s, position); if (formatList.numFormats) formats = (CLIPRDR_FORMAT*) calloc(formatList.numFormats, sizeof(CLIPRDR_FORMAT)); if (!formats) { WLog_ERR(TAG, "calloc failed!"); return CHANNEL_RC_NO_MEMORY; } formatList.formats = formats; while (dataLen) { Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */ dataLen -= 4; formats[index].formatName = NULL; wszFormatName = (WCHAR*) Stream_Pointer(s); if (!wszFormatName[0]) formatNameLength = 0; else formatNameLength = _wcslen(wszFormatName); if (formatNameLength) { ConvertFromUnicode(CP_UTF8, 0, wszFormatName, -1, &(formats[index].formatName), 0, NULL, NULL); } Stream_Seek(s, (formatNameLength + 1) * 2); dataLen -= ((formatNameLength + 1) * 2); index++; } } WLog_DBG(TAG, "ClientFormatList: numFormats: %d", formatList.numFormats); IFCALLRET(context->ClientFormatList, error, context, &formatList); if (error) WLog_ERR(TAG, "ClientFormatList failed with error %lu!", error); for (index = 0; index < formatList.numFormats; index++) { free(formatList.formats[index].formatName); } free(formatList.formats); return error; }
BOOL gcc_read_client_core_data(wStream* s, rdpMcs* mcs, UINT16 blockLength) { char* str = NULL; UINT32 version; BYTE connectionType = 0; UINT32 clientColorDepth; UINT16 colorDepth = 0; UINT16 postBeta2ColorDepth = 0; UINT16 highColorDepth = 0; UINT16 supportedColorDepths = 0; UINT32 serverSelectedProtocol = 0; UINT32 desktopPhysicalWidth = 0; UINT32 desktopPhysicalHeight = 0; UINT16 desktopOrientation = 0; UINT32 desktopScaleFactor = 0; UINT32 deviceScaleFactor = 0; UINT16 earlyCapabilityFlags = 0; rdpSettings* settings = mcs->settings; /* Length of all required fields, until imeFileName */ if (blockLength < 128) return FALSE; Stream_Read_UINT32(s, version); /* version (4 bytes) */ settings->RdpVersion = (version == RDP_VERSION_4 ? 4 : 7); Stream_Read_UINT16(s, settings->DesktopWidth); /* DesktopWidth (2 bytes) */ Stream_Read_UINT16(s, settings->DesktopHeight); /* DesktopHeight (2 bytes) */ Stream_Read_UINT16(s, colorDepth); /* ColorDepth (2 bytes) */ Stream_Seek_UINT16(s); /* SASSequence (Secure Access Sequence) (2 bytes) */ Stream_Read_UINT32(s, settings->KeyboardLayout); /* KeyboardLayout (4 bytes) */ Stream_Read_UINT32(s, settings->ClientBuild); /* ClientBuild (4 bytes) */ /* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */ ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), 32 / 2, &str, 0, NULL, NULL); Stream_Seek(s, 32); sprintf_s(settings->ClientHostname, 31, "%s", str); settings->ClientHostname[31] = 0; free(str); str = NULL; Stream_Read_UINT32(s, settings->KeyboardType); /* KeyboardType (4 bytes) */ Stream_Read_UINT32(s, settings->KeyboardSubType); /* KeyboardSubType (4 bytes) */ Stream_Read_UINT32(s, settings->KeyboardFunctionKey); /* KeyboardFunctionKey (4 bytes) */ WLog_DBG(TAG, "KeyboardLayout=%x, KeyboardType=%x, KeyboardSubType=%x, KeyboardFunctionKey=%x", settings->KeyboardLayout, settings->KeyboardType, settings->KeyboardSubType, settings->KeyboardFunctionKey); Stream_Seek(s, 64); /* imeFileName (64 bytes) */ blockLength -= 128; /** * The following fields are all optional. If one field is present, all of the preceding * fields MUST also be present. If one field is not present, all of the subsequent fields * MUST NOT be present. * We must check the bytes left before reading each field. */ do { if (blockLength < 2) break; Stream_Read_UINT16(s, postBeta2ColorDepth); /* postBeta2ColorDepth (2 bytes) */ blockLength -= 2; if (blockLength < 2) break; Stream_Seek_UINT16(s); /* clientProductID (2 bytes) */ blockLength -= 2; if (blockLength < 4) break; Stream_Seek_UINT32(s); /* serialNumber (4 bytes) */ blockLength -= 4; if (blockLength < 2) break; Stream_Read_UINT16(s, highColorDepth); /* highColorDepth (2 bytes) */ blockLength -= 2; if (blockLength < 2) break; Stream_Read_UINT16(s, supportedColorDepths); /* supportedColorDepths (2 bytes) */ blockLength -= 2; if (blockLength < 2) break; Stream_Read_UINT16(s, earlyCapabilityFlags); /* earlyCapabilityFlags (2 bytes) */ settings->EarlyCapabilityFlags = (UINT32) earlyCapabilityFlags; blockLength -= 2; if (blockLength < 64) break; ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), 64 / 2, &str, 0, NULL, NULL); Stream_Seek(s, 64); /* clientDigProductId (64 bytes) */ sprintf_s(settings->ClientProductId, 32, "%s", str); free(str); blockLength -= 64; if (blockLength < 1) break; Stream_Read_UINT8(s, connectionType); /* connectionType (1 byte) */ blockLength -= 1; if (blockLength < 1) break; Stream_Seek_UINT8(s); /* pad1octet (1 byte) */ blockLength -= 1; if (blockLength < 4) break; Stream_Read_UINT32(s, serverSelectedProtocol); /* serverSelectedProtocol (4 bytes) */ blockLength -= 4; if (blockLength < 4) break; Stream_Read_UINT32(s, desktopPhysicalWidth); /* desktopPhysicalWidth (4 bytes) */ blockLength -= 4; if (blockLength < 4) break; Stream_Read_UINT32(s, desktopPhysicalHeight); /* desktopPhysicalHeight (4 bytes) */ blockLength -= 4; if (blockLength < 2) break; Stream_Read_UINT16(s, desktopOrientation); /* desktopOrientation (2 bytes) */ blockLength -= 2; if (blockLength < 4) break; Stream_Read_UINT32(s, desktopScaleFactor); /* desktopScaleFactor (4 bytes) */ blockLength -= 4; if (blockLength < 4) break; Stream_Read_UINT32(s, deviceScaleFactor); /* deviceScaleFactor (4 bytes) */ blockLength -= 4; if (settings->SelectedProtocol != serverSelectedProtocol) return FALSE; } while (0); if (highColorDepth > 0) { if (earlyCapabilityFlags & RNS_UD_CS_WANT_32BPP_SESSION) clientColorDepth = 32; else clientColorDepth = highColorDepth; } else if (postBeta2ColorDepth > 0) { switch (postBeta2ColorDepth) { case RNS_UD_COLOR_4BPP: clientColorDepth = 4; break; case RNS_UD_COLOR_8BPP: clientColorDepth = 8; break; case RNS_UD_COLOR_16BPP_555: clientColorDepth = 15; break; case RNS_UD_COLOR_16BPP_565: clientColorDepth = 16; break; case RNS_UD_COLOR_24BPP: clientColorDepth = 24; break; default: return FALSE; } } else { switch (colorDepth) { case RNS_UD_COLOR_4BPP: clientColorDepth = 4; break; case RNS_UD_COLOR_8BPP: clientColorDepth = 8; break; default: return FALSE; } } /* * If we are in server mode, accept client's color depth only if * it is smaller than ours. This is what Windows server does. */ if ((clientColorDepth < settings->ColorDepth) || !settings->ServerMode) settings->ColorDepth = clientColorDepth; if (settings->NetworkAutoDetect) settings->NetworkAutoDetect = (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_NETWORK_AUTODETECT) ? TRUE : FALSE; if (settings->SupportHeartbeatPdu) settings->SupportHeartbeatPdu = (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_HEARTBEAT_PDU) ? TRUE : FALSE; if (settings->SupportGraphicsPipeline) settings->SupportGraphicsPipeline = (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL) ? TRUE : FALSE; if (settings->SupportDynamicTimeZone) settings->SupportDynamicTimeZone = (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE) ? TRUE : FALSE; if (!(earlyCapabilityFlags & RNS_UD_CS_VALID_CONNECTION_TYPE)) connectionType = 0; settings->SupportErrorInfoPdu = earlyCapabilityFlags & RNS_UD_CS_SUPPORT_ERRINFO_PDU; settings->ConnectionType = connectionType; return TRUE; }
/** * Function description * * @return 0 on success, otherwise a Win32 error code */ static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp) { int status; void* key; UINT32 FileId; DRIVE_FILE* file; BYTE Information; UINT32 DesiredAccess; UINT32 CreateDisposition; UINT32 CreateOptions; UINT32 PathLength; char* path = NULL; Stream_Read_UINT32(irp->input, DesiredAccess); Stream_Seek(irp->input, 16); /* AllocationSize(8), FileAttributes(4), SharedAccess(4) */ Stream_Read_UINT32(irp->input, CreateDisposition); Stream_Read_UINT32(irp->input, CreateOptions); Stream_Read_UINT32(irp->input, PathLength); status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(irp->input), PathLength / 2, &path, 0, NULL, NULL); if (status < 1) { path = (char*) calloc(1, 1); if (!path) { WLog_ERR(TAG, "calloc failed!"); return CHANNEL_RC_NO_MEMORY; } } FileId = irp->devman->id_sequence++; file = drive_file_new(drive->path, path, FileId, DesiredAccess, CreateDisposition, CreateOptions); if (!file) { irp->IoStatus = STATUS_UNSUCCESSFUL; FileId = 0; Information = 0; } else if (file->err) { FileId = 0; Information = 0; /* map errno to windows result */ irp->IoStatus = drive_map_posix_err(file->err); drive_file_free(file); } else { key = (void*)(size_t) file->id; if (!ListDictionary_Add(drive->files, key, file)) { WLog_ERR(TAG, "ListDictionary_Add failed!"); free(path); return ERROR_INTERNAL_ERROR; } switch (CreateDisposition) { case FILE_SUPERSEDE: case FILE_OPEN: case FILE_CREATE: case FILE_OVERWRITE: Information = FILE_SUPERSEDED; break; case FILE_OPEN_IF: Information = FILE_OPENED; break; case FILE_OVERWRITE_IF: Information = FILE_OVERWRITTEN; break; default: Information = 0; break; } } Stream_Write_UINT32(irp->output, FileId); Stream_Write_UINT8(irp->output, Information); free(path); return irp->Complete(irp); }
BOOL rdp_decrypt(rdpRdp* rdp, wStream* s, int length, UINT16 securityFlags) { BYTE cmac[8]; BYTE wmac[8]; if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS) { UINT16 len; BYTE version, pad; BYTE* sig; if (Stream_GetRemainingLength(s) < 12) return FALSE; Stream_Read_UINT16(s, len); /* 0x10 */ Stream_Read_UINT8(s, version); /* 0x1 */ Stream_Read_UINT8(s, pad); sig = Stream_Pointer(s); Stream_Seek(s, 8); /* signature */ length -= 12; if (!security_fips_decrypt(Stream_Pointer(s), length, rdp)) { DEBUG_WARN( "FATAL: cannot decrypt\n"); return FALSE; /* TODO */ } if (!security_fips_check_signature(Stream_Pointer(s), length - pad, sig, rdp)) { DEBUG_WARN( "FATAL: invalid packet signature\n"); return FALSE; /* TODO */ } Stream_Length(s) -= pad; return TRUE; } if (Stream_GetRemainingLength(s) < 8) return FALSE; Stream_Read(s, wmac, sizeof(wmac)); length -= sizeof(wmac); if (!security_decrypt(Stream_Pointer(s), length, rdp)) return FALSE; if (securityFlags & SEC_SECURE_CHECKSUM) security_salted_mac_signature(rdp, Stream_Pointer(s), length, FALSE, cmac); else security_mac_signature(rdp, Stream_Pointer(s), length, cmac); if (memcmp(wmac, cmac, sizeof(wmac)) != 0) { DEBUG_WARN( "WARNING: invalid packet signature\n"); /* * Because Standard RDP Security is totally broken, * and cannot protect against MITM, don't treat signature * verification failure as critical. This at least enables * us to work with broken RDP clients and servers that * generate invalid signatures. */ //return FALSE; } return TRUE; }
void gcc_write_server_security_data(wStream* s, rdpMcs* mcs) { CryptoMd5 md5; BYTE* sigData; int expLen, keyLen, sigDataLen; BYTE encryptedSignature[TSSK_KEY_LENGTH]; BYTE signature[sizeof(initial_signature)]; UINT32 headerLen, serverRandomLen, serverCertLen, wPublicKeyBlobLen; rdpSettings* settings = mcs->settings; /** * Re: settings->EncryptionLevel: * This is configured/set by the server implementation and serves the same * purpose as the "Encryption Level" setting in the RDP-Tcp configuration * dialog of Microsoft's Remote Desktop Session Host Configuration. * Re: settings->EncryptionMethods: * at this point this setting contains the client's supported encryption * methods we've received in gcc_read_client_security_data() */ if (!settings->UseRdpSecurityLayer) { /* TLS/NLA is used: disable rdp style encryption */ settings->EncryptionLevel = ENCRYPTION_LEVEL_NONE; } /* verify server encryption level value */ switch (settings->EncryptionLevel) { case ENCRYPTION_LEVEL_NONE: WLog_INFO(TAG, "Active rdp encryption level: NONE"); break; case ENCRYPTION_LEVEL_FIPS: WLog_INFO(TAG, "Active rdp encryption level: FIPS Compliant"); break; case ENCRYPTION_LEVEL_HIGH: WLog_INFO(TAG, "Active rdp encryption level: HIGH"); break; case ENCRYPTION_LEVEL_LOW: WLog_INFO(TAG, "Active rdp encryption level: LOW"); break; case ENCRYPTION_LEVEL_CLIENT_COMPATIBLE: WLog_INFO(TAG, "Active rdp encryption level: CLIENT-COMPATIBLE"); break; default: WLog_ERR(TAG, "Invalid server encryption level 0x%08X", settings->EncryptionLevel); WLog_ERR(TAG, "Switching to encryption level CLIENT-COMPATIBLE"); settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE; } /* choose rdp encryption method based on server level and client methods */ switch (settings->EncryptionLevel) { case ENCRYPTION_LEVEL_NONE: /* The only valid method is NONE in this case */ settings->EncryptionMethods = ENCRYPTION_METHOD_NONE; break; case ENCRYPTION_LEVEL_FIPS: /* The only valid method is FIPS in this case */ if (!(settings->EncryptionMethods & ENCRYPTION_METHOD_FIPS)) { WLog_WARN(TAG, "client does not support FIPS as required by server configuration"); } settings->EncryptionMethods = ENCRYPTION_METHOD_FIPS; break; case ENCRYPTION_LEVEL_HIGH: /* Maximum key strength supported by the server must be used (128 bit)*/ if (!(settings->EncryptionMethods & ENCRYPTION_METHOD_128BIT)) { WLog_WARN(TAG, "client does not support 128 bit encryption method as required by server configuration"); } settings->EncryptionMethods = ENCRYPTION_METHOD_128BIT; break; case ENCRYPTION_LEVEL_LOW: case ENCRYPTION_LEVEL_CLIENT_COMPATIBLE: /* Maximum key strength supported by the client must be used */ if (settings->EncryptionMethods & ENCRYPTION_METHOD_128BIT) settings->EncryptionMethods = ENCRYPTION_METHOD_128BIT; else if (settings->EncryptionMethods & ENCRYPTION_METHOD_56BIT) settings->EncryptionMethods = ENCRYPTION_METHOD_56BIT; else if (settings->EncryptionMethods & ENCRYPTION_METHOD_40BIT) settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT; else if (settings->EncryptionMethods & ENCRYPTION_METHOD_FIPS) settings->EncryptionMethods = ENCRYPTION_METHOD_FIPS; else { WLog_WARN(TAG, "client has not announced any supported encryption methods"); settings->EncryptionMethods = ENCRYPTION_METHOD_128BIT; } break; default: WLog_ERR(TAG, "internal error: unknown encryption level"); } /* log selected encryption method */ switch (settings->EncryptionMethods) { case ENCRYPTION_METHOD_NONE: WLog_INFO(TAG, "Selected rdp encryption method: NONE"); break; case ENCRYPTION_METHOD_40BIT: WLog_INFO(TAG, "Selected rdp encryption method: 40BIT"); break; case ENCRYPTION_METHOD_56BIT: WLog_INFO(TAG, "Selected rdp encryption method: 56BIT"); break; case ENCRYPTION_METHOD_128BIT: WLog_INFO(TAG, "Selected rdp encryption method: 128BIT"); break; case ENCRYPTION_METHOD_FIPS: WLog_INFO(TAG, "Selected rdp encryption method: FIPS"); break; default: WLog_ERR(TAG, "internal error: unknown encryption method"); } headerLen = 12; keyLen = 0; wPublicKeyBlobLen = 0; serverRandomLen = 0; serverCertLen = 0; if (settings->EncryptionMethods != ENCRYPTION_METHOD_NONE) { serverRandomLen = 32; keyLen = settings->RdpServerRsaKey->ModulusLength; expLen = sizeof(settings->RdpServerRsaKey->exponent); wPublicKeyBlobLen = 4; /* magic (RSA1) */ wPublicKeyBlobLen += 4; /* keylen */ wPublicKeyBlobLen += 4; /* bitlen */ wPublicKeyBlobLen += 4; /* datalen */ wPublicKeyBlobLen += expLen; wPublicKeyBlobLen += keyLen; wPublicKeyBlobLen += 8; /* 8 bytes of zero padding */ serverCertLen = 4; /* dwVersion */ serverCertLen += 4; /* dwSigAlgId */ serverCertLen += 4; /* dwKeyAlgId */ serverCertLen += 2; /* wPublicKeyBlobType */ serverCertLen += 2; /* wPublicKeyBlobLen */ serverCertLen += wPublicKeyBlobLen; serverCertLen += 2; /* wSignatureBlobType */ serverCertLen += 2; /* wSignatureBlobLen */ serverCertLen += sizeof(encryptedSignature); /* SignatureBlob */ serverCertLen += 8; /* 8 bytes of zero padding */ headerLen += sizeof(serverRandomLen); headerLen += sizeof(serverCertLen); headerLen += serverRandomLen; headerLen += serverCertLen; } gcc_write_user_data_header(s, SC_SECURITY, headerLen); Stream_Write_UINT32(s, settings->EncryptionMethods); /* encryptionMethod */ Stream_Write_UINT32(s, settings->EncryptionLevel); /* encryptionLevel */ if (settings->EncryptionMethods == ENCRYPTION_METHOD_NONE) { return; } Stream_Write_UINT32(s, serverRandomLen); /* serverRandomLen */ Stream_Write_UINT32(s, serverCertLen); /* serverCertLen */ settings->ServerRandomLength = serverRandomLen; settings->ServerRandom = (BYTE*) malloc(serverRandomLen); crypto_nonce(settings->ServerRandom, serverRandomLen); Stream_Write(s, settings->ServerRandom, serverRandomLen); sigData = Stream_Pointer(s); Stream_Write_UINT32(s, CERT_CHAIN_VERSION_1); /* dwVersion (4 bytes) */ Stream_Write_UINT32(s, SIGNATURE_ALG_RSA); /* dwSigAlgId */ Stream_Write_UINT32(s, KEY_EXCHANGE_ALG_RSA); /* dwKeyAlgId */ Stream_Write_UINT16(s, BB_RSA_KEY_BLOB); /* wPublicKeyBlobType */ Stream_Write_UINT16(s, wPublicKeyBlobLen); /* wPublicKeyBlobLen */ Stream_Write(s, "RSA1", 4); /* magic */ Stream_Write_UINT32(s, keyLen + 8); /* keylen */ Stream_Write_UINT32(s, keyLen * 8); /* bitlen */ Stream_Write_UINT32(s, keyLen - 1); /* datalen */ Stream_Write(s, settings->RdpServerRsaKey->exponent, expLen); Stream_Write(s, settings->RdpServerRsaKey->Modulus, keyLen); Stream_Zero(s, 8); sigDataLen = Stream_Pointer(s) - sigData; Stream_Write_UINT16(s, BB_RSA_SIGNATURE_BLOB); /* wSignatureBlobType */ Stream_Write_UINT16(s, sizeof(encryptedSignature) + 8); /* wSignatureBlobLen */ memcpy(signature, initial_signature, sizeof(initial_signature)); md5 = crypto_md5_init(); if (!md5) { WLog_ERR(TAG, "unable to allocate a md5"); return; } crypto_md5_update(md5, sigData, sigDataLen); crypto_md5_final(md5, signature); crypto_rsa_private_encrypt(signature, sizeof(signature), TSSK_KEY_LENGTH, tssk_modulus, tssk_privateExponent, encryptedSignature); Stream_Write(s, encryptedSignature, sizeof(encryptedSignature)); Stream_Zero(s, 8); }
BOOL certificate_read_server_proprietary_certificate(rdpCertificate* certificate, wStream* s) { UINT32 dwSigAlgId; UINT32 dwKeyAlgId; UINT32 wPublicKeyBlobType; UINT32 wPublicKeyBlobLen; UINT32 wSignatureBlobType; UINT32 wSignatureBlobLen; BYTE* sigdata; int sigdatalen; if (Stream_GetRemainingLength(s) < 12) return FALSE; /* -4, because we need to include dwVersion */ sigdata = Stream_Pointer(s) - 4; Stream_Read_UINT32(s, dwSigAlgId); Stream_Read_UINT32(s, dwKeyAlgId); if (!((dwSigAlgId == SIGNATURE_ALG_RSA) && (dwKeyAlgId == KEY_EXCHANGE_ALG_RSA))) { WLog_ERR(TAG, "unsupported signature or key algorithm, dwSigAlgId=%d dwKeyAlgId=%d", dwSigAlgId, dwKeyAlgId); return FALSE; } Stream_Read_UINT16(s, wPublicKeyBlobType); if (wPublicKeyBlobType != BB_RSA_KEY_BLOB) { WLog_ERR(TAG, "unsupported public key blob type %d", wPublicKeyBlobType); return FALSE; } Stream_Read_UINT16(s, wPublicKeyBlobLen); if (Stream_GetRemainingLength(s) < wPublicKeyBlobLen) return FALSE; if (!certificate_process_server_public_key(certificate, s, wPublicKeyBlobLen)) { WLog_ERR(TAG, "error in server public key"); return FALSE; } if (Stream_GetRemainingLength(s) < 4) return FALSE; sigdatalen = Stream_Pointer(s) - sigdata; Stream_Read_UINT16(s, wSignatureBlobType); if (wSignatureBlobType != BB_RSA_SIGNATURE_BLOB) { WLog_ERR(TAG, "unsupported blob signature %d", wSignatureBlobType); return FALSE; } Stream_Read_UINT16(s, wSignatureBlobLen); if (Stream_GetRemainingLength(s) < wSignatureBlobLen) { WLog_ERR(TAG, "not enought bytes for signature(len=%d)", wSignatureBlobLen); return FALSE; } if (wSignatureBlobLen != 72) { WLog_ERR(TAG, "invalid signature length (got %d, expected %d)", wSignatureBlobLen, 64); return FALSE; } if (!certificate_process_server_public_signature(certificate, sigdata, sigdatalen, s, wSignatureBlobLen)) { WLog_ERR(TAG, "unable to parse server public signature"); return FALSE; } return TRUE; }
int transport_write(rdpTransport* transport, wStream* s) { int length; int status = -1; EnterCriticalSection(&(transport->WriteLock)); length = Stream_GetPosition(s); Stream_SetPosition(s, 0); #ifdef WITH_DEBUG_TRANSPORT if (length > 0) { fprintf(stderr, "Local > Remote\n"); winpr_HexDump(Stream_Buffer(s), length); } #endif if (length > 0) { WLog_Packet(transport->log, WLOG_TRACE, Stream_Buffer(s), length, WLOG_PACKET_OUTBOUND); } while (length > 0) { status = BIO_write(transport->frontBio, Stream_Pointer(s), length); if (status <= 0) { /* the buffered BIO that is at the end of the chain always says OK for writing, * so a retry means that for any reason we need to read. The most probable * is a SSL or TSG BIO in the chain. */ if (!BIO_should_retry(transport->frontBio)) return status; /* non-blocking can live with blocked IOs */ if (!transport->blocking) return status; if (transport_wait_for_write(transport) < 0) { fprintf(stderr, "%s: error when selecting for write\n", __FUNCTION__); return -1; } continue; } if (transport->blocking || transport->settings->WaitForOutputBufferFlush) { /* blocking transport, we must ensure the write buffer is really empty */ rdpTcp *out = transport->TcpOut; while (out->writeBlocked) { if (transport_wait_for_write(transport) < 0) { fprintf(stderr, "%s: error when selecting for write\n", __FUNCTION__); return -1; } if (!transport_bio_buffered_drain(out->bufferedBio)) { fprintf(stderr, "%s: error when draining outputBuffer\n", __FUNCTION__); return -1; } } } length -= status; Stream_Seek(s, status); } if (status < 0) { /* A write error indicates that the peer has dropped the connection */ transport->layer = TRANSPORT_LAYER_CLOSED; } if (s->pool) Stream_Release(s); LeaveCriticalSection(&(transport->WriteLock)); return status; }
int tsmf_ifman_update_geometry_info(TSMF_IFMAN* ifman) { TSMF_PRESENTATION* presentation; UINT32 numGeometryInfo; UINT32 Left; UINT32 Top; UINT32 Width; UINT32 Height; UINT32 cbVisibleRect; RDP_RECT* rects = NULL; int num_rects = 0; int error = 0; int i; int pos; presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input)); Stream_Seek(ifman->input, 16); Stream_Read_UINT32(ifman->input, numGeometryInfo); pos = Stream_GetPosition(ifman->input); Stream_Seek(ifman->input, 12); /* VideoWindowId (8 bytes), VideoWindowState (4 bytes) */ Stream_Read_UINT32(ifman->input, Width); Stream_Read_UINT32(ifman->input, Height); Stream_Read_UINT32(ifman->input, Left); Stream_Read_UINT32(ifman->input, Top); Stream_SetPosition(ifman->input, pos + numGeometryInfo); Stream_Read_UINT32(ifman->input, cbVisibleRect); num_rects = cbVisibleRect / 16; DEBUG_DVC("numGeometryInfo %d Width %d Height %d Left %d Top %d cbVisibleRect %d num_rects %d", numGeometryInfo, Width, Height, Left, Top, cbVisibleRect, num_rects); if (presentation == NULL) { error = 1; } else { if (num_rects > 0) { rects = (RDP_RECT*) malloc(sizeof(RDP_RECT) * num_rects); ZeroMemory(rects, sizeof(RDP_RECT) * num_rects); for (i = 0; i < num_rects; i++) { Stream_Read_UINT16(ifman->input, rects[i].y); /* Top */ Stream_Seek_UINT16(ifman->input); Stream_Read_UINT16(ifman->input, rects[i].x); /* Left */ Stream_Seek_UINT16(ifman->input); Stream_Read_UINT16(ifman->input, rects[i].height); /* Bottom */ Stream_Seek_UINT16(ifman->input); Stream_Read_UINT16(ifman->input, rects[i].width); /* Right */ Stream_Seek_UINT16(ifman->input); rects[i].width -= rects[i].x; rects[i].height -= rects[i].y; DEBUG_DVC("rect %d: %d %d %d %d", i, rects[i].x, rects[i].y, rects[i].width, rects[i].height); } } tsmf_presentation_set_geometry_info(presentation, Left, Top, Width, Height, num_rects, rects); } ifman->output_pending = TRUE; return error; }
BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length, wStream* input) { char* s = NULL; mode_t m; UINT64 size; int status; char* fullpath; struct STAT st; #if defined(__linux__) && !defined(ANDROID) || defined(sun) struct timespec tv[2]; #else struct timeval tv[2]; #endif UINT64 LastWriteTime; UINT32 FileAttributes; UINT32 FileNameLength; m = 0; switch (FsInformationClass) { case FileBasicInformation: /* http://msdn.microsoft.com/en-us/library/cc232094.aspx */ Stream_Seek_UINT64(input); /* CreationTime */ Stream_Seek_UINT64(input); /* LastAccessTime */ Stream_Read_UINT64(input, LastWriteTime); Stream_Seek_UINT64(input); /* ChangeTime */ Stream_Read_UINT32(input, FileAttributes); if (FSTAT(file->fd, &st) != 0) return FALSE; tv[0].tv_sec = st.st_atime; tv[1].tv_sec = (LastWriteTime > 0 ? FILE_TIME_RDP_TO_SYSTEM(LastWriteTime) : st.st_mtime); #ifndef WIN32 /* TODO on win32 */ #ifdef ANDROID tv[0].tv_usec = 0; tv[1].tv_usec = 0; utimes(file->fullpath, tv); #elif defined (__linux__) || defined (sun) tv[0].tv_nsec = 0; tv[1].tv_nsec = 0; futimens(file->fd, tv); #else tv[0].tv_usec = 0; tv[1].tv_usec = 0; futimes(file->fd, tv); #endif if (FileAttributes > 0) { m = st.st_mode; if ((FileAttributes & FILE_ATTRIBUTE_READONLY) == 0) m |= S_IWUSR; else m &= ~S_IWUSR; if (m != st.st_mode) fchmod(file->fd, st.st_mode); } #endif break; case FileEndOfFileInformation: /* http://msdn.microsoft.com/en-us/library/cc232067.aspx */ case FileAllocationInformation: /* http://msdn.microsoft.com/en-us/library/cc232076.aspx */ Stream_Read_UINT64(input, size); #ifndef _WIN32 if (ftruncate(file->fd, size) != 0) return FALSE; #endif break; case FileDispositionInformation: /* http://msdn.microsoft.com/en-us/library/cc232098.aspx */ /* http://msdn.microsoft.com/en-us/library/cc241371.aspx */ if (file->is_dir && !dir_empty(file->fullpath)) break; if (Length) Stream_Read_UINT8(input, file->delete_pending); else file->delete_pending = 1; break; case FileRenameInformation: /* http://msdn.microsoft.com/en-us/library/cc232085.aspx */ Stream_Seek_UINT8(input); /* ReplaceIfExists */ Stream_Seek_UINT8(input); /* RootDirectory */ Stream_Read_UINT32(input, FileNameLength); status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(input), FileNameLength / 2, &s, 0, NULL, NULL); if (status < 1) if (!(s = (char*) calloc(1, 1))) { WLog_ERR(TAG, "calloc failed!"); return FALSE; } fullpath = drive_file_combine_fullpath(file->basepath, s); if (!fullpath) { WLog_ERR(TAG, "drive_file_combine_fullpath failed!"); free (s); return FALSE; } free(s); #ifdef _WIN32 if (file->fd) close(file->fd); #endif if (rename(file->fullpath, fullpath) == 0) { drive_file_set_fullpath(file, fullpath); #ifdef _WIN32 file->fd = OPEN(fullpath, O_RDWR | O_BINARY); #endif } else { free(fullpath); return FALSE; } break; default: return FALSE; } return TRUE; }
static int remdesk_recv_ctl_authenticate_pdu(RemdeskServerContext* context, wStream* s, REMDESK_CHANNEL_HEADER* header) { int status; int cchStringW; WCHAR* pStringW; UINT32 msgLength; int cbExpertBlobW = 0; WCHAR* expertBlobW = NULL; int cbRaConnectionStringW = 0; WCHAR* raConnectionStringW = NULL; REMDESK_CTL_AUTHENTICATE_PDU pdu; msgLength = header->DataLength - 4; pStringW = (WCHAR*) Stream_Pointer(s); raConnectionStringW = pStringW; cchStringW = 0; while ((msgLength > 0) && pStringW[cchStringW]) { msgLength -= 2; cchStringW++; } if (pStringW[cchStringW] || !cchStringW) return -1; cchStringW++; cbRaConnectionStringW = cchStringW * 2; pStringW += cchStringW; expertBlobW = pStringW; cchStringW = 0; while ((msgLength > 0) && pStringW[cchStringW]) { msgLength -= 2; cchStringW++; } if (pStringW[cchStringW] || !cchStringW) return -1; cchStringW++; cbExpertBlobW = cchStringW * 2; pdu.raConnectionString = NULL; status = ConvertFromUnicode(CP_UTF8, 0, raConnectionStringW, cbRaConnectionStringW / 2, &pdu.raConnectionString, 0, NULL, NULL); if (status <= 0) return -1; pdu.expertBlob = NULL; status = ConvertFromUnicode(CP_UTF8, 0, expertBlobW, cbExpertBlobW / 2, &pdu.expertBlob, 0, NULL, NULL); if (status <= 0) return -1; printf("RaConnectionString: %s ExpertBlob: %s\n", pdu.raConnectionString, pdu.expertBlob); free(pdu.raConnectionString); free(pdu.expertBlob); return 1; }
static BOOL nego_read_request_token_or_cookie(rdpNego* nego, wStream* s) { /* routingToken and cookie are optional and mutually exclusive! * * routingToken (variable): An optional and variable-length routing * token (used for load balancing) terminated by a 0x0D0A two-byte * sequence: (check [MSFT-SDLBTS] for details!) * Cookie:[space]msts=[ip address].[port].[reserved][\x0D\x0A] * * cookie (variable): An optional and variable-length ANSI character * string terminated by a 0x0D0A two-byte sequence: * Cookie:[space]mstshash=[ANSISTRING][\x0D\x0A] */ BYTE* str = NULL; UINT16 crlf = 0; size_t pos, len; BOOL result = FALSE; BOOL isToken = FALSE; str = Stream_Pointer(s); pos = Stream_GetPosition(s); /* minimum length for token is 15 */ if (Stream_GetRemainingLength(s) < 15) return TRUE; if (memcmp(Stream_Pointer(s), "Cookie: mstshash=", 17) != 0) { isToken = TRUE; } else { /* not a token, minimum length for cookie is 19 */ if (Stream_GetRemainingLength(s) < 19) return TRUE; Stream_Seek(s, 17); } while (Stream_GetRemainingLength(s) >= 2) { Stream_Read_UINT16(s, crlf); if (crlf == 0x0A0D) break; Stream_Rewind(s, 1); } if (crlf == 0x0A0D) { Stream_Rewind(s, 2); len = Stream_GetPosition(s) - pos; Stream_Write_UINT16(s, 0); if (strlen((char*)str) == len) { if (isToken) result = nego_set_routing_token(nego, str, len); else result = nego_set_cookie(nego, (char*)str); } } if (!result) { Stream_SetPosition(s, pos); WLog_ERR(TAG, "invalid %s received", isToken ? "routing token" : "cookie"); } else { WLog_DBG(TAG, "received %s [%s]", isToken ? "routing token" : "cookie", str); } return result; }
/** * Function description * * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_decode_AVC444(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd) { UINT error; UINT32 tmp; size_t pos1, pos2; wStream* s; RDPGFX_AVC444_BITMAP_STREAM h264; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; s = Stream_New(cmd->data, cmd->length); if (!s) { WLog_ERR(TAG, "Stream_New failed!"); return CHANNEL_RC_NO_MEMORY; } if (Stream_GetRemainingLength(s) < 4) return ERROR_INVALID_DATA; Stream_Read_UINT32(s, tmp); h264.cbAvc420EncodedBitstream1 = tmp & 0x3FFFFFFFUL; h264.LC = (tmp >> 30UL) & 0x03UL; if (h264.LC == 0x03) return ERROR_INVALID_DATA; pos1 = Stream_GetPosition(s); if ((error = rdpgfx_read_h264_metablock(gfx, s, &(h264.bitstream[0].meta)))) { WLog_ERR(TAG, "rdpgfx_read_h264_metablock failed with error %"PRIu32"!", error); return error; } pos2 = Stream_GetPosition(s); h264.bitstream[0].data = Stream_Pointer(s); if (h264.LC == 0) { tmp = h264.cbAvc420EncodedBitstream1 - pos2 + pos1; if (Stream_GetRemainingLength(s) < tmp) return ERROR_INVALID_DATA; h264.bitstream[0].length = tmp; Stream_Seek(s, tmp); if ((error = rdpgfx_read_h264_metablock(gfx, s, &(h264.bitstream[1].meta)))) { WLog_ERR(TAG, "rdpgfx_read_h264_metablock failed with error %"PRIu32"!", error); return error; } h264.bitstream[1].data = Stream_Pointer(s); h264.bitstream[1].length = Stream_GetRemainingLength(s); } else { h264.bitstream[0].length = Stream_GetRemainingLength(s); memset(&h264.bitstream[1], 0, sizeof(h264.bitstream[1])); } Stream_Free(s, FALSE); cmd->extra = (void*) &h264; if (context) { IFCALLRET(context->SurfaceCommand, error, context, cmd); if (error) WLog_ERR(TAG, "context->SurfaceCommand failed with error %"PRIu32"", error); } free(h264.bitstream[0].meta.regionRects); free(h264.bitstream[0].meta.quantQualityVals); free(h264.bitstream[1].meta.regionRects); free(h264.bitstream[1].meta.quantQualityVals); return error; }
BOOL rdp_read_info_packet(wStream* s, rdpSettings* settings) { UINT32 flags; UINT16 cbDomain; UINT16 cbUserName; UINT16 cbPassword; UINT16 cbAlternateShell; UINT16 cbWorkingDir; if (Stream_GetRemainingLength(s) < 18) // invalid packet return FALSE; Stream_Seek_UINT32(s); /* CodePage */ Stream_Read_UINT32(s, flags); /* flags */ settings->AudioCapture = ((flags & RNS_INFO_AUDIOCAPTURE) ? TRUE : FALSE); settings->AudioPlayback = ((flags & INFO_NOAUDIOPLAYBACK) ? FALSE : TRUE); settings->AutoLogonEnabled = ((flags & INFO_AUTOLOGON) ? TRUE : FALSE); settings->RemoteApplicationMode = ((flags & INFO_RAIL) ? TRUE : FALSE); settings->RemoteConsoleAudio = ((flags & INFO_REMOTECONSOLEAUDIO) ? TRUE : FALSE); settings->CompressionEnabled = ((flags & INFO_COMPRESSION) ? TRUE : FALSE); Stream_Read_UINT16(s, cbDomain); /* cbDomain */ Stream_Read_UINT16(s, cbUserName); /* cbUserName */ Stream_Read_UINT16(s, cbPassword); /* cbPassword */ Stream_Read_UINT16(s, cbAlternateShell); /* cbAlternateShell */ Stream_Read_UINT16(s, cbWorkingDir); /* cbWorkingDir */ if (Stream_GetRemainingLength(s) < cbDomain + 2) return FALSE; if (cbDomain > 0) { ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbDomain / 2, &settings->Domain, 0, NULL, NULL); Stream_Seek(s, cbDomain); } Stream_Seek(s, 2); if (Stream_GetRemainingLength(s) < cbUserName + 2) return FALSE; if (cbUserName > 0) { ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbUserName / 2, &settings->Username, 0, NULL, NULL); Stream_Seek(s, cbUserName); } Stream_Seek(s, 2); if (Stream_GetRemainingLength(s) < cbPassword + 2) return FALSE; if (cbPassword > 0) { ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbPassword / 2, &settings->Password, 0, NULL, NULL); Stream_Seek(s, cbPassword); } Stream_Seek(s, 2); if (Stream_GetRemainingLength(s) < cbAlternateShell + 2) return FALSE; if (cbAlternateShell > 0) { ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbAlternateShell / 2, &settings->AlternateShell, 0, NULL, NULL); Stream_Seek(s, cbAlternateShell); } Stream_Seek(s, 2); if (Stream_GetRemainingLength(s) < cbWorkingDir + 2) return FALSE; if (cbWorkingDir > 0) { ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbWorkingDir / 2, &settings->ShellWorkingDirectory, 0, NULL, NULL); Stream_Seek(s, cbWorkingDir); } Stream_Seek(s, 2); if (settings->RdpVersion >= 5) return rdp_read_extended_info_packet(s, settings); /* extraInfo */ return TRUE; }
void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags) { CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); if (context->custom) { UINT32 index; int formatNameLength; CLIPRDR_FORMAT* formats; CLIPRDR_FORMAT_LIST formatList; formatList.msgType = CB_FORMAT_LIST; formatList.msgFlags = msgFlags; formatList.dataLen = dataLen; formatList.cFormats = 0; while (dataLen) { Stream_Seek(s, 4); /* formatId */ dataLen -= 4; formatNameLength = _wcslen((WCHAR*) Stream_Pointer(s)); Stream_Seek(s, (formatNameLength + 1) * 2); dataLen -= ((formatNameLength + 1) * 2); formatList.cFormats++; } index = 0; dataLen = formatList.dataLen; Stream_Rewind(s, dataLen); formats = (CLIPRDR_FORMAT*) malloc(sizeof(CLIPRDR_FORMAT) * formatList.cFormats); formatList.formats = formats; while (dataLen) { Stream_Read_UINT32(s, formats[index].formatId); /* formatId */ dataLen -= 4; formats[index].formatName = NULL; formatNameLength = _wcslen((WCHAR*) Stream_Pointer(s)); if (formatNameLength) { formatNameLength = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), -1, &(formats[index].formatName), 0, NULL, NULL); Stream_Seek(s, formatNameLength * 2); dataLen -= (formatNameLength * 2); } else { Stream_Seek(s, 2); dataLen -= 2; } index++; } if (context->ServerFormatList) context->ServerFormatList(context, &formatList); for (index = 0; index < formatList.cFormats; index++) free(formats[index].formatName); free(formats); } else { int i; UINT32 format; BOOL supported; CLIPRDR_FORMAT_NAME* format_name; RDP_CB_FORMAT_LIST_EVENT* cb_event; cb_event = (RDP_CB_FORMAT_LIST_EVENT*) freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_FormatList, NULL, NULL); if (dataLen > 0) { cb_event->raw_format_data = (BYTE*) malloc(dataLen); memcpy(cb_event->raw_format_data, Stream_Pointer(s), dataLen); cb_event->raw_format_data_size = dataLen; cb_event->raw_format_unicode = (msgFlags & CB_ASCII_NAMES) ? FALSE : TRUE; } if (cliprdr->use_long_format_names) cliprdr_process_long_format_names(cliprdr, s, dataLen, msgFlags); else cliprdr_process_short_format_names(cliprdr, s, dataLen, msgFlags); if (cliprdr->num_format_names > 0) cb_event->formats = (UINT32*) malloc(sizeof(UINT32) * cliprdr->num_format_names); cb_event->num_formats = 0; for (i = 0; i < cliprdr->num_format_names; i++) { supported = TRUE; format_name = &cliprdr->format_names[i]; format = format_name->id; switch (format) { case CB_FORMAT_TEXT: case CB_FORMAT_DIB: case CB_FORMAT_UNICODETEXT: break; default: if (format_name->length > 0) { DEBUG_CLIPRDR("format: %s", format_name->name); if (strcmp(format_name->name, "HTML Format") == 0) { format = CB_FORMAT_HTML; break; } if (strcmp(format_name->name, "PNG") == 0) { format = CB_FORMAT_PNG; break; } if (strcmp(format_name->name, "JFIF") == 0) { format = CB_FORMAT_JPEG; break; } if (strcmp(format_name->name, "GIF") == 0) { format = CB_FORMAT_GIF; break; } } else { supported = FALSE; } break; } if (supported) cb_event->formats[cb_event->num_formats++] = format; if (format_name->length > 0) free(format_name->name); } free(cliprdr->format_names); cliprdr->format_names = NULL; cliprdr->num_format_names = 0; svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event); cliprdr_send_format_list_response(cliprdr); } }
static BOOL TestStream_Verify(wStream* s, int mincap, int len, size_t pos) { if (Stream_Buffer(s) == NULL) { printf("stream buffer is null\n"); return FALSE; } if (Stream_Pointer(s) == NULL) { printf("stream pointer is null\n"); return FALSE; } if (Stream_Pointer(s) < Stream_Buffer(s)) { printf("stream pointer (%p) or buffer (%p) is invalid\n", (void*) Stream_Pointer(s), (void*) Stream_Buffer(s)); return FALSE; } if (Stream_Capacity(s) < mincap) { printf("stream capacity is %"PRIuz" but minimum expected value is %d\n", Stream_Capacity(s), mincap); return FALSE; } if (Stream_Length(s) != len) { printf("stream has unexpected length (%"PRIuz" instead of %d)\n", Stream_Length(s), len); return FALSE; } if (Stream_GetPosition(s) != pos) { printf("stream has unexpected position (%"PRIuz" instead of %d)\n", Stream_GetPosition(s), pos); return FALSE; } if (Stream_GetPosition(s) > Stream_Length(s)) { printf("stream position (%"PRIuz") exceeds length (%"PRIuz")\n", Stream_GetPosition(s), Stream_Length(s)); return FALSE; } if (Stream_GetPosition(s) > Stream_Capacity(s)) { printf("stream position (%"PRIuz") exceeds capacity (%"PRIuz")\n", Stream_GetPosition(s), Stream_Capacity(s)); return FALSE; } if (Stream_Length(s) > Stream_Capacity(s)) { printf("stream length (%"PRIuz") exceeds capacity (%"PRIuz")\n", Stream_Length(s), Stream_Capacity(s)); return FALSE; } if (Stream_GetRemainingLength(s) != len - pos) { printf("stream remaining length (%"PRIuz" instead of %d)\n", Stream_GetRemainingLength(s), len - pos); return FALSE; } return TRUE; }
BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) { UINT16 clientAddressFamily; UINT16 cbClientAddress; UINT16 cbClientDir; UINT16 cbAutoReconnectLen; rdpSettings* settings = rdp->settings; WCHAR* wstr; if (Stream_GetRemainingLength(s) < 4) return FALSE; Stream_Read_UINT16(s, clientAddressFamily); /* clientAddressFamily (2 bytes) */ Stream_Read_UINT16(s, cbClientAddress); /* cbClientAddress (2 bytes) */ /* cbClientAddress is the size in bytes of the character data in the clientAddress field. * This size includes the length of the mandatory null terminator. * The maximum allowed value is 80 bytes * Note: Although according to [MS-RDPBCGR 2.2.1.11.1.1.1] the null terminator * is mandatory, connections via Microsoft's TS Gateway set cbClientAddress to 0. */ if ((cbClientAddress % 2) || cbClientAddress > 80) { WLog_ERR(TAG, "protocol error: invalid cbClientAddress value: %u", cbClientAddress); return FALSE; } settings->IPv6Enabled = (clientAddressFamily == ADDRESS_FAMILY_INET6 ? TRUE : FALSE); if (Stream_GetRemainingLength(s) < cbClientAddress) return FALSE; if (settings->ClientAddress) { free(settings->ClientAddress); settings->ClientAddress = NULL; } if (cbClientAddress) { wstr = (WCHAR*) Stream_Pointer(s); if (wstr[cbClientAddress / 2 - 1]) { WLog_ERR(TAG, "protocol error: clientAddress must be null terminated"); return FALSE; } if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &settings->ClientAddress, 0, NULL, NULL) < 1) { WLog_ERR(TAG, "failed to convert client address"); return FALSE; } Stream_Seek(s, cbClientAddress); WLog_DBG(TAG, "rdp client address: [%s]", settings->ClientAddress); } if (Stream_GetRemainingLength(s) < 2) return FALSE; Stream_Read_UINT16(s, cbClientDir); /* cbClientDir (2 bytes) */ /* cbClientDir is the size in bytes of the character data in the clientDir field. * This size includes the length of the mandatory null terminator. * The maximum allowed value is 512 bytes. * Note: Although according to [MS-RDPBCGR 2.2.1.11.1.1.1] the null terminator * is mandatory the Microsoft Android client (starting with version 8.1.31.44) * sets cbClientDir to 0. */ if ((cbClientDir % 2) || cbClientDir > 512) { WLog_ERR(TAG, "protocol error: invalid cbClientDir value: %u", cbClientDir); return FALSE; } if (Stream_GetRemainingLength(s) < cbClientDir) return FALSE; if (settings->ClientDir) { free(settings->ClientDir); settings->ClientDir = NULL; } if (cbClientDir) { wstr = (WCHAR*) Stream_Pointer(s); if (wstr[cbClientDir / 2 - 1]) { WLog_ERR(TAG, "protocol error: clientDir must be null terminated"); return FALSE; } if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), -1, &settings->ClientDir, 0, NULL, NULL) < 1) { WLog_ERR(TAG, "failed to convert client directory"); return FALSE; } Stream_Seek(s, cbClientDir); WLog_DBG(TAG, "rdp client dir: [%s]", settings->ClientDir); } /** * down below all fields are optional but if one field is not present, * then all of the subsequent fields also MUST NOT be present. */ /* optional: clientTimeZone (172 bytes) */ if (Stream_GetRemainingLength(s) == 0) return TRUE; if (!rdp_read_client_time_zone(s, settings)) return FALSE; /* optional: clientSessionId (4 bytes), should be set to 0 */ if (Stream_GetRemainingLength(s) == 0) return TRUE; if (Stream_GetRemainingLength(s) < 4) return FALSE; Stream_Seek_UINT32(s); /* optional: performanceFlags (4 bytes) */ if (Stream_GetRemainingLength(s) == 0) return TRUE; if (Stream_GetRemainingLength(s) < 4) return FALSE; Stream_Read_UINT32(s, settings->PerformanceFlags); freerdp_performance_flags_split(settings); /* optional: cbAutoReconnectLen (2 bytes) */ if (Stream_GetRemainingLength(s) == 0) return TRUE; if (Stream_GetRemainingLength(s) < 2) return FALSE; Stream_Read_UINT16(s, cbAutoReconnectLen); /* optional: autoReconnectCookie (28 bytes) */ /* must be present if cbAutoReconnectLen is > 0 */ if (cbAutoReconnectLen > 0) return rdp_read_client_auto_reconnect_cookie(rdp, s); /* TODO */ /* reserved1 (2 bytes) */ /* reserved2 (2 bytes) */ /* cbDynamicDSTTimeZoneKeyName (2 bytes) */ /* dynamicDSTTimeZoneKeyName (variable) */ /* dynamicDaylightTimeDisabled (2 bytes) */ return TRUE; }
int rdp_recv_data_pdu(rdpRdp* rdp, wStream* s) { BYTE type; UINT32 roff; UINT32 rlen; wStream* cs; BYTE* buffer; UINT16 length; UINT32 share_id; BYTE compressed_type; UINT16 compressed_len; if (!rdp_read_share_data_header(s, &length, &type, &share_id, &compressed_type, &compressed_len)) return -1; cs = s; if (compressed_type & PACKET_COMPRESSED) { if (Stream_GetRemainingLength(s) < compressed_len - 18) { fprintf(stderr, "decompress_rdp: not enough bytes for compressed_len=%d\n", compressed_len); return -1; } if (decompress_rdp(rdp->mppc_dec, Stream_Pointer(s), compressed_len - 18, compressed_type, &roff, &rlen)) { buffer = rdp->mppc_dec->history_buf + roff; cs = StreamPool_Take(rdp->transport->ReceivePool, rlen); Stream_SetPosition(cs, 0); Stream_Write(cs, buffer, rlen); Stream_SealLength(cs); Stream_SetPosition(cs, 0); } else { fprintf(stderr, "decompress_rdp() failed\n"); return -1; } Stream_Seek(s, compressed_len - 18); } #ifdef WITH_DEBUG_RDP /* if (type != DATA_PDU_TYPE_UPDATE) */ DEBUG_RDP("recv %s Data PDU (0x%02X), length:%d", type < ARRAYSIZE(DATA_PDU_TYPE_STRINGS) ? DATA_PDU_TYPE_STRINGS[type] : "???", type, length); #endif switch (type) { case DATA_PDU_TYPE_UPDATE: if (!update_recv(rdp->update, cs)) return -1; break; case DATA_PDU_TYPE_CONTROL: if (!rdp_recv_server_control_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_POINTER: if (!update_recv_pointer(rdp->update, cs)) return -1; break; case DATA_PDU_TYPE_INPUT: break; case DATA_PDU_TYPE_SYNCHRONIZE: if (!rdp_recv_synchronize_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_REFRESH_RECT: break; case DATA_PDU_TYPE_PLAY_SOUND: if (!update_recv_play_sound(rdp->update, cs)) return -1; break; case DATA_PDU_TYPE_SUPPRESS_OUTPUT: break; case DATA_PDU_TYPE_SHUTDOWN_REQUEST: break; case DATA_PDU_TYPE_SHUTDOWN_DENIED: break; case DATA_PDU_TYPE_SAVE_SESSION_INFO: if (!rdp_recv_save_session_info(rdp, cs)) return -1; break; case DATA_PDU_TYPE_FONT_LIST: break; case DATA_PDU_TYPE_FONT_MAP: if (!rdp_recv_font_map_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_SET_KEYBOARD_INDICATORS: break; case DATA_PDU_TYPE_BITMAP_CACHE_PERSISTENT_LIST: break; case DATA_PDU_TYPE_BITMAP_CACHE_ERROR: break; case DATA_PDU_TYPE_SET_KEYBOARD_IME_STATUS: break; case DATA_PDU_TYPE_OFFSCREEN_CACHE_ERROR: break; case DATA_PDU_TYPE_SET_ERROR_INFO: if (!rdp_recv_set_error_info_data_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_DRAW_NINEGRID_ERROR: break; case DATA_PDU_TYPE_DRAW_GDIPLUS_ERROR: break; case DATA_PDU_TYPE_ARC_STATUS: break; case DATA_PDU_TYPE_STATUS_INFO: break; case DATA_PDU_TYPE_MONITOR_LAYOUT: break; default: break; } if (cs != s) Stream_Release(cs); return 0; }
HttpResponse* http_response_recv(rdpTls* tls) { wStream* s; int size; int count; int status; int position; char* line; char* buffer; char* header; char* payload; int bodyLength; int payloadOffset; HttpResponse* response; size = 1024; payload = NULL; payloadOffset = 0; s = Stream_New(NULL, size); if (!s) goto out_free; buffer = (char*) Stream_Buffer(s); response = http_response_new(); if (!response) goto out_free; response->ContentLength = 0; while (TRUE) { while (!payloadOffset) { status = BIO_read(tls->bio, Stream_Pointer(s), Stream_Capacity(s) - Stream_GetPosition(s)); if (status <= 0) { if (!BIO_should_retry(tls->bio)) goto out_error; USleep(100); continue; } #ifdef HAVE_VALGRIND_MEMCHECK_H VALGRIND_MAKE_MEM_DEFINED(Stream_Pointer(s), status); #endif Stream_Seek(s, status); if (Stream_GetRemainingLength(s) < 1024) { Stream_EnsureRemainingCapacity(s, 1024); buffer = (char*) Stream_Buffer(s); payload = &buffer[payloadOffset]; } position = Stream_GetPosition(s); if (position >= 4) { line = string_strnstr(buffer, "\r\n\r\n", position); if (line) { payloadOffset = (line - buffer) + 4; payload = &buffer[payloadOffset]; } } } if (payloadOffset) { count = 0; line = buffer; position = Stream_GetPosition(s); while ((line = string_strnstr(line, "\r\n", payloadOffset - (line - buffer) - 2))) { line += 2; count++; } response->count = count; if (count) { response->lines = (char**) calloc(response->count, sizeof(char*)); if (!response->lines) goto out_error; } header = (char*) malloc(payloadOffset); if (!header) goto out_error; CopyMemory(header, buffer, payloadOffset); header[payloadOffset - 1] = '\0'; header[payloadOffset - 2] = '\0'; count = 0; line = strtok(header, "\r\n"); while (line && response->lines) { response->lines[count] = _strdup(line); if (!response->lines[count]) goto out_error; line = strtok(NULL, "\r\n"); count++; } free(header); if (!http_response_parse_header(response)) goto out_error; response->BodyLength = Stream_GetPosition(s) - payloadOffset; if (response->BodyLength > 0) { response->BodyContent = (BYTE*) malloc(response->BodyLength); if (!response->BodyContent) goto out_error; CopyMemory(response->BodyContent, payload, response->BodyLength); } bodyLength = 0; /* expected body length */ if (response->ContentType) { if (_stricmp(response->ContentType, "text/plain") == 0) { bodyLength = response->ContentLength; } } if (bodyLength != response->BodyLength) { WLog_WARN(TAG, "http_response_recv: %s unexpected body length: actual: %d, expected: %d", response->ContentType, response->ContentLength, response->BodyLength); } break; } if (Stream_GetRemainingLength(s) < 1024) { Stream_EnsureRemainingCapacity(s, 1024); buffer = (char*) Stream_Buffer(s); payload = &buffer[payloadOffset]; } } Stream_Free(s, TRUE); return response; out_error: http_response_free(response); out_free: Stream_Free(s, TRUE); return NULL; }
BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) { UINT16 clientAddressFamily; UINT16 cbClientAddress; UINT16 cbClientDir; UINT16 cbAutoReconnectLen; rdpSettings* settings = rdp->settings; if (Stream_GetRemainingLength(s) < 4) return FALSE; Stream_Read_UINT16(s, clientAddressFamily); /* clientAddressFamily (2 bytes) */ Stream_Read_UINT16(s, cbClientAddress); /* cbClientAddress (2 bytes) */ settings->IPv6Enabled = (clientAddressFamily == ADDRESS_FAMILY_INET6 ? TRUE : FALSE); if (Stream_GetRemainingLength(s) < cbClientAddress) return FALSE; if (settings->ClientAddress) { free(settings->ClientAddress); settings->ClientAddress = NULL; } ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbClientAddress / 2, &settings->ClientAddress, 0, NULL, NULL); Stream_Seek(s, cbClientAddress); if (Stream_GetRemainingLength(s) < 2) return FALSE; Stream_Read_UINT16(s, cbClientDir); /* cbClientDir (2 bytes) */ if (Stream_GetRemainingLength(s) < cbClientDir) return FALSE; if (settings->ClientDir) { free(settings->ClientDir); settings->ClientDir = NULL; } ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbClientDir / 2, &settings->ClientDir, 0, NULL, NULL); Stream_Seek(s, cbClientDir); if (!rdp_read_client_time_zone(s, settings)) return FALSE; if (Stream_GetRemainingLength(s) < 10) return FALSE; Stream_Seek_UINT32(s); /* clientSessionId (4 bytes), should be set to 0 */ Stream_Read_UINT32(s, settings->PerformanceFlags); /* performanceFlags (4 bytes) */ freerdp_performance_flags_split(settings); Stream_Read_UINT16(s, cbAutoReconnectLen); /* cbAutoReconnectLen (2 bytes) */ if (cbAutoReconnectLen > 0) return rdp_read_client_auto_reconnect_cookie(rdp, s); /* autoReconnectCookie */ /* reserved1 (2 bytes) */ /* reserved2 (2 bytes) */ return TRUE; }
BOOL gcc_read_client_core_data(wStream* s, rdpSettings* settings, UINT16 blockLength) { char* str = NULL; UINT32 version; UINT32 color_depth; UINT16 colorDepth = 0; UINT16 postBeta2ColorDepth = 0; UINT16 highColorDepth = 0; UINT16 supportedColorDepths = 0; UINT32 serverSelectedProtocol = 0; /* Length of all required fields, until imeFileName */ if (blockLength < 128) return FALSE; Stream_Read_UINT32(s, version); /* version */ settings->RdpVersion = (version == RDP_VERSION_4 ? 4 : 7); Stream_Read_UINT16(s, settings->DesktopWidth); /* DesktopWidth */ Stream_Read_UINT16(s, settings->DesktopHeight); /* DesktopHeight */ Stream_Read_UINT16(s, colorDepth); /* ColorDepth */ Stream_Seek_UINT16(s); /* SASSequence (Secure Access Sequence) */ Stream_Read_UINT32(s, settings->KeyboardLayout); /* KeyboardLayout */ Stream_Read_UINT32(s, settings->ClientBuild); /* ClientBuild */ /* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */ ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), 32 / 2, &str, 0, NULL, NULL); Stream_Seek(s, 32); sprintf_s(settings->ClientHostname, 31, "%s", str); settings->ClientHostname[31] = 0; free(str); str = NULL; Stream_Read_UINT32(s, settings->KeyboardType); /* KeyboardType */ Stream_Read_UINT32(s, settings->KeyboardSubType); /* KeyboardSubType */ Stream_Read_UINT32(s, settings->KeyboardFunctionKey); /* KeyboardFunctionKey */ Stream_Seek(s, 64); /* imeFileName */ blockLength -= 128; /** * The following fields are all optional. If one field is present, all of the preceding * fields MUST also be present. If one field is not present, all of the subsequent fields * MUST NOT be present. * We must check the bytes left before reading each field. */ do { if (blockLength < 2) break; Stream_Read_UINT16(s, postBeta2ColorDepth); /* postBeta2ColorDepth */ blockLength -= 2; if (blockLength < 2) break; Stream_Seek_UINT16(s); /* clientProductID */ blockLength -= 2; if (blockLength < 4) break; Stream_Seek_UINT32(s); /* serialNumber */ blockLength -= 4; if (blockLength < 2) break; Stream_Read_UINT16(s, highColorDepth); /* highColorDepth */ blockLength -= 2; if (blockLength < 2) break; Stream_Read_UINT16(s, supportedColorDepths); /* supportedColorDepths */ blockLength -= 2; if (blockLength < 2) break; Stream_Read_UINT16(s, settings->EarlyCapabilityFlags); /* earlyCapabilityFlags */ blockLength -= 2; if (blockLength < 64) break; ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), 64 / 2, &str, 0, NULL, NULL); Stream_Seek(s, 64); sprintf_s(settings->ClientProductId, 32, "%s", str); free(str); blockLength -= 64; if (blockLength < 1) break; Stream_Read_UINT8(s, settings->PerformanceFlags); /* connectionType */ blockLength -= 1; if (blockLength < 1) break; Stream_Seek_UINT8(s); /* pad1octet */ blockLength -= 1; if (blockLength < 4) break; Stream_Read_UINT32(s, serverSelectedProtocol); /* serverSelectedProtocol */ blockLength -= 4; if (settings->SelectedProtocol != serverSelectedProtocol) return FALSE; } while (0); if (highColorDepth > 0) { if (settings->EarlyCapabilityFlags & RNS_UD_CS_WANT_32BPP_SESSION) color_depth = 32; else color_depth = highColorDepth; } else if (postBeta2ColorDepth > 0) { switch (postBeta2ColorDepth) { case RNS_UD_COLOR_4BPP: color_depth = 4; break; case RNS_UD_COLOR_8BPP: color_depth = 8; break; case RNS_UD_COLOR_16BPP_555: color_depth = 15; break; case RNS_UD_COLOR_16BPP_565: color_depth = 16; break; case RNS_UD_COLOR_24BPP: color_depth = 24; break; default: return FALSE; } } else { switch (colorDepth) { case RNS_UD_COLOR_4BPP: color_depth = 4; break; case RNS_UD_COLOR_8BPP: color_depth = 8; break; default: return FALSE; } } /* * If we are in server mode, accept client's color depth only if * it is smaller than ours. This is what Windows server does. */ if ((color_depth < settings->ColorDepth) || !settings->ServerMode) settings->ColorDepth = color_depth; return TRUE; }
int rdp_recv_data_pdu(rdpRdp* rdp, wStream* s) { BYTE type; wStream* cs; UINT16 length; UINT32 shareId; BYTE compressedType; UINT16 compressedLength; if (!rdp_read_share_data_header(s, &length, &type, &shareId, &compressedType, &compressedLength)) return -1; cs = s; if (compressedType & PACKET_COMPRESSED) { UINT32 DstSize = 0; BYTE* pDstData = NULL; UINT32 SrcSize = compressedLength - 18; if (Stream_GetRemainingLength(s) < (size_t) SrcSize) { DEBUG_WARN( "bulk_decompress: not enough bytes for compressedLength %d\n", compressedLength); return -1; } if (bulk_decompress(rdp->bulk, Stream_Pointer(s), SrcSize, &pDstData, &DstSize, compressedType)) { cs = StreamPool_Take(rdp->transport->ReceivePool, DstSize); Stream_SetPosition(cs, 0); Stream_Write(cs, pDstData, DstSize); Stream_SealLength(cs); Stream_SetPosition(cs, 0); } else { DEBUG_WARN( "bulk_decompress() failed\n"); return -1; } Stream_Seek(s, SrcSize); } #ifdef WITH_DEBUG_RDP DEBUG_MSG("recv %s Data PDU (0x%02X), length: %d\n", type < ARRAYSIZE(DATA_PDU_TYPE_STRINGS) ? DATA_PDU_TYPE_STRINGS[type] : "???", type, length); #endif switch (type) { case DATA_PDU_TYPE_UPDATE: if (!update_recv(rdp->update, cs)) return -1; break; case DATA_PDU_TYPE_CONTROL: if (!rdp_recv_server_control_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_POINTER: if (!update_recv_pointer(rdp->update, cs)) return -1; break; case DATA_PDU_TYPE_SYNCHRONIZE: if (!rdp_recv_synchronize_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_PLAY_SOUND: if (!update_recv_play_sound(rdp->update, cs)) return -1; break; case DATA_PDU_TYPE_SHUTDOWN_DENIED: if (!rdp_recv_server_shutdown_denied_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_SAVE_SESSION_INFO: if (!rdp_recv_save_session_info(rdp, cs)) return -1; break; case DATA_PDU_TYPE_FONT_MAP: if (!rdp_recv_font_map_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_SET_KEYBOARD_INDICATORS: if (!rdp_recv_server_set_keyboard_indicators_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_SET_KEYBOARD_IME_STATUS: if (!rdp_recv_server_set_keyboard_ime_status_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_SET_ERROR_INFO: if (!rdp_recv_set_error_info_data_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_ARC_STATUS: if (!rdp_recv_server_auto_reconnect_status_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_STATUS_INFO: if (!rdp_recv_server_status_info_pdu(rdp, cs)) return -1; break; case DATA_PDU_TYPE_MONITOR_LAYOUT: if (!rdp_recv_monitor_layout_pdu(rdp, cs)) return -1; break; default: break; } if (cs != s) Stream_Release(cs); return 0; }
/** * Function description * * @return 0 on success, otherwise a Win32 error code */ UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags) { UINT32 index; UINT32 position; BOOL asciiNames; int formatNameLength; char* szFormatName; WCHAR* wszFormatName; CLIPRDR_FORMAT* formats = NULL; CLIPRDR_FORMAT_LIST formatList; CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); UINT error = CHANNEL_RC_OK; if (!context->custom) { WLog_ERR(TAG, "context->custom not set!"); return ERROR_INTERNAL_ERROR; } asciiNames = (msgFlags & CB_ASCII_NAMES) ? TRUE : FALSE; formatList.msgType = CB_FORMAT_LIST; formatList.msgFlags = msgFlags; formatList.dataLen = dataLen; index = 0; formatList.numFormats = 0; position = Stream_GetPosition(s); if (!formatList.dataLen) { /* empty format list */ formatList.formats = NULL; formatList.numFormats = 0; } else if (!cliprdr->useLongFormatNames) { formatList.numFormats = (dataLen / 36); if ((formatList.numFormats * 36) != dataLen) { WLog_ERR(TAG, "Invalid short format list length: %d", dataLen); return ERROR_INTERNAL_ERROR; } if (formatList.numFormats) formats = (CLIPRDR_FORMAT*) calloc(formatList.numFormats, sizeof(CLIPRDR_FORMAT)); if (!formats) { WLog_ERR(TAG, "calloc failed!"); return CHANNEL_RC_NO_MEMORY; } formatList.formats = formats; while (dataLen) { Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */ dataLen -= 4; formats[index].formatName = NULL; if (asciiNames) { szFormatName = (char*) Stream_Pointer(s); if (szFormatName[0]) { formats[index].formatName = (char*) malloc(32 + 1); if (!formats[index].formatName) { WLog_ERR(TAG, "calloc failed!"); error = CHANNEL_RC_NO_MEMORY; goto error_out; } CopyMemory(formats[index].formatName, szFormatName, 32); formats[index].formatName[32] = '\0'; } } else { wszFormatName = (WCHAR*) Stream_Pointer(s); if (wszFormatName[0]) { ConvertFromUnicode(CP_UTF8, 0, wszFormatName, 16, &(formats[index].formatName), 0, NULL, NULL); } } Stream_Seek(s, 32); dataLen -= 32; index++; } } else { while (dataLen) { Stream_Seek(s, 4); /* formatId (4 bytes) */ dataLen -= 4; wszFormatName = (WCHAR*) Stream_Pointer(s); if (!wszFormatName[0]) formatNameLength = 0; else formatNameLength = _wcslen(wszFormatName); Stream_Seek(s, (formatNameLength + 1) * 2); dataLen -= ((formatNameLength + 1) * 2); formatList.numFormats++; } dataLen = formatList.dataLen; Stream_SetPosition(s, position); if (formatList.numFormats) formats = (CLIPRDR_FORMAT*) calloc(formatList.numFormats, sizeof(CLIPRDR_FORMAT)); if (!formats) { WLog_ERR(TAG, "calloc failed!"); return CHANNEL_RC_NO_MEMORY; } formatList.formats = formats; while (dataLen) { Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */ dataLen -= 4; formats[index].formatName = NULL; wszFormatName = (WCHAR*) Stream_Pointer(s); if (!wszFormatName[0]) formatNameLength = 0; else formatNameLength = _wcslen(wszFormatName); if (formatNameLength) { ConvertFromUnicode(CP_UTF8, 0, wszFormatName, -1, &(formats[index].formatName), 0, NULL, NULL); } Stream_Seek(s, (formatNameLength + 1) * 2); dataLen -= ((formatNameLength + 1) * 2); index++; } } WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatList: numFormats: %d", formatList.numFormats); if (context->ServerFormatList) { if ((error = context->ServerFormatList(context, &formatList))) WLog_ERR(TAG, "ServerFormatList failed with error %d", error); } error_out: if (formats) { for (index = 0; index < formatList.numFormats; index++) { free(formats[index].formatName); } free(formats); } return error; }
BOOL nla_read_ts_password_creds(rdpNla* nla, wStream* s) { int length; if (!nla->identity) { WLog_ERR(TAG, "nla->identity is NULL!"); return FALSE; } /* TSPasswordCreds (SEQUENCE) * Initialise to default values. */ nla->identity->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; nla->identity->UserLength = (UINT32) 0; nla->identity->User = NULL; nla->identity->DomainLength = (UINT32) 0; nla->identity->Domain = NULL; nla->identity->Password = NULL; nla->identity->PasswordLength = (UINT32) 0; if (!ber_read_sequence_tag(s, &length)) return FALSE; /* The sequence is empty, return early, * TSPasswordCreds (SEQUENCE) is optional. */ if (length == 0) return TRUE; /* [0] domainName (OCTET STRING) */ if (!ber_read_contextual_tag(s, 0, &length, TRUE) || !ber_read_octet_string_tag(s, &length)) { return FALSE; } nla->identity->DomainLength = (UINT32) length; if (nla->identity->DomainLength > 0) { nla->identity->Domain = (UINT16*) malloc(length); if (!nla->identity->Domain) return FALSE; CopyMemory(nla->identity->Domain, Stream_Pointer(s), nla->identity->DomainLength); Stream_Seek(s, nla->identity->DomainLength); nla->identity->DomainLength /= 2; } /* [1] userName (OCTET STRING) */ if (!ber_read_contextual_tag(s, 1, &length, TRUE) || !ber_read_octet_string_tag(s, &length)) { return FALSE; } nla->identity->UserLength = (UINT32) length; if (nla->identity->UserLength > 0) { nla->identity->User = (UINT16 *) malloc(length); if (!nla->identity->User) return FALSE; CopyMemory(nla->identity->User, Stream_Pointer(s), nla->identity->UserLength); Stream_Seek(s, nla->identity->UserLength); nla->identity->UserLength /= 2; } /* [2] password (OCTET STRING) */ if (!ber_read_contextual_tag(s, 2, &length, TRUE) || !ber_read_octet_string_tag(s, &length)) { return FALSE; } nla->identity->PasswordLength = (UINT32) length; if (nla->identity->PasswordLength > 0) { nla->identity->Password = (UINT16 *) malloc(length); if (!nla->identity->Password) return FALSE; CopyMemory(nla->identity->Password, Stream_Pointer(s), nla->identity->PasswordLength); Stream_Seek(s, nla->identity->PasswordLength); nla->identity->PasswordLength /= 2; } return TRUE; }
int transport_write(rdpTransport* transport, wStream* s) { int length; int status = -1; int writtenlength = 0; EnterCriticalSection(&(transport->WriteLock)); length = Stream_GetPosition(s); writtenlength = length; Stream_SetPosition(s, 0); if (length > 0) { WLog_Packet(WLog_Get(TAG), WLOG_TRACE, Stream_Buffer(s), length, WLOG_PACKET_OUTBOUND); } while (length > 0) { status = BIO_write(transport->frontBio, Stream_Pointer(s), length); if (status <= 0) { /* the buffered BIO that is at the end of the chain always says OK for writing, * so a retry means that for any reason we need to read. The most probable * is a SSL or TSG BIO in the chain. */ if (!BIO_should_retry(transport->frontBio)) { WLog_ERR_BIO(TAG, "BIO_should_retry", transport->frontBio); goto out_cleanup; } /* non-blocking can live with blocked IOs */ if (!transport->blocking) { WLog_ERR_BIO(TAG, "BIO_write", transport->frontBio); goto out_cleanup; } if (BIO_wait_write(transport->frontBio, 100) < 0) { WLog_ERR_BIO(TAG, "BIO_wait_write", transport->frontBio); status = -1; goto out_cleanup; } continue; } if (transport->blocking || transport->settings->WaitForOutputBufferFlush) { while (BIO_write_blocked(transport->frontBio)) { if (BIO_wait_write(transport->frontBio, 100) < 0) { WLog_ERR(TAG, "error when selecting for write"); status = -1; goto out_cleanup; } if (BIO_flush(transport->frontBio) < 1) { WLog_ERR(TAG, "error when flushing outputBuffer"); status = -1; goto out_cleanup; } } } length -= status; Stream_Seek(s, status); } transport->written += writtenlength; out_cleanup: if (status < 0) { /* A write error indicates that the peer has dropped the connection */ transport->layer = TRANSPORT_LAYER_CLOSED; } if (s->pool) Stream_Release(s); LeaveCriticalSection(&(transport->WriteLock)); return status; }
BOOL gcc_read_server_data_blocks(wStream* s, rdpMcs* mcs, int length) { UINT16 type; UINT16 offset = 0; UINT16 blockLength; BYTE* holdp; while (offset < length) { holdp = Stream_Pointer(s); if (!gcc_read_user_data_header(s, &type, &blockLength)) { WLog_ERR(TAG, "gcc_read_server_data_blocks: gcc_read_user_data_header failed"); return FALSE; } switch (type) { case SC_CORE: if (!gcc_read_server_core_data(s, mcs)) { WLog_ERR(TAG, "gcc_read_server_data_blocks: gcc_read_server_core_data failed"); return FALSE; } break; case SC_SECURITY: if (!gcc_read_server_security_data(s, mcs)) { WLog_ERR(TAG, "gcc_read_server_data_blocks: gcc_read_server_security_data failed"); return FALSE; } break; case SC_NET: if (!gcc_read_server_network_data(s, mcs)) { WLog_ERR(TAG, "gcc_read_server_data_blocks: gcc_read_server_network_data failed"); return FALSE; } break; case SC_MCS_MSGCHANNEL: if (!gcc_read_server_message_channel_data(s, mcs)) { WLog_ERR(TAG, "gcc_read_server_data_blocks: gcc_read_server_message_channel_data failed"); return FALSE; } break; case SC_MULTITRANSPORT: if (!gcc_read_server_multitransport_channel_data(s, mcs)) { WLog_ERR(TAG, "gcc_read_server_data_blocks: gcc_read_server_multitransport_channel_data failed"); return FALSE; } break; default: WLog_ERR(TAG, "gcc_read_server_data_blocks: ignoring type=%hu", type); break; } offset += blockLength; Stream_Pointer(s) = holdp + blockLength; } return TRUE; }
void gcc_write_server_security_data(wStream* s, rdpMcs* mcs) { CryptoMd5 md5; BYTE* sigData; int expLen, keyLen, sigDataLen; BYTE encryptedSignature[TSSK_KEY_LENGTH]; BYTE signature[sizeof(initial_signature)]; UINT32 headerLen, serverRandomLen, serverCertLen, wPublicKeyBlobLen; rdpSettings* settings = mcs->settings; if (!settings->DisableEncryption) { settings->EncryptionMethods = ENCRYPTION_METHOD_NONE; settings->EncryptionLevel = ENCRYPTION_LEVEL_NONE; } else if ((settings->EncryptionMethods & ENCRYPTION_METHOD_FIPS) != 0) { settings->EncryptionMethods = ENCRYPTION_METHOD_FIPS; } else if ((settings->EncryptionMethods & ENCRYPTION_METHOD_128BIT) != 0) { settings->EncryptionMethods = ENCRYPTION_METHOD_128BIT; } else if ((settings->EncryptionMethods & ENCRYPTION_METHOD_40BIT) != 0) { settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT; } if (settings->EncryptionMethods != ENCRYPTION_METHOD_NONE) settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE; headerLen = 12; keyLen = 0; wPublicKeyBlobLen = 0; serverRandomLen = 0; serverCertLen = 0; if (settings->EncryptionMethods != ENCRYPTION_METHOD_NONE || settings->EncryptionLevel != ENCRYPTION_LEVEL_NONE) { serverRandomLen = 32; keyLen = settings->RdpServerRsaKey->ModulusLength; expLen = sizeof(settings->RdpServerRsaKey->exponent); wPublicKeyBlobLen = 4; /* magic (RSA1) */ wPublicKeyBlobLen += 4; /* keylen */ wPublicKeyBlobLen += 4; /* bitlen */ wPublicKeyBlobLen += 4; /* datalen */ wPublicKeyBlobLen += expLen; wPublicKeyBlobLen += keyLen; wPublicKeyBlobLen += 8; /* 8 bytes of zero padding */ serverCertLen = 4; /* dwVersion */ serverCertLen += 4; /* dwSigAlgId */ serverCertLen += 4; /* dwKeyAlgId */ serverCertLen += 2; /* wPublicKeyBlobType */ serverCertLen += 2; /* wPublicKeyBlobLen */ serverCertLen += wPublicKeyBlobLen; serverCertLen += 2; /* wSignatureBlobType */ serverCertLen += 2; /* wSignatureBlobLen */ serverCertLen += sizeof(encryptedSignature); /* SignatureBlob */ serverCertLen += 8; /* 8 bytes of zero padding */ headerLen += sizeof(serverRandomLen); headerLen += sizeof(serverCertLen); headerLen += serverRandomLen; headerLen += serverCertLen; } gcc_write_user_data_header(s, SC_SECURITY, headerLen); Stream_Write_UINT32(s, settings->EncryptionMethods); /* encryptionMethod */ Stream_Write_UINT32(s, settings->EncryptionLevel); /* encryptionLevel */ if (settings->EncryptionMethods == ENCRYPTION_METHOD_NONE && settings->EncryptionLevel == ENCRYPTION_LEVEL_NONE) { return; } Stream_Write_UINT32(s, serverRandomLen); /* serverRandomLen */ Stream_Write_UINT32(s, serverCertLen); /* serverCertLen */ settings->ServerRandomLength = serverRandomLen; settings->ServerRandom = (BYTE*) malloc(serverRandomLen); crypto_nonce(settings->ServerRandom, serverRandomLen); Stream_Write(s, settings->ServerRandom, serverRandomLen); sigData = Stream_Pointer(s); Stream_Write_UINT32(s, CERT_CHAIN_VERSION_1); /* dwVersion (4 bytes) */ Stream_Write_UINT32(s, SIGNATURE_ALG_RSA); /* dwSigAlgId */ Stream_Write_UINT32(s, KEY_EXCHANGE_ALG_RSA); /* dwKeyAlgId */ Stream_Write_UINT16(s, BB_RSA_KEY_BLOB); /* wPublicKeyBlobType */ Stream_Write_UINT16(s, wPublicKeyBlobLen); /* wPublicKeyBlobLen */ Stream_Write(s, "RSA1", 4); /* magic */ Stream_Write_UINT32(s, keyLen + 8); /* keylen */ Stream_Write_UINT32(s, keyLen * 8); /* bitlen */ Stream_Write_UINT32(s, keyLen - 1); /* datalen */ Stream_Write(s, settings->RdpServerRsaKey->exponent, expLen); Stream_Write(s, settings->RdpServerRsaKey->Modulus, keyLen); Stream_Zero(s, 8); sigDataLen = Stream_Pointer(s) - sigData; Stream_Write_UINT16(s, BB_RSA_SIGNATURE_BLOB); /* wSignatureBlobType */ Stream_Write_UINT16(s, keyLen + 8); /* wSignatureBlobLen */ memcpy(signature, initial_signature, sizeof(initial_signature)); md5 = crypto_md5_init(); crypto_md5_update(md5, sigData, sigDataLen); crypto_md5_final(md5, signature); crypto_rsa_private_encrypt(signature, sizeof(signature), TSSK_KEY_LENGTH, tssk_modulus, tssk_privateExponent, encryptedSignature); Stream_Write(s, encryptedSignature, sizeof(encryptedSignature)); Stream_Zero(s, 8); }
BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length, wStream* input) { char* s = NULL; mode_t m; UINT64 size; int status; char* fullpath; struct STAT st; struct timeval tv[2]; UINT64 LastWriteTime; UINT32 FileAttributes; UINT32 FileNameLength; m = 0; switch (FsInformationClass) { case FileBasicInformation: /* http://msdn.microsoft.com/en-us/library/cc232094.aspx */ Stream_Seek_UINT64(input); /* CreationTime */ Stream_Seek_UINT64(input); /* LastAccessTime */ Stream_Read_UINT64(input, LastWriteTime); Stream_Seek_UINT64(input); /* ChangeTime */ Stream_Read_UINT32(input, FileAttributes); if (FSTAT(file->fd, &st) != 0) return FALSE; tv[0].tv_sec = st.st_atime; tv[0].tv_usec = 0; tv[1].tv_sec = (LastWriteTime > 0 ? FILE_TIME_RDP_TO_SYSTEM(LastWriteTime) : st.st_mtime); tv[1].tv_usec = 0; #ifndef WIN32 /* TODO on win32 */ #ifdef ANDROID utimes(file->fullpath, tv); #else futimes(file->fd, tv); #endif if (FileAttributes > 0) { m = st.st_mode; if ((FileAttributes & FILE_ATTRIBUTE_READONLY) == 0) m |= S_IWUSR; else m &= ~S_IWUSR; if (m != st.st_mode) fchmod(file->fd, m); } #endif break; case FileEndOfFileInformation: /* http://msdn.microsoft.com/en-us/library/cc232067.aspx */ case FileAllocationInformation: /* http://msdn.microsoft.com/en-us/library/cc232076.aspx */ Stream_Read_UINT64(input, size); if (ftruncate(file->fd, size) != 0) return FALSE; break; case FileDispositionInformation: /* http://msdn.microsoft.com/en-us/library/cc232098.aspx */ /* http://msdn.microsoft.com/en-us/library/cc241371.aspx */ if (Length) Stream_Read_UINT8(input, file->delete_pending); else file->delete_pending = 1; if (file->delete_pending && file->is_dir) { /* mstsc causes this to FAIL if the directory is not empty, * and that's what the server is expecting. If we wait for * the close to flag a failure, cut and paste of a folder * will lose the folder's contents. */ int status; status = rmdir(file->fullpath); if (status == 0) { /* Put it back so the normal pending delete will work. */ mkdir(file->fullpath, 0755); } else { return FALSE; } } break; case FileRenameInformation: /* http://msdn.microsoft.com/en-us/library/cc232085.aspx */ Stream_Seek_UINT8(input); /* ReplaceIfExists */ Stream_Seek_UINT8(input); /* RootDirectory */ Stream_Read_UINT32(input, FileNameLength); status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(input), FileNameLength / 2, &s, 0, NULL, NULL); if (status < 1) s = (char*) calloc(1, 1); fullpath = drive_file_combine_fullpath(file->basepath, s); free(s); /* TODO rename does not work on win32 */ if (rename(file->fullpath, fullpath) == 0) { DEBUG_SVC("renamed %s to %s", file->fullpath, fullpath); drive_file_set_fullpath(file, fullpath); } else { DEBUG_WARN("rename %s to %s failed, errno = %d", file->fullpath, fullpath, errno); free(fullpath); return FALSE; } break; default: DEBUG_WARN("invalid FsInformationClass %d", FsInformationClass); return FALSE; } return TRUE; }
BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, wStream* s) { int i; UINT32 cbFormat; BOOL ret = TRUE; memset(mediatype, 0, sizeof(TS_AM_MEDIA_TYPE)); /* MajorType */ DEBUG_DVC("MajorType:"); tsmf_print_guid(Stream_Pointer(s)); for (i = 0; tsmf_major_type_map[i].type != TSMF_MAJOR_TYPE_UNKNOWN; i++) { if (memcmp(tsmf_major_type_map[i].guid, Stream_Pointer(s), 16) == 0) break; } mediatype->MajorType = tsmf_major_type_map[i].type; if (mediatype->MajorType == TSMF_MAJOR_TYPE_UNKNOWN) ret = FALSE; DEBUG_DVC("MajorType %s", tsmf_major_type_map[i].name); Stream_Seek(s, 16); /* SubType */ DEBUG_DVC("SubType:"); tsmf_print_guid(Stream_Pointer(s)); for (i = 0; tsmf_sub_type_map[i].type != TSMF_SUB_TYPE_UNKNOWN; i++) { if (memcmp(tsmf_sub_type_map[i].guid, Stream_Pointer(s), 16) == 0) break; } mediatype->SubType = tsmf_sub_type_map[i].type; if (mediatype->SubType == TSMF_SUB_TYPE_UNKNOWN) ret = FALSE; DEBUG_DVC("SubType %s", tsmf_sub_type_map[i].name); Stream_Seek(s, 16); /* bFixedSizeSamples, bTemporalCompression, SampleSize */ Stream_Seek(s, 12); /* FormatType */ DEBUG_DVC("FormatType:"); tsmf_print_guid(Stream_Pointer(s)); for (i = 0; tsmf_format_type_map[i].type != TSMF_FORMAT_TYPE_UNKNOWN; i++) { if (memcmp(tsmf_format_type_map[i].guid, Stream_Pointer(s), 16) == 0) break; } mediatype->FormatType = tsmf_format_type_map[i].type; if (mediatype->FormatType == TSMF_FORMAT_TYPE_UNKNOWN) ret = FALSE; DEBUG_DVC("FormatType %s", tsmf_format_type_map[i].name); Stream_Seek(s, 16); /* cbFormat */ Stream_Read_UINT32(s, cbFormat); DEBUG_DVC("cbFormat %d", cbFormat); #ifdef WITH_DEBUG_DVC winpr_HexDump(Stream_Pointer(s), cbFormat); #endif switch (mediatype->FormatType) { case TSMF_FORMAT_TYPE_MFVIDEOFORMAT: /* http://msdn.microsoft.com/en-us/library/aa473808.aspx */ Stream_Seek(s, 8); /* dwSize and ? */ Stream_Read_UINT32(s, mediatype->Width); /* videoInfo.dwWidth */ Stream_Read_UINT32(s, mediatype->Height); /* videoInfo.dwHeight */ Stream_Seek(s, 32); /* videoInfo.FramesPerSecond */ Stream_Read_UINT32(s, mediatype->SamplesPerSecond.Numerator); Stream_Read_UINT32(s, mediatype->SamplesPerSecond.Denominator); Stream_Seek(s, 80); Stream_Read_UINT32(s, mediatype->BitRate); /* compressedInfo.AvgBitrate */ Stream_Seek(s, 36); if (cbFormat > 176) { mediatype->ExtraDataSize = cbFormat - 176; mediatype->ExtraData = Stream_Pointer(s); } break; case TSMF_FORMAT_TYPE_WAVEFORMATEX: /* http://msdn.microsoft.com/en-us/library/dd757720.aspx */ Stream_Seek_UINT16(s); Stream_Read_UINT16(s, mediatype->Channels); Stream_Read_UINT32(s, mediatype->SamplesPerSecond.Numerator); mediatype->SamplesPerSecond.Denominator = 1; Stream_Read_UINT32(s, mediatype->BitRate); mediatype->BitRate *= 8; Stream_Read_UINT16(s, mediatype->BlockAlign); Stream_Read_UINT16(s, mediatype->BitsPerSample); Stream_Read_UINT16(s, mediatype->ExtraDataSize); if (mediatype->ExtraDataSize > 0) mediatype->ExtraData = Stream_Pointer(s); break; case TSMF_FORMAT_TYPE_MPEG1VIDEOINFO: /* http://msdn.microsoft.com/en-us/library/dd390700.aspx */ i = tsmf_codec_parse_VIDEOINFOHEADER(mediatype, s); i += tsmf_codec_parse_BITMAPINFOHEADER(mediatype, s, TRUE); if (cbFormat > i) { mediatype->ExtraDataSize = cbFormat - i; mediatype->ExtraData = Stream_Pointer(s); } break; case TSMF_FORMAT_TYPE_MPEG2VIDEOINFO: /* http://msdn.microsoft.com/en-us/library/dd390707.aspx */ i = tsmf_codec_parse_VIDEOINFOHEADER2(mediatype, s); i += tsmf_codec_parse_BITMAPINFOHEADER(mediatype, s, TRUE); if (cbFormat > i) { mediatype->ExtraDataSize = cbFormat - i; mediatype->ExtraData = Stream_Pointer(s); } break; case TSMF_FORMAT_TYPE_VIDEOINFO2: i = tsmf_codec_parse_VIDEOINFOHEADER2(mediatype, s); i += tsmf_codec_parse_BITMAPINFOHEADER(mediatype, s, FALSE); if (cbFormat > i) { mediatype->ExtraDataSize = cbFormat - i; mediatype->ExtraData = Stream_Pointer(s); } break; default: break; } if (mediatype->SamplesPerSecond.Numerator == 0) mediatype->SamplesPerSecond.Numerator = 1; if (mediatype->SamplesPerSecond.Denominator == 0) mediatype->SamplesPerSecond.Denominator = 1; return ret; }
/** * Function description * * @return 0 on success, otherwise a Win32 error code */ static UINT audin_server_recv_data(audin_server* audin, wStream* s, UINT32 length) { AUDIO_FORMAT* format; int sbytes_per_sample; int sbytes_per_frame; BYTE* src; int size; int frames; UINT success = CHANNEL_RC_OK; if (audin->context.selected_client_format < 0) { WLog_ERR(TAG, "audin->context.selected_client_format = %d", audin->context.selected_client_format); return ERROR_INVALID_DATA; } format = &audin->context.client_formats[audin->context.selected_client_format]; if (format->wFormatTag == WAVE_FORMAT_ADPCM) { audin->dsp_context->decode_ms_adpcm(audin->dsp_context, Stream_Pointer(s), length, format->nChannels, format->nBlockAlign); size = audin->dsp_context->adpcm_size; src = audin->dsp_context->adpcm_buffer; sbytes_per_sample = 2; sbytes_per_frame = format->nChannels * 2; } else if (format->wFormatTag == WAVE_FORMAT_DVI_ADPCM) { audin->dsp_context->decode_ima_adpcm(audin->dsp_context, Stream_Pointer(s), length, format->nChannels, format->nBlockAlign); size = audin->dsp_context->adpcm_size; src = audin->dsp_context->adpcm_buffer; sbytes_per_sample = 2; sbytes_per_frame = format->nChannels * 2; } else { size = length; src = Stream_Pointer(s); sbytes_per_sample = format->wBitsPerSample / 8; sbytes_per_frame = format->nChannels * sbytes_per_sample; } if (format->nSamplesPerSec == audin->context.dst_format.nSamplesPerSec && format->nChannels == audin->context.dst_format.nChannels) { frames = size / sbytes_per_frame; } else { audin->dsp_context->resample(audin->dsp_context, src, sbytes_per_sample, format->nChannels, format->nSamplesPerSec, size / sbytes_per_frame, audin->context.dst_format.nChannels, audin->context.dst_format.nSamplesPerSec); frames = audin->dsp_context->resampled_frames; src = audin->dsp_context->resampled_buffer; } IFCALLRET(audin->context.ReceiveSamples, success, &audin->context, src, frames); if (success) WLog_ERR(TAG, "context.ReceiveSamples failed with error %lu", success); return success; }
/** * Function description * * @return 0 on success, otherwise a Win32 error code */ static UINT cliprdr_server_format_list(CliprdrServerContext* context, CLIPRDR_FORMAT_LIST* formatList) { wStream* s; UINT32 index; int length = 0; int cchWideChar; LPWSTR lpWideCharStr; int formatNameSize; int formatNameLength; char* szFormatName; WCHAR* wszFormatName; BOOL asciiNames = FALSE; CLIPRDR_FORMAT* format; CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; if (!cliprdr->useLongFormatNames) { length = formatList->numFormats * 36; s = cliprdr_server_packet_new(CB_FORMAT_LIST, 0, length); if (!s) { WLog_ERR(TAG, "cliprdr_server_packet_new failed!"); return ERROR_INTERNAL_ERROR; } for (index = 0; index < formatList->numFormats; index++) { format = (CLIPRDR_FORMAT*) &(formatList->formats[index]); Stream_Write_UINT32(s, format->formatId); /* formatId (4 bytes) */ formatNameSize = 0; formatNameLength = 0; szFormatName = format->formatName; if (asciiNames) { if (szFormatName) formatNameLength = strlen(szFormatName); if (formatNameLength > 31) formatNameLength = 31; Stream_Write(s, szFormatName, formatNameLength); Stream_Zero(s, 32 - formatNameLength); } else { wszFormatName = NULL; if (szFormatName) formatNameSize = ConvertToUnicode(CP_UTF8, 0, szFormatName, -1, &wszFormatName, 0); if (formatNameSize > 15) formatNameSize = 15; if (wszFormatName) Stream_Write(s, wszFormatName, formatNameSize * 2); Stream_Zero(s, 32 - (formatNameSize * 2)); free(wszFormatName); } } } else { for (index = 0; index < formatList->numFormats; index++) { format = (CLIPRDR_FORMAT*) &(formatList->formats[index]); length += 4; formatNameSize = 2; if (format->formatName) formatNameSize = MultiByteToWideChar(CP_UTF8, 0, format->formatName, -1, NULL, 0) * 2; length += formatNameSize; } s = cliprdr_server_packet_new(CB_FORMAT_LIST, 0, length); if (!s) { WLog_ERR(TAG, "cliprdr_server_packet_new failed!"); return ERROR_INTERNAL_ERROR; } for (index = 0; index < formatList->numFormats; index++) { format = (CLIPRDR_FORMAT*) &(formatList->formats[index]); Stream_Write_UINT32(s, format->formatId); /* formatId (4 bytes) */ if (format->formatName) { lpWideCharStr = (LPWSTR) Stream_Pointer(s); cchWideChar = (Stream_Capacity(s) - Stream_GetPosition(s)) / 2; formatNameSize = MultiByteToWideChar(CP_UTF8, 0, format->formatName, -1, lpWideCharStr, cchWideChar) * 2; Stream_Seek(s, formatNameSize); } else { Stream_Write_UINT16(s, 0); } } } WLog_DBG(TAG, "ServerFormatList: numFormats: %d", formatList->numFormats); return cliprdr_server_packet_send(cliprdr, s); }