static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder* decoder, const BYTE *data, UINT32 data_size, UINT32 extensions) { TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; int len; int frame_size; UINT32 src_size; const BYTE *src; BYTE *dst; int dst_offset; #if 0 WLog_DBG(TAG, ("tsmf_ffmpeg_decode_audio: data_size %d", data_size)); int i; for(i = 0; i < data_size; i++) { WLog_DBG(TAG, ("%02X ", data[i])); if (i % 16 == 15) WLog_DBG(TAG, ("\n")); } #endif if (mdecoder->decoded_size_max == 0) mdecoder->decoded_size_max = MAX_AUDIO_FRAME_SIZE + 16; mdecoder->decoded_data = calloc(1, mdecoder->decoded_size_max); if (!mdecoder->decoded_data) return FALSE; /* align the memory for SSE2 needs */ dst = (BYTE *)(((uintptr_t) mdecoder->decoded_data + 15) & ~ 0x0F); dst_offset = dst - mdecoder->decoded_data; src = data; src_size = data_size; while(src_size > 0) { /* Ensure enough space for decoding */ if (mdecoder->decoded_size_max - mdecoder->decoded_size < MAX_AUDIO_FRAME_SIZE) { BYTE *tmp_data; tmp_data = realloc(mdecoder->decoded_data, mdecoder->decoded_size_max * 2 + 16); if (!tmp_data) return FALSE; mdecoder->decoded_size_max = mdecoder->decoded_size_max * 2 + 16; mdecoder->decoded_data = tmp_data; dst = (BYTE *)(((uintptr_t)mdecoder->decoded_data + 15) & ~ 0x0F); if (dst - mdecoder->decoded_data != dst_offset) { /* re-align the memory if the alignment has changed after realloc */ memmove(dst, mdecoder->decoded_data + dst_offset, mdecoder->decoded_size); dst_offset = dst - mdecoder->decoded_data; } dst += mdecoder->decoded_size; } frame_size = mdecoder->decoded_size_max - mdecoder->decoded_size; #if LIBAVCODEC_VERSION_MAJOR < 52 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR <= 20) len = avcodec_decode_audio2(mdecoder->codec_context, (int16_t *) dst, &frame_size, src, src_size); #else { AVFrame *decoded_frame = avcodec_alloc_frame(); int got_frame = 0; AVPacket pkt; av_init_packet(&pkt); pkt.data = (BYTE *) src; pkt.size = src_size; len = avcodec_decode_audio4(mdecoder->codec_context, decoded_frame, &got_frame, &pkt); if (len >= 0 && got_frame) { frame_size = av_samples_get_buffer_size(NULL, mdecoder->codec_context->channels, decoded_frame->nb_samples, mdecoder->codec_context->sample_fmt, 1); memcpy(dst, decoded_frame->data[0], frame_size); } av_free(decoded_frame); } #endif if (len <= 0 || frame_size <= 0) { WLog_ERR(TAG, "error decoding"); break; } src += len; src_size -= len; mdecoder->decoded_size += frame_size; dst += frame_size; } if (mdecoder->decoded_size == 0) { free(mdecoder->decoded_data); mdecoder->decoded_data = NULL; } else if (dst_offset) { /* move the aligned decoded data to original place */ memmove(mdecoder->decoded_data, mdecoder->decoded_data + dst_offset, mdecoder->decoded_size); } DEBUG_TSMF("data_size %d decoded_size %d", data_size, mdecoder->decoded_size); return TRUE; }
void nego_enable_rdp(rdpNego* nego, BOOL enable_rdp) { WLog_DBG(TAG, "Enabling RDP security: %s", enable_rdp ? "TRUE" : "FALSE"); nego->EnabledProtocols[PROTOCOL_RDP] = enable_rdp; }
void nego_enable_nla(rdpNego* nego, BOOL enable_nla) { WLog_DBG(TAG, "Enabling NLA security: %s", enable_nla ? "TRUE" : "FALSE"); nego->EnabledProtocols[PROTOCOL_NLA] = enable_nla; }
static BOOL freerdp_listener_check_fds(freerdp_listener* instance) { int i; void* sin_addr; int peer_sockfd; freerdp_peer* client = NULL; socklen_t peer_addr_size; struct sockaddr_storage peer_addr; rdpListener* listener = (rdpListener*) instance->listener; static const BYTE localhost6_bytes[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; if (listener->num_sockfds < 1) return FALSE; for (i = 0; i < listener->num_sockfds; i++) { peer_addr_size = sizeof(peer_addr); peer_sockfd = accept(listener->sockfds[i], (struct sockaddr*) &peer_addr, &peer_addr_size); if (peer_sockfd == -1) { #ifdef _WIN32 int wsa_error = WSAGetLastError(); /* No data available */ if (wsa_error == WSAEWOULDBLOCK) continue; #else if (errno == EAGAIN || errno == EWOULDBLOCK) continue; #endif WLog_DBG(TAG, "accept"); if (client) free(client); return FALSE; } client = freerdp_peer_new(peer_sockfd); sin_addr = NULL; if (peer_addr.ss_family == AF_INET) { sin_addr = &(((struct sockaddr_in*) &peer_addr)->sin_addr); if ((*(UINT32*) sin_addr) == 0x0100007f) client->local = TRUE; } else if (peer_addr.ss_family == AF_INET6) { sin_addr = &(((struct sockaddr_in6*) &peer_addr)->sin6_addr); if (memcmp(sin_addr, localhost6_bytes, 16) == 0) client->local = TRUE; } #ifndef _WIN32 else if (peer_addr.ss_family == AF_UNIX) client->local = TRUE; #endif if (sin_addr) inet_ntop(peer_addr.ss_family, sin_addr, client->hostname, sizeof(client->hostname)); IFCALL(instance->PeerAccepted, instance, client); } return TRUE; }
void nego_set_negotiation_enabled(rdpNego* nego, BOOL NegotiateSecurityLayer) { WLog_DBG(TAG, "Enabling security layer negotiation: %s", NegotiateSecurityLayer ? "TRUE" : "FALSE"); nego->NegotiateSecurityLayer = NegotiateSecurityLayer; }
/** * Function description * * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_recv_reset_graphics_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) { int pad; UINT32 index; MONITOR_DEF* monitor; RDPGFX_RESET_GRAPHICS_PDU pdu; RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; UINT error = CHANNEL_RC_OK; if (Stream_GetRemainingLength(s) < 12) { WLog_ERR(TAG, "not enough data!"); return ERROR_INVALID_DATA; } Stream_Read_UINT32(s, pdu.width); /* width (4 bytes) */ Stream_Read_UINT32(s, pdu.height); /* height (4 bytes) */ Stream_Read_UINT32(s, pdu.monitorCount); /* monitorCount (4 bytes) */ if (Stream_GetRemainingLength(s) < (pdu.monitorCount * 20)) { WLog_ERR(TAG, "not enough data!"); return ERROR_INVALID_DATA; } pdu.monitorDefArray = (MONITOR_DEF*) calloc(pdu.monitorCount, sizeof(MONITOR_DEF)); if (!pdu.monitorDefArray) { WLog_ERR(TAG, "calloc failed!"); return CHANNEL_RC_NO_MEMORY; } for (index = 0; index < pdu.monitorCount; index++) { monitor = &(pdu.monitorDefArray[index]); Stream_Read_UINT32(s, monitor->left); /* left (4 bytes) */ Stream_Read_UINT32(s, monitor->top); /* top (4 bytes) */ Stream_Read_UINT32(s, monitor->right); /* right (4 bytes) */ Stream_Read_UINT32(s, monitor->bottom); /* bottom (4 bytes) */ Stream_Read_UINT32(s, monitor->flags); /* flags (4 bytes) */ } pad = 340 - (RDPGFX_HEADER_SIZE + 12 + (pdu.monitorCount * 20)); if (Stream_GetRemainingLength(s) < (size_t) pad) { WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); free(pdu.monitorDefArray); return CHANNEL_RC_NO_MEMORY; } Stream_Seek(s, pad); /* pad (total size is 340 bytes) */ WLog_DBG(TAG, "RecvResetGraphicsPdu: width: %d height: %d count: %d", pdu.width, pdu.height, pdu.monitorCount); if (context) { IFCALLRET(context->ResetGraphics, error, context, &pdu); if (error) WLog_ERR(TAG, "context->ResetGraphics failed with error %lu", error); } free(pdu.monitorDefArray); return error; }
/** * Function description * * @return 0 on success, otherwise a Win32 error code */ UINT rdpgfx_recv_solid_fill_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) { UINT16 index; RECTANGLE_16* fillRect; RDPGFX_SOLID_FILL_PDU pdu; RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; UINT error; if (Stream_GetRemainingLength(s) < 8) { WLog_ERR(TAG, "not enough data!"); return ERROR_INVALID_DATA; } Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ if ((error = rdpgfx_read_color32(s, &(pdu.fillPixel)))) /* fillPixel (4 bytes) */ { WLog_ERR(TAG, "rdpgfx_read_color32 failed with error %lu!", error); return error; } Stream_Read_UINT16(s, pdu.fillRectCount); /* fillRectCount (2 bytes) */ if (Stream_GetRemainingLength(s) < (size_t) (pdu.fillRectCount * 8)) { WLog_ERR(TAG, "not enough data!"); return ERROR_INVALID_DATA; } pdu.fillRects = (RECTANGLE_16*) calloc(pdu.fillRectCount, sizeof(RECTANGLE_16)); if (!pdu.fillRects) { WLog_ERR(TAG, "calloc failed!"); return CHANNEL_RC_NO_MEMORY; } for (index = 0; index < pdu.fillRectCount; index++) { fillRect = &(pdu.fillRects[index]); if ((error = rdpgfx_read_rect16(s, fillRect))) { WLog_ERR(TAG, "rdpgfx_read_rect16 failed with error %lu!", error); free(pdu.fillRects); return error; } } WLog_DBG(TAG, "RecvSolidFillPdu: surfaceId: %d fillRectCount: %d", pdu.surfaceId, pdu.fillRectCount); if (context) { IFCALLRET(context->SolidFill, error, context, &pdu); if (error) WLog_ERR(TAG, "context->SolidFill failed with error %lu", error); } free(pdu.fillRects); return error; }
BOOL tf_peer_post_connect(freerdp_peer* client) { testPeerContext* context = (testPeerContext*) client->context; /** * This callback is called when the entire connection sequence is done, i.e. we've received the * Font List PDU from the client and sent out the Font Map PDU. * The server may start sending graphics output and receiving keyboard/mouse input after this * callback returns. */ WLog_DBG(TAG, "Client %s is activated (osMajorType %d osMinorType %d)", client->local ? "(local)" : client->hostname, client->settings->OsMajorType, client->settings->OsMinorType); if (client->settings->AutoLogonEnabled) { WLog_DBG(TAG, " and wants to login automatically as %s\\%s", client->settings->Domain ? client->settings->Domain : "", client->settings->Username); /* A real server may perform OS login here if NLA is not executed previously. */ } WLog_DBG(TAG, ""); WLog_DBG(TAG, "Client requested desktop: %dx%dx%d", client->settings->DesktopWidth, client->settings->DesktopHeight, client->settings->ColorDepth); #if (SAMPLE_SERVER_USE_CLIENT_RESOLUTION == 1) context->rfx_context->width = client->settings->DesktopWidth; context->rfx_context->height = client->settings->DesktopHeight; WLog_DBG(TAG, "Using resolution requested by client."); #else client->settings->DesktopWidth = context->rfx_context->width; client->settings->DesktopHeight = context->rfx_context->height; WLog_DBG(TAG, "Resizing client to %dx%d", client->settings->DesktopWidth, client->settings->DesktopHeight); client->update->DesktopResize(client->update->context); #endif /* A real server should tag the peer as activated here and start sending updates in main loop. */ test_peer_load_icon(client); if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, "rdpdbg")) { context->debug_channel = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "rdpdbg"); if (context->debug_channel != NULL) { WLog_DBG(TAG, "Open channel rdpdbg."); if (!(context->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) { WLog_ERR(TAG, "Failed to create stop event"); return FALSE; } if (!(context->debug_channel_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) tf_debug_channel_thread_func, (void*) context, 0, NULL))) { WLog_ERR(TAG, "Failed to create debug channel thread"); CloseHandle(context->stopEvent); context->stopEvent = NULL; return FALSE; } } } if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, "rdpsnd")) { sf_peer_rdpsnd_init(context); /* Audio Output */ } if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, "encomsp")) { sf_peer_encomsp_init(context); /* Lync Multiparty */ } /* Dynamic Virtual Channels */ sf_peer_audin_init(context); /* Audio Input */ /* Return FALSE here would stop the execution of the peer main loop. */ return TRUE; }
BOOL tf_peer_synchronize_event(rdpInput* input, UINT32 flags) { WLog_DBG(TAG, "Client sent a synchronize event (flags:0x%X)", flags); return TRUE; }
/* * Handle rpdsnd messages - server side * * @param Server side context * * @return -1 if no data could be read, * 0 on error (like connection close), * 1 on succsess (also if further bytes need to be read) */ int rdpsnd_server_handle_messages(RdpsndServerContext *context) { DWORD bytesReturned; BOOL ret; RdpsndServerPrivate *priv = context->priv; wStream *s = priv->input_stream; if (!WTSVirtualChannelRead(priv->ChannelHandle, 0, (PCHAR)Stream_Pointer(s), priv->expectedBytes, &bytesReturned)) { if (GetLastError() == ERROR_NO_DATA) return -1; WLog_ERR(TAG, "%s: channel connection closed\n", __FUNCTION__); return 0; } priv->expectedBytes -= bytesReturned; Stream_Seek(s, bytesReturned); if (priv->expectedBytes) return 1; Stream_SealLength(s); Stream_SetPosition(s, 0); if (priv->waitingHeader) { /* header case */ Stream_Read_UINT8(s, priv->msgType); Stream_Seek_UINT8(s); /* bPad */ Stream_Read_UINT16(s, priv->expectedBytes); priv->waitingHeader = FALSE; Stream_SetPosition(s, 0); if (priv->expectedBytes) { Stream_EnsureCapacity(s, priv->expectedBytes); return 1; } } /* when here we have the header + the body */ #ifdef WITH_DEBUG_SND WLog_DBG(TAG, "message type %d", priv->msgType); #endif priv->expectedBytes = 4; priv->waitingHeader = TRUE; switch (priv->msgType) { case SNDC_WAVECONFIRM: ret = rdpsnd_server_recv_waveconfirm(context, s); break; case SNDC_FORMATS: ret = rdpsnd_server_recv_formats(context, s); if (ret && context->clientVersion < 6) IFCALL(context->Activated, context); break; case SNDC_QUALITYMODE: ret = rdpsnd_server_recv_quality_mode(context, s); Stream_SetPosition(s, 0); /* in case the Activated callback tries to treat some messages */ if (ret && context->clientVersion >= 6) IFCALL(context->Activated, context); break; default: WLog_ERR(TAG, "%s: UNKOWN MESSAGE TYPE!! (%#0X)\n\n", __FUNCTION__, priv->msgType); ret = FALSE; break; } Stream_SetPosition(s, 0); if (ret) return 1; else return 0; }
/** * Function description * * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_server_receive_pdu(RdpgfxServerContext* context, wStream* s) { int beg, end; RDPGFX_HEADER header; UINT error = CHANNEL_RC_OK; beg = Stream_GetPosition(s); if ((error = rdpgfx_read_header(s, &header))) { WLog_ERR(TAG, "rdpgfx_read_header failed with error %"PRIu32"!", error); return error; } WLog_DBG(TAG, "cmdId: %s (0x%04"PRIX16") flags: 0x%04"PRIX16" pduLength: %"PRIu32"", rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, header.flags, header.pduLength); switch (header.cmdId) { case RDPGFX_CMDID_FRAMEACKNOWLEDGE: if ((error = rdpgfx_recv_frame_acknowledge_pdu(context, s))) WLog_ERR(TAG, "rdpgfx_recv_frame_acknowledge_pdu " "failed with error %"PRIu32"!", error); break; case RDPGFX_CMDID_CACHEIMPORTOFFER: if ((error = rdpgfx_recv_cache_import_offer_pdu(context, s))) WLog_ERR(TAG, "rdpgfx_recv_cache_import_offer_pdu " "failed with error %"PRIu32"!", error); break; case RDPGFX_CMDID_CAPSADVERTISE: if ((error = rdpgfx_recv_caps_advertise_pdu(context, s))) WLog_ERR(TAG, "rdpgfx_recv_caps_advertise_pdu " "failed with error %"PRIu32"!", error); break; case RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE: if ((error = rdpgfx_recv_qoe_frame_acknowledge_pdu(context, s))) WLog_ERR(TAG, "rdpgfx_recv_qoe_frame_acknowledge_pdu " "failed with error %"PRIu32"!", error); break; default: error = CHANNEL_RC_BAD_PROC; break; } if (error) { WLog_ERR(TAG, "Error while parsing GFX cmdId: %s (0x%04"PRIX16")", rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId); return error; } end = Stream_GetPosition(s); if (end != (beg + header.pduLength)) { WLog_ERR(TAG, "Unexpected gfx pdu end: Actual: %d, Expected: %"PRIu32"", end, (beg + header.pduLength)); Stream_SetPosition(s, (beg + header.pduLength)); } return error; }
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) { WLog_DBG(TAG, "Local > Remote"); winpr_HexDump(TAG, WLOG_DEBUG, 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) { WLog_ERR(TAG, "error when selecting for write"); 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) { WLog_ERR(TAG, "error when selecting for write"); return -1; } if (!transport_bio_buffered_drain(out->bufferedBio)) { WLog_ERR(TAG, "error when draining outputBuffer"); 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; }
/** * @brief Try to read a complete PDU (NLA, fast-path or tpkt) from the underlying transport. * * If possible a complete PDU is read, in case of non blocking transport this might not succeed. * Except in case of an error the passed stream will point to the last byte read (correct * position). When the pdu read is completed the stream is sealed and the pointer set to 0 * * @param[in] transport rdpTransport * @param[in] s wStream * @return < 0 on error; 0 if not enough data is available (non blocking mode); > 0 number of * bytes of the *complete* pdu read */ int transport_read_pdu(rdpTransport* transport, wStream* s) { int status; int position; int pduLength; BYTE* header; position = 0; pduLength = 0; if (!transport) return -1; if (!s) return -1; position = Stream_GetPosition(s); /* Make sure there is enough space for the longest header within the stream */ Stream_EnsureCapacity(s, 4); /* Make sure at least two bytes are read for futher processing */ if (position < 2 && (status = transport_read_layer_bytes(transport, s, 2 - position)) != 1) { /* No data available at the moment */ return status; } header = Stream_Buffer(s); if (transport->NlaMode) { /* * In case NlaMode is set TSRequest package(s) are expected * 0x30 = DER encoded data with these bits set: * bit 6 P/C constructed * bit 5 tag number - sequence */ if (header[0] == 0x30) { /* TSRequest (NLA) */ if (header[1] & 0x80) { if ((header[1] & ~(0x80)) == 1) { if ((status = transport_read_layer_bytes(transport, s, 1)) != 1) return status; pduLength = header[2]; pduLength += 3; } else if ((header[1] & ~(0x80)) == 2) { if ((status = transport_read_layer_bytes(transport, s, 2)) != 1) return status; pduLength = (header[2] << 8) | header[3]; pduLength += 4; } else { WLog_ERR(TAG, "Error reading TSRequest!"); return -1; } } else { pduLength = header[1]; pduLength += 2; } } } else { if (header[0] == 0x03) { /* TPKT header */ if ((status = transport_read_layer_bytes(transport, s, 2)) != 1) return status; pduLength = (header[2] << 8) | header[3]; /* min and max values according to ITU-T Rec. T.123 (01/2007) section 8 */ if (pduLength < 7 || pduLength > 0xFFFF) { WLog_ERR(TAG, "tpkt - invalid pduLength: %d", pduLength); return -1; } } else { /* Fast-Path Header */ if (header[1] & 0x80) { if ((status = transport_read_layer_bytes(transport, s, 1)) != 1) return status; pduLength = ((header[1] & 0x7F) << 8) | header[2]; } else pduLength = header[1]; /* * fast-path has 7 bits for length so the maximum size, including headers is 0x8000 * The theoretical minimum fast-path PDU consists only of two header bytes plus one * byte for data (e.g. fast-path input synchronize pdu) */ if (pduLength < 3 || pduLength > 0x8000) { WLog_ERR(TAG, "fast path - invalid pduLength: %d", pduLength); return -1; } } } Stream_EnsureCapacity(s, Stream_GetPosition(s) + pduLength); status = transport_read_layer_bytes(transport, s, pduLength - Stream_GetPosition(s)); if (status != 1) return status; #ifdef WITH_DEBUG_TRANSPORT /* dump when whole PDU is read */ if (Stream_GetPosition(s) >= pduLength) { WLog_DBG(TAG, "Local < Remote"); winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), pduLength); } #endif if (Stream_GetPosition(s) >= pduLength) WLog_Packet(transport->log, WLOG_TRACE, Stream_Buffer(s), pduLength, WLOG_PACKET_INBOUND); Stream_SealLength(s); Stream_SetPosition(s, 0); return Stream_Length(s); }
int rdpei_write_touch_frame(wStream* s, RDPINPUT_TOUCH_FRAME* frame) { UINT32 index; int rectSize = 2; RDPINPUT_CONTACT_DATA* contact; #ifdef WITH_DEBUG_RDPEI WLog_DBG(TAG, "contactCount: %d", frame->contactCount); WLog_DBG(TAG, "frameOffset: 0x%08X", (UINT32) frame->frameOffset); #endif rdpei_write_2byte_unsigned(s, frame->contactCount); /* contactCount (TWO_BYTE_UNSIGNED_INTEGER) */ /** * the time offset from the previous frame (in microseconds). * If this is the first frame being transmitted then this field MUST be set to zero. */ rdpei_write_8byte_unsigned(s, frame->frameOffset * 1000); /* frameOffset (EIGHT_BYTE_UNSIGNED_INTEGER) */ Stream_EnsureRemainingCapacity(s, (size_t) frame->contactCount * 64); for (index = 0; index < frame->contactCount; index++) { contact = &frame->contacts[index]; contact->fieldsPresent |= CONTACT_DATA_CONTACTRECT_PRESENT; contact->contactRectLeft = contact->x - rectSize; contact->contactRectTop = contact->y - rectSize; contact->contactRectRight = contact->x + rectSize; contact->contactRectBottom = contact->y + rectSize; #ifdef WITH_DEBUG_RDPEI WLog_DBG(TAG, "contact[%d].contactId: %d", index, contact->contactId); WLog_DBG(TAG, "contact[%d].fieldsPresent: %d", index, contact->fieldsPresent); WLog_DBG(TAG, "contact[%d].x: %d", index, contact->x); WLog_DBG(TAG, "contact[%d].y: %d", index, contact->y); WLog_DBG(TAG, "contact[%d].contactFlags: 0x%04X", index, contact->contactFlags); rdpei_print_contact_flags(contact->contactFlags); #endif Stream_Write_UINT8(s, contact->contactId); /* contactId (1 byte) */ /* fieldsPresent (TWO_BYTE_UNSIGNED_INTEGER) */ rdpei_write_2byte_unsigned(s, contact->fieldsPresent); rdpei_write_4byte_signed(s, contact->x); /* x (FOUR_BYTE_SIGNED_INTEGER) */ rdpei_write_4byte_signed(s, contact->y); /* y (FOUR_BYTE_SIGNED_INTEGER) */ /* contactFlags (FOUR_BYTE_UNSIGNED_INTEGER) */ rdpei_write_4byte_unsigned(s, contact->contactFlags); if (contact->fieldsPresent & CONTACT_DATA_CONTACTRECT_PRESENT) { /* contactRectLeft (TWO_BYTE_SIGNED_INTEGER) */ rdpei_write_2byte_signed(s, contact->contactRectLeft); /* contactRectTop (TWO_BYTE_SIGNED_INTEGER) */ rdpei_write_2byte_signed(s, contact->contactRectTop); /* contactRectRight (TWO_BYTE_SIGNED_INTEGER) */ rdpei_write_2byte_signed(s, contact->contactRectRight); /* contactRectBottom (TWO_BYTE_SIGNED_INTEGER) */ rdpei_write_2byte_signed(s, contact->contactRectBottom); } if (contact->fieldsPresent & CONTACT_DATA_ORIENTATION_PRESENT) { /* orientation (FOUR_BYTE_UNSIGNED_INTEGER) */ rdpei_write_4byte_unsigned(s, contact->orientation); } if (contact->fieldsPresent & CONTACT_DATA_PRESSURE_PRESENT) { /* pressure (FOUR_BYTE_UNSIGNED_INTEGER) */ rdpei_write_4byte_unsigned(s, contact->pressure); } } return 0; }
/** * Function description * * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_recv_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) { int beg, end; RDPGFX_HEADER header; UINT error; beg = Stream_GetPosition(s); if ((error = rdpgfx_read_header(s, &header))) { WLog_ERR(TAG, "rdpgfx_read_header failed with error %lu!", error); return error; } #if 1 WLog_DBG(TAG, "cmdId: %s (0x%04X) flags: 0x%04X pduLength: %d", rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, header.flags, header.pduLength); #endif switch (header.cmdId) { case RDPGFX_CMDID_WIRETOSURFACE_1: if ((error = rdpgfx_recv_wire_to_surface_1_pdu(callback, s))) WLog_ERR(TAG, "rdpgfx_recv_wire_to_surface_1_pdu failed with error %lu!", error); break; case RDPGFX_CMDID_WIRETOSURFACE_2: if ((error = rdpgfx_recv_wire_to_surface_2_pdu(callback, s))) WLog_ERR(TAG, "rdpgfx_recv_wire_to_surface_2_pdu failed with error %lu!", error); break; case RDPGFX_CMDID_DELETEENCODINGCONTEXT: if ((error = rdpgfx_recv_delete_encoding_context_pdu(callback, s))) WLog_ERR(TAG, "rdpgfx_recv_delete_encoding_context_pdu failed with error %lu!", error); break; case RDPGFX_CMDID_SOLIDFILL: if ((error = rdpgfx_recv_solid_fill_pdu(callback, s))) WLog_ERR(TAG, "rdpgfx_recv_solid_fill_pdu failed with error %lu!", error); break; case RDPGFX_CMDID_SURFACETOSURFACE: if ((error = rdpgfx_recv_surface_to_surface_pdu(callback, s))) WLog_ERR(TAG, "rdpgfx_recv_surface_to_surface_pdu failed with error %lu!", error); break; case RDPGFX_CMDID_SURFACETOCACHE: if ((error = rdpgfx_recv_surface_to_cache_pdu(callback, s))) WLog_ERR(TAG, "rdpgfx_recv_surface_to_cache_pdu failed with error %lu!", error); break; case RDPGFX_CMDID_CACHETOSURFACE: if ((error = rdpgfx_recv_cache_to_surface_pdu(callback, s))) WLog_ERR(TAG, "rdpgfx_recv_cache_to_surface_pdu failed with error %lu!", error); break; case RDPGFX_CMDID_EVICTCACHEENTRY: if ((error = rdpgfx_recv_evict_cache_entry_pdu(callback, s))) WLog_ERR(TAG, "rdpgfx_recv_evict_cache_entry_pdu failed with error %lu!", error); break; case RDPGFX_CMDID_CREATESURFACE: if ((error = rdpgfx_recv_create_surface_pdu(callback, s))) WLog_ERR(TAG, "rdpgfx_recv_create_surface_pdu failed with error %lu!", error); break; case RDPGFX_CMDID_DELETESURFACE: if ((error = rdpgfx_recv_delete_surface_pdu(callback, s))) WLog_ERR(TAG, "rdpgfx_recv_delete_surface_pdu failed with error %lu!", error); break; case RDPGFX_CMDID_STARTFRAME: if ((error = rdpgfx_recv_start_frame_pdu(callback, s))) WLog_ERR(TAG, "rdpgfx_recv_start_frame_pdu failed with error %lu!", error); break; case RDPGFX_CMDID_ENDFRAME: if ((error = rdpgfx_recv_end_frame_pdu(callback, s))) WLog_ERR(TAG, "rdpgfx_recv_end_frame_pdu failed with error %lu!", error); break; case RDPGFX_CMDID_RESETGRAPHICS: if ((error = rdpgfx_recv_reset_graphics_pdu(callback, s))) WLog_ERR(TAG, "rdpgfx_recv_reset_graphics_pdu failed with error %lu!", error); break; case RDPGFX_CMDID_MAPSURFACETOOUTPUT: if ((error = rdpgfx_recv_map_surface_to_output_pdu(callback, s))) WLog_ERR(TAG, "rdpgfx_recv_map_surface_to_output_pdu failed with error %lu!", error); break; case RDPGFX_CMDID_CACHEIMPORTREPLY: if ((error = rdpgfx_recv_cache_import_reply_pdu(callback, s))) WLog_ERR(TAG, "rdpgfx_recv_cache_import_reply_pdu failed with error %lu!", error); break; case RDPGFX_CMDID_CAPSCONFIRM: if ((error = rdpgfx_recv_caps_confirm_pdu(callback, s))) WLog_ERR(TAG, "rdpgfx_recv_caps_confirm_pdu failed with error %lu!", error); break; case RDPGFX_CMDID_MAPSURFACETOWINDOW: if ((error = rdpgfx_recv_map_surface_to_window_pdu(callback, s))) WLog_ERR(TAG, "rdpgfx_recv_map_surface_to_window_pdu failed with error %lu!", error); break; default: error = CHANNEL_RC_BAD_PROC; break; } if (error) { WLog_ERR(TAG, "Error while parsing GFX cmdId: %s (0x%04X)", rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId); return error; } end = Stream_GetPosition(s); if (end != (beg + header.pduLength)) { WLog_ERR(TAG, "Unexpected gfx pdu end: Actual: %d, Expected: %d", end, (beg + header.pduLength)); Stream_SetPosition(s, (beg + header.pduLength)); } return error; }
BOOL tf_peer_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) { WLog_DBG(TAG, "Client sent a unicode keyboard event (flags:0x%X code:0x%X)", flags, code); return TRUE; }
/** * Function description * * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_plugin_terminated(IWTSPlugin* pPlugin) { int count; int index; ULONG_PTR* pKeys = NULL; RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) pPlugin; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; UINT error = CHANNEL_RC_OK; WLog_DBG(TAG, "Terminated"); if (gfx->listener_callback) { free(gfx->listener_callback); gfx->listener_callback = NULL; } if (gfx->zgfx) { zgfx_context_free(gfx->zgfx); gfx->zgfx = NULL; } count = HashTable_GetKeys(gfx->SurfaceTable, &pKeys); for (index = 0; index < count; index++) { RDPGFX_DELETE_SURFACE_PDU pdu; pdu.surfaceId = ((UINT16) pKeys[index]) - 1; if (context) { IFCALLRET(context->DeleteSurface, error, context, &pdu); if (error) { WLog_ERR(TAG, "context->DeleteSurface failed with error %lu", error); free(pKeys); free(context); free(gfx); return error; } } } free(pKeys); HashTable_Free(gfx->SurfaceTable); for (index = 0; index < gfx->MaxCacheSlot; index++) { if (gfx->CacheSlots[index]) { RDPGFX_EVICT_CACHE_ENTRY_PDU pdu; pdu.cacheSlot = (UINT16) index; if (context) { IFCALLRET(context->EvictCacheEntry, error, context, &pdu); if (error) { WLog_ERR(TAG, "context->EvictCacheEntry failed with error %lu", error); free(context); free(gfx); return error; } } gfx->CacheSlots[index] = NULL; } } free(context); free(gfx); return CHANNEL_RC_OK; }
int xcrush_compress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags) { int status = 0; UINT32 DstSize = 0; BYTE* pDstData = NULL; BYTE* CompressedData = NULL; UINT32 CompressedDataSize = 0; BYTE* OriginalData = NULL; UINT32 OriginalDataSize = 0; UINT32 Level1ComprFlags = 0; UINT32 Level2ComprFlags = 0; UINT32 CompressionLevel = 3; if (SrcSize > 16384) return -1001; if ((SrcSize + 2) > *pDstSize) return -1002; OriginalData = *ppDstData; OriginalDataSize = SrcSize; pDstData = xcrush->BlockBuffer; CompressedDataSize = SrcSize; status = xcrush_compress_l1(xcrush, pSrcData, SrcSize, &pDstData, &CompressedDataSize, &Level1ComprFlags); if (status < 0) return status; if (Level1ComprFlags & L1_COMPRESSED) { CompressedData = pDstData; if (CompressedDataSize > SrcSize) return -1003; } else { CompressedData = pSrcData; if (CompressedDataSize != SrcSize) return -1004; } status = 0; pDstData = &OriginalData[2]; DstSize = OriginalDataSize - 2; if (CompressedDataSize > 50) { status = mppc_compress(xcrush->mppc, CompressedData, CompressedDataSize, &pDstData, &DstSize, &Level2ComprFlags); } if (status < 0) return status; if (!status || (Level2ComprFlags & PACKET_FLUSHED)) { if (CompressedDataSize > DstSize) { xcrush_context_reset(xcrush, TRUE); *ppDstData = pSrcData; *pDstSize = SrcSize; *pFlags = 0; return 1; } DstSize = CompressedDataSize; CopyMemory(&OriginalData[2], CompressedData, CompressedDataSize); } if (Level2ComprFlags & PACKET_COMPRESSED) { Level2ComprFlags |= xcrush->CompressionFlags; xcrush->CompressionFlags = 0; } else if (Level2ComprFlags & PACKET_FLUSHED) { xcrush->CompressionFlags = PACKET_FLUSHED; } Level1ComprFlags |= L1_INNER_COMPRESSION; OriginalData[0] = (BYTE) Level1ComprFlags; OriginalData[1] = (BYTE) Level2ComprFlags; #if 0 WLog_DBG(TAG, "XCrushCompress: Level1ComprFlags: %s Level2ComprFlags: %s", xcrush_get_level_1_compression_flags_string(Level1ComprFlags), xcrush_get_level_2_compression_flags_string(Level2ComprFlags)); #endif if (*pDstSize < (DstSize + 2)) return -1006; *pDstSize = DstSize + 2; *pFlags = PACKET_COMPRESSED | CompressionLevel; return 1; }
/** * 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[3]; 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; } 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 %lu!", 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; }
BOOL NamedPipeWrite(PVOID Object, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) { int io_status; WINPR_NAMED_PIPE* pipe; BOOL status = TRUE; if (lpOverlapped) { WLog_ERR(TAG, "WinPR %s does not support the lpOverlapped parameter", __FUNCTION__); SetLastError(ERROR_NOT_SUPPORTED); return FALSE; } pipe = (WINPR_NAMED_PIPE*) Object; if (!(pipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)) { if (pipe->clientfd == -1) return FALSE; do { io_status = write(pipe->clientfd, lpBuffer, nNumberOfBytesToWrite); } while ((io_status < 0) && (errno == EINTR)); if (io_status < 0) { *lpNumberOfBytesWritten = 0; switch (errno) { case EWOULDBLOCK: io_status = 0; status = TRUE; break; default: status = FALSE; } } *lpNumberOfBytesWritten = io_status; return status; } else { /* Overlapped I/O */ if (!lpOverlapped) return FALSE; if (pipe->clientfd == -1) return FALSE; pipe->lpOverlapped = lpOverlapped; #ifdef HAVE_AIO_H { struct aiocb cb; ZeroMemory(&cb, sizeof(struct aiocb)); cb.aio_fildes = pipe->clientfd; cb.aio_buf = (void*) lpBuffer; cb.aio_nbytes = nNumberOfBytesToWrite; cb.aio_offset = lpOverlapped->Offset; cb.aio_sigevent.sigev_notify = SIGEV_SIGNAL; cb.aio_sigevent.sigev_signo = SIGIO; cb.aio_sigevent.sigev_value.sival_ptr = (void*) lpOverlapped; InstallAioSignalHandler(); io_status = aio_write(&cb); WLog_DBG("aio_write status: %d", io_status); if (io_status < 0) status = FALSE; return status; } #else /* synchronous behavior */ lpOverlapped->Internal = 1; lpOverlapped->InternalHigh = (ULONG_PTR) nNumberOfBytesToWrite; lpOverlapped->Pointer = (PVOID) lpBuffer; SetEvent(lpOverlapped->hEvent); #endif } return TRUE; }
/** * Function description * * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_recv_surface_to_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) { UINT16 index; RDPGFX_POINT16* destPt; RDPGFX_SURFACE_TO_SURFACE_PDU pdu; RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; UINT error; if (Stream_GetRemainingLength(s) < 14) { WLog_ERR(TAG, "not enough data!"); return ERROR_INVALID_DATA; } Stream_Read_UINT16(s, pdu.surfaceIdSrc); /* surfaceIdSrc (2 bytes) */ Stream_Read_UINT16(s, pdu.surfaceIdDest); /* surfaceIdDest (2 bytes) */ if ((error = rdpgfx_read_rect16(s, &(pdu.rectSrc)))) /* rectSrc (8 bytes ) */ { WLog_ERR(TAG, "rdpgfx_read_rect16 failed with error %lu!", error); return error; } Stream_Read_UINT16(s, pdu.destPtsCount); /* destPtsCount (2 bytes) */ if (Stream_GetRemainingLength(s) < (size_t) (pdu.destPtsCount * 4)) { WLog_ERR(TAG, "not enough data!"); return ERROR_INVALID_DATA; } pdu.destPts = (RDPGFX_POINT16*) calloc(pdu.destPtsCount, sizeof(RDPGFX_POINT16)); if (!pdu.destPts) { WLog_ERR(TAG, "calloc failed!"); return CHANNEL_RC_NO_MEMORY; } for (index = 0; index < pdu.destPtsCount; index++) { destPt = &(pdu.destPts[index]); if ((error = rdpgfx_read_point16(s, destPt))) { WLog_ERR(TAG, "rdpgfx_read_point16 failed with error %lu!", error); free(pdu.destPts); return error; } } WLog_DBG(TAG, "RecvSurfaceToSurfacePdu: surfaceIdSrc: %d surfaceIdDest: %d " "left: %d top: %d right: %d bottom: %d destPtsCount: %d", pdu.surfaceIdSrc, pdu.surfaceIdDest, pdu.rectSrc.left, pdu.rectSrc.top, pdu.rectSrc.right, pdu.rectSrc.bottom, pdu.destPtsCount); if (context) { IFCALLRET(context->SurfaceToSurface, error, context, &pdu); if (error) WLog_ERR(TAG, "context->SurfaceToSurface failed with error %lu", error); } free(pdu.destPts); return error; }
int nla_client_begin(rdpNla* nla) { if (nla_client_init(nla) < 1) return -1; if (nla->state != NLA_STATE_INITIAL) return -1; nla->outputBufferDesc.ulVersion = SECBUFFER_VERSION; nla->outputBufferDesc.cBuffers = 1; nla->outputBufferDesc.pBuffers = &nla->outputBuffer; nla->outputBuffer.BufferType = SECBUFFER_TOKEN; nla->outputBuffer.cbBuffer = nla->cbMaxToken; nla->outputBuffer.pvBuffer = malloc(nla->outputBuffer.cbBuffer); if (!nla->outputBuffer.pvBuffer) return -1; nla->status = nla->table->InitializeSecurityContext(&nla->credentials, NULL, nla->ServicePrincipalName, nla->fContextReq, 0, SECURITY_NATIVE_DREP, NULL, 0, &nla->context, &nla->outputBufferDesc, &nla->pfContextAttr, &nla->expiration); WLog_VRB(TAG, " InitializeSecurityContext status %s [%08X]", GetSecurityStatusString(nla->status), nla->status); if ((nla->status == SEC_I_COMPLETE_AND_CONTINUE) || (nla->status == SEC_I_COMPLETE_NEEDED)) { if (nla->table->CompleteAuthToken) { SECURITY_STATUS status; status = nla->table->CompleteAuthToken(&nla->context, &nla->outputBufferDesc); if (status != SEC_E_OK) { WLog_WARN(TAG, "CompleteAuthToken status %s [%08X]", GetSecurityStatusString(status), status); return -1; } } if (nla->status == SEC_I_COMPLETE_NEEDED) nla->status = SEC_E_OK; else if (nla->status == SEC_I_COMPLETE_AND_CONTINUE) nla->status = SEC_I_CONTINUE_NEEDED; } if (nla->status != SEC_I_CONTINUE_NEEDED) return -1; if (nla->outputBuffer.cbBuffer < 1) return -1; nla->negoToken.pvBuffer = nla->outputBuffer.pvBuffer; nla->negoToken.cbBuffer = nla->outputBuffer.cbBuffer; WLog_DBG(TAG, "Sending Authentication Token"); winpr_HexDump(TAG, WLOG_DEBUG, nla->negoToken.pvBuffer, nla->negoToken.cbBuffer); if (!nla_send(nla)) { nla_buffer_free(nla); return -1; } nla_buffer_free(nla); nla->state = NLA_STATE_NEGO_TOKEN; return 1; }
int rpc_client_on_fragment_received_event(rdpRpc* rpc) { BYTE* buffer; UINT32 StubOffset; UINT32 StubLength; wStream* fragment; rpcconn_hdr_t* header; freerdp* instance; instance = (freerdp*)rpc->transport->settings->instance; if (!rpc->client->pdu) rpc->client->pdu = rpc_client_receive_pool_take(rpc); fragment = Queue_Dequeue(rpc->client->FragmentQueue); buffer = (BYTE*) Stream_Buffer(fragment); header = (rpcconn_hdr_t*) Stream_Buffer(fragment); if (rpc->State < RPC_CLIENT_STATE_CONTEXT_NEGOTIATED) { rpc->client->pdu->Flags = 0; rpc->client->pdu->CallId = header->common.call_id; Stream_EnsureCapacity(rpc->client->pdu->s, Stream_Length(fragment)); Stream_Write(rpc->client->pdu->s, buffer, Stream_Length(fragment)); Stream_Length(rpc->client->pdu->s) = Stream_GetPosition(rpc->client->pdu->s); rpc_client_fragment_pool_return(rpc, fragment); Queue_Enqueue(rpc->client->ReceiveQueue, rpc->client->pdu); SetEvent(rpc->transport->ReceiveEvent); rpc->client->pdu = NULL; return 0; } switch (header->common.ptype) { case PTYPE_RTS: if (rpc->VirtualConnection->State < VIRTUAL_CONNECTION_STATE_OPENED) { WLog_ERR(TAG, "warning: unhandled RTS PDU"); return 0; } WLog_DBG(TAG, "Receiving Out-of-Sequence RTS PDU"); rts_recv_out_of_sequence_pdu(rpc, buffer, header->common.frag_length); rpc_client_fragment_pool_return(rpc, fragment); return 0; case PTYPE_FAULT: rpc_recv_fault_pdu(header); Queue_Enqueue(rpc->client->ReceiveQueue, NULL); return -1; case PTYPE_RESPONSE: break; default: WLog_ERR(TAG, "unexpected RPC PDU type %d", header->common.ptype); Queue_Enqueue(rpc->client->ReceiveQueue, NULL); return -1; } rpc->VirtualConnection->DefaultOutChannel->BytesReceived += header->common.frag_length; rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow -= header->common.frag_length; if (!rpc_get_stub_data_info(rpc, buffer, &StubOffset, &StubLength)) { WLog_ERR(TAG, "expected stub"); Queue_Enqueue(rpc->client->ReceiveQueue, NULL); return -1; } if (StubLength == 4) { //WLog_ERR(TAG, "Ignoring TsProxySendToServer Response"); //WLog_DBG(TAG, "Got stub length 4 with flags %d and callid %d", header->common.pfc_flags, header->common.call_id); /* received a disconnect request from the server? */ if ((header->common.call_id == rpc->PipeCallId) && (header->common.pfc_flags & PFC_LAST_FRAG)) { TerminateEventArgs e; instance->context->rdp->disconnect = TRUE; rpc->transport->tsg->state = TSG_STATE_TUNNEL_CLOSE_PENDING; EventArgsInit(&e, "freerdp"); e.code = 0; PubSub_OnTerminate(instance->context->pubSub, instance->context, &e); } rpc_client_fragment_pool_return(rpc, fragment); return 0; } Stream_EnsureCapacity(rpc->client->pdu->s, header->response.alloc_hint); buffer = (BYTE*) Stream_Buffer(fragment); header = (rpcconn_hdr_t*) Stream_Buffer(fragment); if (rpc->StubFragCount == 0) rpc->StubCallId = header->common.call_id; if (rpc->StubCallId != header->common.call_id) { WLog_ERR(TAG, "invalid call_id: actual: %d, expected: %d, frag_count: %d", rpc->StubCallId, header->common.call_id, rpc->StubFragCount); } Stream_Write(rpc->client->pdu->s, &buffer[StubOffset], StubLength); rpc->StubFragCount++; rpc_client_fragment_pool_return(rpc, fragment); if (rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow < (rpc->ReceiveWindow / 2)) { //WLog_ERR(TAG, "Sending Flow Control Ack PDU"); rts_send_flow_control_ack_pdu(rpc); } /** * If alloc_hint is set to a nonzero value and a request or a response is fragmented into multiple * PDUs, implementations of these extensions SHOULD set the alloc_hint field in every PDU to be the * combined stub data length of all remaining fragment PDUs. */ if (header->response.alloc_hint == StubLength) { rpc->client->pdu->Flags = RPC_PDU_FLAG_STUB; rpc->client->pdu->CallId = rpc->StubCallId; Stream_Length(rpc->client->pdu->s) = Stream_GetPosition(rpc->client->pdu->s); rpc->StubFragCount = 0; rpc->StubCallId = 0; Queue_Enqueue(rpc->client->ReceiveQueue, rpc->client->pdu); rpc->client->pdu = NULL; return 0; } return 0; }
int nla_client_recv(rdpNla* nla) { int status = -1; if (nla->state == NLA_STATE_NEGO_TOKEN) { nla->inputBufferDesc.ulVersion = SECBUFFER_VERSION; nla->inputBufferDesc.cBuffers = 1; nla->inputBufferDesc.pBuffers = &nla->inputBuffer; nla->inputBuffer.BufferType = SECBUFFER_TOKEN; nla->inputBuffer.pvBuffer = nla->negoToken.pvBuffer; nla->inputBuffer.cbBuffer = nla->negoToken.cbBuffer; nla->outputBufferDesc.ulVersion = SECBUFFER_VERSION; nla->outputBufferDesc.cBuffers = 1; nla->outputBufferDesc.pBuffers = &nla->outputBuffer; nla->outputBuffer.BufferType = SECBUFFER_TOKEN; nla->outputBuffer.cbBuffer = nla->cbMaxToken; nla->outputBuffer.pvBuffer = malloc(nla->outputBuffer.cbBuffer); if (!nla->outputBuffer.pvBuffer) return -1; nla->status = nla->table->InitializeSecurityContext(&nla->credentials, &nla->context, nla->ServicePrincipalName, nla->fContextReq, 0, SECURITY_NATIVE_DREP, &nla->inputBufferDesc, 0, &nla->context, &nla->outputBufferDesc, &nla->pfContextAttr, &nla->expiration); WLog_VRB(TAG, "InitializeSecurityContext %s [%08X]", GetSecurityStatusString(nla->status), nla->status); free(nla->inputBuffer.pvBuffer); nla->inputBuffer.pvBuffer = NULL; if ((nla->status == SEC_I_COMPLETE_AND_CONTINUE) || (nla->status == SEC_I_COMPLETE_NEEDED)) { if (nla->table->CompleteAuthToken) { SECURITY_STATUS status; status = nla->table->CompleteAuthToken(&nla->context, &nla->outputBufferDesc); if (status != SEC_E_OK) { WLog_WARN(TAG, "CompleteAuthToken status %s [%08X]", GetSecurityStatusString(status), status); return -1; } } if (nla->status == SEC_I_COMPLETE_NEEDED) nla->status = SEC_E_OK; else if (nla->status == SEC_I_COMPLETE_AND_CONTINUE) nla->status = SEC_I_CONTINUE_NEEDED; } if (nla->status == SEC_E_OK) { nla->havePubKeyAuth = TRUE; nla->status = nla->table->QueryContextAttributes(&nla->context, SECPKG_ATTR_SIZES, &nla->ContextSizes); if (nla->status != SEC_E_OK) { WLog_ERR(TAG, "QueryContextAttributes SECPKG_ATTR_SIZES failure %s [%08X]", GetSecurityStatusString(nla->status), nla->status); return -1; } nla->status = nla_encrypt_public_key_echo(nla); if (nla->status != SEC_E_OK) return -1; } nla->negoToken.pvBuffer = nla->outputBuffer.pvBuffer; nla->negoToken.cbBuffer = nla->outputBuffer.cbBuffer; WLog_DBG(TAG, "Sending Authentication Token"); winpr_HexDump(TAG, WLOG_DEBUG, nla->negoToken.pvBuffer, nla->negoToken.cbBuffer); if (!nla_send(nla)) { nla_buffer_free(nla); return -1; } nla_buffer_free(nla); if (nla->status == SEC_E_OK) nla->state = NLA_STATE_PUB_KEY_AUTH; status = 1; } else if (nla->state == NLA_STATE_PUB_KEY_AUTH) { /* Verify Server Public Key Echo */ nla->status = nla_decrypt_public_key_echo(nla); nla_buffer_free(nla); if (nla->status != SEC_E_OK) { WLog_ERR(TAG, "Could not verify public key echo %s [%08X]", GetSecurityStatusString(nla->status), nla->status); return -1; } /* Send encrypted credentials */ nla->status = nla_encrypt_ts_credentials(nla); if (nla->status != SEC_E_OK) { WLog_ERR(TAG, "nla_encrypt_ts_credentials status %s [%08X]", GetSecurityStatusString(nla->status), nla->status); return -1; } if (!nla_send(nla)) { nla_buffer_free(nla); return -1; } nla_buffer_free(nla); nla->table->FreeCredentialsHandle(&nla->credentials); if (nla->status != SEC_E_OK) { WLog_ERR(TAG, "FreeCredentialsHandle status %s [%08X]", GetSecurityStatusString(nla->status), nla->status); } nla->status = nla->table->FreeContextBuffer(nla->pPackageInfo); if (nla->status != SEC_E_OK) { WLog_ERR(TAG, "FreeContextBuffer status %s [%08X]", GetSecurityStatusString(nla->status), nla->status); } if (nla->status != SEC_E_OK) return -1; nla->state = NLA_STATE_AUTH_INFO; status = 1; } return status; }
void nego_set_restricted_admin_mode_required(rdpNego* nego, BOOL RestrictedAdminModeRequired) { WLog_DBG(TAG, "Enabling restricted admin mode: %s", RestrictedAdminModeRequired ? "TRUE" : "FALSE"); nego->RestrictedAdminModeRequired = RestrictedAdminModeRequired; }
int nla_server_authenticate(rdpNla* nla) { if (nla_server_init(nla) < 1) return -1; while (TRUE) { /* receive authentication token */ nla->inputBufferDesc.ulVersion = SECBUFFER_VERSION; nla->inputBufferDesc.cBuffers = 1; nla->inputBufferDesc.pBuffers = &nla->inputBuffer; nla->inputBuffer.BufferType = SECBUFFER_TOKEN; if (nla_recv(nla) < 0) return -1; WLog_DBG(TAG, "Receiving Authentication Token"); nla_buffer_print(nla); nla->inputBuffer.pvBuffer = nla->negoToken.pvBuffer; nla->inputBuffer.cbBuffer = nla->negoToken.cbBuffer; if (nla->negoToken.cbBuffer < 1) { WLog_ERR(TAG, "CredSSP: invalid negoToken!"); return -1; } nla->outputBufferDesc.ulVersion = SECBUFFER_VERSION; nla->outputBufferDesc.cBuffers = 1; nla->outputBufferDesc.pBuffers = &nla->outputBuffer; nla->outputBuffer.BufferType = SECBUFFER_TOKEN; nla->outputBuffer.cbBuffer = nla->cbMaxToken; nla->outputBuffer.pvBuffer = malloc(nla->outputBuffer.cbBuffer); if (!nla->outputBuffer.pvBuffer) return -1; nla->status = nla->table->AcceptSecurityContext(&nla->credentials, nla-> haveContext? &nla->context: NULL, &nla->inputBufferDesc, nla->fContextReq, SECURITY_NATIVE_DREP, &nla->context, &nla->outputBufferDesc, &nla->pfContextAttr, &nla->expiration); WLog_VRB(TAG, "AcceptSecurityContext status %s [%08X]", GetSecurityStatusString(nla->status), nla->status); nla->negoToken.pvBuffer = nla->outputBuffer.pvBuffer; nla->negoToken.cbBuffer = nla->outputBuffer.cbBuffer; if ((nla->status == SEC_I_COMPLETE_AND_CONTINUE) || (nla->status == SEC_I_COMPLETE_NEEDED)) { if (nla->table->CompleteAuthToken) { SECURITY_STATUS status; status = nla->table->CompleteAuthToken(&nla->context, &nla->outputBufferDesc); if (status != SEC_E_OK) { WLog_WARN(TAG, "CompleteAuthToken status %s [%08X]", GetSecurityStatusString(status), status); return -1; } } if (nla->status == SEC_I_COMPLETE_NEEDED) nla->status = SEC_E_OK; else if (nla->status == SEC_I_COMPLETE_AND_CONTINUE) nla->status = SEC_I_CONTINUE_NEEDED; } if (nla->status == SEC_E_OK) { if (nla->outputBuffer.cbBuffer != 0) { if (!nla_send(nla)) { nla_buffer_free(nla); return -1; } if (nla_recv(nla) < 0) return -1; WLog_DBG(TAG, "Receiving pubkey Token"); nla_buffer_print(nla); } nla->havePubKeyAuth = TRUE; nla->status = nla->table->QueryContextAttributes(&nla->context, SECPKG_ATTR_SIZES, &nla->ContextSizes); if (nla->status != SEC_E_OK) { WLog_ERR(TAG, "QueryContextAttributes SECPKG_ATTR_SIZES failure %s [%08X]", GetSecurityStatusString(nla->status), nla->status); return -1; } nla->status = nla_decrypt_public_key_echo(nla); if (nla->status != SEC_E_OK) { WLog_ERR(TAG, "Error: could not verify client's public key echo %s [%08X]", GetSecurityStatusString(nla->status), nla->status); return -1; } sspi_SecBufferFree(&nla->negoToken); nla->negoToken.pvBuffer = NULL; nla->negoToken.cbBuffer = 0; nla->status = nla_encrypt_public_key_echo(nla); if (nla->status != SEC_E_OK) return -1; } if ((nla->status != SEC_E_OK) && (nla->status != SEC_I_CONTINUE_NEEDED)) { /* Special handling of these specific error codes as NTSTATUS_FROM_WIN32 unfortunately does not map directly to the corresponding NTSTATUS values */ switch (GetLastError()) { case ERROR_PASSWORD_MUST_CHANGE: nla->errorCode = STATUS_PASSWORD_MUST_CHANGE; break; case ERROR_PASSWORD_EXPIRED: nla->errorCode = STATUS_PASSWORD_EXPIRED; break; case ERROR_ACCOUNT_DISABLED: nla->errorCode = STATUS_ACCOUNT_DISABLED; break; default: nla->errorCode = NTSTATUS_FROM_WIN32(GetLastError()); break; } WLog_ERR(TAG, "AcceptSecurityContext status %s [%08X]", GetSecurityStatusString(nla->status), nla->status); nla_send(nla); return -1; /* Access Denied */ } /* send authentication token */ WLog_DBG(TAG, "Sending Authentication Token"); nla_buffer_print(nla); if (!nla_send(nla)) { nla_buffer_free(nla); return -1; } nla_buffer_free(nla); if (nla->status != SEC_I_CONTINUE_NEEDED) break; nla->haveContext = TRUE; } /* Receive encrypted credentials */ if (nla_recv(nla) < 0) return -1; nla->status = nla_decrypt_ts_credentials(nla); if (nla->status != SEC_E_OK) { WLog_ERR(TAG, "Could not decrypt TSCredentials status %s [%08X]", GetSecurityStatusString(nla->status), nla->status); return -1; } nla->status = nla->table->ImpersonateSecurityContext(&nla->context); if (nla->status != SEC_E_OK) { WLog_ERR(TAG, "ImpersonateSecurityContext status %s [%08X]", GetSecurityStatusString(nla->status), nla->status); return -1; } else { nla->status = nla->table->RevertSecurityContext(&nla->context); if (nla->status != SEC_E_OK) { WLog_ERR(TAG, "RevertSecurityContext status %s [%08X]", GetSecurityStatusString(nla->status), nla->status); return -1; } } nla->status = nla->table->FreeContextBuffer(nla->pPackageInfo); if (nla->status != SEC_E_OK) { WLog_ERR(TAG, "DeleteSecurityContext status %s [%08X]", GetSecurityStatusString(nla->status), nla->status); return -1; } return 1; }
void nego_enable_tls(rdpNego* nego, BOOL enable_tls) { WLog_DBG(TAG, "Enabling TLS security: %s", enable_tls ? "TRUE" : "FALSE"); nego->EnabledProtocols[PROTOCOL_TLS] = enable_tls; }
BOOL rpc_get_stub_data_info(rdpRpc* rpc, BYTE* buffer, UINT32* offset, UINT32* length) { UINT32 alloc_hint = 0; rpcconn_hdr_t* header; UINT32 frag_length; UINT32 auth_length; UINT32 auth_pad_length; UINT32 sec_trailer_offset; rpc_sec_trailer* sec_trailer; *offset = RPC_COMMON_FIELDS_LENGTH; header = ((rpcconn_hdr_t*) buffer); switch (header->common.ptype) { case PTYPE_RESPONSE: *offset += 8; rpc_offset_align(offset, 8); alloc_hint = header->response.alloc_hint; break; case PTYPE_REQUEST: *offset += 4; rpc_offset_align(offset, 8); alloc_hint = header->request.alloc_hint; break; case PTYPE_RTS: *offset += 4; break; default: WLog_ERR(TAG, "Unknown PTYPE: 0x%02"PRIX8"", header->common.ptype); return FALSE; } if (!length) return TRUE; if (header->common.ptype == PTYPE_REQUEST) { UINT32 sec_trailer_offset; sec_trailer_offset = header->common.frag_length - header->common.auth_length - 8; *length = sec_trailer_offset - *offset; return TRUE; } frag_length = header->common.frag_length; auth_length = header->common.auth_length; sec_trailer_offset = frag_length - auth_length - 8; sec_trailer = (rpc_sec_trailer*) &buffer[sec_trailer_offset]; auth_pad_length = sec_trailer->auth_pad_length; #if 0 WLog_DBG(TAG, "sec_trailer: type: %"PRIu8" level: %"PRIu8" pad_length: %"PRIu8" reserved: %"PRIu8" context_id: %"PRIu32"", sec_trailer->auth_type, sec_trailer->auth_level, sec_trailer->auth_pad_length, sec_trailer->auth_reserved, sec_trailer->auth_context_id); #endif /** * According to [MS-RPCE], auth_pad_length is the number of padding * octets used to 4-byte align the security trailer, but in practice * we get values up to 15, which indicates 16-byte alignment. */ if ((frag_length - (sec_trailer_offset + 8)) != auth_length) { WLog_ERR(TAG, "invalid auth_length: actual: %"PRIu32", expected: %"PRIu32"", auth_length, (frag_length - (sec_trailer_offset + 8))); } *length = frag_length - auth_length - 24 - 8 - auth_pad_length; return TRUE; }
void nego_enable_ext(rdpNego* nego, BOOL enable_ext) { WLog_DBG(TAG, "Enabling NLA extended security: %s", enable_ext ? "TRUE" : "FALSE"); nego->EnabledProtocols[PROTOCOL_EXT] = enable_ext; }
DWORD WINAPI wf_client_thread(LPVOID lpParam) { MSG msg; int width; int height; BOOL msg_ret; int quit_msg; DWORD nCount; HANDLE handles[64]; wfContext* wfc; freerdp* instance; rdpContext* context; rdpChannels* channels; rdpSettings* settings; BOOL async_input; BOOL async_transport; HANDLE input_thread; instance = (freerdp*) lpParam; context = instance->context; wfc = (wfContext*) instance->context; if (!freerdp_connect(instance)) return 0; channels = instance->context->channels; settings = instance->context->settings; async_input = settings->AsyncInput; async_transport = settings->AsyncTransport; if (async_input) { input_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) wf_input_thread, instance, 0, NULL); } while (1) { nCount = 0; if (freerdp_focus_required(instance)) { wf_event_focus_in(wfc); wf_event_focus_in(wfc); } if (!async_transport) { DWORD tmp = freerdp_get_event_handles(context, &handles[nCount], 64 - nCount); if (tmp == 0) { WLog_ERR(TAG, "freerdp_get_event_handles failed"); break; } nCount += tmp; } if (MsgWaitForMultipleObjects(nCount, handles, FALSE, 1000, QS_ALLINPUT) == WAIT_FAILED) { WLog_ERR(TAG, "wfreerdp_run: WaitForMultipleObjects failed: 0x%04X", GetLastError()); break; } if (!async_transport) { if (!freerdp_check_event_handles(context)) { if (wf_auto_reconnect(instance)) continue; WLog_ERR(TAG, "Failed to check FreeRDP file descriptor"); break; } } if (freerdp_shall_disconnect(instance)) break; quit_msg = FALSE; while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { msg_ret = GetMessage(&msg, NULL, 0, 0); if (instance->settings->EmbeddedWindow) { if ((msg.message == WM_SETFOCUS) && (msg.lParam == 1)) { PostMessage(wfc->hwnd, WM_SETFOCUS, 0, 0); } else if ((msg.message == WM_KILLFOCUS) && (msg.lParam == 1)) { PostMessage(wfc->hwnd, WM_KILLFOCUS, 0, 0); } } if (msg.message == WM_SIZE) { width = LOWORD(msg.lParam); height = HIWORD(msg.lParam); SetWindowPos(wfc->hwnd, HWND_TOP, 0, 0, width, height, SWP_FRAMECHANGED); } if ((msg_ret == 0) || (msg_ret == -1)) { quit_msg = TRUE; break; } TranslateMessage(&msg); DispatchMessage(&msg); } if (quit_msg) break; } /* cleanup */ freerdp_channels_disconnect(channels, instance); if (async_input) { wMessageQueue* input_queue; input_queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE); MessageQueue_PostQuit(input_queue, 0); WaitForSingleObject(input_thread, INFINITE); CloseHandle(input_thread); } freerdp_disconnect(instance); WLog_DBG(TAG, "Main thread exited."); ExitThread(0); return 0; }