1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #include "channels/common-svc.h"
21 #include "channels/rdpdr/rdpdr-fs-messages-dir-info.h"
22 #include "channels/rdpdr/rdpdr-fs-messages-file-info.h"
23 #include "channels/rdpdr/rdpdr-fs-messages-vol-info.h"
24 #include "channels/rdpdr/rdpdr-fs-messages.h"
25 #include "channels/rdpdr/rdpdr.h"
26 #include "download.h"
27 #include "fs.h"
28 #include "unicode.h"
29
30 #include <freerdp/channels/rdpdr.h>
31 #include <guacamole/client.h>
32 #include <winpr/nt.h>
33 #include <winpr/stream.h>
34 #include <winpr/wtypes.h>
35
36 #include <stdint.h>
37 #include <stdlib.h>
38 #include <string.h>
39
guac_rdpdr_fs_process_create(guac_rdp_common_svc * svc,guac_rdpdr_device * device,guac_rdpdr_iorequest * iorequest,wStream * input_stream)40 void guac_rdpdr_fs_process_create(guac_rdp_common_svc* svc,
41 guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
42 wStream* input_stream) {
43
44 wStream* output_stream;
45 int file_id;
46
47 int desired_access, file_attributes;
48 int create_disposition, create_options, path_length;
49 char path[GUAC_RDP_FS_MAX_PATH];
50
51 /* Check remaining stream data prior to reading. */
52 if (Stream_GetRemainingLength(input_stream) < 32) {
53 guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Create Drive "
54 "Request PDU does not contain the expected number of bytes. "
55 "Drive redirection may not work as expected.");
56 return;
57 }
58
59 /* Read "create" information */
60 Stream_Read_UINT32(input_stream, desired_access);
61 Stream_Seek_UINT64(input_stream); /* allocation size */
62 Stream_Read_UINT32(input_stream, file_attributes);
63 Stream_Seek_UINT32(input_stream); /* shared access */
64 Stream_Read_UINT32(input_stream, create_disposition);
65 Stream_Read_UINT32(input_stream, create_options);
66 Stream_Read_UINT32(input_stream, path_length);
67
68 /* Check to make sure the stream contains path_length bytes. */
69 if(Stream_GetRemainingLength(input_stream) < path_length) {
70 guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Create Drive "
71 "Request PDU does not contain the expected number of bytes. "
72 "Drive redirection may not work as expected.");
73 return;
74 }
75
76 /* Convert path to UTF-8 */
77 guac_rdp_utf16_to_utf8(Stream_Pointer(input_stream), path_length/2 - 1,
78 path, sizeof(path));
79
80 /* Open file */
81 file_id = guac_rdp_fs_open((guac_rdp_fs*) device->data, path,
82 desired_access, file_attributes,
83 create_disposition, create_options);
84
85 guac_client_log(svc->client, GUAC_LOG_DEBUG,
86 "%s: [file_id=%i] "
87 "desired_access=0x%x, file_attributes=0x%x, "
88 "create_disposition=0x%x, create_options=0x%x, path=\"%s\"",
89 __func__, file_id,
90 desired_access, file_attributes,
91 create_disposition, create_options, path);
92
93 /* If an error occurred, notify server */
94 if (file_id < 0) {
95 guac_client_log(svc->client, GUAC_LOG_ERROR,
96 "File open refused (%i): \"%s\"", file_id, path);
97
98 output_stream = guac_rdpdr_new_io_completion(device,
99 iorequest->completion_id, guac_rdp_fs_get_status(file_id), 5);
100 Stream_Write_UINT32(output_stream, 0); /* fileId */
101 Stream_Write_UINT8(output_stream, 0); /* information */
102 }
103
104 /* Otherwise, open succeeded */
105 else {
106
107 guac_rdp_fs_file* file;
108
109 output_stream = guac_rdpdr_new_io_completion(device,
110 iorequest->completion_id, STATUS_SUCCESS, 5);
111 Stream_Write_UINT32(output_stream, file_id); /* fileId */
112 Stream_Write_UINT8(output_stream, 0); /* information */
113
114 /* Create \Download if it doesn't exist */
115 file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, file_id);
116 if (file != NULL && strcmp(file->absolute_path, "\\") == 0) {
117
118 /* Only create Download folder if downloads are enabled. */
119 if (!((guac_rdp_fs*) device->data)->disable_download) {
120 int download_id =
121 guac_rdp_fs_open((guac_rdp_fs*) device->data, "\\Download",
122 GENERIC_READ, 0, FILE_OPEN_IF, FILE_DIRECTORY_FILE);
123
124 if (download_id >= 0)
125 guac_rdp_fs_close((guac_rdp_fs*) device->data, download_id);
126 }
127
128 }
129
130 }
131
132 guac_rdp_common_svc_write(svc, output_stream);
133
134 }
135
guac_rdpdr_fs_process_read(guac_rdp_common_svc * svc,guac_rdpdr_device * device,guac_rdpdr_iorequest * iorequest,wStream * input_stream)136 void guac_rdpdr_fs_process_read(guac_rdp_common_svc* svc,
137 guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
138 wStream* input_stream) {
139
140 UINT32 length;
141 UINT64 offset;
142 char* buffer;
143 int bytes_read;
144
145 wStream* output_stream;
146
147 /* Check remaining bytes before reading stream. */
148 if (Stream_GetRemainingLength(input_stream) < 12) {
149 guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Drive Read "
150 "Request PDU does not contain the expected number of bytes. "
151 "Drive redirection may not work as expected.");
152 return;
153 }
154
155 /* Read packet */
156 Stream_Read_UINT32(input_stream, length);
157 Stream_Read_UINT64(input_stream, offset);
158
159 guac_client_log(svc->client, GUAC_LOG_DEBUG,
160 "%s: [file_id=%i] length=%i, offset=%" PRIu64,
161 __func__, iorequest->file_id, length, (uint64_t) offset);
162
163 /* Ensure buffer size does not exceed a safe maximum */
164 if (length > GUAC_RDP_MAX_READ_BUFFER)
165 length = GUAC_RDP_MAX_READ_BUFFER;
166
167 /* Allocate buffer */
168 buffer = malloc(length);
169
170 /* Attempt read */
171 bytes_read = guac_rdp_fs_read((guac_rdp_fs*) device->data,
172 iorequest->file_id, offset, buffer, length);
173
174 /* If error, return invalid parameter */
175 if (bytes_read < 0) {
176 output_stream = guac_rdpdr_new_io_completion(device,
177 iorequest->completion_id, guac_rdp_fs_get_status(bytes_read), 4);
178 Stream_Write_UINT32(output_stream, 0); /* Length */
179 }
180
181 /* Otherwise, send bytes read */
182 else {
183 output_stream = guac_rdpdr_new_io_completion(device,
184 iorequest->completion_id, STATUS_SUCCESS, 4+bytes_read);
185 Stream_Write_UINT32(output_stream, bytes_read); /* Length */
186 Stream_Write(output_stream, buffer, bytes_read); /* ReadData */
187 }
188
189 guac_rdp_common_svc_write(svc, output_stream);
190 free(buffer);
191
192 }
193
guac_rdpdr_fs_process_write(guac_rdp_common_svc * svc,guac_rdpdr_device * device,guac_rdpdr_iorequest * iorequest,wStream * input_stream)194 void guac_rdpdr_fs_process_write(guac_rdp_common_svc* svc,
195 guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
196 wStream* input_stream) {
197
198 UINT32 length;
199 UINT64 offset;
200 int bytes_written;
201
202 wStream* output_stream;
203
204 /* Check remaining length. */
205 if (Stream_GetRemainingLength(input_stream) < 32) {
206 guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Drive Write "
207 "Request PDU does not contain the expected number of bytes. "
208 "Drive redirection may not work as expected.");
209 return;
210 }
211
212 /* Read packet */
213 Stream_Read_UINT32(input_stream, length);
214 Stream_Read_UINT64(input_stream, offset);
215 Stream_Seek(input_stream, 20); /* Padding */
216
217 guac_client_log(svc->client, GUAC_LOG_DEBUG,
218 "%s: [file_id=%i] length=%i, offset=%" PRIu64,
219 __func__, iorequest->file_id, length, (uint64_t) offset);
220
221 /* Check to make sure stream contains at least length bytes */
222 if (Stream_GetRemainingLength(input_stream) < length) {
223 guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Drive Write "
224 "Request PDU does not contain the expected number of bytes. "
225 "Drive redirection may not work as expected.");
226 return;
227 }
228
229 /* Attempt write */
230 bytes_written = guac_rdp_fs_write((guac_rdp_fs*) device->data,
231 iorequest->file_id, offset, Stream_Pointer(input_stream), length);
232
233 /* If error, return invalid parameter */
234 if (bytes_written < 0) {
235 output_stream = guac_rdpdr_new_io_completion(device,
236 iorequest->completion_id, guac_rdp_fs_get_status(bytes_written), 5);
237 Stream_Write_UINT32(output_stream, 0); /* Length */
238 Stream_Write_UINT8(output_stream, 0); /* Padding */
239 }
240
241 /* Otherwise, send success */
242 else {
243 output_stream = guac_rdpdr_new_io_completion(device,
244 iorequest->completion_id, STATUS_SUCCESS, 5);
245 Stream_Write_UINT32(output_stream, bytes_written); /* Length */
246 Stream_Write_UINT8(output_stream, 0); /* Padding */
247 }
248
249 guac_rdp_common_svc_write(svc, output_stream);
250
251 }
252
guac_rdpdr_fs_process_close(guac_rdp_common_svc * svc,guac_rdpdr_device * device,guac_rdpdr_iorequest * iorequest,wStream * input_stream)253 void guac_rdpdr_fs_process_close(guac_rdp_common_svc* svc,
254 guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
255 wStream* input_stream) {
256
257 wStream* output_stream;
258 guac_rdp_fs_file* file;
259
260 guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]",
261 __func__, iorequest->file_id);
262
263 /* Get file */
264 file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, iorequest->file_id);
265 if (file == NULL)
266 return;
267
268 /* If file was written to, and it's in the \Download folder, start stream */
269 if (file->bytes_written > 0
270 && strncmp(file->absolute_path, "\\Download\\", 10) == 0
271 && !((guac_rdp_fs*) device->data)->disable_download) {
272 guac_client_for_owner(svc->client, guac_rdp_download_to_user, file->absolute_path);
273 guac_rdp_fs_delete((guac_rdp_fs*) device->data, iorequest->file_id);
274 }
275
276 /* Close file */
277 guac_rdp_fs_close((guac_rdp_fs*) device->data, iorequest->file_id);
278
279 output_stream = guac_rdpdr_new_io_completion(device,
280 iorequest->completion_id, STATUS_SUCCESS, 4);
281 Stream_Write(output_stream, "\0\0\0\0", 4); /* Padding */
282
283 guac_rdp_common_svc_write(svc, output_stream);
284
285 }
286
guac_rdpdr_fs_process_volume_info(guac_rdp_common_svc * svc,guac_rdpdr_device * device,guac_rdpdr_iorequest * iorequest,wStream * input_stream)287 void guac_rdpdr_fs_process_volume_info(guac_rdp_common_svc* svc,
288 guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
289 wStream* input_stream) {
290
291 int fs_information_class;
292
293 /* Check remaining length */
294 if (Stream_GetRemainingLength(input_stream) < 4) {
295 guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Drive Query "
296 "Volume Information PDU does not contain the expected number "
297 "of bytes. Drive redirection may not work as expected.");
298 return;
299 }
300
301 Stream_Read_UINT32(input_stream, fs_information_class);
302
303 /* Dispatch to appropriate class-specific handler */
304 switch (fs_information_class) {
305
306 case FileFsVolumeInformation:
307 guac_rdpdr_fs_process_query_volume_info(svc, device, iorequest, input_stream);
308 break;
309
310 case FileFsSizeInformation:
311 guac_rdpdr_fs_process_query_size_info(svc, device, iorequest, input_stream);
312 break;
313
314 case FileFsDeviceInformation:
315 guac_rdpdr_fs_process_query_device_info(svc, device, iorequest, input_stream);
316 break;
317
318 case FileFsAttributeInformation:
319 guac_rdpdr_fs_process_query_attribute_info(svc, device, iorequest, input_stream);
320 break;
321
322 case FileFsFullSizeInformation:
323 guac_rdpdr_fs_process_query_full_size_info(svc, device, iorequest, input_stream);
324 break;
325
326 default:
327 guac_client_log(svc->client, GUAC_LOG_DEBUG,
328 "Unknown volume information class: 0x%x", fs_information_class);
329 }
330
331 }
332
guac_rdpdr_fs_process_file_info(guac_rdp_common_svc * svc,guac_rdpdr_device * device,guac_rdpdr_iorequest * iorequest,wStream * input_stream)333 void guac_rdpdr_fs_process_file_info(guac_rdp_common_svc* svc,
334 guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
335 wStream* input_stream) {
336
337 int fs_information_class;
338
339 /* Check remaining length */
340 if (Stream_GetRemainingLength(input_stream) < 4) {
341 guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Drive Query "
342 "Information PDU does not contain the expected number of "
343 "bytes. Drive redirection may not work as expected.");
344 return;
345 }
346
347 Stream_Read_UINT32(input_stream, fs_information_class);
348
349 /* Dispatch to appropriate class-specific handler */
350 switch (fs_information_class) {
351
352 case FileBasicInformation:
353 guac_rdpdr_fs_process_query_basic_info(svc, device, iorequest, input_stream);
354 break;
355
356 case FileStandardInformation:
357 guac_rdpdr_fs_process_query_standard_info(svc, device, iorequest, input_stream);
358 break;
359
360 case FileAttributeTagInformation:
361 guac_rdpdr_fs_process_query_attribute_tag_info(svc, device, iorequest, input_stream);
362 break;
363
364 default:
365 guac_client_log(svc->client, GUAC_LOG_DEBUG,
366 "Unknown file information class: 0x%x", fs_information_class);
367 }
368
369 }
370
guac_rdpdr_fs_process_set_volume_info(guac_rdp_common_svc * svc,guac_rdpdr_device * device,guac_rdpdr_iorequest * iorequest,wStream * input_stream)371 void guac_rdpdr_fs_process_set_volume_info(guac_rdp_common_svc* svc,
372 guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
373 wStream* input_stream) {
374
375 wStream* output_stream = guac_rdpdr_new_io_completion(device,
376 iorequest->completion_id, STATUS_NOT_SUPPORTED, 0);
377
378 guac_client_log(svc->client, GUAC_LOG_DEBUG,
379 "%s: [file_id=%i] Set volume info not supported",
380 __func__, iorequest->file_id);
381
382 guac_rdp_common_svc_write(svc, output_stream);
383
384 }
385
guac_rdpdr_fs_process_set_file_info(guac_rdp_common_svc * svc,guac_rdpdr_device * device,guac_rdpdr_iorequest * iorequest,wStream * input_stream)386 void guac_rdpdr_fs_process_set_file_info(guac_rdp_common_svc* svc,
387 guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
388 wStream* input_stream) {
389
390 int fs_information_class;
391 int length;
392
393 /* Check remaining length */
394 if (Stream_GetRemainingLength(input_stream) < 32) {
395 guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Drive Set "
396 "Information PDU does not contain the expected number of "
397 "bytes. Drive redirection may not work as expected.");
398 return;
399 }
400
401 Stream_Read_UINT32(input_stream, fs_information_class);
402 Stream_Read_UINT32(input_stream, length); /* Length */
403 Stream_Seek(input_stream, 24); /* Padding */
404
405 /* Dispatch to appropriate class-specific handler */
406 switch (fs_information_class) {
407
408 case FileBasicInformation:
409 guac_rdpdr_fs_process_set_basic_info(svc, device, iorequest, length, input_stream);
410 break;
411
412 case FileEndOfFileInformation:
413 guac_rdpdr_fs_process_set_end_of_file_info(svc, device, iorequest, length, input_stream);
414 break;
415
416 case FileDispositionInformation:
417 guac_rdpdr_fs_process_set_disposition_info(svc, device, iorequest, length, input_stream);
418 break;
419
420 case FileRenameInformation:
421 guac_rdpdr_fs_process_set_rename_info(svc, device, iorequest, length, input_stream);
422 break;
423
424 case FileAllocationInformation:
425 guac_rdpdr_fs_process_set_allocation_info(svc, device, iorequest, length, input_stream);
426 break;
427
428 default:
429 guac_client_log(svc->client, GUAC_LOG_DEBUG,
430 "Unknown file information class: 0x%x",
431 fs_information_class);
432 }
433
434 }
435
guac_rdpdr_fs_process_device_control(guac_rdp_common_svc * svc,guac_rdpdr_device * device,guac_rdpdr_iorequest * iorequest,wStream * input_stream)436 void guac_rdpdr_fs_process_device_control(guac_rdp_common_svc* svc,
437 guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
438 wStream* input_stream) {
439
440 wStream* output_stream = guac_rdpdr_new_io_completion(device,
441 iorequest->completion_id, STATUS_INVALID_PARAMETER, 4);
442
443 guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i] IGNORED",
444 __func__, iorequest->file_id);
445
446 /* No content for now */
447 Stream_Write_UINT32(output_stream, 0);
448
449 guac_rdp_common_svc_write(svc, output_stream);
450
451 }
452
guac_rdpdr_fs_process_notify_change_directory(guac_rdp_common_svc * svc,guac_rdpdr_device * device,guac_rdpdr_iorequest * iorequest,wStream * input_stream)453 void guac_rdpdr_fs_process_notify_change_directory(guac_rdp_common_svc* svc,
454 guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
455 wStream* input_stream) {
456
457 guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i] Not "
458 "implemented", __func__, iorequest->file_id);
459
460 }
461
guac_rdpdr_fs_process_query_directory(guac_rdp_common_svc * svc,guac_rdpdr_device * device,guac_rdpdr_iorequest * iorequest,wStream * input_stream)462 void guac_rdpdr_fs_process_query_directory(guac_rdp_common_svc* svc,
463 guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
464 wStream* input_stream) {
465
466 wStream* output_stream;
467
468 guac_rdp_fs_file* file;
469 int fs_information_class, initial_query;
470 int path_length;
471
472 const char* entry_name;
473
474 /* Get file */
475 file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, iorequest->file_id);
476 if (file == NULL)
477 return;
478
479 if (Stream_GetRemainingLength(input_stream) < 9) {
480 guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Drive Query "
481 "Directory PDU does not contain the expected number of bytes. "
482 "Drive redirection may not work as expected.");
483 return;
484 }
485
486 /* Read main header */
487 Stream_Read_UINT32(input_stream, fs_information_class);
488 Stream_Read_UINT8(input_stream, initial_query);
489 Stream_Read_UINT32(input_stream, path_length);
490
491 /* If this is the first query, the path is included after padding */
492 if (initial_query) {
493
494 /*
495 * Check to make sure Stream has at least the 23 padding bytes in it
496 * prior to seeking.
497 */
498 if (Stream_GetRemainingLength(input_stream) < (23 + path_length)) {
499 guac_client_log(svc->client, GUAC_LOG_WARNING, "Server Drive Query "
500 "Directory PDU does not contain the expected number of "
501 "bytes. Drive redirection may not work as expected.");
502 return;
503 }
504
505 Stream_Seek(input_stream, 23); /* Padding */
506
507 /* Convert path to UTF-8 */
508 guac_rdp_utf16_to_utf8(Stream_Pointer(input_stream), path_length/2 - 1,
509 file->dir_pattern, sizeof(file->dir_pattern));
510
511 }
512
513 guac_client_log(svc->client, GUAC_LOG_DEBUG, "%s: [file_id=%i] "
514 "initial_query=%i, dir_pattern=\"%s\"", __func__,
515 iorequest->file_id, initial_query, file->dir_pattern);
516
517 /* Find first matching entry in directory */
518 while ((entry_name = guac_rdp_fs_read_dir((guac_rdp_fs*) device->data,
519 iorequest->file_id)) != NULL) {
520
521 /* Convert to absolute path */
522 char entry_path[GUAC_RDP_FS_MAX_PATH];
523 if (guac_rdp_fs_convert_path(file->absolute_path,
524 entry_name, entry_path) == 0) {
525
526 int entry_file_id;
527
528 /* Pattern defined and match fails, continue with next file */
529 if (guac_rdp_fs_matches(entry_path, file->dir_pattern))
530 continue;
531
532 /* Open directory entry */
533 entry_file_id = guac_rdp_fs_open((guac_rdp_fs*) device->data,
534 entry_path, FILE_READ_DATA, 0, FILE_OPEN, 0);
535
536 if (entry_file_id >= 0) {
537
538 /* Dispatch to appropriate class-specific handler */
539 switch (fs_information_class) {
540
541 case FileDirectoryInformation:
542 guac_rdpdr_fs_process_query_directory_info(svc, device,
543 iorequest, entry_name, entry_file_id);
544 break;
545
546 case FileFullDirectoryInformation:
547 guac_rdpdr_fs_process_query_full_directory_info(svc,
548 device, iorequest, entry_name, entry_file_id);
549 break;
550
551 case FileBothDirectoryInformation:
552 guac_rdpdr_fs_process_query_both_directory_info(svc,
553 device, iorequest, entry_name, entry_file_id);
554 break;
555
556 case FileNamesInformation:
557 guac_rdpdr_fs_process_query_names_info(svc, device,
558 iorequest, entry_name, entry_file_id);
559 break;
560
561 default:
562 guac_client_log(svc->client, GUAC_LOG_DEBUG,
563 "Unknown dir information class: 0x%x",
564 fs_information_class);
565 }
566
567 guac_rdp_fs_close((guac_rdp_fs*) device->data, entry_file_id);
568 return;
569
570 } /* end if file exists */
571 } /* end if path valid */
572 } /* end if entry exists */
573
574 /*
575 * Handle errors as a lack of files.
576 */
577
578 output_stream = guac_rdpdr_new_io_completion(device,
579 iorequest->completion_id, STATUS_NO_MORE_FILES, 5);
580
581 Stream_Write_UINT32(output_stream, 0); /* Length */
582 Stream_Write_UINT8(output_stream, 0); /* Padding */
583
584 guac_rdp_common_svc_write(svc, output_stream);
585
586 }
587
guac_rdpdr_fs_process_lock_control(guac_rdp_common_svc * svc,guac_rdpdr_device * device,guac_rdpdr_iorequest * iorequest,wStream * input_stream)588 void guac_rdpdr_fs_process_lock_control(guac_rdp_common_svc* svc,
589 guac_rdpdr_device* device, guac_rdpdr_iorequest* iorequest,
590 wStream* input_stream) {
591
592 wStream* output_stream = guac_rdpdr_new_io_completion(device,
593 iorequest->completion_id, STATUS_NOT_SUPPORTED, 5);
594
595 guac_client_log(svc->client, GUAC_LOG_DEBUG,
596 "%s: [file_id=%i] Lock not supported",
597 __func__, iorequest->file_id);
598
599 Stream_Zero(output_stream, 5); /* Padding */
600
601 guac_rdp_common_svc_write(svc, output_stream);
602
603 }
604
605