summaryrefslogtreecommitdiffstats
path: root/libfreerdp/core/channels.c
diff options
context:
space:
mode:
Diffstat (limited to 'libfreerdp/core/channels.c')
-rw-r--r--libfreerdp/core/channels.c316
1 files changed, 316 insertions, 0 deletions
diff --git a/libfreerdp/core/channels.c b/libfreerdp/core/channels.c
new file mode 100644
index 0000000..0c2ad98
--- /dev/null
+++ b/libfreerdp/core/channels.c
@@ -0,0 +1,316 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * Virtual Channels
+ *
+ * Copyright 2011 Vic Lee
+ * Copyright 2015 Copyright 2015 Thincast Technologies GmbH
+ *
+ * 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.
+ */
+
+#include <freerdp/config.h>
+
+#include "settings.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <winpr/crt.h>
+#include <winpr/assert.h>
+#include <winpr/stream.h>
+#include <winpr/wtsapi.h>
+
+#include <freerdp/freerdp.h>
+#include <freerdp/constants.h>
+
+#include <freerdp/log.h>
+#include <freerdp/svc.h>
+#include <freerdp/peer.h>
+#include <freerdp/addin.h>
+
+#include <freerdp/client/channels.h>
+#include <freerdp/client/drdynvc.h>
+#include <freerdp/channels/channels.h>
+
+#include "rdp.h"
+#include "client.h"
+#include "server.h"
+#include "channels.h"
+
+#define TAG FREERDP_TAG("core.channels")
+
+BOOL freerdp_channel_send(rdpRdp* rdp, UINT16 channelId, const BYTE* data, size_t size)
+{
+ size_t left = 0;
+ UINT32 flags = 0;
+ size_t chunkSize = 0;
+ rdpMcs* mcs = NULL;
+ const rdpMcsChannel* channel = NULL;
+
+ WINPR_ASSERT(rdp);
+ WINPR_ASSERT(data || (size == 0));
+
+ mcs = rdp->mcs;
+ WINPR_ASSERT(mcs);
+ for (UINT32 i = 0; i < mcs->channelCount; i++)
+ {
+ const rdpMcsChannel* cur = &mcs->channels[i];
+ if (cur->ChannelId == channelId)
+ {
+ channel = cur;
+ break;
+ }
+ }
+
+ if (!channel)
+ {
+ WLog_ERR(TAG, "freerdp_channel_send: unknown channelId %" PRIu16 "", channelId);
+ return FALSE;
+ }
+
+ flags = CHANNEL_FLAG_FIRST;
+ left = size;
+
+ while (left > 0)
+ {
+ if (left > rdp->settings->VCChunkSize)
+ {
+ chunkSize = rdp->settings->VCChunkSize;
+ }
+ else
+ {
+ chunkSize = left;
+ flags |= CHANNEL_FLAG_LAST;
+ }
+
+ if (!rdp->settings->ServerMode && (channel->options & CHANNEL_OPTION_SHOW_PROTOCOL))
+ {
+ flags |= CHANNEL_FLAG_SHOW_PROTOCOL;
+ }
+
+ if (!freerdp_channel_send_packet(rdp, channelId, size, flags, data, chunkSize))
+ return FALSE;
+
+ data += chunkSize;
+ left -= chunkSize;
+ flags = 0;
+ }
+
+ return TRUE;
+}
+
+BOOL freerdp_channel_process(freerdp* instance, wStream* s, UINT16 channelId, size_t packetLength)
+{
+ BOOL rc = FALSE;
+ UINT32 length = 0;
+ UINT32 flags = 0;
+ size_t chunkLength = 0;
+
+ WINPR_ASSERT(instance);
+
+ if (packetLength < 8)
+ {
+ WLog_ERR(TAG, "Header length %" PRIdz " bytes promised, none available", packetLength);
+ return FALSE;
+ }
+ packetLength -= 8;
+
+ if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
+ return FALSE;
+
+ /* [MS-RDPBCGR] 3.1.5.2.2 Processing of Virtual Channel PDU
+ * chunked data. Length is the total size of the combined data,
+ * chunkLength is the actual data received.
+ * check chunkLength against packetLength, which is the TPKT header size.
+ */
+ Stream_Read_UINT32(s, length);
+ Stream_Read_UINT32(s, flags);
+ chunkLength = Stream_GetRemainingLength(s);
+ if (packetLength != chunkLength)
+ {
+ WLog_ERR(TAG, "Header length %" PRIdz " != actual length %" PRIdz, packetLength,
+ chunkLength);
+ return FALSE;
+ }
+
+ IFCALLRET(instance->ReceiveChannelData, rc, instance, channelId, Stream_Pointer(s), chunkLength,
+ flags, length);
+ if (!rc)
+ {
+ WLog_WARN(TAG, "ReceiveChannelData returned %d", rc);
+ return FALSE;
+ }
+
+ return Stream_SafeSeek(s, chunkLength);
+}
+
+BOOL freerdp_channel_peer_process(freerdp_peer* client, wStream* s, UINT16 channelId)
+{
+ UINT32 length = 0;
+ UINT32 flags = 0;
+ size_t chunkLength = 0;
+
+ WINPR_ASSERT(client);
+ WINPR_ASSERT(s);
+
+ if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
+ return FALSE;
+
+ Stream_Read_UINT32(s, length);
+ Stream_Read_UINT32(s, flags);
+ chunkLength = Stream_GetRemainingLength(s);
+
+ if (client->VirtualChannelRead)
+ {
+ int rc = 0;
+ BOOL found = FALSE;
+ HANDLE hChannel = 0;
+ rdpContext* context = client->context;
+ rdpMcs* mcs = context->rdp->mcs;
+
+ for (UINT32 index = 0; index < mcs->channelCount; index++)
+ {
+ const rdpMcsChannel* mcsChannel = &(mcs->channels[index]);
+
+ if (mcsChannel->ChannelId == channelId)
+ {
+ hChannel = (HANDLE)mcsChannel->handle;
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found)
+ return FALSE;
+
+ rc = client->VirtualChannelRead(client, hChannel, Stream_Pointer(s), chunkLength);
+ if (rc < 0)
+ return FALSE;
+ }
+ else if (client->ReceiveChannelData)
+ {
+ BOOL rc = client->ReceiveChannelData(client, channelId, Stream_Pointer(s), chunkLength,
+ flags, length);
+ if (!rc)
+ return FALSE;
+ }
+ if (!Stream_SafeSeek(s, chunkLength))
+ {
+ WLog_WARN(TAG, "Short PDU, need %" PRIuz " bytes, got %" PRIuz, chunkLength,
+ Stream_GetRemainingLength(s));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static const WtsApiFunctionTable FreeRDP_WtsApiFunctionTable = {
+ 0, /* dwVersion */
+ 0, /* dwFlags */
+
+ FreeRDP_WTSStopRemoteControlSession, /* StopRemoteControlSession */
+ FreeRDP_WTSStartRemoteControlSessionW, /* StartRemoteControlSessionW */
+ FreeRDP_WTSStartRemoteControlSessionA, /* StartRemoteControlSessionA */
+ FreeRDP_WTSConnectSessionW, /* ConnectSessionW */
+ FreeRDP_WTSConnectSessionA, /* ConnectSessionA */
+ FreeRDP_WTSEnumerateServersW, /* EnumerateServersW */
+ FreeRDP_WTSEnumerateServersA, /* EnumerateServersA */
+ FreeRDP_WTSOpenServerW, /* OpenServerW */
+ FreeRDP_WTSOpenServerA, /* OpenServerA */
+ FreeRDP_WTSOpenServerExW, /* OpenServerExW */
+ FreeRDP_WTSOpenServerExA, /* OpenServerExA */
+ FreeRDP_WTSCloseServer, /* CloseServer */
+ FreeRDP_WTSEnumerateSessionsW, /* EnumerateSessionsW */
+ FreeRDP_WTSEnumerateSessionsA, /* EnumerateSessionsA */
+ FreeRDP_WTSEnumerateSessionsExW, /* EnumerateSessionsExW */
+ FreeRDP_WTSEnumerateSessionsExA, /* EnumerateSessionsExA */
+ FreeRDP_WTSEnumerateProcessesW, /* EnumerateProcessesW */
+ FreeRDP_WTSEnumerateProcessesA, /* EnumerateProcessesA */
+ FreeRDP_WTSTerminateProcess, /* TerminateProcess */
+ FreeRDP_WTSQuerySessionInformationW, /* QuerySessionInformationW */
+ FreeRDP_WTSQuerySessionInformationA, /* QuerySessionInformationA */
+ FreeRDP_WTSQueryUserConfigW, /* QueryUserConfigW */
+ FreeRDP_WTSQueryUserConfigA, /* QueryUserConfigA */
+ FreeRDP_WTSSetUserConfigW, /* SetUserConfigW */
+ FreeRDP_WTSSetUserConfigA, /* SetUserConfigA */
+ FreeRDP_WTSSendMessageW, /* SendMessageW */
+ FreeRDP_WTSSendMessageA, /* SendMessageA */
+ FreeRDP_WTSDisconnectSession, /* DisconnectSession */
+ FreeRDP_WTSLogoffSession, /* LogoffSession */
+ FreeRDP_WTSShutdownSystem, /* ShutdownSystem */
+ FreeRDP_WTSWaitSystemEvent, /* WaitSystemEvent */
+ FreeRDP_WTSVirtualChannelOpen, /* VirtualChannelOpen */
+ FreeRDP_WTSVirtualChannelOpenEx, /* VirtualChannelOpenEx */
+ FreeRDP_WTSVirtualChannelClose, /* VirtualChannelClose */
+ FreeRDP_WTSVirtualChannelRead, /* VirtualChannelRead */
+ FreeRDP_WTSVirtualChannelWrite, /* VirtualChannelWrite */
+ FreeRDP_WTSVirtualChannelPurgeInput, /* VirtualChannelPurgeInput */
+ FreeRDP_WTSVirtualChannelPurgeOutput, /* VirtualChannelPurgeOutput */
+ FreeRDP_WTSVirtualChannelQuery, /* VirtualChannelQuery */
+ FreeRDP_WTSFreeMemory, /* FreeMemory */
+ FreeRDP_WTSRegisterSessionNotification, /* RegisterSessionNotification */
+ FreeRDP_WTSUnRegisterSessionNotification, /* UnRegisterSessionNotification */
+ FreeRDP_WTSRegisterSessionNotificationEx, /* RegisterSessionNotificationEx */
+ FreeRDP_WTSUnRegisterSessionNotificationEx, /* UnRegisterSessionNotificationEx */
+ FreeRDP_WTSQueryUserToken, /* QueryUserToken */
+ FreeRDP_WTSFreeMemoryExW, /* FreeMemoryExW */
+ FreeRDP_WTSFreeMemoryExA, /* FreeMemoryExA */
+ FreeRDP_WTSEnumerateProcessesExW, /* EnumerateProcessesExW */
+ FreeRDP_WTSEnumerateProcessesExA, /* EnumerateProcessesExA */
+ FreeRDP_WTSEnumerateListenersW, /* EnumerateListenersW */
+ FreeRDP_WTSEnumerateListenersA, /* EnumerateListenersA */
+ FreeRDP_WTSQueryListenerConfigW, /* QueryListenerConfigW */
+ FreeRDP_WTSQueryListenerConfigA, /* QueryListenerConfigA */
+ FreeRDP_WTSCreateListenerW, /* CreateListenerW */
+ FreeRDP_WTSCreateListenerA, /* CreateListenerA */
+ FreeRDP_WTSSetListenerSecurityW, /* SetListenerSecurityW */
+ FreeRDP_WTSSetListenerSecurityA, /* SetListenerSecurityA */
+ FreeRDP_WTSGetListenerSecurityW, /* GetListenerSecurityW */
+ FreeRDP_WTSGetListenerSecurityA, /* GetListenerSecurityA */
+ FreeRDP_WTSEnableChildSessions, /* EnableChildSessions */
+ FreeRDP_WTSIsChildSessionsEnabled, /* IsChildSessionsEnabled */
+ FreeRDP_WTSGetChildSessionId, /* GetChildSessionId */
+ FreeRDP_WTSGetActiveConsoleSessionId, /* GetActiveConsoleSessionId */
+ FreeRDP_WTSLogonUser,
+ FreeRDP_WTSLogoffUser,
+ FreeRDP_WTSStartRemoteControlSessionExW,
+ FreeRDP_WTSStartRemoteControlSessionExA
+};
+
+const WtsApiFunctionTable* FreeRDP_InitWtsApi(void)
+{
+ return &FreeRDP_WtsApiFunctionTable;
+}
+
+BOOL freerdp_channel_send_packet(rdpRdp* rdp, UINT16 channelId, size_t totalSize, UINT32 flags,
+ const BYTE* data, size_t chunkSize)
+{
+ wStream* s = rdp_send_stream_init(rdp);
+
+ if (!s)
+ return FALSE;
+
+ Stream_Write_UINT32(s, totalSize);
+ Stream_Write_UINT32(s, flags);
+
+ if (!Stream_EnsureCapacity(s, chunkSize))
+ {
+ Stream_Release(s);
+ return FALSE;
+ }
+
+ Stream_Write(s, data, chunkSize);
+
+ /* WLog_DBG(TAG, "sending data (flags=0x%x size=%d)", flags, size); */
+ return rdp_send(rdp, s, channelId);
+}