2014-02-15 17:42:59 -05:00
|
|
|
/**
|
|
|
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
|
|
|
* Server Channels
|
|
|
|
|
*
|
|
|
|
|
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
2015-05-29 04:46:50 -07:00
|
|
|
* Copyright 2015 Thincast Technologies GmbH
|
|
|
|
|
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
2014-02-15 17:42:59 -05:00
|
|
|
*
|
|
|
|
|
* 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 11:20:38 +01:00
|
|
|
#include <freerdp/config.h>
|
2014-02-15 17:42:59 -05:00
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
2024-10-14 15:50:38 +02:00
|
|
|
#include <stdint.h>
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2024-10-14 15:50:38 +02:00
|
|
|
#include <winpr/wtypes.h>
|
2014-02-15 17:42:59 -05:00
|
|
|
#include <winpr/crt.h>
|
|
|
|
|
#include <winpr/synch.h>
|
|
|
|
|
#include <winpr/stream.h>
|
2024-12-19 14:45:06 +01:00
|
|
|
#include <winpr/assert.h>
|
|
|
|
|
#include <winpr/cast.h>
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2014-09-12 14:36:29 +02:00
|
|
|
#include <freerdp/log.h>
|
2014-02-15 17:42:59 -05:00
|
|
|
#include <freerdp/constants.h>
|
|
|
|
|
#include <freerdp/server/channels.h>
|
2021-08-25 10:02:46 +02:00
|
|
|
#include <freerdp/channels/drdynvc.h>
|
2023-01-12 13:58:47 +01:00
|
|
|
#include <freerdp/utils/drdynvc.h>
|
2014-02-15 17:42:59 -05:00
|
|
|
|
|
|
|
|
#include "rdp.h"
|
|
|
|
|
|
|
|
|
|
#include "server.h"
|
|
|
|
|
|
2014-09-12 14:36:29 +02:00
|
|
|
#define TAG FREERDP_TAG("core.server")
|
2014-02-15 17:42:59 -05:00
|
|
|
#ifdef WITH_DEBUG_DVC
|
2016-10-07 14:04:40 +02:00
|
|
|
#define DEBUG_DVC(...) WLog_DBG(TAG, __VA_ARGS__)
|
2014-02-15 17:42:59 -05:00
|
|
|
#else
|
2019-11-06 15:24:51 +01:00
|
|
|
#define DEBUG_DVC(...) \
|
|
|
|
|
do \
|
|
|
|
|
{ \
|
|
|
|
|
} while (0)
|
2014-02-15 17:42:59 -05:00
|
|
|
#endif
|
|
|
|
|
|
2023-04-27 10:43:36 +02:00
|
|
|
#define DVC_MAX_DATA_PDU_SIZE 1600
|
|
|
|
|
|
2022-02-14 13:59:22 +00:00
|
|
|
typedef struct
|
2014-07-14 20:00:38 +08:00
|
|
|
{
|
|
|
|
|
UINT16 channelId;
|
|
|
|
|
UINT16 reserved;
|
|
|
|
|
UINT32 length;
|
|
|
|
|
UINT32 offset;
|
2022-02-14 13:59:22 +00:00
|
|
|
} wtsChannelMessage;
|
2014-07-14 20:00:38 +08:00
|
|
|
|
2025-02-12 11:39:35 +01:00
|
|
|
static const DWORD g_err_oom = WINPR_CXX_COMPAT_CAST(DWORD, E_OUTOFMEMORY);
|
|
|
|
|
|
2026-03-03 15:21:40 +01:00
|
|
|
static DWORD g_SessionId = 0;
|
2026-02-26 15:06:27 +01:00
|
|
|
static wHashTable* g_ServerHandles = nullptr;
|
2026-03-03 15:21:40 +01:00
|
|
|
static INIT_ONCE g_HandleInitializer = INIT_ONCE_STATIC_INIT;
|
2014-02-16 23:00:58 -05:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
static rdpPeerChannel* wts_get_dvc_channel_by_id(WTSVirtualChannelManager* vcm, UINT32 ChannelId)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2021-08-24 14:09:40 +02:00
|
|
|
WINPR_ASSERT(vcm);
|
2023-10-03 21:41:39 +02:00
|
|
|
return HashTable_GetItemValue(vcm->dynamicVirtualChannels, &ChannelId);
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
static BOOL wts_queue_receive_data(rdpPeerChannel* channel, const BYTE* Buffer, UINT32 Length)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
BYTE* buffer = nullptr;
|
|
|
|
|
wtsChannelMessage* messageCtx = nullptr;
|
2021-08-24 14:09:40 +02:00
|
|
|
|
|
|
|
|
WINPR_ASSERT(channel);
|
2019-11-06 15:24:51 +01:00
|
|
|
messageCtx = (wtsChannelMessage*)malloc(sizeof(wtsChannelMessage) + Length);
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2015-05-25 22:55:37 +02:00
|
|
|
if (!messageCtx)
|
|
|
|
|
return FALSE;
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2024-12-19 14:45:06 +01:00
|
|
|
WINPR_ASSERT(channel->channelId <= UINT16_MAX);
|
|
|
|
|
messageCtx->channelId = (UINT16)channel->channelId;
|
2014-07-14 20:00:38 +08:00
|
|
|
messageCtx->length = Length;
|
|
|
|
|
messageCtx->offset = 0;
|
2016-10-07 14:04:40 +02:00
|
|
|
buffer = (BYTE*)(messageCtx + 1);
|
2014-07-14 20:00:38 +08:00
|
|
|
CopyMemory(buffer, Buffer, Length);
|
2026-02-26 15:06:27 +01:00
|
|
|
return MessageQueue_Post(channel->queue, messageCtx, 0, nullptr, nullptr);
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
static BOOL wts_queue_send_item(rdpPeerChannel* channel, BYTE* Buffer, UINT32 Length)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
BYTE* buffer = nullptr;
|
2024-01-23 16:49:54 +01:00
|
|
|
UINT32 length = 0;
|
2024-12-19 14:45:06 +01:00
|
|
|
|
2021-08-24 14:09:40 +02:00
|
|
|
WINPR_ASSERT(channel);
|
|
|
|
|
WINPR_ASSERT(channel->vcm);
|
2014-02-15 19:21:41 -05:00
|
|
|
buffer = Buffer;
|
|
|
|
|
length = Length;
|
2024-12-19 14:45:06 +01:00
|
|
|
|
|
|
|
|
WINPR_ASSERT(channel->channelId <= UINT16_MAX);
|
|
|
|
|
const UINT16 channelId = (UINT16)channel->channelId;
|
2019-11-06 15:24:51 +01:00
|
|
|
return MessageQueue_Post(channel->vcm->queue, (void*)(UINT_PTR)channelId, 0, (void*)buffer,
|
|
|
|
|
(void*)(UINT_PTR)length);
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
|
2024-10-14 15:50:38 +02:00
|
|
|
static unsigned wts_read_variable_uint(wStream* s, int cbLen, UINT32* val)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2021-08-24 14:09:40 +02:00
|
|
|
WINPR_ASSERT(s);
|
|
|
|
|
WINPR_ASSERT(val);
|
2014-02-15 17:42:59 -05:00
|
|
|
switch (cbLen)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
2022-04-19 14:29:17 +02:00
|
|
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
|
2014-02-15 17:42:59 -05:00
|
|
|
return 0;
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2014-02-15 17:42:59 -05:00
|
|
|
Stream_Read_UINT8(s, *val);
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
case 1:
|
2022-04-19 14:29:17 +02:00
|
|
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
|
2014-02-15 17:42:59 -05:00
|
|
|
return 0;
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2014-02-15 17:42:59 -05:00
|
|
|
Stream_Read_UINT16(s, *val);
|
|
|
|
|
return 2;
|
|
|
|
|
|
2022-03-07 13:40:09 +01:00
|
|
|
case 2:
|
2022-04-19 14:29:17 +02:00
|
|
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
|
2014-02-15 17:42:59 -05:00
|
|
|
return 0;
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2014-02-15 17:42:59 -05:00
|
|
|
Stream_Read_UINT32(s, *val);
|
|
|
|
|
return 4;
|
2022-03-07 13:40:09 +01:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
WLog_ERR(TAG, "invalid wts variable uint len %d", cbLen);
|
|
|
|
|
return 0;
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
static BOOL wts_read_drdynvc_capabilities_response(rdpPeerChannel* channel, UINT32 length)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2024-01-23 16:49:54 +01:00
|
|
|
UINT16 Version = 0;
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2021-08-24 14:09:40 +02:00
|
|
|
WINPR_ASSERT(channel);
|
|
|
|
|
WINPR_ASSERT(channel->vcm);
|
2014-02-15 17:42:59 -05:00
|
|
|
if (length < 3)
|
2015-05-23 22:47:18 +02:00
|
|
|
return FALSE;
|
2014-02-15 17:42:59 -05:00
|
|
|
|
|
|
|
|
Stream_Seek_UINT8(channel->receiveData); /* Pad (1 byte) */
|
|
|
|
|
Stream_Read_UINT16(channel->receiveData, Version);
|
2019-11-06 15:24:51 +01:00
|
|
|
DEBUG_DVC("Version: %" PRIu16 "", Version);
|
2023-09-14 15:11:23 +02:00
|
|
|
|
|
|
|
|
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));
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
static BOOL wts_read_drdynvc_create_response(rdpPeerChannel* channel, wStream* s, UINT32 length)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2024-01-23 16:49:54 +01:00
|
|
|
UINT32 CreationStatus = 0;
|
2022-06-07 06:31:48 +02:00
|
|
|
BOOL status = TRUE;
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2021-08-24 14:09:40 +02:00
|
|
|
WINPR_ASSERT(channel);
|
|
|
|
|
WINPR_ASSERT(s);
|
2014-02-15 17:42:59 -05:00
|
|
|
if (length < 4)
|
2015-05-23 22:47:18 +02:00
|
|
|
return FALSE;
|
2014-02-15 17:42:59 -05:00
|
|
|
|
|
|
|
|
Stream_Read_UINT32(s, CreationStatus);
|
|
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if ((INT32)CreationStatus < 0)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2019-11-06 15:24:51 +01:00
|
|
|
DEBUG_DVC("ChannelId %" PRIu32 " creation failed (%" PRId32 ")", channel->channelId,
|
|
|
|
|
(INT32)CreationStatus);
|
2014-02-15 17:42:59 -05:00
|
|
|
channel->dvc_open_state = DVC_OPEN_STATE_FAILED;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-11-06 15:24:51 +01:00
|
|
|
DEBUG_DVC("ChannelId %" PRIu32 " creation succeeded", channel->channelId);
|
2014-02-15 17:42:59 -05:00
|
|
|
channel->dvc_open_state = DVC_OPEN_STATE_SUCCEEDED;
|
|
|
|
|
}
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2022-12-26 00:01:27 +01:00
|
|
|
channel->creationStatus = (INT32)CreationStatus;
|
2022-06-07 06:31:48 +02:00
|
|
|
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;
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
static BOOL wts_read_drdynvc_data_first(rdpPeerChannel* channel, wStream* s, int cbLen,
|
|
|
|
|
UINT32 length)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2021-08-24 14:09:40 +02:00
|
|
|
WINPR_ASSERT(channel);
|
|
|
|
|
WINPR_ASSERT(s);
|
2024-12-19 14:45:06 +01:00
|
|
|
const UINT32 value = wts_read_variable_uint(s, cbLen, &channel->dvc_total_length);
|
2014-02-15 17:42:59 -05:00
|
|
|
|
|
|
|
|
if (value == 0)
|
2015-05-23 22:47:18 +02:00
|
|
|
return FALSE;
|
2024-12-19 14:45:06 +01:00
|
|
|
if (value > length)
|
|
|
|
|
length = 0;
|
|
|
|
|
else
|
|
|
|
|
length -= value;
|
2014-02-15 17:42:59 -05:00
|
|
|
|
|
|
|
|
if (length > channel->dvc_total_length)
|
2015-05-23 22:47:18 +02:00
|
|
|
return FALSE;
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2026-02-27 20:04:43 +01:00
|
|
|
Stream_ResetPosition(channel->receiveData);
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2020-04-15 17:47:42 +02:00
|
|
|
if (!Stream_EnsureRemainingCapacity(channel->receiveData, channel->dvc_total_length))
|
2015-05-23 22:47:18 +02:00
|
|
|
return FALSE;
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2023-06-07 15:38:21 +02:00
|
|
|
Stream_Write(channel->receiveData, Stream_ConstPointer(s), length);
|
2015-05-23 22:47:18 +02:00
|
|
|
return TRUE;
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
static BOOL wts_read_drdynvc_data(rdpPeerChannel* channel, wStream* s, UINT32 length)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2015-06-23 12:08:47 +02:00
|
|
|
BOOL ret = FALSE;
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2021-08-24 14:09:40 +02:00
|
|
|
WINPR_ASSERT(channel);
|
|
|
|
|
WINPR_ASSERT(s);
|
2014-02-15 17:42:59 -05:00
|
|
|
if (channel->dvc_total_length > 0)
|
|
|
|
|
{
|
2019-11-06 15:24:51 +01:00
|
|
|
if (Stream_GetPosition(channel->receiveData) + length > channel->dvc_total_length)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
|
|
|
|
channel->dvc_total_length = 0;
|
2015-05-23 22:47:18 +02:00
|
|
|
WLog_ERR(TAG, "incorrect fragment data, discarded.");
|
|
|
|
|
return FALSE;
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
|
2023-06-07 15:38:21 +02:00
|
|
|
Stream_Write(channel->receiveData, Stream_ConstPointer(s), length);
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2019-02-07 14:22:28 +01:00
|
|
|
if (Stream_GetPosition(channel->receiveData) >= channel->dvc_total_length)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2016-10-07 14:04:40 +02:00
|
|
|
ret = wts_queue_receive_data(channel, Stream_Buffer(channel->receiveData),
|
|
|
|
|
channel->dvc_total_length);
|
2014-02-15 17:42:59 -05:00
|
|
|
channel->dvc_total_length = 0;
|
|
|
|
|
}
|
2020-03-03 12:27:01 +01:00
|
|
|
else
|
|
|
|
|
ret = TRUE;
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-06-07 15:38:21 +02:00
|
|
|
ret = wts_queue_receive_data(channel, Stream_ConstPointer(s), length);
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2015-05-23 22:47:18 +02:00
|
|
|
return ret;
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void wts_read_drdynvc_close_response(rdpPeerChannel* channel)
|
|
|
|
|
{
|
2021-08-24 14:09:40 +02:00
|
|
|
WINPR_ASSERT(channel);
|
2019-11-06 15:24:51 +01:00
|
|
|
DEBUG_DVC("ChannelId %" PRIu32 " close response", channel->channelId);
|
2014-02-15 17:42:59 -05:00
|
|
|
channel->dvc_open_state = DVC_OPEN_STATE_CLOSED;
|
2019-10-25 13:20:28 +02:00
|
|
|
MessageQueue_PostQuit(channel->queue, 0);
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
|
2015-05-23 22:47:18 +02:00
|
|
|
static BOOL wts_read_drdynvc_pdu(rdpPeerChannel* channel)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2024-01-23 16:49:54 +01:00
|
|
|
UINT8 Cmd = 0;
|
|
|
|
|
UINT8 Sp = 0;
|
|
|
|
|
UINT8 cbChId = 0;
|
2023-01-13 13:25:32 +01:00
|
|
|
UINT32 ChannelId = 0;
|
2026-02-26 15:06:27 +01:00
|
|
|
rdpPeerChannel* dvc = nullptr;
|
2021-08-24 14:09:40 +02:00
|
|
|
|
|
|
|
|
WINPR_ASSERT(channel);
|
|
|
|
|
WINPR_ASSERT(channel->vcm);
|
|
|
|
|
|
2024-10-14 15:50:38 +02:00
|
|
|
size_t length = Stream_GetPosition(channel->receiveData);
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2024-10-14 15:50:38 +02:00
|
|
|
if ((length < 1) || (length > UINT32_MAX))
|
2015-05-23 22:47:18 +02:00
|
|
|
return FALSE;
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2026-02-27 20:04:43 +01:00
|
|
|
Stream_ResetPosition(channel->receiveData);
|
2024-10-14 15:50:38 +02:00
|
|
|
const UINT8 value = Stream_Get_UINT8(channel->receiveData);
|
2014-02-15 17:42:59 -05:00
|
|
|
length--;
|
|
|
|
|
Cmd = (value & 0xf0) >> 4;
|
|
|
|
|
Sp = (value & 0x0c) >> 2;
|
|
|
|
|
cbChId = (value & 0x03) >> 0;
|
|
|
|
|
|
|
|
|
|
if (Cmd == CAPABILITY_REQUEST_PDU)
|
2024-10-14 15:50:38 +02:00
|
|
|
return wts_read_drdynvc_capabilities_response(channel, (UINT32)length);
|
2022-03-07 13:40:09 +01:00
|
|
|
|
|
|
|
|
if (channel->vcm->drdynvc_state == DRDYNVC_STATE_READY)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2024-01-23 16:49:54 +01:00
|
|
|
BOOL haveChannelId = 0;
|
2022-03-07 13:40:09 +01:00
|
|
|
switch (Cmd)
|
|
|
|
|
{
|
2022-06-23 07:57:38 +02:00
|
|
|
case SOFT_SYNC_REQUEST_PDU:
|
|
|
|
|
case SOFT_SYNC_RESPONSE_PDU:
|
|
|
|
|
haveChannelId = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
haveChannelId = TRUE;
|
|
|
|
|
break;
|
2022-03-07 13:40:09 +01:00
|
|
|
}
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2022-03-07 13:40:09 +01:00
|
|
|
if (haveChannelId)
|
|
|
|
|
{
|
2024-10-14 15:50:38 +02:00
|
|
|
const unsigned val = wts_read_variable_uint(channel->receiveData, cbChId, &ChannelId);
|
|
|
|
|
if (val == 0)
|
2022-03-07 13:40:09 +01:00
|
|
|
return FALSE;
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2024-10-14 15:50:38 +02:00
|
|
|
length -= val;
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2024-10-14 15:50:38 +02:00
|
|
|
DEBUG_DVC("Cmd %s ChannelId %" PRIu32 " length %" PRIuz "",
|
2023-01-12 13:58:47 +01:00
|
|
|
drdynvc_get_packet_type(Cmd), ChannelId, length);
|
2022-03-07 13:40:09 +01:00
|
|
|
dvc = wts_get_dvc_channel_by_id(channel->vcm, ChannelId);
|
|
|
|
|
if (!dvc)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2023-10-03 21:41:39 +02:00
|
|
|
DEBUG_DVC("ChannelId %" PRIu32 " does not exist.", ChannelId);
|
2022-03-07 13:40:09 +01:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2022-03-07 13:40:09 +01:00
|
|
|
switch (Cmd)
|
|
|
|
|
{
|
|
|
|
|
case CREATE_REQUEST_PDU:
|
2024-10-14 15:50:38 +02:00
|
|
|
return wts_read_drdynvc_create_response(dvc, channel->receiveData, (UINT32)length);
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2022-03-07 13:40:09 +01:00
|
|
|
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 13:38:09 +01: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;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-14 15:50:38 +02:00
|
|
|
return wts_read_drdynvc_data_first(dvc, channel->receiveData, Sp, (UINT32)length);
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2022-03-07 13:40:09 +01:00
|
|
|
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 13:38:09 +01: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;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-14 15:50:38 +02:00
|
|
|
return wts_read_drdynvc_data(dvc, channel->receiveData, (UINT32)length);
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2022-03-07 13:40:09 +01:00
|
|
|
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 07:57:38 +02:00
|
|
|
WLog_ERR(TAG, "SoftSync response not handled yet(and rather strange to receive "
|
|
|
|
|
"that packet as our code doesn't send SoftSync requests");
|
2022-03-07 13:40:09 +01:00
|
|
|
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;
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-11-06 15:24:51 +01:00
|
|
|
WLog_ERR(TAG, "received Cmd %d but channel is not ready.", Cmd);
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2015-05-23 22:47:18 +02:00
|
|
|
return TRUE;
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
|
2014-10-07 14:56:57 -04:00
|
|
|
static int wts_write_variable_uint(wStream* s, UINT32 val)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2024-01-23 16:49:54 +01:00
|
|
|
int cb = 0;
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2021-08-24 14:09:40 +02:00
|
|
|
WINPR_ASSERT(s);
|
2014-02-15 17:42:59 -05:00
|
|
|
if (val <= 0xFF)
|
|
|
|
|
{
|
|
|
|
|
cb = 0;
|
2024-12-19 14:45:06 +01:00
|
|
|
Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, val));
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
else if (val <= 0xFFFF)
|
|
|
|
|
{
|
|
|
|
|
cb = 1;
|
2024-12-19 14:45:06 +01:00
|
|
|
Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, val));
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-04-29 14:21:37 +08:00
|
|
|
cb = 2;
|
2014-10-07 14:56:57 -04:00
|
|
|
Stream_Write_UINT32(s, val);
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cb;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-07 14:56:57 -04:00
|
|
|
static void wts_write_drdynvc_header(wStream* s, BYTE Cmd, UINT32 ChannelId)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
BYTE* bm = nullptr;
|
2024-01-23 16:49:54 +01:00
|
|
|
int cbChId = 0;
|
2021-08-24 14:09:40 +02:00
|
|
|
|
|
|
|
|
WINPR_ASSERT(s);
|
|
|
|
|
|
2014-02-15 17:42:59 -05:00
|
|
|
Stream_GetPointer(s, bm);
|
|
|
|
|
Stream_Seek_UINT8(s);
|
|
|
|
|
cbChId = wts_write_variable_uint(s, ChannelId);
|
2024-12-19 14:45:06 +01:00
|
|
|
*bm = (((Cmd & 0x0F) << 4) | cbChId) & 0xFF;
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
static BOOL wts_write_drdynvc_create_request(wStream* s, UINT32 ChannelId, const char* ChannelName)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2024-01-23 16:49:54 +01:00
|
|
|
size_t len = 0;
|
2021-08-24 14:09:40 +02:00
|
|
|
|
|
|
|
|
WINPR_ASSERT(s);
|
|
|
|
|
WINPR_ASSERT(ChannelName);
|
|
|
|
|
|
2014-02-15 17:42:59 -05:00
|
|
|
wts_write_drdynvc_header(s, CREATE_REQUEST_PDU, ChannelId);
|
2019-11-11 10:01:19 +01:00
|
|
|
len = strlen(ChannelName) + 1;
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2019-10-29 10:18:09 +01:00
|
|
|
if (!Stream_EnsureRemainingCapacity(s, len))
|
2015-05-18 11:28:00 +02:00
|
|
|
return FALSE;
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2014-02-15 17:42:59 -05:00
|
|
|
Stream_Write(s, ChannelName, len);
|
2015-05-18 11:28:00 +02:00
|
|
|
return TRUE;
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
static BOOL WTSProcessChannelData(rdpPeerChannel* channel, UINT16 channelId, const BYTE* data,
|
2020-03-04 14:52:19 +01:00
|
|
|
size_t s, UINT32 flags, size_t t)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2015-05-23 22:47:18 +02:00
|
|
|
BOOL ret = TRUE;
|
2024-08-29 11:11:11 +02:00
|
|
|
const size_t size = s;
|
|
|
|
|
const size_t totalSize = t;
|
2020-03-04 14:52:19 +01:00
|
|
|
|
2021-08-24 14:09:40 +02:00
|
|
|
WINPR_ASSERT(channel);
|
|
|
|
|
WINPR_ASSERT(channel->vcm);
|
2020-03-04 14:52:19 +01:00
|
|
|
WINPR_UNUSED(channelId);
|
2015-05-23 22:47:18 +02:00
|
|
|
|
2014-02-15 17:42:59 -05:00
|
|
|
if (flags & CHANNEL_FLAG_FIRST)
|
|
|
|
|
{
|
2026-02-27 20:04:43 +01:00
|
|
|
Stream_ResetPosition(channel->receiveData);
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
|
2015-05-23 22:47:18 +02:00
|
|
|
if (!Stream_EnsureRemainingCapacity(channel->receiveData, size))
|
|
|
|
|
return FALSE;
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2014-02-15 17:42:59 -05:00
|
|
|
Stream_Write(channel->receiveData, data, size);
|
|
|
|
|
|
|
|
|
|
if (flags & CHANNEL_FLAG_LAST)
|
|
|
|
|
{
|
2014-02-15 18:41:40 -05:00
|
|
|
if (Stream_GetPosition(channel->receiveData) != totalSize)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2015-05-23 22:47:18 +02:00
|
|
|
WLog_ERR(TAG, "read error");
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2014-02-15 17:42:59 -05:00
|
|
|
if (channel == channel->vcm->drdynvc_channel)
|
|
|
|
|
{
|
2015-05-23 22:47:18 +02:00
|
|
|
ret = wts_read_drdynvc_pdu(channel);
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-10-14 15:50:38 +02:00
|
|
|
const size_t pos = Stream_GetPosition(channel->receiveData);
|
|
|
|
|
if (pos > UINT32_MAX)
|
|
|
|
|
ret = FALSE;
|
|
|
|
|
else
|
|
|
|
|
ret = wts_queue_receive_data(channel, Stream_Buffer(channel->receiveData),
|
|
|
|
|
(UINT32)pos);
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2026-02-27 20:04:43 +01:00
|
|
|
Stream_ResetPosition(channel->receiveData);
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
2015-05-23 22:47:18 +02:00
|
|
|
|
|
|
|
|
return ret;
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
|
2020-03-09 10:58:02 +01:00
|
|
|
static BOOL WTSReceiveChannelData(freerdp_peer* client, UINT16 channelId, const BYTE* data,
|
|
|
|
|
size_t size, UINT32 flags, size_t totalSize)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
rdpMcs* mcs = nullptr;
|
2021-08-24 14:09:40 +02:00
|
|
|
|
|
|
|
|
WINPR_ASSERT(client);
|
|
|
|
|
WINPR_ASSERT(client->context);
|
|
|
|
|
WINPR_ASSERT(client->context->rdp);
|
2022-10-10 11:27:46 +02:00
|
|
|
|
2021-08-24 14:09:40 +02:00
|
|
|
mcs = client->context->rdp->mcs;
|
|
|
|
|
WINPR_ASSERT(mcs);
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2024-01-30 10:25:38 +01:00
|
|
|
for (UINT32 i = 0; i < mcs->channelCount; i++)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2021-08-24 14:09:40 +02:00
|
|
|
rdpMcsChannel* cur = &mcs->channels[i];
|
|
|
|
|
if (cur->ChannelId == channelId)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2021-08-24 14:09:40 +02:00
|
|
|
rdpPeerChannel* channel = (rdpPeerChannel*)cur->handle;
|
2020-02-21 09:17:00 +01:00
|
|
|
|
|
|
|
|
if (channel)
|
2021-02-15 17:04:50 +08:00
|
|
|
return WTSProcessChannelData(channel, channelId, data, size, flags, totalSize);
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-23 12:03:18 +01:00
|
|
|
WLog_WARN(TAG, "unknown channelId %" PRIu16 " ignored", channelId);
|
2021-02-15 17:04:50 +08:00
|
|
|
|
|
|
|
|
return TRUE;
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
|
2021-08-24 15:04:58 +02:00
|
|
|
#if defined(WITH_FREERDP_DEPRECATED)
|
2019-11-06 15:24:51 +01:00
|
|
|
void WTSVirtualChannelManagerGetFileDescriptor(HANDLE hServer, void** fds, int* fds_count)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
void* fd = nullptr;
|
2019-11-06 15:24:51 +01:00
|
|
|
WTSVirtualChannelManager* vcm = (WTSVirtualChannelManager*)hServer;
|
2021-08-24 14:09:40 +02:00
|
|
|
WINPR_ASSERT(vcm);
|
|
|
|
|
WINPR_ASSERT(fds);
|
|
|
|
|
WINPR_ASSERT(fds_count);
|
|
|
|
|
|
2014-02-15 19:21:41 -05:00
|
|
|
fd = GetEventWaitObject(MessageQueue_Event(vcm->queue));
|
2014-02-15 17:42:59 -05:00
|
|
|
|
|
|
|
|
if (fd)
|
|
|
|
|
{
|
|
|
|
|
fds[*fds_count] = fd;
|
|
|
|
|
(*fds_count)++;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-15 18:41:40 -05:00
|
|
|
#if 0
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2014-02-15 17:42:59 -05:00
|
|
|
if (vcm->drdynvc_channel)
|
|
|
|
|
{
|
|
|
|
|
fd = GetEventWaitObject(vcm->drdynvc_channel->receiveEvent);
|
|
|
|
|
|
|
|
|
|
if (fd)
|
|
|
|
|
{
|
|
|
|
|
fds[*fds_count] = fd;
|
|
|
|
|
(*fds_count)++;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2014-02-15 18:41:40 -05:00
|
|
|
#endif
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
2021-08-24 15:04:58 +02:00
|
|
|
#endif
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2022-06-23 09:17:49 +02:00
|
|
|
BOOL WTSVirtualChannelManagerOpen(HANDLE hServer)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2022-06-23 09:17:49 +02:00
|
|
|
WTSVirtualChannelManager* vcm = (WTSVirtualChannelManager*)hServer;
|
|
|
|
|
|
2020-08-09 13:38:50 +03:00
|
|
|
if (!vcm)
|
|
|
|
|
return FALSE;
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2022-06-23 09:17:49 +02:00
|
|
|
if (vcm->drdynvc_state == DRDYNVC_STATE_NONE)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
rdpPeerChannel* channel = nullptr;
|
2020-08-09 13:38:50 +03:00
|
|
|
|
2014-02-15 17:42:59 -05:00
|
|
|
/* Initialize drdynvc channel once and only once. */
|
|
|
|
|
vcm->drdynvc_state = DRDYNVC_STATE_INITIALIZED;
|
2021-08-25 10:02:46 +02:00
|
|
|
channel = (rdpPeerChannel*)WTSVirtualChannelOpen((HANDLE)vcm, WTS_CURRENT_SESSION,
|
|
|
|
|
DRDYNVC_SVC_CHANNEL_NAME);
|
2014-02-15 17:42:59 -05:00
|
|
|
|
|
|
|
|
if (channel)
|
|
|
|
|
{
|
2026-02-24 20:18:25 +01:00
|
|
|
BYTE capaBuffer[12] = WINPR_C_ARRAY_INIT;
|
|
|
|
|
wStream staticS = WINPR_C_ARRAY_INIT;
|
2023-09-14 15:11:23 +02:00
|
|
|
wStream* s = Stream_StaticInit(&staticS, capaBuffer, sizeof(capaBuffer));
|
|
|
|
|
|
2014-02-15 17:42:59 -05:00
|
|
|
vcm->drdynvc_channel = channel;
|
2023-09-14 15:11:23 +02:00
|
|
|
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 */
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2024-10-14 15:50:38 +02:00
|
|
|
const size_t pos = Stream_GetPosition(s);
|
|
|
|
|
WINPR_ASSERT(pos <= UINT32_MAX);
|
2024-01-23 16:49:54 +01:00
|
|
|
ULONG written = 0;
|
2024-10-14 15:50:38 +02:00
|
|
|
if (!WTSVirtualChannelWrite(channel, (PCHAR)capaBuffer, (UINT32)pos, &written))
|
2015-05-29 04:46:50 -07:00
|
|
|
return FALSE;
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-09 13:38:50 +03:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL WTSVirtualChannelManagerCheckFileDescriptorEx(HANDLE hServer, BOOL autoOpen)
|
|
|
|
|
{
|
2026-02-24 20:18:25 +01:00
|
|
|
wMessage message = WINPR_C_ARRAY_INIT;
|
2020-08-09 13:38:50 +03:00
|
|
|
BOOL status = TRUE;
|
2026-02-26 15:06:27 +01:00
|
|
|
WTSVirtualChannelManager* vcm = nullptr;
|
2020-08-09 13:38:50 +03:00
|
|
|
|
|
|
|
|
if (!hServer || hServer == INVALID_HANDLE_VALUE)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
vcm = (WTSVirtualChannelManager*)hServer;
|
|
|
|
|
|
|
|
|
|
if (autoOpen)
|
|
|
|
|
{
|
2022-06-23 09:17:49 +02:00
|
|
|
if (!WTSVirtualChannelManagerOpen(hServer))
|
2020-08-09 13:38:50 +03:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-15 19:21:41 -05:00
|
|
|
while (MessageQueue_Peek(vcm->queue, &message, TRUE))
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
BYTE* buffer = nullptr;
|
2024-01-23 16:49:54 +01:00
|
|
|
UINT32 length = 0;
|
|
|
|
|
UINT16 channelId = 0;
|
2019-11-06 15:24:51 +01:00
|
|
|
channelId = (UINT16)(UINT_PTR)message.context;
|
|
|
|
|
buffer = (BYTE*)message.wParam;
|
|
|
|
|
length = (UINT32)(UINT_PTR)message.lParam;
|
2014-02-15 18:41:40 -05:00
|
|
|
|
2021-09-17 09:27:01 +02:00
|
|
|
WINPR_ASSERT(vcm->client);
|
|
|
|
|
WINPR_ASSERT(vcm->client->SendChannelData);
|
2020-03-09 10:33:58 +01:00
|
|
|
if (!vcm->client->SendChannelData(vcm->client, channelId, buffer, length))
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2014-02-15 18:41:40 -05:00
|
|
|
status = FALSE;
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
|
2014-02-15 19:21:41 -05:00
|
|
|
free(buffer);
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2014-02-15 18:41:40 -05:00
|
|
|
if (!status)
|
2014-02-15 17:42:59 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-15 18:41:40 -05:00
|
|
|
return status;
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
|
2020-08-09 13:38:50 +03:00
|
|
|
BOOL WTSVirtualChannelManagerCheckFileDescriptor(HANDLE hServer)
|
|
|
|
|
{
|
|
|
|
|
return WTSVirtualChannelManagerCheckFileDescriptorEx(hServer, TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-27 13:30:04 -05:00
|
|
|
HANDLE WTSVirtualChannelManagerGetEventHandle(HANDLE hServer)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2019-11-06 15:24:51 +01:00
|
|
|
WTSVirtualChannelManager* vcm = (WTSVirtualChannelManager*)hServer;
|
2021-08-24 14:09:40 +02:00
|
|
|
WINPR_ASSERT(vcm);
|
2014-02-15 19:21:41 -05:00
|
|
|
return MessageQueue_Event(vcm->queue);
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
static rdpMcsChannel* wts_get_joined_channel_by_name(rdpMcs* mcs, const char* channel_name)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2021-08-24 14:09:40 +02:00
|
|
|
if (!mcs || !channel_name || !strnlen(channel_name, CHANNEL_NAME_LEN + 1))
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2014-05-07 20:20:02 +02:00
|
|
|
|
2024-01-30 10:25:38 +01:00
|
|
|
for (UINT32 index = 0; index < mcs->channelCount; index++)
|
2014-05-07 20:20:02 +02:00
|
|
|
{
|
2021-08-24 14:09:40 +02:00
|
|
|
rdpMcsChannel* mchannel = &mcs->channels[index];
|
|
|
|
|
if (mchannel->joined)
|
2014-05-07 20:20:02 +02:00
|
|
|
{
|
2021-08-24 14:09:40 +02:00
|
|
|
if (_strnicmp(mchannel->Name, channel_name, CHANNEL_NAME_LEN + 1) == 0)
|
|
|
|
|
return mchannel;
|
2014-10-07 14:56:57 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2014-05-07 20:20:02 +02:00
|
|
|
}
|
2014-02-27 13:30:04 -05:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
static rdpMcsChannel* wts_get_joined_channel_by_id(rdpMcs* mcs, const UINT16 channel_id)
|
2014-05-07 20:20:02 +02:00
|
|
|
{
|
|
|
|
|
if (!mcs || !channel_id)
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2021-08-24 14:09:40 +02:00
|
|
|
WINPR_ASSERT(mcs->channels);
|
2024-01-30 10:25:38 +01:00
|
|
|
for (UINT32 index = 0; index < mcs->channelCount; index++)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2021-08-24 14:09:40 +02:00
|
|
|
rdpMcsChannel* mchannel = &mcs->channels[index];
|
|
|
|
|
if (mchannel->joined)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2021-08-24 14:09:40 +02:00
|
|
|
if (mchannel->ChannelId == channel_id)
|
2014-05-07 20:20:02 +02:00
|
|
|
return &mcs->channels[index];
|
2014-10-07 14:56:57 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2014-05-07 20:20:02 +02:00
|
|
|
}
|
|
|
|
|
|
2014-10-07 14:56:57 -04:00
|
|
|
BOOL WTSIsChannelJoinedByName(freerdp_peer* client, const char* channel_name)
|
2014-05-07 20:20:02 +02:00
|
|
|
{
|
|
|
|
|
if (!client || !client->context || !client->context->rdp)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2026-02-26 15:06:27 +01:00
|
|
|
return (wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name) != nullptr);
|
2014-05-07 20:20:02 +02:00
|
|
|
}
|
|
|
|
|
|
2025-03-19 16:36:37 +01:00
|
|
|
BOOL WTSIsChannelJoinedById(freerdp_peer* client, UINT16 channel_id)
|
2014-05-07 20:20:02 +02:00
|
|
|
{
|
|
|
|
|
if (!client || !client->context || !client->context->rdp)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2026-02-26 15:06:27 +01:00
|
|
|
return (wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id) != nullptr);
|
2014-05-07 20:20:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL WTSVirtualChannelManagerIsChannelJoined(HANDLE hServer, const char* name)
|
|
|
|
|
{
|
2019-11-06 15:24:51 +01:00
|
|
|
WTSVirtualChannelManager* vcm = (WTSVirtualChannelManager*)hServer;
|
2014-05-07 20:20:02 +02:00
|
|
|
|
|
|
|
|
if (!vcm || !vcm->rdp)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2026-02-26 15:06:27 +01:00
|
|
|
return (wts_get_joined_channel_by_name(vcm->rdp->mcs, name) != nullptr);
|
2014-05-07 20:20:02 +02:00
|
|
|
}
|
|
|
|
|
|
2016-05-04 00:48:59 +08:00
|
|
|
BYTE WTSVirtualChannelManagerGetDrdynvcState(HANDLE hServer)
|
|
|
|
|
{
|
2019-11-06 15:24:51 +01:00
|
|
|
WTSVirtualChannelManager* vcm = (WTSVirtualChannelManager*)hServer;
|
2021-08-24 14:09:40 +02:00
|
|
|
WINPR_ASSERT(vcm);
|
2016-05-04 00:48:59 +08:00
|
|
|
return vcm->drdynvc_state;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-07 06:31:48 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-07 14:56:57 -04:00
|
|
|
UINT16 WTSChannelGetId(freerdp_peer* client, const char* channel_name)
|
2014-05-07 20:20:02 +02:00
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
rdpMcsChannel* channel = nullptr;
|
2014-05-07 20:20:02 +02:00
|
|
|
|
2021-08-24 14:09:40 +02:00
|
|
|
WINPR_ASSERT(channel_name);
|
2014-05-07 20:20:02 +02:00
|
|
|
if (!client || !client->context || !client->context->rdp)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
channel = wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name);
|
2014-10-07 14:56:57 -04:00
|
|
|
|
2014-05-07 20:20:02 +02:00
|
|
|
if (!channel)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return channel->ChannelId;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-07 06:31:48 +02:00
|
|
|
UINT32 WTSChannelGetIdByHandle(HANDLE hChannelHandle)
|
|
|
|
|
{
|
|
|
|
|
rdpPeerChannel* channel = hChannelHandle;
|
|
|
|
|
|
|
|
|
|
WINPR_ASSERT(channel);
|
|
|
|
|
|
|
|
|
|
return channel->channelId;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
BOOL WTSChannelSetHandleByName(freerdp_peer* client, const char* channel_name, void* handle)
|
2014-05-07 20:20:02 +02:00
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
rdpMcsChannel* channel = nullptr;
|
2014-10-07 14:56:57 -04:00
|
|
|
|
2021-08-24 14:09:40 +02:00
|
|
|
WINPR_ASSERT(channel_name);
|
2014-05-07 20:20:02 +02:00
|
|
|
if (!client || !client->context || !client->context->rdp)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
channel = wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name);
|
2014-10-07 14:56:57 -04:00
|
|
|
|
2014-05-07 20:20:02 +02:00
|
|
|
if (!channel)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
channel->handle = handle;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-19 16:36:37 +01:00
|
|
|
BOOL WTSChannelSetHandleById(freerdp_peer* client, UINT16 channel_id, void* handle)
|
2014-05-07 20:20:02 +02:00
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
rdpMcsChannel* channel = nullptr;
|
2014-10-07 14:56:57 -04:00
|
|
|
|
2014-05-07 20:20:02 +02:00
|
|
|
if (!client || !client->context || !client->context->rdp)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
channel = wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id);
|
2014-10-07 14:56:57 -04:00
|
|
|
|
2014-05-07 20:20:02 +02:00
|
|
|
if (!channel)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
channel->handle = handle;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-07 14:04:40 +02:00
|
|
|
void* WTSChannelGetHandleByName(freerdp_peer* client, const char* channel_name)
|
2014-05-07 20:20:02 +02:00
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
rdpMcsChannel* channel = nullptr;
|
2014-10-07 14:56:57 -04:00
|
|
|
|
2021-08-24 14:09:40 +02:00
|
|
|
WINPR_ASSERT(channel_name);
|
2014-05-07 20:20:02 +02:00
|
|
|
if (!client || !client->context || !client->context->rdp)
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2014-05-07 20:20:02 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
channel = wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name);
|
2014-10-07 14:56:57 -04:00
|
|
|
|
2014-05-07 20:20:02 +02:00
|
|
|
if (!channel)
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2014-05-07 20:20:02 +02:00
|
|
|
|
|
|
|
|
return channel->handle;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-19 16:36:37 +01:00
|
|
|
void* WTSChannelGetHandleById(freerdp_peer* client, UINT16 channel_id)
|
2014-05-07 20:20:02 +02:00
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
rdpMcsChannel* channel = nullptr;
|
2014-10-07 14:56:57 -04:00
|
|
|
|
2014-05-07 20:20:02 +02:00
|
|
|
if (!client || !client->context || !client->context->rdp)
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2014-05-07 20:20:02 +02:00
|
|
|
|
|
|
|
|
channel = wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id);
|
2014-10-07 14:56:57 -04:00
|
|
|
|
2014-05-07 20:20:02 +02:00
|
|
|
if (!channel)
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2014-05-07 20:20:02 +02:00
|
|
|
return channel->handle;
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
|
2020-02-02 15:01:38 +02:00
|
|
|
const char* WTSChannelGetName(freerdp_peer* client, UINT16 channel_id)
|
|
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
rdpMcsChannel* channel = nullptr;
|
2020-02-02 15:01:38 +02:00
|
|
|
|
|
|
|
|
if (!client || !client->context || !client->context->rdp)
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2020-02-02 15:01:38 +02:00
|
|
|
|
|
|
|
|
channel = wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id);
|
|
|
|
|
|
|
|
|
|
if (!channel)
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2020-02-02 15:01:38 +02:00
|
|
|
|
|
|
|
|
return (const char*)channel->Name;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-21 10:43:23 +03:00
|
|
|
char** WTSGetAcceptedChannelNames(freerdp_peer* client, size_t* count)
|
|
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
rdpMcs* mcs = nullptr;
|
|
|
|
|
char** names = nullptr;
|
2020-09-21 10:43:23 +03:00
|
|
|
|
|
|
|
|
if (!client || !client->context || !count)
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2020-09-21 10:43:23 +03:00
|
|
|
|
2021-08-24 14:09:40 +02:00
|
|
|
WINPR_ASSERT(client->context->rdp);
|
2020-09-21 10:43:23 +03:00
|
|
|
mcs = client->context->rdp->mcs;
|
2021-08-24 14:09:40 +02:00
|
|
|
WINPR_ASSERT(mcs);
|
2020-09-21 10:43:23 +03:00
|
|
|
*count = mcs->channelCount;
|
|
|
|
|
|
|
|
|
|
names = (char**)calloc(mcs->channelCount, sizeof(char*));
|
|
|
|
|
if (!names)
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2020-09-21 10:43:23 +03:00
|
|
|
|
2024-01-30 10:25:38 +01:00
|
|
|
for (UINT32 index = 0; index < mcs->channelCount; index++)
|
2021-08-24 14:09:40 +02:00
|
|
|
{
|
|
|
|
|
rdpMcsChannel* mchannel = &mcs->channels[index];
|
|
|
|
|
names[index] = mchannel->Name;
|
|
|
|
|
}
|
2020-09-21 10:43:23 +03:00
|
|
|
|
|
|
|
|
return names;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-02 08:34:07 -03:00
|
|
|
INT64 WTSChannelGetOptions(freerdp_peer* client, UINT16 channel_id)
|
|
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
rdpMcsChannel* channel = nullptr;
|
2022-06-02 08: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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionW(WINPR_ATTR_UNUSED LPWSTR pTargetServerName,
|
|
|
|
|
WINPR_ATTR_UNUSED ULONG TargetLogonId,
|
|
|
|
|
WINPR_ATTR_UNUSED BYTE HotkeyVk,
|
|
|
|
|
WINPR_ATTR_UNUSED USHORT HotkeyModifiers)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionA(WINPR_ATTR_UNUSED LPSTR pTargetServerName,
|
|
|
|
|
WINPR_ATTR_UNUSED ULONG TargetLogonId,
|
|
|
|
|
WINPR_ATTR_UNUSED BYTE HotkeyVk,
|
|
|
|
|
WINPR_ATTR_UNUSED USHORT HotkeyModifiers)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
2014-02-15 18:41:40 -05:00
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionExW(WINPR_ATTR_UNUSED LPWSTR pTargetServerName,
|
|
|
|
|
WINPR_ATTR_UNUSED ULONG TargetLogonId,
|
|
|
|
|
WINPR_ATTR_UNUSED BYTE HotkeyVk,
|
|
|
|
|
WINPR_ATTR_UNUSED USHORT HotkeyModifiers,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD flags)
|
2015-02-16 12:16:54 +01:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2015-02-16 12:16:54 +01:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionExA(WINPR_ATTR_UNUSED LPSTR pTargetServerName,
|
|
|
|
|
WINPR_ATTR_UNUSED ULONG TargetLogonId,
|
|
|
|
|
WINPR_ATTR_UNUSED BYTE HotkeyVk,
|
|
|
|
|
WINPR_ATTR_UNUSED USHORT HotkeyModifiers,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD flags)
|
2015-02-16 12:16:54 +01:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2015-02-16 12:16:54 +01:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSStopRemoteControlSession(WINPR_ATTR_UNUSED ULONG LogonId)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSConnectSessionW(WINPR_ATTR_UNUSED ULONG LogonId,
|
|
|
|
|
WINPR_ATTR_UNUSED ULONG TargetLogonId,
|
|
|
|
|
WINPR_ATTR_UNUSED PWSTR pPassword,
|
|
|
|
|
WINPR_ATTR_UNUSED BOOL bWait)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSConnectSessionA(WINPR_ATTR_UNUSED ULONG LogonId,
|
|
|
|
|
WINPR_ATTR_UNUSED ULONG TargetLogonId,
|
|
|
|
|
WINPR_ATTR_UNUSED PSTR pPassword,
|
|
|
|
|
WINPR_ATTR_UNUSED BOOL bWait)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSEnumerateServersW(WINPR_ATTR_UNUSED LPWSTR pDomainName,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Reserved,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Version,
|
|
|
|
|
WINPR_ATTR_UNUSED PWTS_SERVER_INFOW* ppServerInfo,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD* pCount)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSEnumerateServersA(WINPR_ATTR_UNUSED LPSTR pDomainName,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Reserved,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Version,
|
|
|
|
|
WINPR_ATTR_UNUSED PWTS_SERVER_INFOA* ppServerInfo,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD* pCount)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
HANDLE WINAPI FreeRDP_WTSOpenServerW(WINPR_ATTR_UNUSED LPWSTR pServerName)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
|
}
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2020-01-02 15:48:13 +02:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-16 20:52:11 +01:00
|
|
|
static void channel_free(rdpPeerChannel* channel)
|
|
|
|
|
{
|
|
|
|
|
server_channel_common_free(channel);
|
|
|
|
|
}
|
2021-09-17 09:27:01 +02:00
|
|
|
|
2021-10-18 11:36:14 +02:00
|
|
|
static void array_channel_free(void* ptr)
|
|
|
|
|
{
|
|
|
|
|
rdpPeerChannel* channel = ptr;
|
|
|
|
|
channel_free(channel);
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-03 21:41:39 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-03 15:21:40 +01:00
|
|
|
static void clearHandles(void)
|
|
|
|
|
{
|
|
|
|
|
HashTable_Free(g_ServerHandles);
|
|
|
|
|
g_ServerHandles = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOL CALLBACK initializeHandles(WINPR_ATTR_UNUSED PINIT_ONCE once,
|
|
|
|
|
WINPR_ATTR_UNUSED PVOID param,
|
|
|
|
|
WINPR_ATTR_UNUSED PVOID* context)
|
|
|
|
|
{
|
|
|
|
|
WINPR_ASSERT(g_ServerHandles == nullptr);
|
|
|
|
|
g_ServerHandles = HashTable_New(TRUE);
|
|
|
|
|
g_SessionId = 1;
|
|
|
|
|
(void)atexit(clearHandles);
|
|
|
|
|
return g_ServerHandles != nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void wtsCloseVCM(WTSVirtualChannelManager* vcm, bool closeDrdynvc)
|
|
|
|
|
{
|
|
|
|
|
WINPR_ASSERT(vcm);
|
|
|
|
|
|
|
|
|
|
HashTable_Lock(g_ServerHandles);
|
|
|
|
|
if (vcm && (vcm != INVALID_HANDLE_VALUE))
|
|
|
|
|
{
|
|
|
|
|
HashTable_Remove(g_ServerHandles, (void*)(UINT_PTR)vcm->SessionId);
|
|
|
|
|
|
|
|
|
|
HashTable_Free(vcm->dynamicVirtualChannels);
|
|
|
|
|
|
|
|
|
|
if (vcm->drdynvc_channel)
|
|
|
|
|
{
|
|
|
|
|
if (closeDrdynvc)
|
|
|
|
|
(void)WTSVirtualChannelClose(vcm->drdynvc_channel);
|
|
|
|
|
vcm->drdynvc_channel = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MessageQueue_Free(vcm->queue);
|
|
|
|
|
free(vcm);
|
|
|
|
|
}
|
|
|
|
|
HashTable_Unlock(g_ServerHandles);
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-28 14:49:57 -05:00
|
|
|
HANDLE WINAPI FreeRDP_WTSOpenServerA(LPSTR pServerName)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2026-02-24 20:18:25 +01:00
|
|
|
wObject queueCallbacks = WINPR_C_ARRAY_INIT;
|
2020-01-02 15:48:13 +02:00
|
|
|
|
2026-03-03 15:21:40 +01:00
|
|
|
rdpContext* context = (rdpContext*)pServerName;
|
2014-02-16 22:07:00 -05:00
|
|
|
|
|
|
|
|
if (!context)
|
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
|
|
2026-03-03 15:21:40 +01:00
|
|
|
freerdp_peer* client = context->peer;
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2014-02-16 22:07:00 -05:00
|
|
|
if (!client)
|
2015-05-20 19:19:50 +02:00
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_INVALID_DATA);
|
2014-02-16 22:07:00 -05:00
|
|
|
return INVALID_HANDLE_VALUE;
|
2015-05-20 19:19:50 +02:00
|
|
|
}
|
2014-02-16 22:07:00 -05:00
|
|
|
|
2026-03-03 15:21:40 +01:00
|
|
|
if (!InitOnceExecuteOnce(&g_HandleInitializer, initializeHandles, nullptr, nullptr))
|
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
|
|
|
|
|
|
WTSVirtualChannelManager* vcm =
|
|
|
|
|
(WTSVirtualChannelManager*)calloc(1, sizeof(WTSVirtualChannelManager));
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2015-05-18 11:28:00 +02:00
|
|
|
if (!vcm)
|
2026-03-03 15:21:40 +01:00
|
|
|
goto fail;
|
2014-02-16 22:07:00 -05:00
|
|
|
|
2015-05-18 11:28:00 +02:00
|
|
|
vcm->client = client;
|
|
|
|
|
vcm->rdp = context->rdp;
|
2014-02-16 23:00:58 -05:00
|
|
|
|
2020-01-02 15:48:13 +02:00
|
|
|
queueCallbacks.fnObjectFree = wts_virtual_channel_manager_free_message;
|
|
|
|
|
vcm->queue = MessageQueue_New(&queueCallbacks);
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2015-05-18 11:28:00 +02:00
|
|
|
if (!vcm->queue)
|
2026-03-03 15:21:40 +01:00
|
|
|
goto fail;
|
2014-02-16 22:07:00 -05:00
|
|
|
|
2015-05-18 11:28:00 +02:00
|
|
|
vcm->dvc_channel_id_seq = 0;
|
2023-10-03 21:41:39 +02:00
|
|
|
vcm->dynamicVirtualChannels = HashTable_New(TRUE);
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2015-05-18 11:28:00 +02:00
|
|
|
if (!vcm->dynamicVirtualChannels)
|
2026-03-03 15:21:40 +01:00
|
|
|
goto fail;
|
2014-02-16 22:07:00 -05:00
|
|
|
|
2023-10-03 21:41:39 +02:00
|
|
|
if (!HashTable_SetHashFunction(vcm->dynamicVirtualChannels, channelId_Hash))
|
2026-03-03 15:21:40 +01:00
|
|
|
goto fail;
|
2023-10-03 21:41:39 +02:00
|
|
|
|
2021-09-17 09:27:01 +02:00
|
|
|
{
|
2023-10-03 21:41:39 +02:00
|
|
|
wObject* obj = HashTable_ValueObject(vcm->dynamicVirtualChannels);
|
2021-09-17 09:27:01 +02:00
|
|
|
WINPR_ASSERT(obj);
|
2021-10-18 11:36:14 +02:00
|
|
|
obj->fnObjectFree = array_channel_free;
|
2023-10-03 21:41:39 +02:00
|
|
|
|
|
|
|
|
obj = HashTable_KeyObject(vcm->dynamicVirtualChannels);
|
|
|
|
|
obj->fnObjectEquals = dynChannelMatch;
|
2021-09-17 09:27:01 +02:00
|
|
|
}
|
2015-05-18 11:28:00 +02:00
|
|
|
client->ReceiveChannelData = WTSReceiveChannelData;
|
2026-03-03 15:21:40 +01:00
|
|
|
{
|
|
|
|
|
HashTable_Lock(g_ServerHandles);
|
|
|
|
|
vcm->SessionId = g_SessionId++;
|
|
|
|
|
const BOOL rc =
|
|
|
|
|
HashTable_Insert(g_ServerHandles, (void*)(UINT_PTR)vcm->SessionId, (void*)vcm);
|
|
|
|
|
HashTable_Unlock(g_ServerHandles);
|
|
|
|
|
if (!rc)
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HANDLE hServer = (HANDLE)vcm;
|
2014-02-16 22:07:00 -05:00
|
|
|
return hServer;
|
2023-10-03 21:41:39 +02:00
|
|
|
|
2026-03-03 15:21:40 +01:00
|
|
|
fail:
|
|
|
|
|
wtsCloseVCM(vcm, false);
|
2015-05-20 19:19:50 +02:00
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
2015-05-18 11:28:00 +02:00
|
|
|
return INVALID_HANDLE_VALUE;
|
2014-02-16 21:19:25 -05:00
|
|
|
}
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
HANDLE WINAPI FreeRDP_WTSOpenServerExW(WINPR_ATTR_UNUSED LPWSTR pServerName)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
|
}
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2014-02-28 14:49:57 -05:00
|
|
|
HANDLE WINAPI FreeRDP_WTSOpenServerExA(LPSTR pServerName)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2014-02-16 22:07:00 -05:00
|
|
|
return FreeRDP_WTSOpenServerA(pServerName);
|
2014-02-16 21:19:25 -05:00
|
|
|
}
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2014-02-28 14:49:57 -05:00
|
|
|
VOID WINAPI FreeRDP_WTSCloseServer(HANDLE hServer)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2026-03-03 15:21:40 +01:00
|
|
|
WTSVirtualChannelManager* vcm = (WTSVirtualChannelManager*)hServer;
|
|
|
|
|
wtsCloseVCM(vcm, true);
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSEnumerateSessionsW(WINPR_ATTR_UNUSED HANDLE hServer,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Reserved,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Version,
|
|
|
|
|
WINPR_ATTR_UNUSED PWTS_SESSION_INFOW* ppSessionInfo,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD* pCount)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSEnumerateSessionsA(WINPR_ATTR_UNUSED HANDLE hServer,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Reserved,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Version,
|
|
|
|
|
WINPR_ATTR_UNUSED PWTS_SESSION_INFOA* ppSessionInfo,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD* pCount)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSEnumerateSessionsExW(WINPR_ATTR_UNUSED HANDLE hServer,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD* pLevel,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Filter,
|
|
|
|
|
WINPR_ATTR_UNUSED PWTS_SESSION_INFO_1W* ppSessionInfo,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD* pCount)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSEnumerateSessionsExA(WINPR_ATTR_UNUSED HANDLE hServer,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD* pLevel,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Filter,
|
|
|
|
|
WINPR_ATTR_UNUSED PWTS_SESSION_INFO_1A* ppSessionInfo,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD* pCount)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSEnumerateProcessesW(WINPR_ATTR_UNUSED HANDLE hServer,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Reserved,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Version,
|
|
|
|
|
WINPR_ATTR_UNUSED PWTS_PROCESS_INFOW* ppProcessInfo,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD* pCount)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSEnumerateProcessesA(WINPR_ATTR_UNUSED HANDLE hServer,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Reserved,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Version,
|
|
|
|
|
WINPR_ATTR_UNUSED PWTS_PROCESS_INFOA* ppProcessInfo,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD* pCount)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSTerminateProcess(WINPR_ATTR_UNUSED HANDLE hServer,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD ProcessId,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD ExitCode)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSQuerySessionInformationW(WINPR_ATTR_UNUSED HANDLE hServer,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD SessionId,
|
|
|
|
|
WINPR_ATTR_UNUSED WTS_INFO_CLASS WTSInfoClass,
|
|
|
|
|
WINPR_ATTR_UNUSED LPWSTR* ppBuffer,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD* pBytesReturned)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSQuerySessionInformationA(HANDLE hServer, WINPR_ATTR_UNUSED DWORD SessionId,
|
2019-11-06 15:24:51 +01:00
|
|
|
WTS_INFO_CLASS WTSInfoClass, LPSTR* ppBuffer,
|
|
|
|
|
DWORD* pBytesReturned)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2024-01-23 16:49:54 +01:00
|
|
|
DWORD BytesReturned = 0;
|
2026-02-26 15:06:27 +01:00
|
|
|
WTSVirtualChannelManager* vcm = nullptr;
|
2019-11-06 15:24:51 +01:00
|
|
|
vcm = (WTSVirtualChannelManager*)hServer;
|
2014-02-16 23:00:58 -05:00
|
|
|
|
|
|
|
|
if (!vcm)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (WTSInfoClass == WTSSessionId)
|
|
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
ULONG* pBuffer = nullptr;
|
2014-02-16 23:00:58 -05:00
|
|
|
BytesReturned = sizeof(ULONG);
|
2019-11-06 15:24:51 +01:00
|
|
|
pBuffer = (ULONG*)malloc(sizeof(BytesReturned));
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2015-06-16 15:42:07 +02:00
|
|
|
if (!pBuffer)
|
|
|
|
|
{
|
2025-02-12 11:39:35 +01:00
|
|
|
SetLastError(g_err_oom);
|
2015-06-16 15:42:07 +02:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
2014-02-16 23:00:58 -05:00
|
|
|
|
|
|
|
|
*pBuffer = vcm->SessionId;
|
2019-11-06 15:24:51 +01:00
|
|
|
*ppBuffer = (LPSTR)pBuffer;
|
2014-02-16 23:00:58 -05:00
|
|
|
*pBytesReturned = BytesReturned;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSQueryUserConfigW(WINPR_ATTR_UNUSED LPWSTR pServerName,
|
|
|
|
|
WINPR_ATTR_UNUSED LPWSTR pUserName,
|
|
|
|
|
WINPR_ATTR_UNUSED WTS_CONFIG_CLASS WTSConfigClass,
|
|
|
|
|
WINPR_ATTR_UNUSED LPWSTR* ppBuffer,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD* pBytesReturned)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSQueryUserConfigA(WINPR_ATTR_UNUSED LPSTR pServerName,
|
|
|
|
|
WINPR_ATTR_UNUSED LPSTR pUserName,
|
|
|
|
|
WINPR_ATTR_UNUSED WTS_CONFIG_CLASS WTSConfigClass,
|
|
|
|
|
WINPR_ATTR_UNUSED LPSTR* ppBuffer,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD* pBytesReturned)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSSetUserConfigW(WINPR_ATTR_UNUSED LPWSTR pServerName,
|
|
|
|
|
WINPR_ATTR_UNUSED LPWSTR pUserName,
|
|
|
|
|
WINPR_ATTR_UNUSED WTS_CONFIG_CLASS WTSConfigClass,
|
|
|
|
|
WINPR_ATTR_UNUSED LPWSTR pBuffer,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD DataLength)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSSetUserConfigA(WINPR_ATTR_UNUSED LPSTR pServerName,
|
|
|
|
|
WINPR_ATTR_UNUSED LPSTR pUserName,
|
|
|
|
|
WINPR_ATTR_UNUSED WTS_CONFIG_CLASS WTSConfigClass,
|
|
|
|
|
WINPR_ATTR_UNUSED LPSTR pBuffer,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD DataLength)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI
|
|
|
|
|
FreeRDP_WTSSendMessageW(WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED DWORD SessionId,
|
|
|
|
|
WINPR_ATTR_UNUSED LPWSTR pTitle, WINPR_ATTR_UNUSED DWORD TitleLength,
|
|
|
|
|
WINPR_ATTR_UNUSED LPWSTR pMessage, WINPR_ATTR_UNUSED DWORD MessageLength,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Style, WINPR_ATTR_UNUSED DWORD Timeout,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD* pResponse, WINPR_ATTR_UNUSED BOOL bWait)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI
|
|
|
|
|
FreeRDP_WTSSendMessageA(WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED DWORD SessionId,
|
|
|
|
|
WINPR_ATTR_UNUSED LPSTR pTitle, WINPR_ATTR_UNUSED DWORD TitleLength,
|
|
|
|
|
WINPR_ATTR_UNUSED LPSTR pMessage, WINPR_ATTR_UNUSED DWORD MessageLength,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Style, WINPR_ATTR_UNUSED DWORD Timeout,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD* pResponse, WINPR_ATTR_UNUSED BOOL bWait)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSDisconnectSession(WINPR_ATTR_UNUSED HANDLE hServer,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD SessionId,
|
|
|
|
|
WINPR_ATTR_UNUSED BOOL bWait)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSLogoffSession(WINPR_ATTR_UNUSED HANDLE hServer,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD SessionId,
|
|
|
|
|
WINPR_ATTR_UNUSED BOOL bWait)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSShutdownSystem(WINPR_ATTR_UNUSED HANDLE hServer,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD ShutdownFlag)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSWaitSystemEvent(WINPR_ATTR_UNUSED HANDLE hServer,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD EventMask,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD* pEventFlags)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
|
2020-01-16 11:25:43 +02:00
|
|
|
static void peer_channel_queue_free_message(void* obj)
|
|
|
|
|
{
|
2020-02-04 14:51:47 +02:00
|
|
|
wMessage* msg = (wMessage*)obj;
|
|
|
|
|
if (!msg)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
free(msg->context);
|
2026-02-26 15:06:27 +01:00
|
|
|
msg->context = nullptr;
|
2020-01-16 11:25:43 +02:00
|
|
|
}
|
|
|
|
|
|
2020-01-16 11:31:13 +01:00
|
|
|
static rdpPeerChannel* channel_new(WTSVirtualChannelManager* vcm, freerdp_peer* client,
|
2022-10-10 11:27:46 +02:00
|
|
|
UINT32 ChannelId, UINT16 index, UINT16 type, size_t chunkSize,
|
|
|
|
|
const char* name)
|
2020-01-16 11:31:13 +01:00
|
|
|
{
|
2026-02-24 20:18:25 +01:00
|
|
|
wObject queueCallbacks = WINPR_C_ARRAY_INIT;
|
2023-12-16 20:52:11 +01:00
|
|
|
queueCallbacks.fnObjectFree = peer_channel_queue_free_message;
|
|
|
|
|
|
|
|
|
|
rdpPeerChannel* channel =
|
|
|
|
|
server_channel_common_new(client, index, ChannelId, chunkSize, &queueCallbacks, name);
|
2020-01-16 11:31:13 +01:00
|
|
|
|
2021-08-24 14:09:40 +02:00
|
|
|
WINPR_ASSERT(vcm);
|
|
|
|
|
WINPR_ASSERT(client);
|
|
|
|
|
|
2020-01-16 11:31:13 +01:00
|
|
|
if (!channel)
|
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
|
|
channel->vcm = vcm;
|
|
|
|
|
channel->channelType = type;
|
2022-12-26 00:01:27 +01:00
|
|
|
channel->creationStatus =
|
|
|
|
|
(type == RDP_PEER_CHANNEL_TYPE_SVC) ? ERROR_SUCCESS : ERROR_OPERATION_IN_PROGRESS;
|
2020-01-16 11:31:13 +01:00
|
|
|
|
|
|
|
|
return channel;
|
|
|
|
|
fail:
|
|
|
|
|
channel_free(channel);
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2020-01-16 11:31:13 +01:00
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
HANDLE WINAPI FreeRDP_WTSVirtualChannelOpen(HANDLE hServer, WINPR_ATTR_UNUSED DWORD SessionId,
|
|
|
|
|
LPSTR pVirtualName)
|
2014-02-16 20:41:19 -05:00
|
|
|
{
|
2024-01-23 16:49:54 +01:00
|
|
|
size_t length = 0;
|
2026-02-26 15:06:27 +01:00
|
|
|
rdpMcs* mcs = nullptr;
|
|
|
|
|
rdpMcsChannel* joined_channel = nullptr;
|
|
|
|
|
freerdp_peer* client = nullptr;
|
|
|
|
|
rdpPeerChannel* channel = nullptr;
|
|
|
|
|
WTSVirtualChannelManager* vcm = nullptr;
|
|
|
|
|
HANDLE hChannelHandle = nullptr;
|
|
|
|
|
rdpContext* context = nullptr;
|
2019-11-06 15:24:51 +01:00
|
|
|
vcm = (WTSVirtualChannelManager*)hServer;
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2014-02-16 22:07:00 -05:00
|
|
|
if (!vcm)
|
2015-05-20 19:19:50 +02:00
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_INVALID_DATA);
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2015-05-20 19:19:50 +02:00
|
|
|
}
|
2014-02-16 22:07:00 -05:00
|
|
|
|
|
|
|
|
client = vcm->client;
|
2022-03-23 13:18:35 +01:00
|
|
|
WINPR_ASSERT(client);
|
|
|
|
|
|
|
|
|
|
context = client->context;
|
|
|
|
|
WINPR_ASSERT(context);
|
|
|
|
|
WINPR_ASSERT(context->rdp);
|
|
|
|
|
WINPR_ASSERT(context->settings);
|
|
|
|
|
|
|
|
|
|
mcs = context->rdp->mcs;
|
|
|
|
|
WINPR_ASSERT(mcs);
|
|
|
|
|
|
2022-10-10 11:27:46 +02:00
|
|
|
length = strnlen(pVirtualName, CHANNEL_NAME_LEN + 1);
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2022-10-10 11:27:46 +02:00
|
|
|
if (length > CHANNEL_NAME_LEN)
|
2014-02-16 22:07:00 -05:00
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_NOT_FOUND);
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2014-02-16 22:07:00 -05:00
|
|
|
}
|
|
|
|
|
|
2024-01-30 10:25:38 +01:00
|
|
|
UINT32 index = 0;
|
|
|
|
|
for (; index < mcs->channelCount; index++)
|
2014-02-16 22:07:00 -05:00
|
|
|
{
|
2021-08-24 14:09:40 +02:00
|
|
|
rdpMcsChannel* mchannel = &mcs->channels[index];
|
|
|
|
|
if (mchannel->joined && (strncmp(mchannel->Name, pVirtualName, length) == 0))
|
2014-02-16 22:07:00 -05:00
|
|
|
{
|
2021-08-24 14:09:40 +02:00
|
|
|
joined_channel = mchannel;
|
2014-02-16 22:07:00 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-24 14:09:40 +02:00
|
|
|
if (!joined_channel)
|
2014-02-16 22:07:00 -05:00
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_NOT_FOUND);
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2014-02-16 22:07:00 -05:00
|
|
|
}
|
|
|
|
|
|
2021-08-24 14:09:40 +02:00
|
|
|
channel = (rdpPeerChannel*)joined_channel->handle;
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2014-02-16 22:07:00 -05:00
|
|
|
if (!channel)
|
|
|
|
|
{
|
2023-11-02 16:41:00 +01:00
|
|
|
const UINT32 VCChunkSize =
|
|
|
|
|
freerdp_settings_get_uint32(context->settings, FreeRDP_VCChunkSize);
|
2024-12-19 14:45:06 +01:00
|
|
|
|
|
|
|
|
WINPR_ASSERT(index <= UINT16_MAX);
|
|
|
|
|
channel = channel_new(vcm, client, joined_channel->ChannelId, (UINT16)index,
|
2023-11-02 16:41:00 +01:00
|
|
|
RDP_PEER_CHANNEL_TYPE_SVC, VCChunkSize, pVirtualName);
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2015-05-20 19:19:50 +02:00
|
|
|
if (!channel)
|
2020-01-16 11:31:13 +01:00
|
|
|
goto fail;
|
2014-02-16 22:07:00 -05:00
|
|
|
|
2021-08-24 14:09:40 +02:00
|
|
|
joined_channel->handle = channel;
|
2014-02-16 22:07:00 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
hChannelHandle = (HANDLE)channel;
|
2014-02-16 22:07:00 -05:00
|
|
|
return hChannelHandle;
|
2020-01-16 11:31:13 +01:00
|
|
|
fail:
|
|
|
|
|
channel_free(channel);
|
2015-05-18 11:28:00 +02:00
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2014-02-16 20:41:19 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
HANDLE WINAPI FreeRDP_WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualName, DWORD flags)
|
2014-02-16 20:41:19 -05:00
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
wStream* s = nullptr;
|
|
|
|
|
rdpPeerChannel* channel = nullptr;
|
2026-03-03 15:21:40 +01:00
|
|
|
BOOL joined = FALSE;
|
2024-01-23 16:49:54 +01:00
|
|
|
ULONG written = 0;
|
2014-02-16 23:00:58 -05:00
|
|
|
|
|
|
|
|
if (SessionId == WTS_CURRENT_SESSION)
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2014-02-16 23:00:58 -05:00
|
|
|
|
2026-03-03 15:21:40 +01:00
|
|
|
HashTable_Lock(g_ServerHandles);
|
|
|
|
|
WTSVirtualChannelManager* vcm = (WTSVirtualChannelManager*)HashTable_GetItemValue(
|
|
|
|
|
g_ServerHandles, (void*)(UINT_PTR)SessionId);
|
2014-02-16 23:00:58 -05:00
|
|
|
|
|
|
|
|
if (!vcm)
|
2026-03-03 15:21:40 +01:00
|
|
|
goto end;
|
2014-02-16 23:00:58 -05:00
|
|
|
|
2014-02-16 22:07:00 -05:00
|
|
|
if (!(flags & WTS_CHANNEL_OPTION_DYNAMIC))
|
|
|
|
|
{
|
2026-03-03 15:21:40 +01:00
|
|
|
HashTable_Unlock(g_ServerHandles);
|
2019-11-06 15:24:51 +01:00
|
|
|
return FreeRDP_WTSVirtualChannelOpen((HANDLE)vcm, SessionId, pVirtualName);
|
2014-02-16 23:00:58 -05:00
|
|
|
}
|
2014-02-16 22:07:00 -05:00
|
|
|
|
2026-03-03 15:21:40 +01:00
|
|
|
freerdp_peer* client = vcm->client;
|
|
|
|
|
WINPR_ASSERT(client);
|
|
|
|
|
WINPR_ASSERT(client->context);
|
|
|
|
|
WINPR_ASSERT(client->context->rdp);
|
|
|
|
|
|
|
|
|
|
rdpMcs* mcs = client->context->rdp->mcs;
|
|
|
|
|
WINPR_ASSERT(mcs);
|
2014-02-16 23:00:58 -05:00
|
|
|
|
2024-01-30 10:25:38 +01:00
|
|
|
for (UINT32 index = 0; index < mcs->channelCount; index++)
|
2014-02-16 23:00:58 -05:00
|
|
|
{
|
2021-08-24 14:09:40 +02:00
|
|
|
rdpMcsChannel* mchannel = &mcs->channels[index];
|
2021-08-25 10:02:46 +02:00
|
|
|
if (mchannel->joined &&
|
|
|
|
|
(strncmp(mchannel->Name, DRDYNVC_SVC_CHANNEL_NAME, CHANNEL_NAME_LEN + 1) == 0))
|
2014-02-16 23:00:58 -05:00
|
|
|
{
|
|
|
|
|
joined = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2014-02-16 22:07:00 -05:00
|
|
|
}
|
2014-02-16 23:00:58 -05:00
|
|
|
|
|
|
|
|
if (!joined)
|
2014-02-16 22:07:00 -05:00
|
|
|
{
|
2014-02-16 23:00:58 -05:00
|
|
|
SetLastError(ERROR_NOT_FOUND);
|
2026-03-03 15:21:40 +01:00
|
|
|
goto end;
|
2014-02-16 23:00:58 -05:00
|
|
|
}
|
2014-02-16 22:07:00 -05:00
|
|
|
|
2014-02-16 23:00:58 -05:00
|
|
|
if (!vcm->drdynvc_channel || (vcm->drdynvc_state != DRDYNVC_STATE_READY))
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_NOT_READY);
|
2026-03-03 15:21:40 +01:00
|
|
|
goto end;
|
2014-02-16 22:07:00 -05:00
|
|
|
}
|
|
|
|
|
|
2022-03-23 13:18:35 +01:00
|
|
|
WINPR_ASSERT(client);
|
|
|
|
|
WINPR_ASSERT(client->context);
|
|
|
|
|
WINPR_ASSERT(client->context->settings);
|
2022-10-10 11:27:46 +02:00
|
|
|
|
2023-11-02 16:41:00 +01:00
|
|
|
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);
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2015-05-18 11:28:00 +02:00
|
|
|
if (!channel)
|
|
|
|
|
{
|
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
2026-03-03 15:21:40 +01:00
|
|
|
goto end;
|
2015-05-18 11:28:00 +02:00
|
|
|
}
|
2014-02-16 23:00:58 -05:00
|
|
|
|
2024-12-19 14:45:06 +01:00
|
|
|
const LONG hdl = InterlockedIncrement(&vcm->dvc_channel_id_seq);
|
|
|
|
|
channel->channelId = WINPR_ASSERTING_INT_CAST(uint32_t, hdl);
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2023-10-03 21:41:39 +02:00
|
|
|
if (!HashTable_Insert(vcm->dynamicVirtualChannels, &channel->channelId, channel))
|
2022-04-28 08:00:39 +02:00
|
|
|
{
|
|
|
|
|
channel_free(channel);
|
2026-02-26 15:06:27 +01:00
|
|
|
channel = nullptr;
|
2020-01-16 11:31:13 +01:00
|
|
|
goto fail;
|
2022-04-28 08:00:39 +02:00
|
|
|
}
|
2026-02-26 15:06:27 +01:00
|
|
|
s = Stream_New(nullptr, 64);
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2015-05-18 11:28:00 +02:00
|
|
|
if (!s)
|
2022-04-28 08:00:39 +02:00
|
|
|
goto fail;
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2015-05-18 11:28:00 +02:00
|
|
|
if (!wts_write_drdynvc_create_request(s, channel->channelId, pVirtualName))
|
2022-04-28 08:00:39 +02:00
|
|
|
goto fail;
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2026-01-08 10:32:30 +01:00
|
|
|
{
|
|
|
|
|
const size_t pos = Stream_GetPosition(s);
|
|
|
|
|
WINPR_ASSERT(pos <= UINT32_MAX);
|
|
|
|
|
if (!WTSVirtualChannelWrite(vcm->drdynvc_channel, Stream_BufferAs(s, char), (UINT32)pos,
|
|
|
|
|
&written))
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
2014-02-16 23:00:58 -05:00
|
|
|
|
2026-03-03 15:21:40 +01:00
|
|
|
end:
|
2016-10-07 14:04:40 +02:00
|
|
|
Stream_Free(s, TRUE);
|
2026-03-03 15:21:40 +01:00
|
|
|
HashTable_Unlock(g_ServerHandles);
|
2014-04-22 19:02:23 +08:00
|
|
|
return channel;
|
2026-03-03 15:21:40 +01:00
|
|
|
|
2020-01-16 11:31:13 +01:00
|
|
|
fail:
|
2021-09-17 09:27:01 +02:00
|
|
|
Stream_Free(s, TRUE);
|
2022-04-28 08:00:39 +02:00
|
|
|
if (channel)
|
2023-10-03 21:41:39 +02:00
|
|
|
HashTable_Remove(vcm->dynamicVirtualChannels, &channel->channelId);
|
2026-03-03 15:21:40 +01:00
|
|
|
HashTable_Unlock(g_ServerHandles);
|
2021-09-17 09:27:01 +02:00
|
|
|
|
2015-05-18 11:28:00 +02:00
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2014-02-16 20:41:19 -05:00
|
|
|
}
|
|
|
|
|
|
2014-02-28 14:49:57 -05:00
|
|
|
BOOL WINAPI FreeRDP_WTSVirtualChannelClose(HANDLE hChannelHandle)
|
2014-02-16 20:41:19 -05:00
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
wStream* s = nullptr;
|
|
|
|
|
rdpMcs* mcs = nullptr;
|
2021-08-24 14:09:40 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
|
2015-05-29 04:46:50 -07:00
|
|
|
BOOL ret = TRUE;
|
2014-02-16 20:41:19 -05:00
|
|
|
|
|
|
|
|
if (channel)
|
|
|
|
|
{
|
2021-08-24 14:09:40 +02:00
|
|
|
WTSVirtualChannelManager* vcm = channel->vcm;
|
|
|
|
|
|
|
|
|
|
WINPR_ASSERT(vcm);
|
|
|
|
|
WINPR_ASSERT(vcm->client);
|
|
|
|
|
WINPR_ASSERT(vcm->client->context);
|
|
|
|
|
WINPR_ASSERT(vcm->client->context->rdp);
|
2014-02-16 20:41:19 -05:00
|
|
|
mcs = vcm->client->context->rdp->mcs;
|
|
|
|
|
|
|
|
|
|
if (channel->channelType == RDP_PEER_CHANNEL_TYPE_SVC)
|
|
|
|
|
{
|
|
|
|
|
if (channel->index < mcs->channelCount)
|
2021-08-24 14:09:40 +02:00
|
|
|
{
|
|
|
|
|
rdpMcsChannel* cur = &mcs->channels[channel->index];
|
2021-10-18 11:36:14 +02:00
|
|
|
rdpPeerChannel* peerChannel = (rdpPeerChannel*)cur->handle;
|
2023-12-16 20:52:11 +01:00
|
|
|
channel_free(peerChannel);
|
2026-02-26 15:06:27 +01:00
|
|
|
cur->handle = nullptr;
|
2021-08-24 14:09:40 +02:00
|
|
|
}
|
2014-02-16 20:41:19 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (channel->dvc_open_state == DVC_OPEN_STATE_SUCCEEDED)
|
|
|
|
|
{
|
2024-01-23 16:49:54 +01:00
|
|
|
ULONG written = 0;
|
2026-02-26 15:06:27 +01:00
|
|
|
s = Stream_New(nullptr, 8);
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2015-05-29 04:46:50 -07:00
|
|
|
if (!s)
|
|
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "Stream_New failed!");
|
|
|
|
|
ret = FALSE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
wts_write_drdynvc_header(s, CLOSE_REQUEST_PDU, channel->channelId);
|
2024-10-14 15:50:38 +02:00
|
|
|
|
|
|
|
|
const size_t pos = Stream_GetPosition(s);
|
|
|
|
|
WINPR_ASSERT(pos <= UINT32_MAX);
|
2024-10-01 10:25:30 +02:00
|
|
|
ret = WTSVirtualChannelWrite(vcm->drdynvc_channel, Stream_BufferAs(s, char),
|
2024-10-14 15:50:38 +02:00
|
|
|
(UINT32)pos, &written);
|
2015-05-29 04:46:50 -07:00
|
|
|
Stream_Free(s, TRUE);
|
|
|
|
|
}
|
2014-02-16 20:41:19 -05:00
|
|
|
}
|
2023-10-03 21:41:39 +02:00
|
|
|
HashTable_Remove(vcm->dynamicVirtualChannels, &channel->channelId);
|
2014-02-16 20:41:19 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-29 04:46:50 -07:00
|
|
|
return ret;
|
2014-02-16 20:41:19 -05:00
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSVirtualChannelRead(HANDLE hChannelHandle, WINPR_ATTR_UNUSED ULONG TimeOut,
|
|
|
|
|
PCHAR Buffer, ULONG BufferSize, PULONG pBytesRead)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
BYTE* buffer = nullptr;
|
2026-02-24 20:18:25 +01:00
|
|
|
wMessage message = WINPR_C_ARRAY_INIT;
|
2026-02-26 15:06:27 +01:00
|
|
|
wtsChannelMessage* messageCtx = nullptr;
|
2019-11-06 15:24:51 +01:00
|
|
|
rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2021-08-24 14:09:40 +02:00
|
|
|
WINPR_ASSERT(channel);
|
|
|
|
|
|
2014-07-14 20:00:38 +08:00
|
|
|
if (!MessageQueue_Peek(channel->queue, &message, FALSE))
|
2014-02-15 18:41:40 -05:00
|
|
|
{
|
2014-07-14 20:00:38 +08:00
|
|
|
SetLastError(ERROR_NO_DATA);
|
2014-02-15 18:41:40 -05:00
|
|
|
*pBytesRead = 0;
|
2014-07-14 20:00:38 +08:00
|
|
|
return FALSE;
|
2014-02-15 18:41:40 -05:00
|
|
|
}
|
|
|
|
|
|
2023-06-06 17:46:20 +02:00
|
|
|
messageCtx = message.context;
|
2019-12-10 13:59:10 +02:00
|
|
|
|
2026-02-26 15:06:27 +01:00
|
|
|
if (messageCtx == nullptr)
|
2019-12-10 13:59:10 +02:00
|
|
|
return FALSE;
|
|
|
|
|
|
2016-10-07 14:04:40 +02:00
|
|
|
buffer = (BYTE*)(messageCtx + 1);
|
2014-07-14 20:00:38 +08:00
|
|
|
*pBytesRead = messageCtx->length - messageCtx->offset;
|
2014-10-07 14:56:57 -04:00
|
|
|
|
2026-02-26 15:06:27 +01:00
|
|
|
if (Buffer == nullptr || BufferSize == 0)
|
2014-07-14 20:00:38 +08:00
|
|
|
{
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2014-10-07 14:56:57 -04:00
|
|
|
|
2014-07-14 20:00:38 +08:00
|
|
|
if (*pBytesRead > BufferSize)
|
|
|
|
|
*pBytesRead = BufferSize;
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2014-07-14 20:00:38 +08:00
|
|
|
CopyMemory(Buffer, buffer + messageCtx->offset, *pBytesRead);
|
|
|
|
|
messageCtx->offset += *pBytesRead;
|
2014-10-07 14:56:57 -04:00
|
|
|
|
2014-07-14 20:00:38 +08:00
|
|
|
if (messageCtx->offset >= messageCtx->length)
|
|
|
|
|
{
|
2024-09-15 10:19:56 +02:00
|
|
|
(void)MessageQueue_Peek(channel->queue, &message, TRUE);
|
2020-02-04 14:51:47 +02:00
|
|
|
peer_channel_queue_free_message(&message);
|
2014-07-14 20:00:38 +08:00
|
|
|
}
|
2014-02-15 17:42:59 -05:00
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-11 16:12:06 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSVirtualChannelWrite(HANDLE hChannelHandle, PCHAR Buffer, ULONG uLength,
|
2019-11-06 15:24:51 +01:00
|
|
|
PULONG pBytesWritten)
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
wStream* s = nullptr;
|
2024-01-23 16:49:54 +01:00
|
|
|
int cbLen = 0;
|
|
|
|
|
int cbChId = 0;
|
|
|
|
|
int first = 0;
|
2026-02-26 15:06:27 +01:00
|
|
|
BYTE* buffer = nullptr;
|
2025-03-11 16:12:06 +01:00
|
|
|
size_t totalWritten = 0;
|
2019-11-06 15:24:51 +01:00
|
|
|
rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
|
2023-12-16 20:52:11 +01:00
|
|
|
BOOL ret = FALSE;
|
2014-02-15 17:42:59 -05:00
|
|
|
|
|
|
|
|
if (!channel)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2023-12-16 20:52:11 +01:00
|
|
|
EnterCriticalSection(&channel->writeLock);
|
2021-08-24 14:09:40 +02:00
|
|
|
WINPR_ASSERT(channel->vcm);
|
2014-02-15 17:42:59 -05:00
|
|
|
if (channel->channelType == RDP_PEER_CHANNEL_TYPE_SVC)
|
|
|
|
|
{
|
2025-03-11 16:12:06 +01:00
|
|
|
buffer = (BYTE*)malloc(uLength);
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2015-05-25 22:55:37 +02:00
|
|
|
if (!buffer)
|
2015-06-16 15:42:07 +02:00
|
|
|
{
|
2025-02-12 11:39:35 +01:00
|
|
|
SetLastError(g_err_oom);
|
2023-12-16 20:52:11 +01:00
|
|
|
goto fail;
|
2015-06-16 15:42:07 +02:00
|
|
|
}
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2025-03-11 16:12:06 +01:00
|
|
|
CopyMemory(buffer, Buffer, uLength);
|
|
|
|
|
totalWritten = uLength;
|
|
|
|
|
if (!wts_queue_send_item(channel, buffer, uLength))
|
2024-08-29 15:10:21 +02:00
|
|
|
goto fail;
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
2019-11-06 15:24:51 +01:00
|
|
|
else if (!channel->vcm->drdynvc_channel || (channel->vcm->drdynvc_state != DRDYNVC_STATE_READY))
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
|
|
|
|
DEBUG_DVC("drdynvc not ready");
|
2023-12-16 20:52:11 +01:00
|
|
|
goto fail;
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
first = TRUE;
|
2025-03-06 00:34:18 +01:00
|
|
|
|
2025-03-11 16:12:06 +01:00
|
|
|
size_t Length = uLength;
|
2014-02-15 17:42:59 -05:00
|
|
|
while (Length > 0)
|
|
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
s = Stream_New(nullptr, DVC_MAX_DATA_PDU_SIZE);
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2015-05-29 04:46:50 -07:00
|
|
|
if (!s)
|
|
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "Stream_New failed!");
|
2025-02-12 11:39:35 +01:00
|
|
|
SetLastError(g_err_oom);
|
2023-12-16 20:52:11 +01:00
|
|
|
goto fail;
|
2015-05-29 04:46:50 -07:00
|
|
|
}
|
2015-05-23 22:47:18 +02:00
|
|
|
|
2014-02-15 19:21:41 -05:00
|
|
|
buffer = Stream_Buffer(s);
|
2014-02-15 17:42:59 -05:00
|
|
|
Stream_Seek_UINT8(s);
|
|
|
|
|
cbChId = wts_write_variable_uint(s, channel->channelId);
|
|
|
|
|
|
2022-11-19 06:22:09 +01:00
|
|
|
if (first && (Length > Stream_GetRemainingLength(s)))
|
2014-02-15 17:42:59 -05:00
|
|
|
{
|
2025-03-11 16:12:06 +01:00
|
|
|
cbLen = wts_write_variable_uint(s, WINPR_ASSERTING_INT_CAST(uint32_t, Length));
|
2024-12-19 14:45:06 +01:00
|
|
|
buffer[0] = ((DATA_FIRST_PDU << 4) | (cbLen << 2) | cbChId) & 0xFF;
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-12-19 14:45:06 +01:00
|
|
|
buffer[0] = ((DATA_PDU << 4) | cbChId) & 0xFF;
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
first = FALSE;
|
2024-10-14 15:50:38 +02:00
|
|
|
size_t written = Stream_GetRemainingLength(s);
|
2014-02-15 17:42:59 -05:00
|
|
|
|
|
|
|
|
if (written > Length)
|
|
|
|
|
written = Length;
|
|
|
|
|
|
|
|
|
|
Stream_Write(s, Buffer, written);
|
2024-10-14 15:50:38 +02:00
|
|
|
const size_t length = Stream_GetPosition(s);
|
2014-02-15 17:42:59 -05:00
|
|
|
Stream_Free(s, FALSE);
|
2024-10-14 15:50:38 +02:00
|
|
|
if (length > UINT32_MAX)
|
|
|
|
|
goto fail;
|
2014-02-15 17:42:59 -05:00
|
|
|
Length -= written;
|
|
|
|
|
Buffer += written;
|
2016-05-04 00:48:59 +08:00
|
|
|
totalWritten += written;
|
2024-10-14 15:50:38 +02:00
|
|
|
if (!wts_queue_send_item(channel->vcm->drdynvc_channel, buffer, (UINT32)length))
|
2023-12-16 20:52:11 +01:00
|
|
|
goto fail;
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-15 19:21:41 -05:00
|
|
|
if (pBytesWritten)
|
2025-03-11 16:12:06 +01:00
|
|
|
*pBytesWritten = WINPR_ASSERTING_INT_CAST(uint32_t, totalWritten);
|
2014-02-15 17:42:59 -05:00
|
|
|
|
2023-12-16 20:52:11 +01:00
|
|
|
ret = TRUE;
|
|
|
|
|
fail:
|
|
|
|
|
LeaveCriticalSection(&channel->writeLock);
|
2015-05-23 22:47:18 +02:00
|
|
|
return ret;
|
2014-02-15 17:42:59 -05:00
|
|
|
}
|
2014-02-16 21:19:25 -05:00
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSVirtualChannelPurgeInput(WINPR_ATTR_UNUSED HANDLE hChannelHandle)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSVirtualChannelPurgeOutput(WINPR_ATTR_UNUSED HANDLE hChannelHandle)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSVirtualChannelQuery(HANDLE hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass,
|
|
|
|
|
PVOID* ppBuffer, DWORD* pBytesReturned)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
void* pfd = nullptr;
|
2024-01-23 16:49:54 +01:00
|
|
|
BOOL bval = 0;
|
2026-02-24 20:18:25 +01:00
|
|
|
void* fds[10] = WINPR_C_ARRAY_INIT;
|
2026-02-26 15:06:27 +01:00
|
|
|
HANDLE hEvent = nullptr;
|
2014-02-16 21:19:25 -05:00
|
|
|
int fds_count = 0;
|
|
|
|
|
BOOL status = FALSE;
|
2019-11-06 15:24:51 +01:00
|
|
|
rdpPeerChannel* channel = (rdpPeerChannel*)hChannelHandle;
|
2021-08-24 14:09:40 +02:00
|
|
|
|
|
|
|
|
WINPR_ASSERT(channel);
|
|
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
switch ((UINT32)WtsVirtualClass)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
|
|
|
|
case WTSVirtualFileHandle:
|
2022-12-26 00:01:27 +01:00
|
|
|
hEvent = MessageQueue_Event(channel->queue);
|
2014-02-16 21:19:25 -05:00
|
|
|
pfd = GetEventWaitObject(hEvent);
|
|
|
|
|
|
|
|
|
|
if (pfd)
|
|
|
|
|
{
|
|
|
|
|
fds[fds_count] = pfd;
|
|
|
|
|
(fds_count)++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*ppBuffer = malloc(sizeof(void*));
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2015-06-16 15:42:07 +02:00
|
|
|
if (!*ppBuffer)
|
|
|
|
|
{
|
2025-02-12 11:39:35 +01:00
|
|
|
SetLastError(g_err_oom);
|
2016-10-07 14:04:40 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-11-25 15:10:30 +01:00
|
|
|
CopyMemory(*ppBuffer, (void*)&fds[0], sizeof(void*));
|
2015-06-16 15:42:07 +02:00
|
|
|
*pBytesReturned = sizeof(void*);
|
|
|
|
|
status = TRUE;
|
|
|
|
|
}
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2014-02-16 21:19:25 -05:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case WTSVirtualEventHandle:
|
2022-12-26 00:01:27 +01:00
|
|
|
hEvent = MessageQueue_Event(channel->queue);
|
|
|
|
|
|
2014-02-16 21:19:25 -05:00
|
|
|
*ppBuffer = malloc(sizeof(HANDLE));
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2015-06-16 15:42:07 +02:00
|
|
|
if (!*ppBuffer)
|
|
|
|
|
{
|
2025-02-12 11:39:35 +01:00
|
|
|
SetLastError(g_err_oom);
|
2016-10-07 14:04:40 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-11-25 15:10:30 +01:00
|
|
|
CopyMemory(*ppBuffer, (void*)&hEvent, sizeof(HANDLE));
|
2015-06-16 15:42:07 +02:00
|
|
|
*pBytesReturned = sizeof(void*);
|
|
|
|
|
status = TRUE;
|
|
|
|
|
}
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2014-02-16 21:19:25 -05:00
|
|
|
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:
|
2026-02-26 15:06:27 +01:00
|
|
|
*ppBuffer = nullptr;
|
2022-12-23 16:16:58 +01:00
|
|
|
*pBytesReturned = 0;
|
|
|
|
|
return FALSE;
|
2014-02-16 21:19:25 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*ppBuffer = malloc(sizeof(BOOL));
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2015-06-16 15:42:07 +02:00
|
|
|
if (!*ppBuffer)
|
|
|
|
|
{
|
2025-02-12 11:39:35 +01:00
|
|
|
SetLastError(g_err_oom);
|
2015-06-16 15:42:07 +02:00
|
|
|
status = FALSE;
|
2016-10-07 14:04:40 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2015-06-16 15:42:07 +02:00
|
|
|
CopyMemory(*ppBuffer, &bval, sizeof(BOOL));
|
|
|
|
|
*pBytesReturned = sizeof(BOOL);
|
|
|
|
|
}
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2014-02-16 21:19:25 -05:00
|
|
|
break;
|
2022-12-26 00:01:27 +01:00
|
|
|
case WTSVirtualChannelOpenStatus:
|
|
|
|
|
{
|
|
|
|
|
INT32 value = channel->creationStatus;
|
|
|
|
|
status = TRUE;
|
2014-02-16 21:19:25 -05:00
|
|
|
|
2022-12-26 00:01:27 +01:00
|
|
|
*ppBuffer = malloc(sizeof(value));
|
|
|
|
|
if (!*ppBuffer)
|
|
|
|
|
{
|
2025-02-12 11:39:35 +01:00
|
|
|
SetLastError(g_err_oom);
|
2022-12-26 00:01:27 +01:00
|
|
|
status = FALSE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CopyMemory(*ppBuffer, &value, sizeof(value));
|
|
|
|
|
*pBytesReturned = sizeof(value);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2014-02-16 21:19:25 -05:00
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-10-07 14:04:40 +02:00
|
|
|
|
2014-02-16 21:19:25 -05:00
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-28 14:49:57 -05:00
|
|
|
VOID WINAPI FreeRDP_WTSFreeMemory(PVOID pMemory)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
|
|
|
|
free(pMemory);
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSFreeMemoryExW(WINPR_ATTR_UNUSED WTS_TYPE_CLASS WTSTypeClass,
|
|
|
|
|
WINPR_ATTR_UNUSED PVOID pMemory,
|
|
|
|
|
WINPR_ATTR_UNUSED ULONG NumberOfEntries)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSFreeMemoryExA(WINPR_ATTR_UNUSED WTS_TYPE_CLASS WTSTypeClass,
|
|
|
|
|
WINPR_ATTR_UNUSED PVOID pMemory,
|
|
|
|
|
WINPR_ATTR_UNUSED ULONG NumberOfEntries)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSRegisterSessionNotification(WINPR_ATTR_UNUSED HWND hWnd,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD dwFlags)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSUnRegisterSessionNotification(WINPR_ATTR_UNUSED HWND hWnd)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSRegisterSessionNotificationEx(WINPR_ATTR_UNUSED HANDLE hServer,
|
|
|
|
|
WINPR_ATTR_UNUSED HWND hWnd,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD dwFlags)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSUnRegisterSessionNotificationEx(WINPR_ATTR_UNUSED HANDLE hServer,
|
|
|
|
|
WINPR_ATTR_UNUSED HWND hWnd)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSQueryUserToken(WINPR_ATTR_UNUSED ULONG SessionId,
|
|
|
|
|
WINPR_ATTR_UNUSED PHANDLE phToken)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSEnumerateProcessesExW(WINPR_ATTR_UNUSED HANDLE hServer,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD* pLevel,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD SessionId,
|
|
|
|
|
WINPR_ATTR_UNUSED LPWSTR* ppProcessInfo,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD* pCount)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSEnumerateProcessesExA(WINPR_ATTR_UNUSED HANDLE hServer,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD* pLevel,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD SessionId,
|
|
|
|
|
WINPR_ATTR_UNUSED LPSTR* ppProcessInfo,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD* pCount)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSEnumerateListenersW(WINPR_ATTR_UNUSED HANDLE hServer,
|
|
|
|
|
WINPR_ATTR_UNUSED PVOID pReserved,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Reserved,
|
|
|
|
|
WINPR_ATTR_UNUSED PWTSLISTENERNAMEW pListeners,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD* pCount)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSEnumerateListenersA(WINPR_ATTR_UNUSED HANDLE hServer,
|
|
|
|
|
WINPR_ATTR_UNUSED PVOID pReserved,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Reserved,
|
|
|
|
|
WINPR_ATTR_UNUSED PWTSLISTENERNAMEA pListeners,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD* pCount)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSQueryListenerConfigW(WINPR_ATTR_UNUSED HANDLE hServer,
|
|
|
|
|
WINPR_ATTR_UNUSED PVOID pReserved,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Reserved,
|
|
|
|
|
WINPR_ATTR_UNUSED LPWSTR pListenerName,
|
|
|
|
|
WINPR_ATTR_UNUSED PWTSLISTENERCONFIGW pBuffer)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSQueryListenerConfigA(WINPR_ATTR_UNUSED HANDLE hServer,
|
|
|
|
|
WINPR_ATTR_UNUSED PVOID pReserved,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Reserved,
|
|
|
|
|
WINPR_ATTR_UNUSED LPSTR pListenerName,
|
|
|
|
|
WINPR_ATTR_UNUSED PWTSLISTENERCONFIGA pBuffer)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSCreateListenerW(WINPR_ATTR_UNUSED HANDLE hServer,
|
|
|
|
|
WINPR_ATTR_UNUSED PVOID pReserved,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Reserved,
|
|
|
|
|
WINPR_ATTR_UNUSED LPWSTR pListenerName,
|
|
|
|
|
WINPR_ATTR_UNUSED PWTSLISTENERCONFIGW pBuffer,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD flag)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSCreateListenerA(WINPR_ATTR_UNUSED HANDLE hServer,
|
|
|
|
|
WINPR_ATTR_UNUSED PVOID pReserved,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Reserved,
|
|
|
|
|
WINPR_ATTR_UNUSED LPSTR pListenerName,
|
|
|
|
|
WINPR_ATTR_UNUSED PWTSLISTENERCONFIGA pBuffer,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD flag)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSSetListenerSecurityW(
|
|
|
|
|
WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED PVOID pReserved,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Reserved, WINPR_ATTR_UNUSED LPWSTR pListenerName,
|
|
|
|
|
WINPR_ATTR_UNUSED SECURITY_INFORMATION SecurityInformation,
|
|
|
|
|
WINPR_ATTR_UNUSED PSECURITY_DESCRIPTOR pSecurityDescriptor)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSSetListenerSecurityA(
|
|
|
|
|
WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED PVOID pReserved,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Reserved, WINPR_ATTR_UNUSED LPSTR pListenerName,
|
|
|
|
|
WINPR_ATTR_UNUSED SECURITY_INFORMATION SecurityInformation,
|
|
|
|
|
WINPR_ATTR_UNUSED PSECURITY_DESCRIPTOR pSecurityDescriptor)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSGetListenerSecurityW(
|
|
|
|
|
WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED PVOID pReserved,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Reserved, WINPR_ATTR_UNUSED LPWSTR pListenerName,
|
|
|
|
|
WINPR_ATTR_UNUSED SECURITY_INFORMATION SecurityInformation,
|
|
|
|
|
WINPR_ATTR_UNUSED PSECURITY_DESCRIPTOR pSecurityDescriptor, WINPR_ATTR_UNUSED DWORD nLength,
|
|
|
|
|
WINPR_ATTR_UNUSED LPDWORD lpnLengthNeeded)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSGetListenerSecurityA(
|
|
|
|
|
WINPR_ATTR_UNUSED HANDLE hServer, WINPR_ATTR_UNUSED PVOID pReserved,
|
|
|
|
|
WINPR_ATTR_UNUSED DWORD Reserved, WINPR_ATTR_UNUSED LPSTR pListenerName,
|
|
|
|
|
WINPR_ATTR_UNUSED SECURITY_INFORMATION SecurityInformation,
|
|
|
|
|
WINPR_ATTR_UNUSED PSECURITY_DESCRIPTOR pSecurityDescriptor, WINPR_ATTR_UNUSED DWORD nLength,
|
|
|
|
|
WINPR_ATTR_UNUSED LPDWORD lpnLengthNeeded)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL CDECL FreeRDP_WTSEnableChildSessions(WINPR_ATTR_UNUSED BOOL bEnable)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL CDECL FreeRDP_WTSIsChildSessionsEnabled(WINPR_ATTR_UNUSED PBOOL pbEnabled)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL CDECL FreeRDP_WTSGetChildSessionId(WINPR_ATTR_UNUSED PULONG pSessionId)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-28 14:49:57 -05:00
|
|
|
DWORD WINAPI FreeRDP_WTSGetActiveConsoleSessionId(void)
|
2014-02-16 21:19:25 -05:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2014-02-16 21:19:25 -05:00
|
|
|
return 0xFFFFFFFF;
|
|
|
|
|
}
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSLogoffUser(WINPR_ATTR_UNUSED HANDLE hServer)
|
2015-02-12 01:31:00 -08:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2015-02-12 01:31:00 -08:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-13 15:29:10 +01:00
|
|
|
BOOL WINAPI FreeRDP_WTSLogonUser(WINPR_ATTR_UNUSED HANDLE hServer,
|
|
|
|
|
WINPR_ATTR_UNUSED LPCSTR username,
|
|
|
|
|
WINPR_ATTR_UNUSED LPCSTR password, WINPR_ATTR_UNUSED LPCSTR domain)
|
2015-02-12 01:31:00 -08:00
|
|
|
{
|
2025-02-13 15:29:10 +01:00
|
|
|
WLog_ERR("TODO", "TODO: implement");
|
2015-02-12 01:31:00 -08:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
2023-12-16 20:52:11 +01:00
|
|
|
|
|
|
|
|
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)
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2023-12-16 20:52:11 +01:00
|
|
|
|
|
|
|
|
InitializeCriticalSection(&channel->writeLock);
|
|
|
|
|
|
2026-02-26 15:06:27 +01:00
|
|
|
channel->receiveData = Stream_New(nullptr, chunkSize);
|
2023-12-16 20:52:11 +01:00
|
|
|
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:
|
2024-02-04 11:11:29 +01:00
|
|
|
WINPR_PRAGMA_DIAG_PUSH
|
|
|
|
|
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
2023-12-16 20:52:11 +01:00
|
|
|
server_channel_common_free(channel);
|
2024-02-04 11:11:29 +01:00
|
|
|
WINPR_PRAGMA_DIAG_POP
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2023-12-16 20:52:11 +01:00
|
|
|
}
|