Coverage Report

Created: 2024-05-20 06:11

/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/utils/rdpdr_utils.h>
34
35
#include "rdpdr_main.h"
36
#include "rdpdr_capabilities.h"
37
38
0
#define RDPDR_CAPABILITY_HEADER_LENGTH 8
39
40
/* Output device direction general capability set */
41
static void rdpdr_write_general_capset(rdpdrPlugin* rdpdr, wStream* s)
42
0
{
43
0
  WINPR_UNUSED(rdpdr);
44
0
  const RDPDR_CAPABILITY_HEADER header = { CAP_GENERAL_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH + 36,
45
0
                                         GENERAL_CAPABILITY_VERSION_02 };
46
47
0
  const UINT32 ioCode1 = rdpdr->clientIOCode1 & rdpdr->serverIOCode1;
48
0
  const UINT32 ioCode2 = rdpdr->clientIOCode2 & rdpdr->serverIOCode2;
49
50
0
  rdpdr_write_capset_header(rdpdr->log, s, &header);
51
0
  Stream_Write_UINT32(s, rdpdr->clientOsType);    /* osType, ignored on receipt */
52
0
  Stream_Write_UINT32(s, rdpdr->clientOsVersion); /* osVersion, unused and must be set to zero */
53
0
  Stream_Write_UINT16(s, rdpdr->clientVersionMajor); /* protocolMajorVersion, must be set to 1 */
54
0
  Stream_Write_UINT16(s, rdpdr->clientVersionMinor); /* protocolMinorVersion */
55
0
  Stream_Write_UINT32(s, ioCode1);                   /* ioCode1 */
56
0
  Stream_Write_UINT32(s, ioCode2); /* ioCode2, must be set to zero, reserved for future use */
57
0
  Stream_Write_UINT32(s, rdpdr->clientExtendedPDU); /* extendedPDU */
58
0
  Stream_Write_UINT32(s, rdpdr->clientExtraFlags1); /* extraFlags1 */
59
0
  Stream_Write_UINT32(
60
0
      s,
61
0
      rdpdr->clientExtraFlags2); /* extraFlags2, must be set to zero, reserved for future use */
62
0
  Stream_Write_UINT32(
63
0
      s, rdpdr->clientSpecialTypeDeviceCap); /* SpecialTypeDeviceCap, number of special devices to
64
                                                be redirected before logon */
65
0
}
66
67
/* Process device direction general capability set */
68
static UINT rdpdr_process_general_capset(rdpdrPlugin* rdpdr, wStream* s,
69
                                         const RDPDR_CAPABILITY_HEADER* header)
70
0
{
71
0
  WINPR_ASSERT(header);
72
73
0
  if (header->CapabilityLength != 36)
74
0
  {
75
0
    WLog_Print(rdpdr->log, WLOG_ERROR,
76
0
               "CAP_GENERAL_TYPE::CapabilityLength expected 36, got %" PRIu32,
77
0
               header->CapabilityLength);
78
0
    return ERROR_INVALID_DATA;
79
0
  }
80
0
  if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 36))
81
0
    return ERROR_INVALID_DATA;
82
83
0
  Stream_Read_UINT32(s, rdpdr->serverOsType);    /* osType, ignored on receipt */
84
0
  Stream_Read_UINT32(s, rdpdr->serverOsVersion); /* osVersion, unused and must be set to zero */
85
0
  Stream_Read_UINT16(s, rdpdr->serverVersionMajor); /* protocolMajorVersion, must be set to 1 */
86
0
  Stream_Read_UINT16(s, rdpdr->serverVersionMinor); /* protocolMinorVersion */
87
0
  Stream_Read_UINT32(s, rdpdr->serverIOCode1);      /* ioCode1 */
88
0
  Stream_Read_UINT32(
89
0
      s, rdpdr->serverIOCode2); /* ioCode2, must be set to zero, reserved for future use */
90
0
  Stream_Read_UINT32(s, rdpdr->serverExtendedPDU); /* extendedPDU */
91
0
  Stream_Read_UINT32(s, rdpdr->serverExtraFlags1); /* extraFlags1 */
92
0
  Stream_Read_UINT32(
93
0
      s,
94
0
      rdpdr->serverExtraFlags2); /* extraFlags2, must be set to zero, reserved for future use */
95
0
  Stream_Read_UINT32(
96
0
      s, rdpdr->serverSpecialTypeDeviceCap); /* SpecialTypeDeviceCap, number of special devices to
97
                                                be redirected before logon */
98
0
  return CHANNEL_RC_OK;
99
0
}
100
101
/* Output printer direction capability set */
102
static void rdpdr_write_printer_capset(rdpdrPlugin* rdpdr, wStream* s)
103
0
{
104
0
  WINPR_UNUSED(rdpdr);
105
0
  const RDPDR_CAPABILITY_HEADER header = { CAP_PRINTER_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH,
106
0
                                         PRINT_CAPABILITY_VERSION_01 };
107
0
  rdpdr_write_capset_header(rdpdr->log, s, &header);
108
0
}
109
110
/* Process printer direction capability set */
111
static UINT rdpdr_process_printer_capset(rdpdrPlugin* rdpdr, wStream* s,
112
                                         const RDPDR_CAPABILITY_HEADER* header)
113
0
{
114
0
  WINPR_ASSERT(header);
115
0
  Stream_Seek(s, header->CapabilityLength);
116
0
  return CHANNEL_RC_OK;
117
0
}
118
119
/* Output port redirection capability set */
120
static void rdpdr_write_port_capset(rdpdrPlugin* rdpdr, wStream* s)
121
0
{
122
0
  WINPR_UNUSED(rdpdr);
123
0
  const RDPDR_CAPABILITY_HEADER header = { CAP_PORT_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH,
124
0
                                         PORT_CAPABILITY_VERSION_01 };
125
0
  rdpdr_write_capset_header(rdpdr->log, s, &header);
126
0
}
127
128
/* Process port redirection capability set */
129
static UINT rdpdr_process_port_capset(rdpdrPlugin* rdpdr, wStream* s,
130
                                      const RDPDR_CAPABILITY_HEADER* header)
131
0
{
132
0
  WINPR_ASSERT(header);
133
0
  Stream_Seek(s, header->CapabilityLength);
134
0
  return CHANNEL_RC_OK;
135
0
}
136
137
/* Output drive redirection capability set */
138
static void rdpdr_write_drive_capset(rdpdrPlugin* rdpdr, wStream* s)
139
0
{
140
0
  WINPR_UNUSED(rdpdr);
141
0
  const RDPDR_CAPABILITY_HEADER header = { CAP_DRIVE_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH,
142
0
                                         DRIVE_CAPABILITY_VERSION_02 };
143
0
  rdpdr_write_capset_header(rdpdr->log, s, &header);
144
0
}
145
146
/* Process drive redirection capability set */
147
static UINT rdpdr_process_drive_capset(rdpdrPlugin* rdpdr, wStream* s,
148
                                       const RDPDR_CAPABILITY_HEADER* header)
149
0
{
150
0
  WINPR_ASSERT(header);
151
0
  Stream_Seek(s, header->CapabilityLength);
152
0
  return CHANNEL_RC_OK;
153
0
}
154
155
/* Output smart card redirection capability set */
156
static void rdpdr_write_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s)
157
0
{
158
0
  WINPR_UNUSED(rdpdr);
159
0
  const RDPDR_CAPABILITY_HEADER header = { CAP_SMARTCARD_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH,
160
0
                                         SMARTCARD_CAPABILITY_VERSION_01 };
161
0
  rdpdr_write_capset_header(rdpdr->log, s, &header);
162
0
}
163
164
/* Process smartcard redirection capability set */
165
static UINT rdpdr_process_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s,
166
                                           const RDPDR_CAPABILITY_HEADER* header)
167
0
{
168
0
  WINPR_ASSERT(header);
169
0
  Stream_Seek(s, header->CapabilityLength);
170
0
  return CHANNEL_RC_OK;
171
0
}
172
173
UINT rdpdr_process_capability_request(rdpdrPlugin* rdpdr, wStream* s)
174
0
{
175
0
  UINT status = CHANNEL_RC_OK;
176
0
  UINT16 numCapabilities = 0;
177
178
0
  if (!rdpdr || !s)
179
0
    return CHANNEL_RC_NULL_DATA;
180
181
0
  WINPR_ASSERT(rdpdr->state == RDPDR_CHANNEL_STATE_SERVER_CAPS);
182
0
  rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_CLIENT_CAPS);
183
184
0
  if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 4))
185
0
    return ERROR_INVALID_DATA;
186
187
0
  Stream_Read_UINT16(s, numCapabilities);
188
0
  Stream_Seek(s, 2); /* pad (2 bytes) */
189
190
0
  for (UINT16 i = 0; i < numCapabilities; i++)
191
0
  {
192
0
    RDPDR_CAPABILITY_HEADER header = { 0 };
193
0
    UINT error = rdpdr_read_capset_header(rdpdr->log, s, &header);
194
0
    if (error != CHANNEL_RC_OK)
195
0
      return error;
196
197
0
    switch (header.CapabilityType)
198
0
    {
199
0
      case CAP_GENERAL_TYPE:
200
0
        status = rdpdr_process_general_capset(rdpdr, s, &header);
201
0
        break;
202
203
0
      case CAP_PRINTER_TYPE:
204
0
        status = rdpdr_process_printer_capset(rdpdr, s, &header);
205
0
        break;
206
207
0
      case CAP_PORT_TYPE:
208
0
        status = rdpdr_process_port_capset(rdpdr, s, &header);
209
0
        break;
210
211
0
      case CAP_DRIVE_TYPE:
212
0
        status = rdpdr_process_drive_capset(rdpdr, s, &header);
213
0
        break;
214
215
0
      case CAP_SMARTCARD_TYPE:
216
0
        status = rdpdr_process_smartcard_capset(rdpdr, s, &header);
217
0
        break;
218
219
0
      default:
220
221
0
        break;
222
0
    }
223
224
0
    if (status != CHANNEL_RC_OK)
225
0
      return status;
226
0
  }
227
228
0
  return CHANNEL_RC_OK;
229
0
}
230
231
/**
232
 * Function description
233
 *
234
 * @return 0 on success, otherwise a Win32 error code
235
 */
236
UINT rdpdr_send_capability_response(rdpdrPlugin* rdpdr)
237
0
{
238
0
  wStream* s = NULL;
239
240
0
  WINPR_ASSERT(rdpdr);
241
0
  s = StreamPool_Take(rdpdr->pool, 256);
242
243
0
  if (!s)
244
0
  {
245
0
    WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!");
246
0
    return CHANNEL_RC_NO_MEMORY;
247
0
  }
248
249
0
  Stream_Write_UINT16(s, RDPDR_CTYP_CORE);
250
0
  Stream_Write_UINT16(s, PAKID_CORE_CLIENT_CAPABILITY);
251
0
  Stream_Write_UINT16(s, 5); /* numCapabilities */
252
0
  Stream_Write_UINT16(s, 0); /* pad */
253
0
  rdpdr_write_general_capset(rdpdr, s);
254
0
  rdpdr_write_printer_capset(rdpdr, s);
255
0
  rdpdr_write_port_capset(rdpdr, s);
256
0
  rdpdr_write_drive_capset(rdpdr, s);
257
0
  rdpdr_write_smartcard_capset(rdpdr, s);
258
0
  return rdpdr_send(rdpdr, s);
259
0
}