FreeRDP
Loading...
Searching...
No Matches
rdpdr_capabilities.c
1
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#define RDPDR_CAPABILITY_HEADER_LENGTH 8
40
41/* Output device direction general capability set */
42static BOOL rdpdr_write_general_capset(rdpdrPlugin* rdpdr, wStream* s)
43{
44 WINPR_ASSERT(rdpdr);
45 const RDPDR_CAPABILITY_HEADER header = { CAP_GENERAL_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH + 36,
46 GENERAL_CAPABILITY_VERSION_02 };
47
48 const UINT32 ioCode1 = rdpdr->clientIOCode1 & rdpdr->serverIOCode1;
49 const UINT32 ioCode2 = rdpdr->clientIOCode2 & rdpdr->serverIOCode2;
50
51 if (rdpdr_write_capset_header(rdpdr->log, s, &header) != CHANNEL_RC_OK)
52 return FALSE;
53
54 if (!Stream_EnsureRemainingCapacity(s, 36))
55 return FALSE;
56
57 Stream_Write_UINT32(s, rdpdr->clientOsType); /* osType, ignored on receipt */
58 Stream_Write_UINT32(s, rdpdr->clientOsVersion); /* osVersion, unused and must be set to zero */
59 Stream_Write_UINT16(s, rdpdr->clientVersionMajor); /* protocolMajorVersion, must be set to 1 */
60 Stream_Write_UINT16(s, rdpdr->clientVersionMinor); /* protocolMinorVersion */
61 Stream_Write_UINT32(s, ioCode1); /* ioCode1 */
62 Stream_Write_UINT32(s, ioCode2); /* ioCode2, must be set to zero, reserved for future use */
63 Stream_Write_UINT32(s, rdpdr->clientExtendedPDU); /* extendedPDU */
64 Stream_Write_UINT32(s, rdpdr->clientExtraFlags1); /* extraFlags1 */
65 Stream_Write_UINT32(
66 s,
67 rdpdr->clientExtraFlags2); /* extraFlags2, must be set to zero, reserved for future use */
68 Stream_Write_UINT32(
69 s, rdpdr->clientSpecialTypeDeviceCap); /* SpecialTypeDeviceCap, number of special devices to
70 be redirected before logon */
71 return TRUE;
72}
73
74/* Process device direction general capability set */
75static UINT rdpdr_process_general_capset(rdpdrPlugin* rdpdr, wStream* s,
76 const RDPDR_CAPABILITY_HEADER* header)
77{
78 WINPR_ASSERT(header);
79
80 const BOOL gotV1 = header->Version == GENERAL_CAPABILITY_VERSION_01;
81 const size_t expect = gotV1 ? 32 : 36;
82 if (header->CapabilityLength != expect)
83 {
84 WLog_Print(rdpdr->log, WLOG_ERROR,
85 "CAP_GENERAL_TYPE::CapabilityLength expected %" PRIuz ", got %" PRIu32, expect,
86 header->CapabilityLength);
87 return ERROR_INVALID_DATA;
88 }
89 if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, expect))
90 return ERROR_INVALID_DATA;
91
92 rdpdr->serverOsType = Stream_Get_UINT32(s); /* osType, ignored on receipt */
93 rdpdr->serverOsVersion = Stream_Get_UINT32(s); /* osVersion, unused and must be set to zero */
94 rdpdr->serverVersionMajor = Stream_Get_UINT16(s); /* protocolMajorVersion, must be set to 1 */
95 rdpdr->serverVersionMinor = Stream_Get_UINT16(s); /* protocolMinorVersion */
96 rdpdr->serverIOCode1 = Stream_Get_UINT32(s); /* ioCode1 */
97 rdpdr->serverIOCode2 =
98 Stream_Get_UINT32(s); /* ioCode2, must be set to zero, reserved for future use */
99 rdpdr->serverExtendedPDU = Stream_Get_UINT32(s); /* extendedPDU */
100 rdpdr->serverExtraFlags1 = Stream_Get_UINT32(s); /* extraFlags1 */
101 rdpdr->serverExtraFlags2 =
102 Stream_Get_UINT32(s); /* extraFlags2, must be set to zero, reserved for future use */
103 if (gotV1)
104 rdpdr->serverSpecialTypeDeviceCap = 0;
105 else
106 rdpdr->serverSpecialTypeDeviceCap = Stream_Get_UINT32(
107 s); /* SpecialTypeDeviceCap, number of special devices to
108 be redirected before logon */
109 return CHANNEL_RC_OK;
110}
111
112/* Output printer direction capability set */
113static BOOL rdpdr_write_printer_capset(rdpdrPlugin* rdpdr, wStream* s)
114{
115 WINPR_UNUSED(rdpdr);
116 const RDPDR_CAPABILITY_HEADER header = { CAP_PRINTER_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH,
117 PRINT_CAPABILITY_VERSION_01 };
118 return rdpdr_write_capset_header(rdpdr->log, s, &header) == CHANNEL_RC_OK;
119}
120
121/* Process printer direction capability set */
122static UINT rdpdr_process_printer_capset(WINPR_ATTR_UNUSED rdpdrPlugin* rdpdr, wStream* s,
123 const RDPDR_CAPABILITY_HEADER* header)
124{
125 WINPR_ASSERT(header);
126 if (!Stream_SafeSeek(s, header->CapabilityLength))
127 return ERROR_BAD_LENGTH;
128 return CHANNEL_RC_OK;
129}
130
131/* Output port redirection capability set */
132static BOOL rdpdr_write_port_capset(rdpdrPlugin* rdpdr, wStream* s)
133{
134 WINPR_UNUSED(rdpdr);
135 const RDPDR_CAPABILITY_HEADER header = { CAP_PORT_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH,
136 PORT_CAPABILITY_VERSION_01 };
137 return rdpdr_write_capset_header(rdpdr->log, s, &header) == CHANNEL_RC_OK;
138}
139
140/* Process port redirection capability set */
141static UINT rdpdr_process_port_capset(WINPR_ATTR_UNUSED rdpdrPlugin* rdpdr, wStream* s,
142 const RDPDR_CAPABILITY_HEADER* header)
143{
144 WINPR_ASSERT(header);
145 Stream_Seek(s, header->CapabilityLength);
146 return CHANNEL_RC_OK;
147}
148
149/* Output drive redirection capability set */
150static BOOL rdpdr_write_drive_capset(rdpdrPlugin* rdpdr, wStream* s)
151{
152 WINPR_UNUSED(rdpdr);
153 const RDPDR_CAPABILITY_HEADER header = { CAP_DRIVE_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH,
154 DRIVE_CAPABILITY_VERSION_02 };
155 return rdpdr_write_capset_header(rdpdr->log, s, &header) == CHANNEL_RC_OK;
156}
157
158/* Process drive redirection capability set */
159static UINT rdpdr_process_drive_capset(WINPR_ATTR_UNUSED rdpdrPlugin* rdpdr, wStream* s,
160 const RDPDR_CAPABILITY_HEADER* header)
161{
162 WINPR_ASSERT(header);
163 Stream_Seek(s, header->CapabilityLength);
164 return CHANNEL_RC_OK;
165}
166
167/* Output smart card redirection capability set */
168static BOOL rdpdr_write_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s)
169{
170 WINPR_UNUSED(rdpdr);
171 const RDPDR_CAPABILITY_HEADER header = { CAP_SMARTCARD_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH,
172 SMARTCARD_CAPABILITY_VERSION_01 };
173 return rdpdr_write_capset_header(rdpdr->log, s, &header) == CHANNEL_RC_OK;
174}
175
176/* Process smartcard redirection capability set */
177static UINT rdpdr_process_smartcard_capset(WINPR_ATTR_UNUSED rdpdrPlugin* rdpdr, wStream* s,
178 const RDPDR_CAPABILITY_HEADER* header)
179{
180 WINPR_ASSERT(header);
181 Stream_Seek(s, header->CapabilityLength);
182 return CHANNEL_RC_OK;
183}
184
185UINT rdpdr_process_capability_request(rdpdrPlugin* rdpdr, wStream* s)
186{
187 UINT status = CHANNEL_RC_OK;
188 UINT16 numCapabilities = 0;
189
190 if (!rdpdr || !s)
191 return CHANNEL_RC_NULL_DATA;
192
193 if (!rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_CLIENT_CAPS))
194 return ERROR_INVALID_STATE;
195
196 if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 4))
197 return ERROR_INVALID_DATA;
198
199 Stream_Read_UINT16(s, numCapabilities);
200 Stream_Seek(s, 2); /* pad (2 bytes) */
201
202 memset(rdpdr->capabilities, 0, sizeof(rdpdr->capabilities));
203 for (UINT16 i = 0; i < numCapabilities; i++)
204 {
205 RDPDR_CAPABILITY_HEADER header = WINPR_C_ARRAY_INIT;
206 UINT error = rdpdr_read_capset_header(rdpdr->log, s, &header);
207 if (error != CHANNEL_RC_OK)
208 return error;
209
210 switch (header.CapabilityType)
211 {
212 case CAP_GENERAL_TYPE:
213 rdpdr->capabilities[header.CapabilityType] = TRUE;
214 status = rdpdr_process_general_capset(rdpdr, s, &header);
215 break;
216
217 case CAP_PRINTER_TYPE:
218 rdpdr->capabilities[header.CapabilityType] = TRUE;
219 status = rdpdr_process_printer_capset(rdpdr, s, &header);
220 break;
221
222 case CAP_PORT_TYPE:
223 rdpdr->capabilities[header.CapabilityType] = TRUE;
224 status = rdpdr_process_port_capset(rdpdr, s, &header);
225 break;
226
227 case CAP_DRIVE_TYPE:
228 rdpdr->capabilities[header.CapabilityType] = TRUE;
229 status = rdpdr_process_drive_capset(rdpdr, s, &header);
230 break;
231
232 case CAP_SMARTCARD_TYPE:
233 rdpdr->capabilities[header.CapabilityType] = TRUE;
234 status = rdpdr_process_smartcard_capset(rdpdr, s, &header);
235 break;
236
237 default:
238 break;
239 }
240
241 if (status != CHANNEL_RC_OK)
242 return status;
243 }
244
245 return CHANNEL_RC_OK;
246}
247
253UINT rdpdr_send_capability_response(rdpdrPlugin* rdpdr)
254{
255 WINPR_ASSERT(rdpdr);
256 WINPR_ASSERT(rdpdr->rdpcontext);
257
258 rdpSettings* settings = rdpdr->rdpcontext->settings;
259 WINPR_ASSERT(settings);
260
261 wStream* s = StreamPool_Take(rdpdr->pool, 256);
262
263 if (!s)
264 {
265 WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!");
266 return CHANNEL_RC_NO_MEMORY;
267 }
268
269 const RDPDR_DEVICE* cdrives =
270 freerdp_device_collection_find_type(settings, RDPDR_DTYP_FILESYSTEM);
271 const RDPDR_DEVICE* cserial = freerdp_device_collection_find_type(settings, RDPDR_DTYP_SERIAL);
272 const RDPDR_DEVICE* cparallel =
273 freerdp_device_collection_find_type(settings, RDPDR_DTYP_PARALLEL);
274 const RDPDR_DEVICE* csmart =
275 freerdp_device_collection_find_type(settings, RDPDR_DTYP_SMARTCARD);
276 const RDPDR_DEVICE* cprinter = freerdp_device_collection_find_type(settings, RDPDR_DTYP_PRINT);
277
278 /* Only send capabilities the server announced */
279 const BOOL drives = cdrives && rdpdr->capabilities[CAP_DRIVE_TYPE];
280 const BOOL serial = cserial && rdpdr->capabilities[CAP_PORT_TYPE];
281 const BOOL parallel = cparallel && rdpdr->capabilities[CAP_PORT_TYPE];
282 const BOOL smart = csmart && rdpdr->capabilities[CAP_SMARTCARD_TYPE];
283 const BOOL printer = cprinter && rdpdr->capabilities[CAP_PRINTER_TYPE];
284 UINT16 count = 1;
285 if (drives)
286 count++;
287 if (serial || parallel)
288 count++;
289 if (smart)
290 count++;
291 if (printer)
292 count++;
293
294 Stream_Write_UINT16(s, RDPDR_CTYP_CORE);
295 Stream_Write_UINT16(s, PAKID_CORE_CLIENT_CAPABILITY);
296 Stream_Write_UINT16(s, count); /* numCapabilities */
297 Stream_Write_UINT16(s, 0); /* pad */
298
299 if (!rdpdr_write_general_capset(rdpdr, s))
300 goto fail;
301
302 if (printer)
303 {
304 if (!rdpdr_write_printer_capset(rdpdr, s))
305 goto fail;
306 }
307 if (serial || parallel)
308 {
309 if (!rdpdr_write_port_capset(rdpdr, s))
310 goto fail;
311 }
312 if (drives)
313 {
314 if (!rdpdr_write_drive_capset(rdpdr, s))
315 goto fail;
316 }
317 if (smart)
318 {
319 if (!rdpdr_write_smartcard_capset(rdpdr, s))
320 goto fail;
321 }
322 return rdpdr_send(rdpdr, s);
323
324fail:
325 Stream_Release(s);
326 return ERROR_OUTOFMEMORY;
327}