FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
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 Stream_Seek(s, header->CapabilityLength);
127 return CHANNEL_RC_OK;
128}
129
130/* Output port redirection capability set */
131static BOOL rdpdr_write_port_capset(rdpdrPlugin* rdpdr, wStream* s)
132{
133 WINPR_UNUSED(rdpdr);
134 const RDPDR_CAPABILITY_HEADER header = { CAP_PORT_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH,
135 PORT_CAPABILITY_VERSION_01 };
136 return rdpdr_write_capset_header(rdpdr->log, s, &header) == CHANNEL_RC_OK;
137}
138
139/* Process port redirection capability set */
140static UINT rdpdr_process_port_capset(WINPR_ATTR_UNUSED rdpdrPlugin* rdpdr, wStream* s,
141 const RDPDR_CAPABILITY_HEADER* header)
142{
143 WINPR_ASSERT(header);
144 Stream_Seek(s, header->CapabilityLength);
145 return CHANNEL_RC_OK;
146}
147
148/* Output drive redirection capability set */
149static BOOL rdpdr_write_drive_capset(rdpdrPlugin* rdpdr, wStream* s)
150{
151 WINPR_UNUSED(rdpdr);
152 const RDPDR_CAPABILITY_HEADER header = { CAP_DRIVE_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH,
153 DRIVE_CAPABILITY_VERSION_02 };
154 return rdpdr_write_capset_header(rdpdr->log, s, &header) == CHANNEL_RC_OK;
155}
156
157/* Process drive redirection capability set */
158static UINT rdpdr_process_drive_capset(WINPR_ATTR_UNUSED rdpdrPlugin* rdpdr, wStream* s,
159 const RDPDR_CAPABILITY_HEADER* header)
160{
161 WINPR_ASSERT(header);
162 Stream_Seek(s, header->CapabilityLength);
163 return CHANNEL_RC_OK;
164}
165
166/* Output smart card redirection capability set */
167static BOOL rdpdr_write_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s)
168{
169 WINPR_UNUSED(rdpdr);
170 const RDPDR_CAPABILITY_HEADER header = { CAP_SMARTCARD_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH,
171 SMARTCARD_CAPABILITY_VERSION_01 };
172 return rdpdr_write_capset_header(rdpdr->log, s, &header) == CHANNEL_RC_OK;
173}
174
175/* Process smartcard redirection capability set */
176static UINT rdpdr_process_smartcard_capset(WINPR_ATTR_UNUSED rdpdrPlugin* rdpdr, wStream* s,
177 const RDPDR_CAPABILITY_HEADER* header)
178{
179 WINPR_ASSERT(header);
180 Stream_Seek(s, header->CapabilityLength);
181 return CHANNEL_RC_OK;
182}
183
184UINT rdpdr_process_capability_request(rdpdrPlugin* rdpdr, wStream* s)
185{
186 UINT status = CHANNEL_RC_OK;
187 UINT16 numCapabilities = 0;
188
189 if (!rdpdr || !s)
190 return CHANNEL_RC_NULL_DATA;
191
192 WINPR_ASSERT(rdpdr->state == RDPDR_CHANNEL_STATE_SERVER_CAPS);
193 rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_CLIENT_CAPS);
194
195 if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 4))
196 return ERROR_INVALID_DATA;
197
198 Stream_Read_UINT16(s, numCapabilities);
199 Stream_Seek(s, 2); /* pad (2 bytes) */
200
201 memset(rdpdr->capabilities, 0, sizeof(rdpdr->capabilities));
202 for (UINT16 i = 0; i < numCapabilities; i++)
203 {
204 RDPDR_CAPABILITY_HEADER header = { 0 };
205 UINT error = rdpdr_read_capset_header(rdpdr->log, s, &header);
206 if (error != CHANNEL_RC_OK)
207 return error;
208
209 switch (header.CapabilityType)
210 {
211 case CAP_GENERAL_TYPE:
212 rdpdr->capabilities[header.CapabilityType] = TRUE;
213 status = rdpdr_process_general_capset(rdpdr, s, &header);
214 break;
215
216 case CAP_PRINTER_TYPE:
217 rdpdr->capabilities[header.CapabilityType] = TRUE;
218 status = rdpdr_process_printer_capset(rdpdr, s, &header);
219 break;
220
221 case CAP_PORT_TYPE:
222 rdpdr->capabilities[header.CapabilityType] = TRUE;
223 status = rdpdr_process_port_capset(rdpdr, s, &header);
224 break;
225
226 case CAP_DRIVE_TYPE:
227 rdpdr->capabilities[header.CapabilityType] = TRUE;
228 status = rdpdr_process_drive_capset(rdpdr, s, &header);
229 break;
230
231 case CAP_SMARTCARD_TYPE:
232 rdpdr->capabilities[header.CapabilityType] = TRUE;
233 status = rdpdr_process_smartcard_capset(rdpdr, s, &header);
234 break;
235
236 default:
237 break;
238 }
239
240 if (status != CHANNEL_RC_OK)
241 return status;
242 }
243
244 return CHANNEL_RC_OK;
245}
246
252UINT rdpdr_send_capability_response(rdpdrPlugin* rdpdr)
253{
254 WINPR_ASSERT(rdpdr);
255 WINPR_ASSERT(rdpdr->rdpcontext);
256
257 rdpSettings* settings = rdpdr->rdpcontext->settings;
258 WINPR_ASSERT(settings);
259
260 wStream* s = StreamPool_Take(rdpdr->pool, 256);
261
262 if (!s)
263 {
264 WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!");
265 return CHANNEL_RC_NO_MEMORY;
266 }
267
268 const RDPDR_DEVICE* cdrives =
269 freerdp_device_collection_find_type(settings, RDPDR_DTYP_FILESYSTEM);
270 const RDPDR_DEVICE* cserial = freerdp_device_collection_find_type(settings, RDPDR_DTYP_SERIAL);
271 const RDPDR_DEVICE* cparallel =
272 freerdp_device_collection_find_type(settings, RDPDR_DTYP_PARALLEL);
273 const RDPDR_DEVICE* csmart =
274 freerdp_device_collection_find_type(settings, RDPDR_DTYP_SMARTCARD);
275 const RDPDR_DEVICE* cprinter = freerdp_device_collection_find_type(settings, RDPDR_DTYP_PRINT);
276
277 /* Only send capabilities the server announced */
278 const BOOL drives = cdrives && rdpdr->capabilities[CAP_DRIVE_TYPE];
279 const BOOL serial = cserial && rdpdr->capabilities[CAP_PORT_TYPE];
280 const BOOL parallel = cparallel && rdpdr->capabilities[CAP_PORT_TYPE];
281 const BOOL smart = csmart && rdpdr->capabilities[CAP_SMARTCARD_TYPE];
282 const BOOL printer = cprinter && rdpdr->capabilities[CAP_PRINTER_TYPE];
283 UINT16 count = 1;
284 if (drives)
285 count++;
286 if (serial || parallel)
287 count++;
288 if (smart)
289 count++;
290 if (printer)
291 count++;
292
293 Stream_Write_UINT16(s, RDPDR_CTYP_CORE);
294 Stream_Write_UINT16(s, PAKID_CORE_CLIENT_CAPABILITY);
295 Stream_Write_UINT16(s, count); /* numCapabilities */
296 Stream_Write_UINT16(s, 0); /* pad */
297
298 if (!rdpdr_write_general_capset(rdpdr, s))
299 goto fail;
300
301 if (printer)
302 {
303 if (!rdpdr_write_printer_capset(rdpdr, s))
304 goto fail;
305 }
306 if (serial || parallel)
307 {
308 if (!rdpdr_write_port_capset(rdpdr, s))
309 goto fail;
310 }
311 if (drives)
312 {
313 if (!rdpdr_write_drive_capset(rdpdr, s))
314 goto fail;
315 }
316 if (smart)
317 {
318 if (!rdpdr_write_smartcard_capset(rdpdr, s))
319 goto fail;
320 }
321 return rdpdr_send(rdpdr, s);
322
323fail:
324 Stream_Release(s);
325 return ERROR_OUTOFMEMORY;
326}