FreeRDP/libfreerdp/core/server.c

1955 lines
47 KiB
C
Raw Normal View History

/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Server Channels
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2015 Thincast Technologies GmbH
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
2022-02-16 13:20:38 +03:00
#include <freerdp/config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/stream.h>
#include <freerdp/log.h>
#include <freerdp/constants.h>
#include <freerdp/server/channels.h>
2021-08-25 11:02:46 +03:00
#include <freerdp/channels/drdynvc.h>
#include <freerdp/utils/drdynvc.h>
#include "rdp.h"
#include "server.h"
#define TAG FREERDP_TAG("core.server")
#ifdef WITH_DEBUG_DVC
#define DEBUG_DVC(...) WLog_DBG(TAG, __VA_ARGS__)
#else
2019-11-06 17:24:51 +03:00
#define DEBUG_DVC(...) \
do \
{ \
} while (0)
#endif
#define DVC_MAX_DATA_PDU_SIZE 1600
typedef struct
{
UINT16 channelId;
UINT16 reserved;
UINT32 length;
UINT32 offset;
} wtsChannelMessage;
static DWORD g_SessionId = 1;
static wHashTable* g_ServerHandles = NULL;
2019-11-06 17:24:51 +03:00
static rdpPeerChannel* wts_get_dvc_channel_by_id(WTSVirtualChannelManager* vcm, UINT32 ChannelId)
{
WINPR_ASSERT(vcm);
return HashTable_GetItemValue(vcm->dynamicVirtualChannels, &ChannelId);
}
2019-11-06 17:24:51 +03:00
static BOOL wts_queue_receive_data(rdpPeerChannel* channel, const BYTE* Buffer, UINT32 Length)
{
BYTE* buffer = NULL;
wtsChannelMessage* messageCtx = NULL;
WINPR_ASSERT(channel);
2019-11-06 17:24:51 +03:00
messageCtx = (wtsChannelMessage*)malloc(sizeof(wtsChannelMessage) + Length);
2015-05-25 23:55:37 +03:00
if (!messageCtx)
return FALSE;
messageCtx->channelId = channel->channelId;
messageCtx->length = Length;
messageCtx->offset = 0;
buffer = (BYTE*)(messageCtx + 1);
CopyMemory(buffer, Buffer, Length);
2015-05-23 23:47:18 +03:00
return MessageQueue_Post(channel->queue, messageCtx, 0, NULL, NULL);
}
2019-11-06 17:24:51 +03:00
static BOOL wts_queue_send_item(rdpPeerChannel* channel, BYTE* Buffer, UINT32 Length)
{
BYTE* buffer = NULL;
UINT32 length = 0;
UINT16 channelId = 0;
WINPR_ASSERT(channel);
WINPR_ASSERT(channel->vcm);
buffer = Buffer;
length = Length;
channelId = channel->channelId;
2019-11-06 17:24:51 +03:00
return MessageQueue_Post(channel->vcm->queue, (void*)(UINT_PTR)channelId, 0, (void*)buffer,
(void*)(UINT_PTR)length);
}
static int wts_read_variable_uint(wStream* s, int cbLen, UINT32* val)
{
WINPR_ASSERT(s);
WINPR_ASSERT(val);
switch (cbLen)
{
case 0:
if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
return 0;
Stream_Read_UINT8(s, *val);
return 1;
case 1:
if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
return 0;
Stream_Read_UINT16(s, *val);
return 2;
case 2:
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
return 0;
Stream_Read_UINT32(s, *val);
return 4;
default:
WLog_ERR(TAG, "invalid wts variable uint len %d", cbLen);
return 0;
}
}
2019-11-06 17:24:51 +03:00
static BOOL wts_read_drdynvc_capabilities_response(rdpPeerChannel* channel, UINT32 length)
{
UINT16 Version = 0;
WINPR_ASSERT(channel);
WINPR_ASSERT(channel->vcm);
if (length < 3)
2015-05-23 23:47:18 +03:00
return FALSE;
Stream_Seek_UINT8(channel->receiveData); /* Pad (1 byte) */
Stream_Read_UINT16(channel->receiveData, Version);
2019-11-06 17:24:51 +03:00
DEBUG_DVC("Version: %" PRIu16 "", Version);
if (Version < 1)
{
WLog_ERR(TAG, "invalid version %" PRIu16 " for DRDYNVC", Version);
return FALSE;
}
WTSVirtualChannelManager* vcm = channel->vcm;
vcm->drdynvc_state = DRDYNVC_STATE_READY;
/* we only support version 1 for now (no compression yet) */
vcm->dvc_spoken_version = MAX(Version, 1);
return SetEvent(MessageQueue_Event(vcm->queue));
}
2019-11-06 17:24:51 +03:00
static BOOL wts_read_drdynvc_create_response(rdpPeerChannel* channel, wStream* s, UINT32 length)
{
UINT32 CreationStatus = 0;
BOOL status = TRUE;
WINPR_ASSERT(channel);
WINPR_ASSERT(s);
if (length < 4)
2015-05-23 23:47:18 +03:00
return FALSE;
Stream_Read_UINT32(s, CreationStatus);
2019-11-06 17:24:51 +03:00
if ((INT32)CreationStatus < 0)
{
2019-11-06 17:24:51 +03:00
DEBUG_DVC("ChannelId %" PRIu32 " creation failed (%" PRId32 ")", channel->channelId,
(INT32)CreationStatus);
channel->dvc_open_state = DVC_OPEN_STATE_FAILED;
}
else
{
2019-11-06 17:24:51 +03:00
DEBUG_DVC("ChannelId %" PRIu32 " creation succeeded", channel->channelId);
channel->dvc_open_state = DVC_OPEN_STATE_SUCCEEDED;
}
channel->creationStatus = (INT32)CreationStatus;
IFCALLRET(channel->vcm->dvc_creation_status, status, channel->vcm->dvc_creation_status_userdata,
channel->channelId, (INT32)CreationStatus);
if (!status)
WLog_ERR(TAG, "vcm->dvc_creation_status failed!");
return status;
}
2019-11-06 17:24:51 +03:00
static BOOL wts_read_drdynvc_data_first(rdpPeerChannel* channel, wStream* s, int cbLen,
UINT32 length)
{
int value = 0;
WINPR_ASSERT(channel);
WINPR_ASSERT(s);
value = wts_read_variable_uint(s, cbLen, &channel->dvc_total_length);
if (value == 0)
2015-05-23 23:47:18 +03:00
return FALSE;
length -= value;
if (length > channel->dvc_total_length)
2015-05-23 23:47:18 +03:00
return FALSE;
Stream_SetPosition(channel->receiveData, 0);
2020-04-15 18:47:42 +03:00
if (!Stream_EnsureRemainingCapacity(channel->receiveData, channel->dvc_total_length))
2015-05-23 23:47:18 +03:00
return FALSE;
Stream_Write(channel->receiveData, Stream_ConstPointer(s), length);
2015-05-23 23:47:18 +03:00
return TRUE;
}
2019-11-06 17:24:51 +03:00
static BOOL wts_read_drdynvc_data(rdpPeerChannel* channel, wStream* s, UINT32 length)
{
2015-06-23 13:08:47 +03:00
BOOL ret = FALSE;
WINPR_ASSERT(channel);
WINPR_ASSERT(s);
if (channel->dvc_total_length > 0)
{
2019-11-06 17:24:51 +03:00
if (Stream_GetPosition(channel->receiveData) + length > channel->dvc_total_length)
{
channel->dvc_total_length = 0;
2015-05-23 23:47:18 +03:00
WLog_ERR(TAG, "incorrect fragment data, discarded.");
return FALSE;
}
Stream_Write(channel->receiveData, Stream_ConstPointer(s), length);
2019-02-07 16:22:28 +03:00
if (Stream_GetPosition(channel->receiveData) >= channel->dvc_total_length)
{
ret = wts_queue_receive_data(channel, Stream_Buffer(channel->receiveData),
channel->dvc_total_length);
channel->dvc_total_length = 0;
}
else
ret = TRUE;
}
else
{
ret = wts_queue_receive_data(channel, Stream_ConstPointer(s), length);
}
2015-05-23 23:47:18 +03:00
return ret;
}
static void wts_read_drdynvc_close_response(rdpPeerChannel* channel)
{
WINPR_ASSERT(channel);
2019-11-06 17:24:51 +03:00
DEBUG_DVC("ChannelId %" PRIu32 " close response", channel->channelId);
channel->dvc_open_state = DVC_OPEN_STATE_CLOSED;
MessageQueue_PostQuit(channel->queue, 0);
}
2015-05-23 23:47:18 +03:00
static BOOL wts_read_drdynvc_pdu(rdpPeerChannel* channel)
{
UINT32 length = 0;
UINT8 value = 0;
UINT8 Cmd = 0;
UINT8 Sp = 0;
UINT8 cbChId = 0;
2023-01-13 15:25:32 +03:00
UINT32 ChannelId = 0;
2022-04-28 13:16:04 +03:00
rdpPeerChannel* dvc = NULL;
WINPR_ASSERT(channel);
WINPR_ASSERT(channel->vcm);
length = Stream_GetPosition(channel->receiveData);
if (length < 1)
2015-05-23 23:47:18 +03:00
return FALSE;
Stream_SetPosition(channel->receiveData, 0);
Stream_Read_UINT8(channel->receiveData, value);
length--;
Cmd = (value & 0xf0) >> 4;
Sp = (value & 0x0c) >> 2;
cbChId = (value & 0x03) >> 0;
if (Cmd == CAPABILITY_REQUEST_PDU)
2015-05-23 23:47:18 +03:00
return wts_read_drdynvc_capabilities_response(channel, length);
if (channel->vcm->drdynvc_state == DRDYNVC_STATE_READY)
{
BOOL haveChannelId = 0;
switch (Cmd)
{
2022-06-23 08:57:38 +03:00
case SOFT_SYNC_REQUEST_PDU:
case SOFT_SYNC_RESPONSE_PDU:
haveChannelId = FALSE;
break;
default:
haveChannelId = TRUE;
break;
}
if (haveChannelId)
{
value = wts_read_variable_uint(channel->receiveData, cbChId, &ChannelId);
if (value == 0)
return FALSE;
length -= value;
DEBUG_DVC("Cmd %s ChannelId %" PRIu32 " length %" PRIu32 "",
drdynvc_get_packet_type(Cmd), ChannelId, length);
dvc = wts_get_dvc_channel_by_id(channel->vcm, ChannelId);
if (!dvc)
{
DEBUG_DVC("ChannelId %" PRIu32 " does not exist.", ChannelId);
return TRUE;
}
}
switch (Cmd)
{
case CREATE_REQUEST_PDU:
return wts_read_drdynvc_create_response(dvc, channel->receiveData, length);
case DATA_FIRST_PDU:
core/server: Ignore data PDUs for DVCs that were not opened successfully When a FreeRDP-based server tried to open a DVC, but the client answered the DVC create request with a negative CreationStatus in the DVC create response PDU, the server can then assume that no actual PDUs can be received for that channel. However, as long as the channel handle exists, FreeRDP happily forwards any potential PDU for that handle disregarding the CreationStatus. This is problematic, since the channel handling usually runs in its own thread and as a result, the channel may not be destructed yet, when receiving such stray PDU. The PDU may be processed, even though it is not expected to be. A situation, where this becomes problematic is the AUDIO_PLAYBACK_DVC channel. It may be the case, that the client answered the DVC create request with a negative result, the server may try to close the handle and open the static channel (RDPSND) instead, but before the server can close the channel handle, the client actually sends PDUs regarding the format negotiation. In this case, the server may unintentionally already set things up, which was not desired (the DVC is about to be closed anyway). While this specific situation is hypothetical, since it would depend on a malicious client, it is still possible to happen, especially since the server implementation does not invoke the format negotiation, but FreeRDP does it automatically, as soon as the DVC create request is sent. Fix this issue by discarding any data PDUs (DYNVC_DATA_FIRST and DYNVC_DATA) of channels, that were not opened successfully.
2022-12-30 15:38:09 +03:00
if (dvc->dvc_open_state != DVC_OPEN_STATE_SUCCEEDED)
{
WLog_ERR(TAG,
"ChannelId %" PRIu32 " did not open successfully. "
"Ignoring DYNVC_DATA_FIRST PDU",
ChannelId);
return TRUE;
}
return wts_read_drdynvc_data_first(dvc, channel->receiveData, Sp, length);
case DATA_PDU:
core/server: Ignore data PDUs for DVCs that were not opened successfully When a FreeRDP-based server tried to open a DVC, but the client answered the DVC create request with a negative CreationStatus in the DVC create response PDU, the server can then assume that no actual PDUs can be received for that channel. However, as long as the channel handle exists, FreeRDP happily forwards any potential PDU for that handle disregarding the CreationStatus. This is problematic, since the channel handling usually runs in its own thread and as a result, the channel may not be destructed yet, when receiving such stray PDU. The PDU may be processed, even though it is not expected to be. A situation, where this becomes problematic is the AUDIO_PLAYBACK_DVC channel. It may be the case, that the client answered the DVC create request with a negative result, the server may try to close the handle and open the static channel (RDPSND) instead, but before the server can close the channel handle, the client actually sends PDUs regarding the format negotiation. In this case, the server may unintentionally already set things up, which was not desired (the DVC is about to be closed anyway). While this specific situation is hypothetical, since it would depend on a malicious client, it is still possible to happen, especially since the server implementation does not invoke the format negotiation, but FreeRDP does it automatically, as soon as the DVC create request is sent. Fix this issue by discarding any data PDUs (DYNVC_DATA_FIRST and DYNVC_DATA) of channels, that were not opened successfully.
2022-12-30 15:38:09 +03:00
if (dvc->dvc_open_state != DVC_OPEN_STATE_SUCCEEDED)
{
WLog_ERR(TAG,
"ChannelId %" PRIu32 " did not open successfully. "
"Ignoring DYNVC_DATA PDU",
ChannelId);
return TRUE;
}
return wts_read_drdynvc_data(dvc, channel->receiveData, length);
case CLOSE_REQUEST_PDU:
wts_read_drdynvc_close_response(dvc);
break;
case DATA_FIRST_COMPRESSED_PDU:
case DATA_COMPRESSED_PDU:
WLog_ERR(TAG, "Compressed data not handled");
break;
case SOFT_SYNC_RESPONSE_PDU:
2022-06-23 08:57:38 +03:00
WLog_ERR(TAG, "SoftSync response not handled yet(and rather strange to receive "
"that packet as our code doesn't send SoftSync requests");
break;
case SOFT_SYNC_REQUEST_PDU:
WLog_ERR(TAG, "Not expecting a SoftSyncRequest on the server");
return FALSE;
default:
WLog_ERR(TAG, "Cmd %d not recognized.", Cmd);
break;
}
}
else
{
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "received Cmd %d but channel is not ready.", Cmd);
}
2015-05-23 23:47:18 +03:00
return TRUE;
}
static int wts_write_variable_uint(wStream* s, UINT32 val)
{
int cb = 0;
WINPR_ASSERT(s);
if (val <= 0xFF)
{
cb = 0;
Stream_Write_UINT8(s, val);
}
else if (val <= 0xFFFF)
{
cb = 1;
Stream_Write_UINT16(s, val);
}
else
{
cb = 2;
Stream_Write_UINT32(s, val);
}
return cb;
}
static void wts_write_drdynvc_header(wStream* s, BYTE Cmd, UINT32 ChannelId)
{
BYTE* bm = NULL;
int cbChId = 0;
WINPR_ASSERT(s);
Stream_GetPointer(s, bm);
Stream_Seek_UINT8(s);
cbChId = wts_write_variable_uint(s, ChannelId);
*bm = ((Cmd & 0x0F) << 4) | cbChId;
}
2019-11-06 17:24:51 +03:00
static BOOL wts_write_drdynvc_create_request(wStream* s, UINT32 ChannelId, const char* ChannelName)
{
size_t len = 0;
WINPR_ASSERT(s);
WINPR_ASSERT(ChannelName);
wts_write_drdynvc_header(s, CREATE_REQUEST_PDU, ChannelId);
2019-11-11 12:01:19 +03:00
len = strlen(ChannelName) + 1;
if (!Stream_EnsureRemainingCapacity(s, len))
return FALSE;
Stream_Write(s, ChannelName, len);
return TRUE;
}
2019-11-06 17:24:51 +03:00
static BOOL WTSProcessChannelData(rdpPeerChannel* channel, UINT16 channelId, const BYTE* data,
size_t s, UINT32 flags, size_t t)
{
2015-05-23 23:47:18 +03:00
BOOL ret = TRUE;
2024-08-29 12:11:11 +03:00
const size_t size = s;
const size_t totalSize = t;
WINPR_ASSERT(channel);
WINPR_ASSERT(channel->vcm);
WINPR_UNUSED(channelId);
2015-05-23 23:47:18 +03:00
if (flags & CHANNEL_FLAG_FIRST)
{
Stream_SetPosition(channel->receiveData, 0);
}
2015-05-23 23:47:18 +03:00
if (!Stream_EnsureRemainingCapacity(channel->receiveData, size))
return FALSE;
Stream_Write(channel->receiveData, data, size);
if (flags & CHANNEL_FLAG_LAST)
{
if (Stream_GetPosition(channel->receiveData) != totalSize)
{
2015-05-23 23:47:18 +03:00
WLog_ERR(TAG, "read error");
}
if (channel == channel->vcm->drdynvc_channel)
{
2015-05-23 23:47:18 +03:00
ret = wts_read_drdynvc_pdu(channel);
}
else
{
ret = wts_queue_receive_data(channel, Stream_Buffer(channel->receiveData),
Stream_GetPosition(channel->receiveData));
}
Stream_SetPosition(channel->receiveData, 0);
}
2015-05-23 23:47:18 +03:00
return ret;
}
static BOOL WTSReceiveChannelData(freerdp_peer* client, UINT16 channelId, const BYTE* data,
size_t size, UINT32 flags, size_t totalSize)
{
rdpMcs* mcs = NULL;
WINPR_ASSERT(client);
WINPR_ASSERT(client->context);
WINPR_ASSERT(client->context->rdp);
mcs = client->context->rdp->mcs;
WINPR_ASSERT(mcs);
for (UINT32 i = 0; i < mcs->channelCount; i++)
{
rdpMcsChannel* cur = &mcs->channels[i];
if (cur->ChannelId == channelId)
{
rdpPeerChannel* channel = (rdpPeerChannel*)cur->handle;
if (channel)
return WTSProcessChannelData(channel, channelId, data, size, flags, totalSize);
}
}
WLog_WARN(TAG, "unknown channelId %" PRIu16 " ignored", channelId);
return TRUE;
}
#if defined(WITH_FREERDP_DEPRECATED)
2019-11-06 17:24:51 +03:00
void WTSVirtualChannelManagerGetFileDescriptor(HANDLE hServer, void** fds, int* fds_count)
{
void* fd = NULL;
2019-11-06 17:24:51 +03:00
WTSVirtualChannelManager* vcm = (WTSVirtualChannelManager*)hServer;
WINPR_ASSERT(vcm);
WINPR_ASSERT(fds);
WINPR_ASSERT(fds_count);
fd = GetEventWaitObject(MessageQueue_Event(vcm->queue));
if (fd)
{
fds[*fds_count] = fd;
(*fds_count)++;
}
#if 0
if (vcm->drdynvc_channel)
{
fd = GetEventWaitObject(vcm->drdynvc_channel->receiveEvent);
if (fd)
{
fds[*fds_count] = fd;
(*fds_count)++;
}
}
#endif
}
#endif
2022-06-23 10:17:49 +03:00
BOOL WTSVirtualChannelManagerOpen(HANDLE hServer)
{
2022-06-23 10:17:49 +03:00
WTSVirtualChannelManager* vcm = (WTSVirtualChannelManager*)hServer;
if (!vcm)
return FALSE;
2022-06-23 10:17:49 +03:00
if (vcm->drdynvc_state == DRDYNVC_STATE_NONE)
{
rdpPeerChannel* channel = NULL;
/* Initialize drdynvc channel once and only once. */
vcm->drdynvc_state = DRDYNVC_STATE_INITIALIZED;
2021-08-25 11:02:46 +03:00
channel = (rdpPeerChannel*)WTSVirtualChannelOpen((HANDLE)vcm, WTS_CURRENT_SESSION,
DRDYNVC_SVC_CHANNEL_NAME);
if (channel)
{
BYTE capaBuffer[12];
wStream staticS;
wStream* s = Stream_StaticInit(&staticS, capaBuffer, sizeof(capaBuffer));
vcm->drdynvc_channel = channel;
vcm->dvc_spoken_version = 1;
Stream_Write_UINT8(s, 0x50); /* Cmd=5 sp=0 cbId=0 */
Stream_Write_UINT8(s, 0x00); /* Pad */
Stream_Write_UINT16(s, 0x0001); /* Version */
/* TODO: shall implement version 2 and 3 */
ULONG written = 0;
if (!WTSVirtualChannelWrite(channel, (PCHAR)capaBuffer, Stream_GetPosition(s),
&written))
return FALSE;
}
}
return TRUE;
}
BOOL WTSVirtualChannelManagerCheckFileDescriptorEx(HANDLE hServer, BOOL autoOpen)
{
wMessage message = { 0 };
BOOL status = TRUE;
WTSVirtualChannelManager* vcm = NULL;
if (!hServer || hServer == INVALID_HANDLE_VALUE)
return FALSE;
vcm = (WTSVirtualChannelManager*)hServer;
if (autoOpen)
{
2022-06-23 10:17:49 +03:00
if (!WTSVirtualChannelManagerOpen(hServer))
return FALSE;
}
while (MessageQueue_Peek(vcm->queue, &message, TRUE))
{
BYTE* buffer = NULL;
UINT32 length = 0;
UINT16 channelId = 0;
2019-11-06 17:24:51 +03:00
channelId = (UINT16)(UINT_PTR)message.context;
buffer = (BYTE*)message.wParam;
length = (UINT32)(UINT_PTR)message.lParam;
2021-09-17 10:27:01 +03:00
WINPR_ASSERT(vcm->client);
WINPR_ASSERT(vcm->client->SendChannelData);
if (!vcm->client->SendChannelData(vcm->client, channelId, buffer, length))
{
status = FALSE;
}
free(buffer);
if (!status)
break;
}
return status;
}
BOOL WTSVirtualChannelManagerCheckFileDescriptor(HANDLE hServer)
{
return WTSVirtualChannelManagerCheckFileDescriptorEx(hServer, TRUE);
}
HANDLE WTSVirtualChannelManagerGetEventHandle(HANDLE hServer)
{
2019-11-06 17:24:51 +03:00
WTSVirtualChannelManager* vcm = (WTSVirtualChannelManager*)hServer;
WINPR_ASSERT(vcm);
return MessageQueue_Event(vcm->queue);
}
2019-11-06 17:24:51 +03:00
static rdpMcsChannel* wts_get_joined_channel_by_name(rdpMcs* mcs, const char* channel_name)
{
if (!mcs || !channel_name || !strnlen(channel_name, CHANNEL_NAME_LEN + 1))
return NULL;
for (UINT32 index = 0; index < mcs->channelCount; index++)
{
rdpMcsChannel* mchannel = &mcs->channels[index];
if (mchannel->joined)
{
if (_strnicmp(mchannel->Name, channel_name, CHANNEL_NAME_LEN + 1) == 0)
return mchannel;
}
}
return NULL;
}
2019-11-06 17:24:51 +03:00
static rdpMcsChannel* wts_get_joined_channel_by_id(rdpMcs* mcs, const UINT16 channel_id)
{
if (!mcs || !channel_id)
return NULL;
WINPR_ASSERT(mcs->channels);
for (UINT32 index = 0; index < mcs->channelCount; index++)
{
rdpMcsChannel* mchannel = &mcs->channels[index];
if (mchannel->joined)
{
if (mchannel->ChannelId == channel_id)
return &mcs->channels[index];
}
}
return NULL;
}
BOOL WTSIsChannelJoinedByName(freerdp_peer* client, const char* channel_name)
{
if (!client || !client->context || !client->context->rdp)
return FALSE;
2019-11-06 17:24:51 +03:00
return wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name) == NULL ? FALSE
: TRUE;
}
BOOL WTSIsChannelJoinedById(freerdp_peer* client, const UINT16 channel_id)
{
if (!client || !client->context || !client->context->rdp)
return FALSE;
2019-11-06 17:24:51 +03:00
return wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id) == NULL ? FALSE
: TRUE;
}
BOOL WTSVirtualChannelManagerIsChannelJoined(HANDLE hServer, const char* name)
{
2019-11-06 17:24:51 +03:00
WTSVirtualChannelManager* vcm = (WTSVirtualChannelManager*)hServer;
if (!vcm || !vcm->rdp)
return FALSE;
2019-11-06 17:24:51 +03:00
return wts_get_joined_channel_by_name(vcm->rdp->mcs, name) == NULL ? FALSE : TRUE;
}
BYTE WTSVirtualChannelManagerGetDrdynvcState(HANDLE hServer)
{
2019-11-06 17:24:51 +03:00
WTSVirtualChannelManager* vcm = (WTSVirtualChannelManager*)hServer;
WINPR_ASSERT(vcm);
return vcm->drdynvc_state;
}
void WTSVirtualChannelManagerSetDVCCreationCallback(HANDLE hServer, psDVCCreationStatusCallback cb,
void* userdata)
{
WTSVirtualChannelManager* vcm = hServer;
WINPR_ASSERT(vcm);
vcm->dvc_creation_status = cb;
vcm->dvc_creation_status_userdata = userdata;
}
UINT16 WTSChannelGetId(freerdp_peer* client, const char* channel_name)
{
rdpMcsChannel* channel = NULL;
WINPR_ASSERT(channel_name);
if (!client || !client->context || !client->context->rdp)
return 0;
2019-11-06 17:24:51 +03:00
channel = wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name);
if (!channel)
return 0;
return channel->ChannelId;
}
UINT32 WTSChannelGetIdByHandle(HANDLE hChannelHandle)
{
rdpPeerChannel* channel = hChannelHandle;
WINPR_ASSERT(channel);
return channel->channelId;
}
2019-11-06 17:24:51 +03:00
BOOL WTSChannelSetHandleByName(freerdp_peer* client, const char* channel_name, void* handle)
{
rdpMcsChannel* channel = NULL;
WINPR_ASSERT(channel_name);
if (!client || !client->context || !client->context->rdp)
return FALSE;
2019-11-06 17:24:51 +03:00
channel = wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name);
if (!channel)
return FALSE;
channel->handle = handle;
return TRUE;
}
2019-11-06 17:24:51 +03:00
BOOL WTSChannelSetHandleById(freerdp_peer* client, const UINT16 channel_id, void* handle)
{
rdpMcsChannel* channel = NULL;
if (!client || !client->context || !client->context->rdp)
return FALSE;
channel = wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id);
if (!channel)
return FALSE;
channel->handle = handle;
return TRUE;
}
void* WTSChannelGetHandleByName(freerdp_peer* client, const char* channel_name)
{
rdpMcsChannel* channel = NULL;
WINPR_ASSERT(channel_name);
if (!client || !client->context || !client->context->rdp)
return NULL;
2019-11-06 17:24:51 +03:00
channel = wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name);
if (!channel)
return NULL;
return channel->handle;
}
void* WTSChannelGetHandleById(freerdp_peer* client, const UINT16 channel_id)
{
rdpMcsChannel* channel = NULL;
if (!client || !client->context || !client->context->rdp)
return NULL;
channel = wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id);
if (!channel)
return NULL;
return channel->handle;
}
const char* WTSChannelGetName(freerdp_peer* client, UINT16 channel_id)
{
rdpMcsChannel* channel = NULL;
if (!client || !client->context || !client->context->rdp)
return NULL;
channel = wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id);
if (!channel)
return NULL;
return (const char*)channel->Name;
}
char** WTSGetAcceptedChannelNames(freerdp_peer* client, size_t* count)
{
rdpMcs* mcs = NULL;
char** names = NULL;
if (!client || !client->context || !count)
return NULL;
WINPR_ASSERT(client->context->rdp);
mcs = client->context->rdp->mcs;
WINPR_ASSERT(mcs);
*count = mcs->channelCount;
names = (char**)calloc(mcs->channelCount, sizeof(char*));
if (!names)
return NULL;
for (UINT32 index = 0; index < mcs->channelCount; index++)
{
rdpMcsChannel* mchannel = &mcs->channels[index];
names[index] = mchannel->Name;
}
return names;
}
2022-06-02 14:34:07 +03:00
INT64 WTSChannelGetOptions(freerdp_peer* client, UINT16 channel_id)
{
rdpMcsChannel* channel = NULL;
2022-06-02 14:34:07 +03:00
if (!client || !client->context || !client->context->rdp)
return -1;
channel = wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id);
if (!channel)
return -1;
return (INT64)channel->options;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionW(LPWSTR pTargetServerName, ULONG TargetLogonId,
BYTE HotkeyVk, USHORT HotkeyModifiers)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionA(LPSTR pTargetServerName, ULONG TargetLogonId,
BYTE HotkeyVk, USHORT HotkeyModifiers)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionExW(LPWSTR pTargetServerName, ULONG TargetLogonId,
BYTE HotkeyVk, USHORT HotkeyModifiers,
DWORD flags)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionExA(LPSTR pTargetServerName, ULONG TargetLogonId,
BYTE HotkeyVk, USHORT HotkeyModifiers,
DWORD flags)
{
return FALSE;
}
BOOL WINAPI FreeRDP_WTSStopRemoteControlSession(ULONG LogonId)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSConnectSessionW(ULONG LogonId, ULONG TargetLogonId, PWSTR pPassword,
BOOL bWait)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSConnectSessionA(ULONG LogonId, ULONG TargetLogonId, PSTR pPassword,
BOOL bWait)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSEnumerateServersW(LPWSTR pDomainName, DWORD Reserved, DWORD Version,
PWTS_SERVER_INFOW* ppServerInfo, DWORD* pCount)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSEnumerateServersA(LPSTR pDomainName, DWORD Reserved, DWORD Version,
PWTS_SERVER_INFOA* ppServerInfo, DWORD* pCount)
{
return FALSE;
}
HANDLE WINAPI FreeRDP_WTSOpenServerW(LPWSTR pServerName)
{
return INVALID_HANDLE_VALUE;
}
static void wts_virtual_channel_manager_free_message(void* obj)
{
wMessage* msg = (wMessage*)obj;
if (msg)
{
BYTE* buffer = (BYTE*)msg->wParam;
if (buffer)
free(buffer);
}
}
static void channel_free(rdpPeerChannel* channel)
{
server_channel_common_free(channel);
}
2021-09-17 10:27:01 +03:00
static void array_channel_free(void* ptr)
{
rdpPeerChannel* channel = ptr;
channel_free(channel);
}
static BOOL dynChannelMatch(const void* v1, const void* v2)
{
const UINT32* p1 = (const UINT32*)v1;
const UINT32* p2 = (const UINT32*)v2;
return *p1 == *p2;
}
static UINT32 channelId_Hash(const void* key)
{
const UINT32* v = (const UINT32*)key;
return *v;
}
HANDLE WINAPI FreeRDP_WTSOpenServerA(LPSTR pServerName)
{
rdpContext* context = NULL;
freerdp_peer* client = NULL;
WTSVirtualChannelManager* vcm = NULL;
HANDLE hServer = INVALID_HANDLE_VALUE;
wObject queueCallbacks = { 0 };
2019-11-06 17:24:51 +03:00
context = (rdpContext*)pServerName;
if (!context)
return INVALID_HANDLE_VALUE;
client = context->peer;
if (!client)
2015-05-20 20:19:50 +03:00
{
SetLastError(ERROR_INVALID_DATA);
return INVALID_HANDLE_VALUE;
2015-05-20 20:19:50 +03:00
}
2019-11-06 17:24:51 +03:00
vcm = (WTSVirtualChannelManager*)calloc(1, sizeof(WTSVirtualChannelManager));
if (!vcm)
2015-05-20 20:19:50 +03:00
goto error_vcm_alloc;
vcm->client = client;
vcm->rdp = context->rdp;
vcm->SessionId = g_SessionId++;
if (!g_ServerHandles)
{
g_ServerHandles = HashTable_New(TRUE);
if (!g_ServerHandles)
goto error_free;
}
if (!HashTable_Insert(g_ServerHandles, (void*)(UINT_PTR)vcm->SessionId, (void*)vcm))
goto error_free;
queueCallbacks.fnObjectFree = wts_virtual_channel_manager_free_message;
vcm->queue = MessageQueue_New(&queueCallbacks);
if (!vcm->queue)
goto error_queue;
vcm->dvc_channel_id_seq = 0;
vcm->dynamicVirtualChannels = HashTable_New(TRUE);
if (!vcm->dynamicVirtualChannels)
goto error_dynamicVirtualChannels;
if (!HashTable_SetHashFunction(vcm->dynamicVirtualChannels, channelId_Hash))
goto error_hashFunction;
2021-09-17 10:27:01 +03:00
{
wObject* obj = HashTable_ValueObject(vcm->dynamicVirtualChannels);
2021-09-17 10:27:01 +03:00
WINPR_ASSERT(obj);
obj->fnObjectFree = array_channel_free;
obj = HashTable_KeyObject(vcm->dynamicVirtualChannels);
obj->fnObjectEquals = dynChannelMatch;
2021-09-17 10:27:01 +03:00
}
client->ReceiveChannelData = WTSReceiveChannelData;
2019-11-06 17:24:51 +03:00
hServer = (HANDLE)vcm;
return hServer;
error_hashFunction:
HashTable_Free(vcm->dynamicVirtualChannels);
error_dynamicVirtualChannels:
MessageQueue_Free(vcm->queue);
error_queue:
2019-11-06 17:24:51 +03:00
HashTable_Remove(g_ServerHandles, (void*)(UINT_PTR)vcm->SessionId);
error_free:
free(vcm);
2015-05-20 20:19:50 +03:00
error_vcm_alloc:
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return INVALID_HANDLE_VALUE;
}
HANDLE WINAPI FreeRDP_WTSOpenServerExW(LPWSTR pServerName)
{
return INVALID_HANDLE_VALUE;
}
HANDLE WINAPI FreeRDP_WTSOpenServerExA(LPSTR pServerName)
{
return FreeRDP_WTSOpenServerA(pServerName);
}
VOID WINAPI FreeRDP_WTSCloseServer(HANDLE hServer)
{
WTSVirtualChannelManager* vcm = NULL;
2019-11-06 17:24:51 +03:00
vcm = (WTSVirtualChannelManager*)hServer;
2021-09-17 10:27:01 +03:00
if (vcm && (vcm != INVALID_HANDLE_VALUE))
{
2019-11-06 17:24:51 +03:00
HashTable_Remove(g_ServerHandles, (void*)(UINT_PTR)vcm->SessionId);
HashTable_Free(vcm->dynamicVirtualChannels);
if (vcm->drdynvc_channel)
{
WTSVirtualChannelClose(vcm->drdynvc_channel);
vcm->drdynvc_channel = NULL;
}
MessageQueue_Free(vcm->queue);
free(vcm);
}
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSEnumerateSessionsW(HANDLE hServer, DWORD Reserved, DWORD Version,
PWTS_SESSION_INFOW* ppSessionInfo, DWORD* pCount)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSEnumerateSessionsA(HANDLE hServer, DWORD Reserved, DWORD Version,
PWTS_SESSION_INFOA* ppSessionInfo, DWORD* pCount)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSEnumerateSessionsExW(HANDLE hServer, DWORD* pLevel, DWORD Filter,
PWTS_SESSION_INFO_1W* ppSessionInfo, DWORD* pCount)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSEnumerateSessionsExA(HANDLE hServer, DWORD* pLevel, DWORD Filter,
PWTS_SESSION_INFO_1A* ppSessionInfo, DWORD* pCount)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSEnumerateProcessesW(HANDLE hServer, DWORD Reserved, DWORD Version,
PWTS_PROCESS_INFOW* ppProcessInfo, DWORD* pCount)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSEnumerateProcessesA(HANDLE hServer, DWORD Reserved, DWORD Version,
PWTS_PROCESS_INFOA* ppProcessInfo, DWORD* pCount)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSTerminateProcess(HANDLE hServer, DWORD ProcessId, DWORD ExitCode)
{
return FALSE;
}
BOOL WINAPI FreeRDP_WTSQuerySessionInformationW(HANDLE hServer, DWORD SessionId,
2019-11-06 17:24:51 +03:00
WTS_INFO_CLASS WTSInfoClass, LPWSTR* ppBuffer,
DWORD* pBytesReturned)
{
return FALSE;
}
BOOL WINAPI FreeRDP_WTSQuerySessionInformationA(HANDLE hServer, DWORD SessionId,
2019-11-06 17:24:51 +03:00
WTS_INFO_CLASS WTSInfoClass, LPSTR* ppBuffer,
DWORD* pBytesReturned)
{
DWORD BytesReturned = 0;
WTSVirtualChannelManager* vcm = NULL;
2019-11-06 17:24:51 +03:00
vcm = (WTSVirtualChannelManager*)hServer;
if (!vcm)
return FALSE;
if (WTSInfoClass == WTSSessionId)
{
ULONG* pBuffer = NULL;
BytesReturned = sizeof(ULONG);
2019-11-06 17:24:51 +03:00
pBuffer = (ULONG*)malloc(sizeof(BytesReturned));
if (!pBuffer)
{
SetLastError(E_OUTOFMEMORY);
return FALSE;
}
*pBuffer = vcm->SessionId;
2019-11-06 17:24:51 +03:00
*ppBuffer = (LPSTR)pBuffer;
*pBytesReturned = BytesReturned;
return TRUE;
}
return FALSE;
}
BOOL WINAPI FreeRDP_WTSQueryUserConfigW(LPWSTR pServerName, LPWSTR pUserName,
2019-11-06 17:24:51 +03:00
WTS_CONFIG_CLASS WTSConfigClass, LPWSTR* ppBuffer,
DWORD* pBytesReturned)
{
return FALSE;
}
BOOL WINAPI FreeRDP_WTSQueryUserConfigA(LPSTR pServerName, LPSTR pUserName,
2019-11-06 17:24:51 +03:00
WTS_CONFIG_CLASS WTSConfigClass, LPSTR* ppBuffer,
DWORD* pBytesReturned)
{
return FALSE;
}
BOOL WINAPI FreeRDP_WTSSetUserConfigW(LPWSTR pServerName, LPWSTR pUserName,
2019-11-06 17:24:51 +03:00
WTS_CONFIG_CLASS WTSConfigClass, LPWSTR pBuffer,
DWORD DataLength)
{
return FALSE;
}
BOOL WINAPI FreeRDP_WTSSetUserConfigA(LPSTR pServerName, LPSTR pUserName,
2019-11-06 17:24:51 +03:00
WTS_CONFIG_CLASS WTSConfigClass, LPSTR pBuffer,
DWORD DataLength)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSSendMessageW(HANDLE hServer, DWORD SessionId, LPWSTR pTitle,
DWORD TitleLength, LPWSTR pMessage, DWORD MessageLength,
DWORD Style, DWORD Timeout, DWORD* pResponse, BOOL bWait)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSSendMessageA(HANDLE hServer, DWORD SessionId, LPSTR pTitle,
DWORD TitleLength, LPSTR pMessage, DWORD MessageLength,
DWORD Style, DWORD Timeout, DWORD* pResponse, BOOL bWait)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSDisconnectSession(HANDLE hServer, DWORD SessionId, BOOL bWait)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSLogoffSession(HANDLE hServer, DWORD SessionId, BOOL bWait)
{
return FALSE;
}
BOOL WINAPI FreeRDP_WTSShutdownSystem(HANDLE hServer, DWORD ShutdownFlag)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSWaitSystemEvent(HANDLE hServer, DWORD EventMask, DWORD* pEventFlags)
{
return FALSE;
}
static void peer_channel_queue_free_message(void* obj)
{
wMessage* msg = (wMessage*)obj;
if (!msg)
return;
free(msg->context);
msg->context = NULL;
}
static rdpPeerChannel* channel_new(WTSVirtualChannelManager* vcm, freerdp_peer* client,
UINT32 ChannelId, UINT16 index, UINT16 type, size_t chunkSize,
const char* name)
{
wObject queueCallbacks = { 0 };
queueCallbacks.fnObjectFree = peer_channel_queue_free_message;
rdpPeerChannel* channel =
server_channel_common_new(client, index, ChannelId, chunkSize, &queueCallbacks, name);
WINPR_ASSERT(vcm);
WINPR_ASSERT(client);
if (!channel)
goto fail;
channel->vcm = vcm;
channel->channelType = type;
channel->creationStatus =
(type == RDP_PEER_CHANNEL_TYPE_SVC) ? ERROR_SUCCESS : ERROR_OPERATION_IN_PROGRESS;
return channel;
fail:
channel_free(channel);
return NULL;
}
2019-11-06 17:24:51 +03:00
HANDLE WINAPI FreeRDP_WTSVirtualChannelOpen(HANDLE hServer, DWORD SessionId, LPSTR pVirtualName)
{
size_t length = 0;
rdpMcs* mcs = NULL;
rdpMcsChannel* joined_channel = NULL;
freerdp_peer* client = NULL;
rdpPeerChannel* channel = NULL;
WTSVirtualChannelManager* vcm = NULL;
HANDLE hChannelHandle = NULL;
rdpContext* context = NULL;
2019-11-06 17:24:51 +03:00
vcm = (WTSVirtualChannelManager*)hServer;
if (!vcm)
2015-05-20 20:19:50 +03:00
{
SetLastError(ERROR_INVALID_DATA);
return NULL;
2015-05-20 20:19:50 +03:00
}
client = vcm->client;
WINPR_ASSERT(client);
context = client->context;
WINPR_ASSERT(context);
WINPR_ASSERT(context->rdp);
WINPR_ASSERT(context->settings);
mcs = context->rdp->mcs;
WINPR_ASSERT(mcs);
length = strnlen(pVirtualName, CHANNEL_NAME_LEN + 1);
if (length > CHANNEL_NAME_LEN)
{
SetLastError(ERROR_NOT_FOUND);
return NULL;
}
UINT32 index = 0;
for (; index < mcs->channelCount; index++)
{
rdpMcsChannel* mchannel = &mcs->channels[index];
if (mchannel->joined && (strncmp(mchannel->Name, pVirtualName, length) == 0))
{
joined_channel = mchannel;
break;
}
}
if (!joined_channel)
{
SetLastError(ERROR_NOT_FOUND);
return NULL;
}
channel = (rdpPeerChannel*)joined_channel->handle;
if (!channel)
{
const UINT32 VCChunkSize =
freerdp_settings_get_uint32(context->settings, FreeRDP_VCChunkSize);
channel = channel_new(vcm, client, joined_channel->ChannelId, index,
RDP_PEER_CHANNEL_TYPE_SVC, VCChunkSize, pVirtualName);
2015-05-20 20:19:50 +03:00
if (!channel)
goto fail;
joined_channel->handle = channel;
}
2019-11-06 17:24:51 +03:00
hChannelHandle = (HANDLE)channel;
return hChannelHandle;
fail:
channel_free(channel);
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
2019-11-06 17:24:51 +03:00
HANDLE WINAPI FreeRDP_WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualName, DWORD flags)
{
wStream* s = NULL;
rdpMcs* mcs = NULL;
BOOL joined = FALSE;
freerdp_peer* client = NULL;
rdpPeerChannel* channel = NULL;
ULONG written = 0;
WTSVirtualChannelManager* vcm = NULL;
if (SessionId == WTS_CURRENT_SESSION)
return NULL;
2019-11-06 17:24:51 +03:00
vcm = (WTSVirtualChannelManager*)HashTable_GetItemValue(g_ServerHandles,
(void*)(UINT_PTR)SessionId);
if (!vcm)
return NULL;
if (!(flags & WTS_CHANNEL_OPTION_DYNAMIC))
{
2019-11-06 17:24:51 +03:00
return FreeRDP_WTSVirtualChannelOpen((HANDLE)vcm, SessionId, pVirtualName);
}
client = vcm->client;
mcs = client->context->rdp->mcs;
for (UINT32 index = 0; index < mcs->channelCount; index++)
{
rdpMcsChannel* mchannel = &mcs->channels[index];
2021-08-25 11:02:46 +03:00
if (mchannel->joined &&
(strncmp(mchannel->Name, DRDYNVC_SVC_CHANNEL_NAME, CHANNEL_NAME_LEN + 1) == 0))
{
joined = TRUE;
break;
}
}
if (!joined)
{
SetLastError(ERROR_NOT_FOUND);
return NULL;
}
if (!vcm->drdynvc_channel || (vcm->drdynvc_state != DRDYNVC_STATE_READY))
{
SetLastError(ERROR_NOT_READY);
return NULL;
}
WINPR_ASSERT(client);
WINPR_ASSERT(client->context);
WINPR_ASSERT(client->context->settings);
const UINT32 VCChunkSize =
freerdp_settings_get_uint32(client->context->settings, FreeRDP_VCChunkSize);
channel = channel_new(vcm, client, 0, 0, RDP_PEER_CHANNEL_TYPE_DVC, VCChunkSize, pVirtualName);
if (!channel)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
channel->channelId = InterlockedIncrement(&vcm->dvc_channel_id_seq);
if (!HashTable_Insert(vcm->dynamicVirtualChannels, &channel->channelId, channel))
2022-04-28 09:00:39 +03:00
{
channel_free(channel);
channel = NULL;
goto fail;
2022-04-28 09:00:39 +03:00
}
s = Stream_New(NULL, 64);
if (!s)
2022-04-28 09:00:39 +03:00
goto fail;
if (!wts_write_drdynvc_create_request(s, channel->channelId, pVirtualName))
2022-04-28 09:00:39 +03:00
goto fail;
2019-11-06 17:24:51 +03:00
if (!WTSVirtualChannelWrite(vcm->drdynvc_channel, (PCHAR)Stream_Buffer(s),
Stream_GetPosition(s), &written))
2022-04-28 09:00:39 +03:00
goto fail;
Stream_Free(s, TRUE);
return channel;
fail:
2021-09-17 10:27:01 +03:00
Stream_Free(s, TRUE);
2022-04-28 09:00:39 +03:00
if (channel)
HashTable_Remove(vcm->dynamicVirtualChannels, &channel->channelId);
2021-09-17 10:27:01 +03:00
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
BOOL WINAPI FreeRDP_WTSVirtualChannelClose(HANDLE hChannelHandle)
{
wStream* s = NULL;
rdpMcs* mcs = NULL;
2019-11-06 17:24:51 +03:00
rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
BOOL ret = TRUE;
if (channel)
{
WTSVirtualChannelManager* vcm = channel->vcm;
WINPR_ASSERT(vcm);
WINPR_ASSERT(vcm->client);
WINPR_ASSERT(vcm->client->context);
WINPR_ASSERT(vcm->client->context->rdp);
mcs = vcm->client->context->rdp->mcs;
if (channel->channelType == RDP_PEER_CHANNEL_TYPE_SVC)
{
if (channel->index < mcs->channelCount)
{
rdpMcsChannel* cur = &mcs->channels[channel->index];
rdpPeerChannel* peerChannel = (rdpPeerChannel*)cur->handle;
channel_free(peerChannel);
cur->handle = NULL;
}
}
else
{
if (channel->dvc_open_state == DVC_OPEN_STATE_SUCCEEDED)
{
ULONG written = 0;
s = Stream_New(NULL, 8);
if (!s)
{
WLog_ERR(TAG, "Stream_New failed!");
ret = FALSE;
}
else
{
wts_write_drdynvc_header(s, CLOSE_REQUEST_PDU, channel->channelId);
2019-11-06 17:24:51 +03:00
ret = WTSVirtualChannelWrite(vcm->drdynvc_channel, (PCHAR)Stream_Buffer(s),
Stream_GetPosition(s), &written);
Stream_Free(s, TRUE);
}
}
HashTable_Remove(vcm->dynamicVirtualChannels, &channel->channelId);
}
}
return ret;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSVirtualChannelRead(HANDLE hChannelHandle, ULONG TimeOut, PCHAR Buffer,
ULONG BufferSize, PULONG pBytesRead)
{
BYTE* buffer = NULL;
wMessage message = { 0 };
wtsChannelMessage* messageCtx = NULL;
2019-11-06 17:24:51 +03:00
rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
WINPR_ASSERT(channel);
if (!MessageQueue_Peek(channel->queue, &message, FALSE))
{
SetLastError(ERROR_NO_DATA);
*pBytesRead = 0;
return FALSE;
}
messageCtx = message.context;
if (messageCtx == NULL)
return FALSE;
buffer = (BYTE*)(messageCtx + 1);
*pBytesRead = messageCtx->length - messageCtx->offset;
if (Buffer == NULL || BufferSize == 0)
{
return TRUE;
}
if (*pBytesRead > BufferSize)
*pBytesRead = BufferSize;
CopyMemory(Buffer, buffer + messageCtx->offset, *pBytesRead);
messageCtx->offset += *pBytesRead;
if (messageCtx->offset >= messageCtx->length)
{
MessageQueue_Peek(channel->queue, &message, TRUE);
peer_channel_queue_free_message(&message);
}
return TRUE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSVirtualChannelWrite(HANDLE hChannelHandle, PCHAR Buffer, ULONG Length,
PULONG pBytesWritten)
{
wStream* s = NULL;
int cbLen = 0;
int cbChId = 0;
int first = 0;
BYTE* buffer = NULL;
UINT32 length = 0;
UINT32 written = 0;
UINT32 totalWritten = 0;
2019-11-06 17:24:51 +03:00
rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
BOOL ret = FALSE;
if (!channel)
return FALSE;
EnterCriticalSection(&channel->writeLock);
WINPR_ASSERT(channel->vcm);
if (channel->channelType == RDP_PEER_CHANNEL_TYPE_SVC)
{
length = Length;
buffer = (BYTE*)malloc(length);
2015-05-25 23:55:37 +03:00
if (!buffer)
{
SetLastError(E_OUTOFMEMORY);
goto fail;
}
CopyMemory(buffer, Buffer, length);
totalWritten = Length;
2015-05-23 23:47:18 +03:00
ret = wts_queue_send_item(channel, buffer, length);
}
2019-11-06 17:24:51 +03:00
else if (!channel->vcm->drdynvc_channel || (channel->vcm->drdynvc_state != DRDYNVC_STATE_READY))
{
DEBUG_DVC("drdynvc not ready");
goto fail;
}
else
{
rdpContext* context = NULL;
first = TRUE;
WINPR_ASSERT(channel->client);
context = channel->client->context;
WINPR_ASSERT(context);
while (Length > 0)
{
s = Stream_New(NULL, DVC_MAX_DATA_PDU_SIZE);
if (!s)
{
WLog_ERR(TAG, "Stream_New failed!");
SetLastError(E_OUTOFMEMORY);
goto fail;
}
2015-05-23 23:47:18 +03:00
buffer = Stream_Buffer(s);
Stream_Seek_UINT8(s);
cbChId = wts_write_variable_uint(s, channel->channelId);
if (first && (Length > Stream_GetRemainingLength(s)))
{
cbLen = wts_write_variable_uint(s, Length);
buffer[0] = (DATA_FIRST_PDU << 4) | (cbLen << 2) | cbChId;
}
else
{
buffer[0] = (DATA_PDU << 4) | cbChId;
}
first = FALSE;
written = Stream_GetRemainingLength(s);
if (written > Length)
written = Length;
Stream_Write(s, Buffer, written);
length = Stream_GetPosition(s);
Stream_Free(s, FALSE);
Length -= written;
Buffer += written;
totalWritten += written;
if (!wts_queue_send_item(channel->vcm->drdynvc_channel, buffer, length))
goto fail;
}
}
if (pBytesWritten)
*pBytesWritten = totalWritten;
ret = TRUE;
fail:
LeaveCriticalSection(&channel->writeLock);
2015-05-23 23:47:18 +03:00
return ret;
}
BOOL WINAPI FreeRDP_WTSVirtualChannelPurgeInput(HANDLE hChannelHandle)
{
return TRUE;
}
BOOL WINAPI FreeRDP_WTSVirtualChannelPurgeOutput(HANDLE hChannelHandle)
{
return TRUE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSVirtualChannelQuery(HANDLE hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass,
PVOID* ppBuffer, DWORD* pBytesReturned)
{
void* pfd = NULL;
BOOL bval = 0;
void* fds[10] = { 0 };
HANDLE hEvent = NULL;
int fds_count = 0;
BOOL status = FALSE;
2019-11-06 17:24:51 +03:00
rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
WINPR_ASSERT(channel);
2019-11-06 17:24:51 +03:00
switch ((UINT32)WtsVirtualClass)
{
case WTSVirtualFileHandle:
hEvent = MessageQueue_Event(channel->queue);
pfd = GetEventWaitObject(hEvent);
if (pfd)
{
fds[fds_count] = pfd;
(fds_count)++;
}
*ppBuffer = malloc(sizeof(void*));
if (!*ppBuffer)
{
SetLastError(E_OUTOFMEMORY);
}
else
{
CopyMemory(*ppBuffer, &fds[0], sizeof(void*));
*pBytesReturned = sizeof(void*);
status = TRUE;
}
break;
case WTSVirtualEventHandle:
hEvent = MessageQueue_Event(channel->queue);
*ppBuffer = malloc(sizeof(HANDLE));
if (!*ppBuffer)
{
SetLastError(E_OUTOFMEMORY);
}
else
{
CopyMemory(*ppBuffer, &(hEvent), sizeof(HANDLE));
*pBytesReturned = sizeof(void*);
status = TRUE;
}
break;
case WTSVirtualChannelReady:
if (channel->channelType == RDP_PEER_CHANNEL_TYPE_SVC)
{
bval = TRUE;
status = TRUE;
}
else
{
switch (channel->dvc_open_state)
{
case DVC_OPEN_STATE_NONE:
bval = FALSE;
status = TRUE;
break;
case DVC_OPEN_STATE_SUCCEEDED:
bval = TRUE;
status = TRUE;
break;
default:
*ppBuffer = NULL;
*pBytesReturned = 0;
return FALSE;
}
}
*ppBuffer = malloc(sizeof(BOOL));
if (!*ppBuffer)
{
SetLastError(E_OUTOFMEMORY);
status = FALSE;
}
else
{
CopyMemory(*ppBuffer, &bval, sizeof(BOOL));
*pBytesReturned = sizeof(BOOL);
}
break;
case WTSVirtualChannelOpenStatus:
{
INT32 value = channel->creationStatus;
status = TRUE;
*ppBuffer = malloc(sizeof(value));
if (!*ppBuffer)
{
SetLastError(E_OUTOFMEMORY);
status = FALSE;
}
else
{
CopyMemory(*ppBuffer, &value, sizeof(value));
*pBytesReturned = sizeof(value);
}
break;
}
default:
break;
}
return status;
}
VOID WINAPI FreeRDP_WTSFreeMemory(PVOID pMemory)
{
free(pMemory);
}
BOOL WINAPI FreeRDP_WTSFreeMemoryExW(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
ULONG NumberOfEntries)
{
return FALSE;
}
BOOL WINAPI FreeRDP_WTSFreeMemoryExA(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
ULONG NumberOfEntries)
{
return FALSE;
}
BOOL WINAPI FreeRDP_WTSRegisterSessionNotification(HWND hWnd, DWORD dwFlags)
{
return FALSE;
}
BOOL WINAPI FreeRDP_WTSUnRegisterSessionNotification(HWND hWnd)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSRegisterSessionNotificationEx(HANDLE hServer, HWND hWnd, DWORD dwFlags)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSUnRegisterSessionNotificationEx(HANDLE hServer, HWND hWnd)
{
return FALSE;
}
BOOL WINAPI FreeRDP_WTSQueryUserToken(ULONG SessionId, PHANDLE phToken)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSEnumerateProcessesExW(HANDLE hServer, DWORD* pLevel, DWORD SessionId,
LPWSTR* ppProcessInfo, DWORD* pCount)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSEnumerateProcessesExA(HANDLE hServer, DWORD* pLevel, DWORD SessionId,
LPSTR* ppProcessInfo, DWORD* pCount)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSEnumerateListenersW(HANDLE hServer, PVOID pReserved, DWORD Reserved,
PWTSLISTENERNAMEW pListeners, DWORD* pCount)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSEnumerateListenersA(HANDLE hServer, PVOID pReserved, DWORD Reserved,
PWTSLISTENERNAMEA pListeners, DWORD* pCount)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSQueryListenerConfigW(HANDLE hServer, PVOID pReserved, DWORD Reserved,
LPWSTR pListenerName, PWTSLISTENERCONFIGW pBuffer)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSQueryListenerConfigA(HANDLE hServer, PVOID pReserved, DWORD Reserved,
LPSTR pListenerName, PWTSLISTENERCONFIGA pBuffer)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSCreateListenerW(HANDLE hServer, PVOID pReserved, DWORD Reserved,
LPWSTR pListenerName, PWTSLISTENERCONFIGW pBuffer,
DWORD flag)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSCreateListenerA(HANDLE hServer, PVOID pReserved, DWORD Reserved,
LPSTR pListenerName, PWTSLISTENERCONFIGA pBuffer, DWORD flag)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSSetListenerSecurityW(HANDLE hServer, PVOID pReserved, DWORD Reserved,
LPWSTR pListenerName,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR pSecurityDescriptor)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSSetListenerSecurityA(HANDLE hServer, PVOID pReserved, DWORD Reserved,
LPSTR pListenerName,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR pSecurityDescriptor)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSGetListenerSecurityW(HANDLE hServer, PVOID pReserved, DWORD Reserved,
LPWSTR pListenerName,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength,
LPDWORD lpnLengthNeeded)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSGetListenerSecurityA(HANDLE hServer, PVOID pReserved, DWORD Reserved,
LPSTR pListenerName,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength,
LPDWORD lpnLengthNeeded)
{
return FALSE;
}
BOOL CDECL FreeRDP_WTSEnableChildSessions(BOOL bEnable)
{
return FALSE;
}
BOOL CDECL FreeRDP_WTSIsChildSessionsEnabled(PBOOL pbEnabled)
{
return FALSE;
}
BOOL CDECL FreeRDP_WTSGetChildSessionId(PULONG pSessionId)
{
return FALSE;
}
DWORD WINAPI FreeRDP_WTSGetActiveConsoleSessionId(void)
{
return 0xFFFFFFFF;
}
BOOL WINAPI FreeRDP_WTSLogoffUser(HANDLE hServer)
{
return FALSE;
}
2019-11-06 17:24:51 +03:00
BOOL WINAPI FreeRDP_WTSLogonUser(HANDLE hServer, LPCSTR username, LPCSTR password, LPCSTR domain)
{
return FALSE;
}
void server_channel_common_free(rdpPeerChannel* channel)
{
if (!channel)
return;
MessageQueue_Free(channel->queue);
Stream_Free(channel->receiveData, TRUE);
DeleteCriticalSection(&channel->writeLock);
free(channel);
}
rdpPeerChannel* server_channel_common_new(freerdp_peer* client, UINT16 index, UINT32 channelId,
size_t chunkSize, const wObject* callback,
const char* name)
{
rdpPeerChannel* channel = (rdpPeerChannel*)calloc(1, sizeof(rdpPeerChannel));
if (!channel)
return NULL;
InitializeCriticalSection(&channel->writeLock);
channel->receiveData = Stream_New(NULL, chunkSize);
if (!channel->receiveData)
goto fail;
channel->queue = MessageQueue_New(callback);
if (!channel->queue)
goto fail;
channel->index = index;
channel->client = client;
channel->channelId = channelId;
strncpy(channel->channelName, name, ARRAYSIZE(channel->channelName) - 1);
return channel;
fail:
WINPR_PRAGMA_DIAG_PUSH
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
server_channel_common_free(channel);
WINPR_PRAGMA_DIAG_POP
return NULL;
}