Coverage Report

Created: 2025-07-01 06:46

/src/FreeRDP/channels/rdpdr/client/rdpdr_capabilities.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Device Redirection Virtual Channel
4
 *
5
 * Copyright 2010-2011 Vic Lee
6
 * Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
7
 * Copyright 2015-2016 Thincast Technologies GmbH
8
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
9
 * Copyright 2016 Armin Novak <armin.novak@thincast.com>
10
 *
11
 * Licensed under the Apache License, Version 2.0 (the "License");
12
 * you may not use this file except in compliance with the License.
13
 * You may obtain a copy of the License at
14
 *
15
 *     http://www.apache.org/licenses/LICENSE-2.0
16
 *
17
 * Unless required by applicable law or agreed to in writing, software
18
 * distributed under the License is distributed on an "AS IS" BASIS,
19
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
 * See the License for the specific language governing permissions and
21
 * limitations under the License.
22
 */
23
24
#include <freerdp/config.h>
25
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <string.h>
29
30
#include <winpr/crt.h>
31
#include <winpr/stream.h>
32
33
#include <freerdp/freerdp.h>
34
#include <freerdp/utils/rdpdr_utils.h>
35
36
#include "rdpdr_main.h"
37
#include "rdpdr_capabilities.h"
38
39
0
#define RDPDR_CAPABILITY_HEADER_LENGTH 8
40
41
/* Output device direction general capability set */
42
static BOOL rdpdr_write_general_capset(rdpdrPlugin* rdpdr, wStream* s)
43
0
{
44
0
  WINPR_ASSERT(rdpdr);
45
0
  const RDPDR_CAPABILITY_HEADER header = { CAP_GENERAL_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH + 36,
46
0
                                         GENERAL_CAPABILITY_VERSION_02 };
47
48
0
  const UINT32 ioCode1 = rdpdr->clientIOCode1 & rdpdr->serverIOCode1;
49
0
  const UINT32 ioCode2 = rdpdr->clientIOCode2 & rdpdr->serverIOCode2;
50
51
0
  if (rdpdr_write_capset_header(rdpdr->log, s, &header) != CHANNEL_RC_OK)
52
0
    return FALSE;
53
54
0
  if (!Stream_EnsureRemainingCapacity(s, 36))
55
0
    return FALSE;
56
57
0
  Stream_Write_UINT32(s, rdpdr->clientOsType);    /* osType, ignored on receipt */
58
0
  Stream_Write_UINT32(s, rdpdr->clientOsVersion); /* osVersion, unused and must be set to zero */
59
0
  Stream_Write_UINT16(s, rdpdr->clientVersionMajor); /* protocolMajorVersion, must be set to 1 */
60
0
  Stream_Write_UINT16(s, rdpdr->clientVersionMinor); /* protocolMinorVersion */
61
0
  Stream_Write_UINT32(s, ioCode1);                   /* ioCode1 */
62
0
  Stream_Write_UINT32(s, ioCode2); /* ioCode2, must be set to zero, reserved for future use */
63
0
  Stream_Write_UINT32(s, rdpdr->clientExtendedPDU); /* extendedPDU */
64
0
  Stream_Write_UINT32(s, rdpdr->clientExtraFlags1); /* extraFlags1 */
65
0
  Stream_Write_UINT32(
66
0
      s,
67
0
      rdpdr->clientExtraFlags2); /* extraFlags2, must be set to zero, reserved for future use */
68
0
  Stream_Write_UINT32(
69
0
      s, rdpdr->clientSpecialTypeDeviceCap); /* SpecialTypeDeviceCap, number of special devices to
70
                                                be redirected before logon */
71
0
  return TRUE;
72
0
}
73
74
/* Process device direction general capability set */
75
static UINT rdpdr_process_general_capset(rdpdrPlugin* rdpdr, wStream* s,
76
                                         const RDPDR_CAPABILITY_HEADER* header)
77
0
{
78
0
  WINPR_ASSERT(header);
79
80
0
  const BOOL gotV1 = header->Version == GENERAL_CAPABILITY_VERSION_01;
81
0
  const size_t expect = gotV1 ? 32 : 36;
82
0
  if (header->CapabilityLength != expect)
83
0
  {
84
0
    WLog_Print(rdpdr->log, WLOG_ERROR,
85
0
               "CAP_GENERAL_TYPE::CapabilityLength expected %" PRIuz ", got %" PRIu32, expect,
86
0
               header->CapabilityLength);
87
0
    return ERROR_INVALID_DATA;
88
0
  }
89
0
  if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, expect))
90
0
    return ERROR_INVALID_DATA;
91
92
0
  rdpdr->serverOsType = Stream_Get_UINT32(s);    /* osType, ignored on receipt */
93
0
  rdpdr->serverOsVersion = Stream_Get_UINT32(s); /* osVersion, unused and must be set to zero */
94
0
  rdpdr->serverVersionMajor = Stream_Get_UINT16(s); /* protocolMajorVersion, must be set to 1 */
95
0
  rdpdr->serverVersionMinor = Stream_Get_UINT16(s); /* protocolMinorVersion */
96
0
  rdpdr->serverIOCode1 = Stream_Get_UINT32(s);      /* ioCode1 */
97
0
  rdpdr->serverIOCode2 =
98
0
      Stream_Get_UINT32(s); /* ioCode2, must be set to zero, reserved for future use */
99
0
  rdpdr->serverExtendedPDU = Stream_Get_UINT32(s); /* extendedPDU */
100
0
  rdpdr->serverExtraFlags1 = Stream_Get_UINT32(s); /* extraFlags1 */
101
0
  rdpdr->serverExtraFlags2 =
102
0
      Stream_Get_UINT32(s); /* extraFlags2, must be set to zero, reserved for future use */
103
0
  if (gotV1)
104
0
    rdpdr->serverSpecialTypeDeviceCap = 0;
105
0
  else
106
0
    rdpdr->serverSpecialTypeDeviceCap = Stream_Get_UINT32(
107
0
        s); /* SpecialTypeDeviceCap, number of special devices to
108
                                                  be redirected before logon */
109
0
  return CHANNEL_RC_OK;
110
0
}
111
112
/* Output printer direction capability set */
113
static BOOL rdpdr_write_printer_capset(rdpdrPlugin* rdpdr, wStream* s)
114
0
{
115
0
  WINPR_UNUSED(rdpdr);
116
0
  const RDPDR_CAPABILITY_HEADER header = { CAP_PRINTER_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH,
117
0
                                         PRINT_CAPABILITY_VERSION_01 };
118
0
  return rdpdr_write_capset_header(rdpdr->log, s, &header) == CHANNEL_RC_OK;
119
0
}
120
121
/* Process printer direction capability set */
122
static UINT rdpdr_process_printer_capset(WINPR_ATTR_UNUSED rdpdrPlugin* rdpdr, wStream* s,
123
                                         const RDPDR_CAPABILITY_HEADER* header)
124
0
{
125
0
  WINPR_ASSERT(header);
126
0
  Stream_Seek(s, header->CapabilityLength);
127
0
  return CHANNEL_RC_OK;
128
0
}
129
130
/* Output port redirection capability set */
131
static BOOL rdpdr_write_port_capset(rdpdrPlugin* rdpdr, wStream* s)
132
0
{
133
0
  WINPR_UNUSED(rdpdr);
134
0
  const RDPDR_CAPABILITY_HEADER header = { CAP_PORT_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH,
135
0
                                         PORT_CAPABILITY_VERSION_01 };
136
0
  return rdpdr_write_capset_header(rdpdr->log, s, &header) == CHANNEL_RC_OK;
137
0
}
138
139
/* Process port redirection capability set */
140
static UINT rdpdr_process_port_capset(WINPR_ATTR_UNUSED rdpdrPlugin* rdpdr, wStream* s,
141
                                      const RDPDR_CAPABILITY_HEADER* header)
142
0
{
143
0
  WINPR_ASSERT(header);
144
0
  Stream_Seek(s, header->CapabilityLength);
145
0
  return CHANNEL_RC_OK;
146
0
}
147
148
/* Output drive redirection capability set */
149
static BOOL rdpdr_write_drive_capset(rdpdrPlugin* rdpdr, wStream* s)
150
0
{
151
0
  WINPR_UNUSED(rdpdr);
152
0
  const RDPDR_CAPABILITY_HEADER header = { CAP_DRIVE_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH,
153
0
                                         DRIVE_CAPABILITY_VERSION_02 };
154
0
  return rdpdr_write_capset_header(rdpdr->log, s, &header) == CHANNEL_RC_OK;
155
0
}
156
157
/* Process drive redirection capability set */
158
static UINT rdpdr_process_drive_capset(WINPR_ATTR_UNUSED rdpdrPlugin* rdpdr, wStream* s,
159
                                       const RDPDR_CAPABILITY_HEADER* header)
160
0
{
161
0
  WINPR_ASSERT(header);
162
0
  Stream_Seek(s, header->CapabilityLength);
163
0
  return CHANNEL_RC_OK;
164
0
}
165
166
/* Output smart card redirection capability set */
167
static BOOL rdpdr_write_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s)
168
0
{
169
0
  WINPR_UNUSED(rdpdr);
170
0
  const RDPDR_CAPABILITY_HEADER header = { CAP_SMARTCARD_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH,
171
0
                                         SMARTCARD_CAPABILITY_VERSION_01 };
172
0
  return rdpdr_write_capset_header(rdpdr->log, s, &header) == CHANNEL_RC_OK;
173
0
}
174
175
/* Process smartcard redirection capability set */
176
static UINT rdpdr_process_smartcard_capset(WINPR_ATTR_UNUSED rdpdrPlugin* rdpdr, wStream* s,
177
                                           const RDPDR_CAPABILITY_HEADER* header)
178
0
{
179
0
  WINPR_ASSERT(header);
180
0
  Stream_Seek(s, header->CapabilityLength);
181
0
  return CHANNEL_RC_OK;
182
0
}
183
184
UINT rdpdr_process_capability_request(rdpdrPlugin* rdpdr, wStream* s)
185
0
{
186
0
  UINT status = CHANNEL_RC_OK;
187
0
  UINT16 numCapabilities = 0;
188
189
0
  if (!rdpdr || !s)
190
0
    return CHANNEL_RC_NULL_DATA;
191
192
0
  rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_CLIENT_CAPS);
193
194
0
  if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 4))
195
0
    return ERROR_INVALID_DATA;
196
197
0
  Stream_Read_UINT16(s, numCapabilities);
198
0
  Stream_Seek(s, 2); /* pad (2 bytes) */
199
200
0
  memset(rdpdr->capabilities, 0, sizeof(rdpdr->capabilities));
201
0
  for (UINT16 i = 0; i < numCapabilities; i++)
202
0
  {
203
0
    RDPDR_CAPABILITY_HEADER header = { 0 };
204
0
    UINT error = rdpdr_read_capset_header(rdpdr->log, s, &header);
205
0
    if (error != CHANNEL_RC_OK)
206
0
      return error;
207
208
0
    switch (header.CapabilityType)
209
0
    {
210
0
      case CAP_GENERAL_TYPE:
211
0
        rdpdr->capabilities[header.CapabilityType] = TRUE;
212
0
        status = rdpdr_process_general_capset(rdpdr, s, &header);
213
0
        break;
214
215
0
      case CAP_PRINTER_TYPE:
216
0
        rdpdr->capabilities[header.CapabilityType] = TRUE;
217
0
        status = rdpdr_process_printer_capset(rdpdr, s, &header);
218
0
        break;
219
220
0
      case CAP_PORT_TYPE:
221
0
        rdpdr->capabilities[header.CapabilityType] = TRUE;
222
0
        status = rdpdr_process_port_capset(rdpdr, s, &header);
223
0
        break;
224
225
0
      case CAP_DRIVE_TYPE:
226
0
        rdpdr->capabilities[header.CapabilityType] = TRUE;
227
0
        status = rdpdr_process_drive_capset(rdpdr, s, &header);
228
0
        break;
229
230
0
      case CAP_SMARTCARD_TYPE:
231
0
        rdpdr->capabilities[header.CapabilityType] = TRUE;
232
0
        status = rdpdr_process_smartcard_capset(rdpdr, s, &header);
233
0
        break;
234
235
0
      default:
236
0
        break;
237
0
    }
238
239
0
    if (status != CHANNEL_RC_OK)
240
0
      return status;
241
0
  }
242
243
0
  return CHANNEL_RC_OK;
244
0
}
245
246
/**
247
 * Function description
248
 *
249
 * @return 0 on success, otherwise a Win32 error code
250
 */
251
UINT rdpdr_send_capability_response(rdpdrPlugin* rdpdr)
252
0
{
253
0
  WINPR_ASSERT(rdpdr);
254
0
  WINPR_ASSERT(rdpdr->rdpcontext);
255
256
0
  rdpSettings* settings = rdpdr->rdpcontext->settings;
257
0
  WINPR_ASSERT(settings);
258
259
0
  wStream* s = StreamPool_Take(rdpdr->pool, 256);
260
261
0
  if (!s)
262
0
  {
263
0
    WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!");
264
0
    return CHANNEL_RC_NO_MEMORY;
265
0
  }
266
267
0
  const RDPDR_DEVICE* cdrives =
268
0
      freerdp_device_collection_find_type(settings, RDPDR_DTYP_FILESYSTEM);
269
0
  const RDPDR_DEVICE* cserial = freerdp_device_collection_find_type(settings, RDPDR_DTYP_SERIAL);
270
0
  const RDPDR_DEVICE* cparallel =
271
0
      freerdp_device_collection_find_type(settings, RDPDR_DTYP_PARALLEL);
272
0
  const RDPDR_DEVICE* csmart =
273
0
      freerdp_device_collection_find_type(settings, RDPDR_DTYP_SMARTCARD);
274
0
  const RDPDR_DEVICE* cprinter = freerdp_device_collection_find_type(settings, RDPDR_DTYP_PRINT);
275
276
  /* Only send capabilities the server announced */
277
0
  const BOOL drives = cdrives && rdpdr->capabilities[CAP_DRIVE_TYPE];
278
0
  const BOOL serial = cserial && rdpdr->capabilities[CAP_PORT_TYPE];
279
0
  const BOOL parallel = cparallel && rdpdr->capabilities[CAP_PORT_TYPE];
280
0
  const BOOL smart = csmart && rdpdr->capabilities[CAP_SMARTCARD_TYPE];
281
0
  const BOOL printer = cprinter && rdpdr->capabilities[CAP_PRINTER_TYPE];
282
0
  UINT16 count = 1;
283
0
  if (drives)
284
0
    count++;
285
0
  if (serial || parallel)
286
0
    count++;
287
0
  if (smart)
288
0
    count++;
289
0
  if (printer)
290
0
    count++;
291
292
0
  Stream_Write_UINT16(s, RDPDR_CTYP_CORE);
293
0
  Stream_Write_UINT16(s, PAKID_CORE_CLIENT_CAPABILITY);
294
0
  Stream_Write_UINT16(s, count); /* numCapabilities */
295
0
  Stream_Write_UINT16(s, 0); /* pad */
296
297
0
  if (!rdpdr_write_general_capset(rdpdr, s))
298
0
    goto fail;
299
300
0
  if (printer)
301
0
  {
302
0
    if (!rdpdr_write_printer_capset(rdpdr, s))
303
0
      goto fail;
304
0
  }
305
0
  if (serial || parallel)
306
0
  {
307
0
    if (!rdpdr_write_port_capset(rdpdr, s))
308
0
      goto fail;
309
0
  }
310
0
  if (drives)
311
0
  {
312
0
    if (!rdpdr_write_drive_capset(rdpdr, s))
313
0
      goto fail;
314
0
  }
315
0
  if (smart)
316
0
  {
317
0
    if (!rdpdr_write_smartcard_capset(rdpdr, s))
318
0
      goto fail;
319
0
  }
320
0
  return rdpdr_send(rdpdr, s);
321
322
0
fail:
323
0
  Stream_Release(s);
324
0
  return ERROR_OUTOFMEMORY;
325
0
}