Coverage Report

Created: 2026-04-12 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/core/channels.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Virtual Channels
4
 *
5
 * Copyright 2011 Vic Lee
6
 * Copyright 2015 Copyright 2015 Thincast Technologies GmbH
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
21
#include <freerdp/config.h>
22
23
#include "settings.h"
24
25
#include <stdio.h>
26
#include <stdlib.h>
27
#include <string.h>
28
29
#include <winpr/crt.h>
30
#include <winpr/assert.h>
31
#include <winpr/stream.h>
32
#include <winpr/wtsapi.h>
33
34
#include <freerdp/freerdp.h>
35
#include <freerdp/constants.h>
36
37
#include <freerdp/log.h>
38
#include <freerdp/svc.h>
39
#include <freerdp/peer.h>
40
#include <freerdp/addin.h>
41
42
#include <freerdp/client/channels.h>
43
#include <freerdp/client/drdynvc.h>
44
#include <freerdp/channels/channels.h>
45
46
#include "rdp.h"
47
#include "client.h"
48
#include "server.h"
49
#include "channels.h"
50
51
#define TAG FREERDP_TAG("core.channels")
52
53
BOOL freerdp_channel_send(rdpRdp* rdp, UINT16 channelId, const BYTE* data, size_t size)
54
0
{
55
0
  size_t left = 0;
56
0
  UINT32 flags = 0;
57
0
  size_t chunkSize = 0;
58
0
  rdpMcs* mcs = nullptr;
59
0
  const rdpMcsChannel* channel = nullptr;
60
61
0
  WINPR_ASSERT(rdp);
62
0
  WINPR_ASSERT(data || (size == 0));
63
64
0
  mcs = rdp->mcs;
65
0
  WINPR_ASSERT(mcs);
66
0
  for (UINT32 i = 0; i < mcs->channelCount; i++)
67
0
  {
68
0
    const rdpMcsChannel* cur = &mcs->channels[i];
69
0
    if (cur->ChannelId == channelId)
70
0
    {
71
0
      channel = cur;
72
0
      break;
73
0
    }
74
0
  }
75
76
0
  if (!channel)
77
0
  {
78
0
    WLog_ERR(TAG, "freerdp_channel_send: unknown channelId %" PRIu16 "", channelId);
79
0
    return FALSE;
80
0
  }
81
82
0
  flags = CHANNEL_FLAG_FIRST;
83
0
  left = size;
84
85
0
  const UINT32 VCChunkSize = freerdp_settings_get_uint32(rdp->settings, FreeRDP_VCChunkSize);
86
0
  const BOOL ServerMode = freerdp_settings_get_bool(rdp->settings, FreeRDP_ServerMode);
87
0
  while (left > 0)
88
0
  {
89
0
    if (left > VCChunkSize)
90
0
    {
91
0
      chunkSize = VCChunkSize;
92
0
    }
93
0
    else
94
0
    {
95
0
      chunkSize = left;
96
0
      flags |= CHANNEL_FLAG_LAST;
97
0
    }
98
99
0
    if (!ServerMode && (channel->options & CHANNEL_OPTION_SHOW_PROTOCOL))
100
0
    {
101
0
      flags |= CHANNEL_FLAG_SHOW_PROTOCOL;
102
0
    }
103
104
0
    if (!freerdp_channel_send_packet(rdp, channelId, size, flags, data, chunkSize))
105
0
      return FALSE;
106
107
0
    data += chunkSize;
108
0
    left -= chunkSize;
109
0
    flags = 0;
110
0
  }
111
112
0
  return TRUE;
113
0
}
114
115
BOOL freerdp_channel_process(freerdp* instance, wStream* s, UINT16 channelId, size_t packetLength)
116
0
{
117
0
  BOOL rc = FALSE;
118
0
  UINT32 length = 0;
119
0
  UINT32 flags = 0;
120
0
  size_t chunkLength = 0;
121
122
0
  WINPR_ASSERT(instance);
123
124
0
  if (packetLength < 8)
125
0
  {
126
0
    WLog_ERR(TAG, "Header length %" PRIuz " bytes promised, none available", packetLength);
127
0
    return FALSE;
128
0
  }
129
0
  packetLength -= 8;
130
131
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
132
0
    return FALSE;
133
134
  /* [MS-RDPBCGR] 3.1.5.2.2 Processing of Virtual Channel PDU
135
   * chunked data. Length is the total size of the combined data,
136
   * chunkLength is the actual data received.
137
   * check chunkLength against packetLength, which is the TPKT header size.
138
   */
139
0
  Stream_Read_UINT32(s, length);
140
0
  Stream_Read_UINT32(s, flags);
141
0
  chunkLength = Stream_GetRemainingLength(s);
142
0
  if (packetLength != chunkLength)
143
0
  {
144
0
    WLog_ERR(TAG, "Header length %" PRIuz " != actual length %" PRIuz, packetLength,
145
0
             chunkLength);
146
0
    return FALSE;
147
0
  }
148
149
0
  IFCALLRET(instance->ReceiveChannelData, rc, instance, channelId, Stream_Pointer(s), chunkLength,
150
0
            flags, length);
151
0
  if (!rc)
152
0
  {
153
0
    WLog_WARN(TAG, "ReceiveChannelData returned %d", rc);
154
0
    return FALSE;
155
0
  }
156
157
0
  return Stream_SafeSeek(s, chunkLength);
158
0
}
159
160
BOOL freerdp_channel_peer_process(freerdp_peer* client, wStream* s, UINT16 channelId)
161
0
{
162
0
  UINT32 length = 0;
163
0
  UINT32 flags = 0;
164
165
0
  WINPR_ASSERT(client);
166
0
  WINPR_ASSERT(s);
167
168
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
169
0
    return FALSE;
170
171
0
  Stream_Read_UINT32(s, length);
172
0
  Stream_Read_UINT32(s, flags);
173
0
  const size_t chunkLength = Stream_GetRemainingLength(s);
174
0
  if (chunkLength > UINT32_MAX)
175
0
    return FALSE;
176
177
0
  if (client->VirtualChannelRead)
178
0
  {
179
0
    int rc = 0;
180
0
    BOOL found = FALSE;
181
0
    HANDLE hChannel = nullptr;
182
0
    rdpContext* context = client->context;
183
0
    rdpMcs* mcs = context->rdp->mcs;
184
185
0
    for (UINT32 index = 0; index < mcs->channelCount; index++)
186
0
    {
187
0
      const rdpMcsChannel* mcsChannel = &(mcs->channels[index]);
188
189
0
      if (mcsChannel->ChannelId == channelId)
190
0
      {
191
0
        hChannel = (HANDLE)mcsChannel->handle;
192
0
        found = TRUE;
193
0
        break;
194
0
      }
195
0
    }
196
197
0
    if (!found)
198
0
      return FALSE;
199
200
0
    rc = client->VirtualChannelRead(client, hChannel, Stream_Pointer(s), (UINT32)chunkLength);
201
0
    if (rc < 0)
202
0
      return FALSE;
203
0
  }
204
0
  else if (client->ReceiveChannelData)
205
0
  {
206
0
    BOOL rc = client->ReceiveChannelData(client, channelId, Stream_Pointer(s),
207
0
                                         (UINT32)chunkLength, flags, length);
208
0
    if (!rc)
209
0
      return FALSE;
210
0
  }
211
0
  if (!Stream_SafeSeek(s, chunkLength))
212
0
  {
213
0
    WLog_WARN(TAG, "Short PDU, need %" PRIuz " bytes, got %" PRIuz, chunkLength,
214
0
              Stream_GetRemainingLength(s));
215
0
    return FALSE;
216
0
  }
217
0
  return TRUE;
218
0
}
219
220
static const WtsApiFunctionTable FreeRDP_WtsApiFunctionTable = {
221
  0, /* dwVersion */
222
  0, /* dwFlags */
223
224
  FreeRDP_WTSStopRemoteControlSession,        /* StopRemoteControlSession */
225
  FreeRDP_WTSStartRemoteControlSessionW,      /* StartRemoteControlSessionW */
226
  FreeRDP_WTSStartRemoteControlSessionA,      /* StartRemoteControlSessionA */
227
  FreeRDP_WTSConnectSessionW,                 /* ConnectSessionW */
228
  FreeRDP_WTSConnectSessionA,                 /* ConnectSessionA */
229
  FreeRDP_WTSEnumerateServersW,               /* EnumerateServersW */
230
  FreeRDP_WTSEnumerateServersA,               /* EnumerateServersA */
231
  FreeRDP_WTSOpenServerW,                     /* OpenServerW */
232
  FreeRDP_WTSOpenServerA,                     /* OpenServerA */
233
  FreeRDP_WTSOpenServerExW,                   /* OpenServerExW */
234
  FreeRDP_WTSOpenServerExA,                   /* OpenServerExA */
235
  FreeRDP_WTSCloseServer,                     /* CloseServer */
236
  FreeRDP_WTSEnumerateSessionsW,              /* EnumerateSessionsW */
237
  FreeRDP_WTSEnumerateSessionsA,              /* EnumerateSessionsA */
238
  FreeRDP_WTSEnumerateSessionsExW,            /* EnumerateSessionsExW */
239
  FreeRDP_WTSEnumerateSessionsExA,            /* EnumerateSessionsExA */
240
  FreeRDP_WTSEnumerateProcessesW,             /* EnumerateProcessesW */
241
  FreeRDP_WTSEnumerateProcessesA,             /* EnumerateProcessesA */
242
  FreeRDP_WTSTerminateProcess,                /* TerminateProcess */
243
  FreeRDP_WTSQuerySessionInformationW,        /* QuerySessionInformationW */
244
  FreeRDP_WTSQuerySessionInformationA,        /* QuerySessionInformationA */
245
  FreeRDP_WTSQueryUserConfigW,                /* QueryUserConfigW */
246
  FreeRDP_WTSQueryUserConfigA,                /* QueryUserConfigA */
247
  FreeRDP_WTSSetUserConfigW,                  /* SetUserConfigW */
248
  FreeRDP_WTSSetUserConfigA,                  /* SetUserConfigA */
249
  FreeRDP_WTSSendMessageW,                    /* SendMessageW */
250
  FreeRDP_WTSSendMessageA,                    /* SendMessageA */
251
  FreeRDP_WTSDisconnectSession,               /* DisconnectSession */
252
  FreeRDP_WTSLogoffSession,                   /* LogoffSession */
253
  FreeRDP_WTSShutdownSystem,                  /* ShutdownSystem */
254
  FreeRDP_WTSWaitSystemEvent,                 /* WaitSystemEvent */
255
  FreeRDP_WTSVirtualChannelOpen,              /* VirtualChannelOpen */
256
  FreeRDP_WTSVirtualChannelOpenEx,            /* VirtualChannelOpenEx */
257
  FreeRDP_WTSVirtualChannelClose,             /* VirtualChannelClose */
258
  FreeRDP_WTSVirtualChannelRead,              /* VirtualChannelRead */
259
  FreeRDP_WTSVirtualChannelWrite,             /* VirtualChannelWrite */
260
  FreeRDP_WTSVirtualChannelPurgeInput,        /* VirtualChannelPurgeInput */
261
  FreeRDP_WTSVirtualChannelPurgeOutput,       /* VirtualChannelPurgeOutput */
262
  FreeRDP_WTSVirtualChannelQuery,             /* VirtualChannelQuery */
263
  FreeRDP_WTSFreeMemory,                      /* FreeMemory */
264
  FreeRDP_WTSRegisterSessionNotification,     /* RegisterSessionNotification */
265
  FreeRDP_WTSUnRegisterSessionNotification,   /* UnRegisterSessionNotification */
266
  FreeRDP_WTSRegisterSessionNotificationEx,   /* RegisterSessionNotificationEx */
267
  FreeRDP_WTSUnRegisterSessionNotificationEx, /* UnRegisterSessionNotificationEx */
268
  FreeRDP_WTSQueryUserToken,                  /* QueryUserToken */
269
  FreeRDP_WTSFreeMemoryExW,                   /* FreeMemoryExW */
270
  FreeRDP_WTSFreeMemoryExA,                   /* FreeMemoryExA */
271
  FreeRDP_WTSEnumerateProcessesExW,           /* EnumerateProcessesExW */
272
  FreeRDP_WTSEnumerateProcessesExA,           /* EnumerateProcessesExA */
273
  FreeRDP_WTSEnumerateListenersW,             /* EnumerateListenersW */
274
  FreeRDP_WTSEnumerateListenersA,             /* EnumerateListenersA */
275
  FreeRDP_WTSQueryListenerConfigW,            /* QueryListenerConfigW */
276
  FreeRDP_WTSQueryListenerConfigA,            /* QueryListenerConfigA */
277
  FreeRDP_WTSCreateListenerW,                 /* CreateListenerW */
278
  FreeRDP_WTSCreateListenerA,                 /* CreateListenerA */
279
  FreeRDP_WTSSetListenerSecurityW,            /* SetListenerSecurityW */
280
  FreeRDP_WTSSetListenerSecurityA,            /* SetListenerSecurityA */
281
  FreeRDP_WTSGetListenerSecurityW,            /* GetListenerSecurityW */
282
  FreeRDP_WTSGetListenerSecurityA,            /* GetListenerSecurityA */
283
  FreeRDP_WTSEnableChildSessions,             /* EnableChildSessions */
284
  FreeRDP_WTSIsChildSessionsEnabled,          /* IsChildSessionsEnabled */
285
  FreeRDP_WTSGetChildSessionId,               /* GetChildSessionId */
286
  FreeRDP_WTSGetActiveConsoleSessionId,       /* GetActiveConsoleSessionId */
287
  FreeRDP_WTSLogonUser,
288
  FreeRDP_WTSLogoffUser,
289
  FreeRDP_WTSStartRemoteControlSessionExW,
290
  FreeRDP_WTSStartRemoteControlSessionExA
291
};
292
293
const WtsApiFunctionTable* FreeRDP_InitWtsApi(void)
294
0
{
295
0
  return &FreeRDP_WtsApiFunctionTable;
296
0
}
297
298
BOOL freerdp_channel_send_packet(rdpRdp* rdp, UINT16 channelId, size_t totalSize, UINT32 flags,
299
                                 const BYTE* data, size_t chunkSize)
300
0
{
301
0
  if (totalSize > UINT32_MAX)
302
0
    return FALSE;
303
304
0
  UINT16 sec_flags = 0;
305
0
  wStream* s = rdp_send_stream_init(rdp, &sec_flags);
306
307
0
  if (!s)
308
0
    return FALSE;
309
310
0
  if (!Stream_EnsureRemainingCapacity(s, chunkSize + 8))
311
0
  {
312
0
    Stream_Release(s);
313
0
    return FALSE;
314
0
  }
315
316
0
  Stream_Write_UINT32(s, (UINT32)totalSize);
317
0
  Stream_Write_UINT32(s, flags);
318
319
0
  Stream_Write(s, data, chunkSize);
320
321
  /* WLog_DBG(TAG, "sending data (flags=0x%x size=%d)",  flags, size); */
322
0
  return rdp_send(rdp, s, channelId, sec_flags);
323
0
}