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