Coverage Report

Created: 2025-07-01 06:46

/src/FreeRDP/libfreerdp/core/channels.c
Line
Count
Source (jump to first uncovered line)
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 = NULL;
59
0
  const rdpMcsChannel* channel = NULL;
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
  while (left > 0)
86
0
  {
87
0
    if (left > rdp->settings->VCChunkSize)
88
0
    {
89
0
      chunkSize = rdp->settings->VCChunkSize;
90
0
    }
91
0
    else
92
0
    {
93
0
      chunkSize = left;
94
0
      flags |= CHANNEL_FLAG_LAST;
95
0
    }
96
97
0
    if (!rdp->settings->ServerMode && (channel->options & CHANNEL_OPTION_SHOW_PROTOCOL))
98
0
    {
99
0
      flags |= CHANNEL_FLAG_SHOW_PROTOCOL;
100
0
    }
101
102
0
    if (!freerdp_channel_send_packet(rdp, channelId, size, flags, data, chunkSize))
103
0
      return FALSE;
104
105
0
    data += chunkSize;
106
0
    left -= chunkSize;
107
0
    flags = 0;
108
0
  }
109
110
0
  return TRUE;
111
0
}
112
113
BOOL freerdp_channel_process(freerdp* instance, wStream* s, UINT16 channelId, size_t packetLength)
114
0
{
115
0
  BOOL rc = FALSE;
116
0
  UINT32 length = 0;
117
0
  UINT32 flags = 0;
118
0
  size_t chunkLength = 0;
119
120
0
  WINPR_ASSERT(instance);
121
122
0
  if (packetLength < 8)
123
0
  {
124
0
    WLog_ERR(TAG, "Header length %" PRIdz " bytes promised, none available", packetLength);
125
0
    return FALSE;
126
0
  }
127
0
  packetLength -= 8;
128
129
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
130
0
    return FALSE;
131
132
  /* [MS-RDPBCGR] 3.1.5.2.2 Processing of Virtual Channel PDU
133
   * chunked data. Length is the total size of the combined data,
134
   * chunkLength is the actual data received.
135
   * check chunkLength against packetLength, which is the TPKT header size.
136
   */
137
0
  Stream_Read_UINT32(s, length);
138
0
  Stream_Read_UINT32(s, flags);
139
0
  chunkLength = Stream_GetRemainingLength(s);
140
0
  if (packetLength != chunkLength)
141
0
  {
142
0
    WLog_ERR(TAG, "Header length %" PRIdz " != actual length %" PRIdz, packetLength,
143
0
             chunkLength);
144
0
    return FALSE;
145
0
  }
146
147
0
  IFCALLRET(instance->ReceiveChannelData, rc, instance, channelId, Stream_Pointer(s), chunkLength,
148
0
            flags, length);
149
0
  if (!rc)
150
0
  {
151
0
    WLog_WARN(TAG, "ReceiveChannelData returned %d", rc);
152
0
    return FALSE;
153
0
  }
154
155
0
  return Stream_SafeSeek(s, chunkLength);
156
0
}
157
158
BOOL freerdp_channel_peer_process(freerdp_peer* client, wStream* s, UINT16 channelId)
159
0
{
160
0
  UINT32 length = 0;
161
0
  UINT32 flags = 0;
162
163
0
  WINPR_ASSERT(client);
164
0
  WINPR_ASSERT(s);
165
166
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
167
0
    return FALSE;
168
169
0
  Stream_Read_UINT32(s, length);
170
0
  Stream_Read_UINT32(s, flags);
171
0
  const size_t chunkLength = Stream_GetRemainingLength(s);
172
0
  if (chunkLength > UINT32_MAX)
173
0
    return FALSE;
174
175
0
  if (client->VirtualChannelRead)
176
0
  {
177
0
    int rc = 0;
178
0
    BOOL found = FALSE;
179
0
    HANDLE hChannel = 0;
180
0
    rdpContext* context = client->context;
181
0
    rdpMcs* mcs = context->rdp->mcs;
182
183
0
    for (UINT32 index = 0; index < mcs->channelCount; index++)
184
0
    {
185
0
      const rdpMcsChannel* mcsChannel = &(mcs->channels[index]);
186
187
0
      if (mcsChannel->ChannelId == channelId)
188
0
      {
189
0
        hChannel = (HANDLE)mcsChannel->handle;
190
0
        found = TRUE;
191
0
        break;
192
0
      }
193
0
    }
194
195
0
    if (!found)
196
0
      return FALSE;
197
198
0
    rc = client->VirtualChannelRead(client, hChannel, Stream_Pointer(s), (UINT32)chunkLength);
199
0
    if (rc < 0)
200
0
      return FALSE;
201
0
  }
202
0
  else if (client->ReceiveChannelData)
203
0
  {
204
0
    BOOL rc = client->ReceiveChannelData(client, channelId, Stream_Pointer(s),
205
0
                                         (UINT32)chunkLength, flags, length);
206
0
    if (!rc)
207
0
      return FALSE;
208
0
  }
209
0
  if (!Stream_SafeSeek(s, chunkLength))
210
0
  {
211
0
    WLog_WARN(TAG, "Short PDU, need %" PRIuz " bytes, got %" PRIuz, chunkLength,
212
0
              Stream_GetRemainingLength(s));
213
0
    return FALSE;
214
0
  }
215
0
  return TRUE;
216
0
}
217
218
static const WtsApiFunctionTable FreeRDP_WtsApiFunctionTable = {
219
  0, /* dwVersion */
220
  0, /* dwFlags */
221
222
  FreeRDP_WTSStopRemoteControlSession,        /* StopRemoteControlSession */
223
  FreeRDP_WTSStartRemoteControlSessionW,      /* StartRemoteControlSessionW */
224
  FreeRDP_WTSStartRemoteControlSessionA,      /* StartRemoteControlSessionA */
225
  FreeRDP_WTSConnectSessionW,                 /* ConnectSessionW */
226
  FreeRDP_WTSConnectSessionA,                 /* ConnectSessionA */
227
  FreeRDP_WTSEnumerateServersW,               /* EnumerateServersW */
228
  FreeRDP_WTSEnumerateServersA,               /* EnumerateServersA */
229
  FreeRDP_WTSOpenServerW,                     /* OpenServerW */
230
  FreeRDP_WTSOpenServerA,                     /* OpenServerA */
231
  FreeRDP_WTSOpenServerExW,                   /* OpenServerExW */
232
  FreeRDP_WTSOpenServerExA,                   /* OpenServerExA */
233
  FreeRDP_WTSCloseServer,                     /* CloseServer */
234
  FreeRDP_WTSEnumerateSessionsW,              /* EnumerateSessionsW */
235
  FreeRDP_WTSEnumerateSessionsA,              /* EnumerateSessionsA */
236
  FreeRDP_WTSEnumerateSessionsExW,            /* EnumerateSessionsExW */
237
  FreeRDP_WTSEnumerateSessionsExA,            /* EnumerateSessionsExA */
238
  FreeRDP_WTSEnumerateProcessesW,             /* EnumerateProcessesW */
239
  FreeRDP_WTSEnumerateProcessesA,             /* EnumerateProcessesA */
240
  FreeRDP_WTSTerminateProcess,                /* TerminateProcess */
241
  FreeRDP_WTSQuerySessionInformationW,        /* QuerySessionInformationW */
242
  FreeRDP_WTSQuerySessionInformationA,        /* QuerySessionInformationA */
243
  FreeRDP_WTSQueryUserConfigW,                /* QueryUserConfigW */
244
  FreeRDP_WTSQueryUserConfigA,                /* QueryUserConfigA */
245
  FreeRDP_WTSSetUserConfigW,                  /* SetUserConfigW */
246
  FreeRDP_WTSSetUserConfigA,                  /* SetUserConfigA */
247
  FreeRDP_WTSSendMessageW,                    /* SendMessageW */
248
  FreeRDP_WTSSendMessageA,                    /* SendMessageA */
249
  FreeRDP_WTSDisconnectSession,               /* DisconnectSession */
250
  FreeRDP_WTSLogoffSession,                   /* LogoffSession */
251
  FreeRDP_WTSShutdownSystem,                  /* ShutdownSystem */
252
  FreeRDP_WTSWaitSystemEvent,                 /* WaitSystemEvent */
253
  FreeRDP_WTSVirtualChannelOpen,              /* VirtualChannelOpen */
254
  FreeRDP_WTSVirtualChannelOpenEx,            /* VirtualChannelOpenEx */
255
  FreeRDP_WTSVirtualChannelClose,             /* VirtualChannelClose */
256
  FreeRDP_WTSVirtualChannelRead,              /* VirtualChannelRead */
257
  FreeRDP_WTSVirtualChannelWrite,             /* VirtualChannelWrite */
258
  FreeRDP_WTSVirtualChannelPurgeInput,        /* VirtualChannelPurgeInput */
259
  FreeRDP_WTSVirtualChannelPurgeOutput,       /* VirtualChannelPurgeOutput */
260
  FreeRDP_WTSVirtualChannelQuery,             /* VirtualChannelQuery */
261
  FreeRDP_WTSFreeMemory,                      /* FreeMemory */
262
  FreeRDP_WTSRegisterSessionNotification,     /* RegisterSessionNotification */
263
  FreeRDP_WTSUnRegisterSessionNotification,   /* UnRegisterSessionNotification */
264
  FreeRDP_WTSRegisterSessionNotificationEx,   /* RegisterSessionNotificationEx */
265
  FreeRDP_WTSUnRegisterSessionNotificationEx, /* UnRegisterSessionNotificationEx */
266
  FreeRDP_WTSQueryUserToken,                  /* QueryUserToken */
267
  FreeRDP_WTSFreeMemoryExW,                   /* FreeMemoryExW */
268
  FreeRDP_WTSFreeMemoryExA,                   /* FreeMemoryExA */
269
  FreeRDP_WTSEnumerateProcessesExW,           /* EnumerateProcessesExW */
270
  FreeRDP_WTSEnumerateProcessesExA,           /* EnumerateProcessesExA */
271
  FreeRDP_WTSEnumerateListenersW,             /* EnumerateListenersW */
272
  FreeRDP_WTSEnumerateListenersA,             /* EnumerateListenersA */
273
  FreeRDP_WTSQueryListenerConfigW,            /* QueryListenerConfigW */
274
  FreeRDP_WTSQueryListenerConfigA,            /* QueryListenerConfigA */
275
  FreeRDP_WTSCreateListenerW,                 /* CreateListenerW */
276
  FreeRDP_WTSCreateListenerA,                 /* CreateListenerA */
277
  FreeRDP_WTSSetListenerSecurityW,            /* SetListenerSecurityW */
278
  FreeRDP_WTSSetListenerSecurityA,            /* SetListenerSecurityA */
279
  FreeRDP_WTSGetListenerSecurityW,            /* GetListenerSecurityW */
280
  FreeRDP_WTSGetListenerSecurityA,            /* GetListenerSecurityA */
281
  FreeRDP_WTSEnableChildSessions,             /* EnableChildSessions */
282
  FreeRDP_WTSIsChildSessionsEnabled,          /* IsChildSessionsEnabled */
283
  FreeRDP_WTSGetChildSessionId,               /* GetChildSessionId */
284
  FreeRDP_WTSGetActiveConsoleSessionId,       /* GetActiveConsoleSessionId */
285
  FreeRDP_WTSLogonUser,
286
  FreeRDP_WTSLogoffUser,
287
  FreeRDP_WTSStartRemoteControlSessionExW,
288
  FreeRDP_WTSStartRemoteControlSessionExA
289
};
290
291
const WtsApiFunctionTable* FreeRDP_InitWtsApi(void)
292
0
{
293
0
  return &FreeRDP_WtsApiFunctionTable;
294
0
}
295
296
BOOL freerdp_channel_send_packet(rdpRdp* rdp, UINT16 channelId, size_t totalSize, UINT32 flags,
297
                                 const BYTE* data, size_t chunkSize)
298
0
{
299
0
  if (totalSize > UINT32_MAX)
300
0
    return FALSE;
301
302
0
  UINT16 sec_flags = 0;
303
0
  wStream* s = rdp_send_stream_init(rdp, &sec_flags);
304
305
0
  if (!s)
306
0
    return FALSE;
307
308
0
  if (!Stream_EnsureRemainingCapacity(s, chunkSize + 8))
309
0
  {
310
0
    Stream_Release(s);
311
0
    return FALSE;
312
0
  }
313
314
0
  Stream_Write_UINT32(s, (UINT32)totalSize);
315
0
  Stream_Write_UINT32(s, flags);
316
317
0
  Stream_Write(s, data, chunkSize);
318
319
  /* WLog_DBG(TAG, "sending data (flags=0x%x size=%d)",  flags, size); */
320
0
  return rdp_send(rdp, s, channelId, sec_flags);
321
0
}