1 /**
2 * FreeRDP: A Remote Desktop Protocol Implementation
3 * Print Virtual Channel
4 *
5 * Copyright 2010-2011 Vic Lee
6 * Copyright 2015 Thincast Technologies GmbH
7 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
8 * Copyright 2016 Armin Novak <armin.novak@gmail.com>
9 * Copyright 2016 David PHAM-VAN <d.phamvan@inuvika.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 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include <winpr/crt.h>
33 #include <winpr/string.h>
34 #include <winpr/synch.h>
35 #include <winpr/thread.h>
36 #include <winpr/stream.h>
37 #include <winpr/interlocked.h>
38 #include <winpr/path.h>
39
40 #include <freerdp/channels/rdpdr.h>
41 #include <freerdp/crypto/crypto.h>
42
43 #include "../printer.h"
44
45 #include <freerdp/client/printer.h>
46
47 #include <freerdp/channels/log.h>
48
49 #define TAG CHANNELS_TAG("printer.client")
50
51 typedef struct _PRINTER_DEVICE PRINTER_DEVICE;
52 struct _PRINTER_DEVICE
53 {
54 DEVICE device;
55
56 rdpPrinter* printer;
57
58 WINPR_PSLIST_HEADER pIrpList;
59
60 HANDLE event;
61 HANDLE stopEvent;
62
63 HANDLE thread;
64 rdpContext* rdpcontext;
65 char port[64];
66 };
67
68 typedef enum
69 {
70 PRN_CONF_PORT = 0,
71 PRN_CONF_PNP = 1,
72 PRN_CONF_DRIVER = 2,
73 PRN_CONF_DATA = 3
74 } prn_conf_t;
75
76 static const char* filemap[] = { "PortDosName", "PnPName", "DriverName",
77 "CachedPrinterConfigData" };
78
get_printer_config_path(const rdpSettings * settings,const WCHAR * name,size_t length)79 static char* get_printer_config_path(const rdpSettings* settings, const WCHAR* name, size_t length)
80 {
81 char* dir = GetCombinedPath(settings->ConfigPath, "printers");
82 char* bname = crypto_base64_encode((const BYTE*)name, (int)length);
83 char* config = GetCombinedPath(dir, bname);
84
85 if (config && !winpr_PathFileExists(config))
86 {
87 if (!winpr_PathMakePath(config, NULL))
88 {
89 free(config);
90 config = NULL;
91 }
92 }
93
94 free(dir);
95 free(bname);
96 return config;
97 }
98
printer_write_setting(const char * path,prn_conf_t type,const void * data,size_t length)99 static BOOL printer_write_setting(const char* path, prn_conf_t type, const void* data,
100 size_t length)
101 {
102 DWORD written = 0;
103 BOOL rc = FALSE;
104 HANDLE file;
105 size_t b64len;
106 char* base64 = NULL;
107 const char* name = filemap[type];
108 char* abs = GetCombinedPath(path, name);
109
110 if (!abs || (length > INT32_MAX))
111 return FALSE;
112
113 file = CreateFileA(abs, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
114 free(abs);
115
116 if (file == INVALID_HANDLE_VALUE)
117 return FALSE;
118
119 if (length > 0)
120 {
121 base64 = crypto_base64_encode(data, length);
122
123 if (!base64)
124 goto fail;
125
126 /* base64 char represents 6bit -> 4*(n/3) is the length which is
127 * always smaller than 2*n */
128 b64len = strnlen(base64, 2 * length);
129 rc = WriteFile(file, base64, b64len, &written, NULL);
130
131 if (b64len != written)
132 rc = FALSE;
133 }
134 else
135 rc = TRUE;
136
137 fail:
138 CloseHandle(file);
139 free(base64);
140 return rc;
141 }
142
printer_config_valid(const char * path)143 static BOOL printer_config_valid(const char* path)
144 {
145 if (!path)
146 return FALSE;
147
148 if (!winpr_PathFileExists(path))
149 return FALSE;
150
151 return TRUE;
152 }
153
printer_read_setting(const char * path,prn_conf_t type,void ** data,UINT32 * length)154 static BOOL printer_read_setting(const char* path, prn_conf_t type, void** data, UINT32* length)
155 {
156 DWORD lowSize, highSize;
157 DWORD read = 0;
158 BOOL rc = FALSE;
159 HANDLE file;
160 char* fdata = NULL;
161 const char* name = filemap[type];
162 char* abs = GetCombinedPath(path, name);
163
164 if (!abs)
165 return FALSE;
166
167 file = CreateFileA(abs, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
168 free(abs);
169
170 if (file == INVALID_HANDLE_VALUE)
171 return FALSE;
172
173 lowSize = GetFileSize(file, &highSize);
174
175 if ((lowSize == INVALID_FILE_SIZE) || (highSize != 0))
176 goto fail;
177
178 if (lowSize != 0)
179 {
180 fdata = malloc(lowSize);
181
182 if (!fdata)
183 goto fail;
184
185 rc = ReadFile(file, fdata, lowSize, &read, NULL);
186
187 if (lowSize != read)
188 rc = FALSE;
189 }
190
191 fail:
192 CloseHandle(file);
193
194 if (rc && (lowSize <= INT_MAX))
195 {
196 int blen = 0;
197 crypto_base64_decode(fdata, (int)lowSize, (BYTE**)data, &blen);
198
199 if (*data && (blen > 0))
200 *length = (UINT32)blen;
201 else
202 {
203 rc = FALSE;
204 *length = 0;
205 }
206 }
207 else
208 {
209 *length = 0;
210 *data = NULL;
211 }
212
213 free(fdata);
214 return rc;
215 }
216
printer_save_to_config(const rdpSettings * settings,const char * PortDosName,size_t PortDosNameLen,const WCHAR * PnPName,size_t PnPNameLen,const WCHAR * DriverName,size_t DriverNameLen,const WCHAR * PrinterName,size_t PrintNameLen,const BYTE * CachedPrinterConfigData,size_t CacheFieldsLen)217 static BOOL printer_save_to_config(const rdpSettings* settings, const char* PortDosName,
218 size_t PortDosNameLen, const WCHAR* PnPName, size_t PnPNameLen,
219 const WCHAR* DriverName, size_t DriverNameLen,
220 const WCHAR* PrinterName, size_t PrintNameLen,
221 const BYTE* CachedPrinterConfigData, size_t CacheFieldsLen)
222 {
223 BOOL rc = FALSE;
224 char* path = get_printer_config_path(settings, PrinterName, PrintNameLen);
225
226 if (!path)
227 goto fail;
228
229 if (!printer_write_setting(path, PRN_CONF_PORT, PortDosName, PortDosNameLen))
230 goto fail;
231
232 if (!printer_write_setting(path, PRN_CONF_PNP, PnPName, PnPNameLen))
233 goto fail;
234
235 if (!printer_write_setting(path, PRN_CONF_DRIVER, DriverName, DriverNameLen))
236 goto fail;
237
238 if (!printer_write_setting(path, PRN_CONF_DATA, CachedPrinterConfigData, CacheFieldsLen))
239 goto fail;
240
241 fail:
242 free(path);
243 return rc;
244 }
245
printer_update_to_config(const rdpSettings * settings,const WCHAR * name,size_t length,const BYTE * data,size_t datalen)246 static BOOL printer_update_to_config(const rdpSettings* settings, const WCHAR* name, size_t length,
247 const BYTE* data, size_t datalen)
248 {
249 BOOL rc = FALSE;
250 char* path = get_printer_config_path(settings, name, length);
251 rc = printer_write_setting(path, PRN_CONF_DATA, data, datalen);
252 free(path);
253 return rc;
254 }
255
printer_remove_config(const rdpSettings * settings,const WCHAR * name,size_t length)256 static BOOL printer_remove_config(const rdpSettings* settings, const WCHAR* name, size_t length)
257 {
258 BOOL rc = FALSE;
259 char* path = get_printer_config_path(settings, name, length);
260
261 if (!printer_config_valid(path))
262 goto fail;
263
264 rc = winpr_RemoveDirectory(path);
265 fail:
266 free(path);
267 return rc;
268 }
269
printer_move_config(const rdpSettings * settings,const WCHAR * oldName,size_t oldLength,const WCHAR * newName,size_t newLength)270 static BOOL printer_move_config(const rdpSettings* settings, const WCHAR* oldName, size_t oldLength,
271 const WCHAR* newName, size_t newLength)
272 {
273 BOOL rc = FALSE;
274 char* oldPath = get_printer_config_path(settings, oldName, oldLength);
275 char* newPath = get_printer_config_path(settings, newName, newLength);
276
277 if (printer_config_valid(oldPath))
278 rc = winpr_MoveFile(oldPath, newPath);
279
280 free(oldPath);
281 free(newPath);
282 return rc;
283 }
284
printer_load_from_config(const rdpSettings * settings,rdpPrinter * printer,PRINTER_DEVICE * printer_dev)285 static BOOL printer_load_from_config(const rdpSettings* settings, rdpPrinter* printer,
286 PRINTER_DEVICE* printer_dev)
287 {
288 BOOL res = FALSE;
289 WCHAR* wname = NULL;
290 size_t wlen;
291 char* path = NULL;
292 int rc;
293 UINT32 flags = 0;
294 void* DriverName = NULL;
295 UINT32 DriverNameLen = 0;
296 void* PnPName = NULL;
297 UINT32 PnPNameLen = 0;
298 void* CachedPrinterConfigData = NULL;
299 UINT32 CachedFieldsLen = 0;
300 UINT32 PrinterNameLen = 0;
301
302 if (!settings || !printer)
303 return FALSE;
304
305 rc = ConvertToUnicode(CP_UTF8, 0, printer->name, -1, &wname, 0);
306
307 if (rc <= 0)
308 goto fail;
309
310 wlen = _wcslen(wname) + 1;
311 path = get_printer_config_path(settings, wname, wlen * sizeof(WCHAR));
312 PrinterNameLen = (wlen + 1) * sizeof(WCHAR);
313
314 if (!path)
315 goto fail;
316
317 if (printer->is_default)
318 flags |= RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER;
319
320 if (!printer_read_setting(path, PRN_CONF_PNP, &PnPName, &PnPNameLen))
321 {
322 }
323
324 if (!printer_read_setting(path, PRN_CONF_DRIVER, &DriverName, &DriverNameLen))
325 {
326 DriverNameLen =
327 ConvertToUnicode(CP_UTF8, 0, printer->driver, -1, (LPWSTR*)&DriverName, 0) * 2 + 1;
328 }
329
330 if (!printer_read_setting(path, PRN_CONF_DATA, &CachedPrinterConfigData, &CachedFieldsLen))
331 {
332 }
333
334 Stream_SetPosition(printer_dev->device.data, 0);
335
336 if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, 24))
337 goto fail;
338
339 Stream_Write_UINT32(printer_dev->device.data, flags);
340 Stream_Write_UINT32(printer_dev->device.data, 0); /* CodePage, reserved */
341 Stream_Write_UINT32(printer_dev->device.data, PnPNameLen); /* PnPNameLen */
342 Stream_Write_UINT32(printer_dev->device.data, DriverNameLen);
343 Stream_Write_UINT32(printer_dev->device.data, PrinterNameLen);
344 Stream_Write_UINT32(printer_dev->device.data, CachedFieldsLen);
345
346 if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, PnPNameLen))
347 goto fail;
348
349 if (PnPNameLen > 0)
350 Stream_Write(printer_dev->device.data, PnPName, PnPNameLen);
351
352 if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, DriverNameLen))
353 goto fail;
354
355 Stream_Write(printer_dev->device.data, DriverName, DriverNameLen);
356
357 if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, PrinterNameLen))
358 goto fail;
359
360 Stream_Write(printer_dev->device.data, wname, PrinterNameLen);
361
362 if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, CachedFieldsLen))
363 goto fail;
364
365 Stream_Write(printer_dev->device.data, CachedPrinterConfigData, CachedFieldsLen);
366 res = TRUE;
367 fail:
368 free(path);
369 free(wname);
370 free(PnPName);
371 free(DriverName);
372 free(CachedPrinterConfigData);
373 return res;
374 }
375
printer_save_default_config(const rdpSettings * settings,rdpPrinter * printer)376 static BOOL printer_save_default_config(const rdpSettings* settings, rdpPrinter* printer)
377 {
378 BOOL res = FALSE;
379 WCHAR* wname = NULL;
380 WCHAR* driver = NULL;
381 size_t wlen, dlen;
382 char* path = NULL;
383 int rc;
384
385 if (!settings || !printer)
386 return FALSE;
387
388 rc = ConvertToUnicode(CP_UTF8, 0, printer->name, -1, &wname, 0);
389
390 if (rc <= 0)
391 goto fail;
392
393 rc = ConvertToUnicode(CP_UTF8, 0, printer->driver, -1, &driver, 0);
394
395 if (rc <= 0)
396 goto fail;
397
398 wlen = _wcslen(wname) + 1;
399 dlen = _wcslen(driver) + 1;
400 path = get_printer_config_path(settings, wname, wlen * sizeof(WCHAR));
401
402 if (!path)
403 goto fail;
404
405 if (dlen > 1)
406 {
407 if (!printer_write_setting(path, PRN_CONF_DRIVER, driver, dlen * sizeof(WCHAR)))
408 goto fail;
409 }
410
411 res = TRUE;
412 fail:
413 free(path);
414 free(wname);
415 free(driver);
416 return res;
417 }
418
419 /**
420 * Function description
421 *
422 * @return 0 on success, otherwise a Win32 error code
423 */
printer_process_irp_create(PRINTER_DEVICE * printer_dev,IRP * irp)424 static UINT printer_process_irp_create(PRINTER_DEVICE* printer_dev, IRP* irp)
425 {
426 rdpPrintJob* printjob = NULL;
427
428 if (printer_dev->printer)
429 printjob =
430 printer_dev->printer->CreatePrintJob(printer_dev->printer, irp->devman->id_sequence++);
431
432 if (printjob)
433 {
434 Stream_Write_UINT32(irp->output, printjob->id); /* FileId */
435 }
436 else
437 {
438 Stream_Write_UINT32(irp->output, 0); /* FileId */
439 irp->IoStatus = STATUS_PRINT_QUEUE_FULL;
440 }
441
442 return irp->Complete(irp);
443 }
444
445 /**
446 * Function description
447 *
448 * @return 0 on success, otherwise a Win32 error code
449 */
printer_process_irp_close(PRINTER_DEVICE * printer_dev,IRP * irp)450 static UINT printer_process_irp_close(PRINTER_DEVICE* printer_dev, IRP* irp)
451 {
452 rdpPrintJob* printjob = NULL;
453
454 if (printer_dev->printer)
455 printjob = printer_dev->printer->FindPrintJob(printer_dev->printer, irp->FileId);
456
457 if (!printjob)
458 {
459 irp->IoStatus = STATUS_UNSUCCESSFUL;
460 }
461 else
462 {
463 printjob->Close(printjob);
464 }
465
466 Stream_Zero(irp->output, 4); /* Padding(4) */
467 return irp->Complete(irp);
468 }
469
470 /**
471 * Function description
472 *
473 * @return 0 on success, otherwise a Win32 error code
474 */
printer_process_irp_write(PRINTER_DEVICE * printer_dev,IRP * irp)475 static UINT printer_process_irp_write(PRINTER_DEVICE* printer_dev, IRP* irp)
476 {
477 UINT32 Length;
478 UINT64 Offset;
479 rdpPrintJob* printjob = NULL;
480 UINT error = CHANNEL_RC_OK;
481 void* ptr;
482
483 if (Stream_GetRemainingLength(irp->input) < 32)
484 return ERROR_INVALID_DATA;
485 Stream_Read_UINT32(irp->input, Length);
486 Stream_Read_UINT64(irp->input, Offset);
487 Stream_Seek(irp->input, 20); /* Padding */
488 ptr = Stream_Pointer(irp->input);
489 if (!Stream_SafeSeek(irp->input, Length))
490 return ERROR_INVALID_DATA;
491 if (printer_dev->printer)
492 printjob = printer_dev->printer->FindPrintJob(printer_dev->printer, irp->FileId);
493
494 if (!printjob)
495 {
496 irp->IoStatus = STATUS_UNSUCCESSFUL;
497 Length = 0;
498 }
499 else
500 {
501 error = printjob->Write(printjob, ptr, Length);
502 }
503
504 if (error)
505 {
506 WLog_ERR(TAG, "printjob->Write failed with error %" PRIu32 "!", error);
507 return error;
508 }
509
510 Stream_Write_UINT32(irp->output, Length);
511 Stream_Write_UINT8(irp->output, 0); /* Padding */
512 return irp->Complete(irp);
513 }
514
515 /**
516 * Function description
517 *
518 * @return 0 on success, otherwise a Win32 error code
519 */
printer_process_irp_device_control(PRINTER_DEVICE * printer_dev,IRP * irp)520 static UINT printer_process_irp_device_control(PRINTER_DEVICE* printer_dev, IRP* irp)
521 {
522 Stream_Write_UINT32(irp->output, 0); /* OutputBufferLength */
523 return irp->Complete(irp);
524 }
525
526 /**
527 * Function description
528 *
529 * @return 0 on success, otherwise a Win32 error code
530 */
printer_process_irp(PRINTER_DEVICE * printer_dev,IRP * irp)531 static UINT printer_process_irp(PRINTER_DEVICE* printer_dev, IRP* irp)
532 {
533 UINT error;
534
535 switch (irp->MajorFunction)
536 {
537 case IRP_MJ_CREATE:
538 if ((error = printer_process_irp_create(printer_dev, irp)))
539 {
540 WLog_ERR(TAG, "printer_process_irp_create failed with error %" PRIu32 "!", error);
541 return error;
542 }
543
544 break;
545
546 case IRP_MJ_CLOSE:
547 if ((error = printer_process_irp_close(printer_dev, irp)))
548 {
549 WLog_ERR(TAG, "printer_process_irp_close failed with error %" PRIu32 "!", error);
550 return error;
551 }
552
553 break;
554
555 case IRP_MJ_WRITE:
556 if ((error = printer_process_irp_write(printer_dev, irp)))
557 {
558 WLog_ERR(TAG, "printer_process_irp_write failed with error %" PRIu32 "!", error);
559 return error;
560 }
561
562 break;
563
564 case IRP_MJ_DEVICE_CONTROL:
565 if ((error = printer_process_irp_device_control(printer_dev, irp)))
566 {
567 WLog_ERR(TAG, "printer_process_irp_device_control failed with error %" PRIu32 "!",
568 error);
569 return error;
570 }
571
572 break;
573
574 default:
575 irp->IoStatus = STATUS_NOT_SUPPORTED;
576 return irp->Complete(irp);
577 break;
578 }
579
580 return CHANNEL_RC_OK;
581 }
582
printer_thread_func(LPVOID arg)583 static DWORD WINAPI printer_thread_func(LPVOID arg)
584 {
585 IRP* irp;
586 PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*)arg;
587 HANDLE obj[] = { printer_dev->event, printer_dev->stopEvent };
588 UINT error = CHANNEL_RC_OK;
589
590 while (1)
591 {
592 DWORD rc = WaitForMultipleObjects(2, obj, FALSE, INFINITE);
593
594 if (rc == WAIT_FAILED)
595 {
596 error = GetLastError();
597 WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error);
598 break;
599 }
600
601 if (rc == WAIT_OBJECT_0 + 1)
602 break;
603 else if (rc != WAIT_OBJECT_0)
604 continue;
605
606 ResetEvent(printer_dev->event);
607 irp = (IRP*)InterlockedPopEntrySList(printer_dev->pIrpList);
608
609 if (irp == NULL)
610 {
611 WLog_ERR(TAG, "InterlockedPopEntrySList failed!");
612 error = ERROR_INTERNAL_ERROR;
613 break;
614 }
615
616 if ((error = printer_process_irp(printer_dev, irp)))
617 {
618 WLog_ERR(TAG, "printer_process_irp failed with error %" PRIu32 "!", error);
619 break;
620 }
621 }
622
623 if (error && printer_dev->rdpcontext)
624 setChannelError(printer_dev->rdpcontext, error, "printer_thread_func reported an error");
625
626 ExitThread(error);
627 return error;
628 }
629
630 /**
631 * Function description
632 *
633 * @return 0 on success, otherwise a Win32 error code
634 */
printer_irp_request(DEVICE * device,IRP * irp)635 static UINT printer_irp_request(DEVICE* device, IRP* irp)
636 {
637 PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*)device;
638 InterlockedPushEntrySList(printer_dev->pIrpList, &(irp->ItemEntry));
639 SetEvent(printer_dev->event);
640 return CHANNEL_RC_OK;
641 }
642
printer_custom_component(DEVICE * device,UINT16 component,UINT16 packetId,wStream * s)643 static UINT printer_custom_component(DEVICE* device, UINT16 component, UINT16 packetId, wStream* s)
644 {
645 UINT32 eventID;
646 PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*)device;
647 const rdpSettings* settings = printer_dev->rdpcontext->settings;
648
649 if (component != RDPDR_CTYP_PRN)
650 return ERROR_INVALID_DATA;
651
652 if (Stream_GetRemainingLength(s) < 4)
653 return ERROR_INVALID_DATA;
654
655 Stream_Read_UINT32(s, eventID);
656
657 switch (packetId)
658 {
659 case PAKID_PRN_CACHE_DATA:
660 switch (eventID)
661 {
662 case RDPDR_ADD_PRINTER_EVENT:
663 {
664 char PortDosName[8];
665 UINT32 PnPNameLen, DriverNameLen, PrintNameLen, CacheFieldsLen;
666 const WCHAR *PnPName, *DriverName, *PrinterName;
667 const BYTE* CachedPrinterConfigData;
668
669 if (Stream_GetRemainingLength(s) < 24)
670 return ERROR_INVALID_DATA;
671
672 Stream_Read(s, PortDosName, sizeof(PortDosName));
673 Stream_Read_UINT32(s, PnPNameLen);
674 Stream_Read_UINT32(s, DriverNameLen);
675 Stream_Read_UINT32(s, PrintNameLen);
676 Stream_Read_UINT32(s, CacheFieldsLen);
677
678 if (Stream_GetRemainingLength(s) < PnPNameLen)
679 return ERROR_INVALID_DATA;
680
681 PnPName = (const WCHAR*)Stream_Pointer(s);
682 Stream_Seek(s, PnPNameLen);
683
684 if (Stream_GetRemainingLength(s) < DriverNameLen)
685 return ERROR_INVALID_DATA;
686
687 DriverName = (const WCHAR*)Stream_Pointer(s);
688 Stream_Seek(s, DriverNameLen);
689
690 if (Stream_GetRemainingLength(s) < PrintNameLen)
691 return ERROR_INVALID_DATA;
692
693 PrinterName = (const WCHAR*)Stream_Pointer(s);
694 Stream_Seek(s, PrintNameLen);
695
696 if (Stream_GetRemainingLength(s) < CacheFieldsLen)
697 return ERROR_INVALID_DATA;
698
699 CachedPrinterConfigData = Stream_Pointer(s);
700 Stream_Seek(s, CacheFieldsLen);
701
702 if (!printer_save_to_config(settings, PortDosName, sizeof(PortDosName), PnPName,
703 PnPNameLen, DriverName, DriverNameLen, PrinterName,
704 PrintNameLen, CachedPrinterConfigData,
705 CacheFieldsLen))
706 return ERROR_INTERNAL_ERROR;
707 }
708 break;
709
710 case RDPDR_UPDATE_PRINTER_EVENT:
711 {
712 UINT32 PrinterNameLen, ConfigDataLen;
713 const WCHAR* PrinterName;
714 const BYTE* ConfigData;
715
716 if (Stream_GetRemainingLength(s) < 8)
717 return ERROR_INVALID_DATA;
718
719 Stream_Read_UINT32(s, PrinterNameLen);
720 Stream_Read_UINT32(s, ConfigDataLen);
721
722 if (Stream_GetRemainingLength(s) < PrinterNameLen)
723 return ERROR_INVALID_DATA;
724
725 PrinterName = (const WCHAR*)Stream_Pointer(s);
726 Stream_Seek(s, PrinterNameLen);
727
728 if (Stream_GetRemainingLength(s) < ConfigDataLen)
729 return ERROR_INVALID_DATA;
730
731 ConfigData = Stream_Pointer(s);
732 Stream_Seek(s, ConfigDataLen);
733
734 if (!printer_update_to_config(settings, PrinterName, PrinterNameLen, ConfigData,
735 ConfigDataLen))
736 return ERROR_INTERNAL_ERROR;
737 }
738 break;
739
740 case RDPDR_DELETE_PRINTER_EVENT:
741 {
742 UINT32 PrinterNameLen;
743 const WCHAR* PrinterName;
744
745 if (Stream_GetRemainingLength(s) < 4)
746 return ERROR_INVALID_DATA;
747
748 Stream_Read_UINT32(s, PrinterNameLen);
749
750 if (Stream_GetRemainingLength(s) < PrinterNameLen)
751 return ERROR_INVALID_DATA;
752
753 PrinterName = (const WCHAR*)Stream_Pointer(s);
754 Stream_Seek(s, PrinterNameLen);
755 printer_remove_config(settings, PrinterName, PrinterNameLen);
756 }
757 break;
758
759 case RDPDR_RENAME_PRINTER_EVENT:
760 {
761 UINT32 OldPrinterNameLen, NewPrinterNameLen;
762 const WCHAR* OldPrinterName;
763 const WCHAR* NewPrinterName;
764
765 if (Stream_GetRemainingLength(s) < 8)
766 return ERROR_INVALID_DATA;
767
768 Stream_Read_UINT32(s, OldPrinterNameLen);
769 Stream_Read_UINT32(s, NewPrinterNameLen);
770
771 if (Stream_GetRemainingLength(s) < OldPrinterNameLen)
772 return ERROR_INVALID_DATA;
773
774 OldPrinterName = (const WCHAR*)Stream_Pointer(s);
775 Stream_Seek(s, OldPrinterNameLen);
776
777 if (Stream_GetRemainingLength(s) < NewPrinterNameLen)
778 return ERROR_INVALID_DATA;
779
780 NewPrinterName = (const WCHAR*)Stream_Pointer(s);
781 Stream_Seek(s, NewPrinterNameLen);
782
783 if (!printer_move_config(settings, OldPrinterName, OldPrinterNameLen,
784 NewPrinterName, NewPrinterNameLen))
785 return ERROR_INTERNAL_ERROR;
786 }
787 break;
788
789 default:
790 WLog_ERR(TAG, "Unknown cache data eventID: 0x%08" PRIX32 "", eventID);
791 return ERROR_INVALID_DATA;
792 }
793
794 break;
795
796 case PAKID_PRN_USING_XPS:
797 {
798 UINT32 flags;
799
800 if (Stream_GetRemainingLength(s) < 4)
801 return ERROR_INVALID_DATA;
802
803 Stream_Read_UINT32(s, flags);
804 WLog_ERR(TAG,
805 "Ignoring unhandled message PAKID_PRN_USING_XPS [printerID=%08" PRIx32
806 ", flags=%08" PRIx32 "]",
807 eventID, flags);
808 }
809 break;
810
811 default:
812 WLog_ERR(TAG, "Unknown printing component packetID: 0x%04" PRIX16 "", packetId);
813 return ERROR_INVALID_DATA;
814 }
815
816 return CHANNEL_RC_OK;
817 }
818
819 /**
820 * Function description
821 *
822 * @return 0 on success, otherwise a Win32 error code
823 */
printer_free(DEVICE * device)824 static UINT printer_free(DEVICE* device)
825 {
826 IRP* irp;
827 PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*)device;
828 UINT error;
829 SetEvent(printer_dev->stopEvent);
830
831 if (WaitForSingleObject(printer_dev->thread, INFINITE) == WAIT_FAILED)
832 {
833 error = GetLastError();
834 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
835
836 /* The analyzer is confused by this premature return value.
837 * Since this case can not be handled gracefully silence the
838 * analyzer here. */
839 #ifndef __clang_analyzer__
840 return error;
841 #endif
842 }
843
844 while ((irp = (IRP*)InterlockedPopEntrySList(printer_dev->pIrpList)) != NULL)
845 irp->Discard(irp);
846
847 CloseHandle(printer_dev->thread);
848 CloseHandle(printer_dev->stopEvent);
849 CloseHandle(printer_dev->event);
850 _aligned_free(printer_dev->pIrpList);
851
852 if (printer_dev->printer)
853 printer_dev->printer->ReleaseRef(printer_dev->printer);
854
855 Stream_Free(printer_dev->device.data, TRUE);
856 free(printer_dev);
857 return CHANNEL_RC_OK;
858 }
859
860 /**
861 * Function description
862 *
863 * @return 0 on success, otherwise a Win32 error code
864 */
printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints,rdpPrinter * printer)865 static UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, rdpPrinter* printer)
866 {
867 PRINTER_DEVICE* printer_dev;
868 UINT error = ERROR_INTERNAL_ERROR;
869 printer_dev = (PRINTER_DEVICE*)calloc(1, sizeof(PRINTER_DEVICE));
870
871 if (!printer_dev)
872 {
873 WLog_ERR(TAG, "calloc failed!");
874 return CHANNEL_RC_NO_MEMORY;
875 }
876
877 printer_dev->device.data = Stream_New(NULL, 1024);
878
879 if (!printer_dev->device.data)
880 goto error_out;
881
882 sprintf_s(printer_dev->port, sizeof(printer_dev->port), "PRN%" PRIdz, printer->id);
883 printer_dev->device.type = RDPDR_DTYP_PRINT;
884 printer_dev->device.name = printer_dev->port;
885 printer_dev->device.IRPRequest = printer_irp_request;
886 printer_dev->device.CustomComponentRequest = printer_custom_component;
887 printer_dev->device.Free = printer_free;
888 printer_dev->rdpcontext = pEntryPoints->rdpcontext;
889 printer_dev->printer = printer;
890 printer_dev->pIrpList = (WINPR_PSLIST_HEADER)_aligned_malloc(sizeof(WINPR_SLIST_HEADER),
891 MEMORY_ALLOCATION_ALIGNMENT);
892
893 if (!printer_dev->pIrpList)
894 {
895 WLog_ERR(TAG, "_aligned_malloc failed!");
896 error = CHANNEL_RC_NO_MEMORY;
897 goto error_out;
898 }
899
900 if (!printer_load_from_config(pEntryPoints->rdpcontext->settings, printer, printer_dev))
901 goto error_out;
902
903 InitializeSListHead(printer_dev->pIrpList);
904
905 if (!(printer_dev->event = CreateEvent(NULL, TRUE, FALSE, NULL)))
906 {
907 WLog_ERR(TAG, "CreateEvent failed!");
908 error = ERROR_INTERNAL_ERROR;
909 goto error_out;
910 }
911
912 if (!(printer_dev->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
913 {
914 WLog_ERR(TAG, "CreateEvent failed!");
915 error = ERROR_INTERNAL_ERROR;
916 goto error_out;
917 }
918
919 if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*)printer_dev)))
920 {
921 WLog_ERR(TAG, "RegisterDevice failed with error %" PRIu32 "!", error);
922 goto error_out;
923 }
924
925 if (!(printer_dev->thread =
926 CreateThread(NULL, 0, printer_thread_func, (void*)printer_dev, 0, NULL)))
927 {
928 WLog_ERR(TAG, "CreateThread failed!");
929 error = ERROR_INTERNAL_ERROR;
930 goto error_out;
931 }
932
933 printer->AddRef(printer);
934 return CHANNEL_RC_OK;
935 error_out:
936 printer_free(&printer_dev->device);
937 return error;
938 }
939
printer_load_backend(const char * backend)940 static rdpPrinterDriver* printer_load_backend(const char* backend)
941 {
942 typedef rdpPrinterDriver* (*backend_load_t)(void);
943 union {
944 PVIRTUALCHANNELENTRY entry;
945 backend_load_t backend;
946 } fktconv;
947
948 fktconv.entry = freerdp_load_channel_addin_entry("printer", backend, NULL, 0);
949 if (!fktconv.entry)
950 return NULL;
951
952 return fktconv.backend();
953 }
954
955 /**
956 * Function description
957 *
958 * @return 0 on success, otherwise a Win32 error code
959 */
960 UINT
961 #ifdef BUILTIN_CHANNELS
printer_DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)962 printer_DeviceServiceEntry
963 #else
964 FREERDP_API
965 DeviceServiceEntry
966 #endif
967 (PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
968 {
969 int i;
970 char* name;
971 char* driver_name;
972 BOOL default_backend = TRUE;
973 RDPDR_PRINTER* device = NULL;
974 rdpPrinterDriver* driver = NULL;
975 UINT error = CHANNEL_RC_OK;
976
977 if (!pEntryPoints || !pEntryPoints->device)
978 return ERROR_INVALID_PARAMETER;
979
980 device = (RDPDR_PRINTER*)pEntryPoints->device;
981 name = device->Name;
982 driver_name = _strdup(device->DriverName);
983
984 /* Secondary argument is one of the following:
985 *
986 * <driver_name> ... name of a printer driver
987 * <driver_name>:<backend_name> ... name of a printer driver and local printer backend to use
988 */
989 if (driver_name)
990 {
991 char* sep = strstr(driver_name, ":");
992 if (sep)
993 {
994 const char* backend = sep + 1;
995 *sep = '\0';
996 driver = printer_load_backend(backend);
997 default_backend = FALSE;
998 }
999 }
1000
1001 if (!driver && default_backend)
1002 {
1003 const char* backend =
1004 #if defined(WITH_CUPS)
1005 "cups"
1006 #elif defined(_WIN32)
1007 "win"
1008 #else
1009 ""
1010 #endif
1011 ;
1012
1013 driver = printer_load_backend(backend);
1014 }
1015
1016 if (!driver)
1017 {
1018 WLog_ERR(TAG, "Could not get a printer driver!");
1019 error = CHANNEL_RC_INITIALIZATION_ERROR;
1020 goto fail;
1021 }
1022
1023 if (name && name[0])
1024 {
1025 rdpPrinter* printer = driver->GetPrinter(driver, name, driver_name);
1026
1027 if (!printer)
1028 {
1029 WLog_ERR(TAG, "Could not get printer %s!", name);
1030 error = CHANNEL_RC_INITIALIZATION_ERROR;
1031 goto fail;
1032 }
1033
1034 if (!printer_save_default_config(pEntryPoints->rdpcontext->settings, printer))
1035 {
1036 error = CHANNEL_RC_INITIALIZATION_ERROR;
1037 printer->ReleaseRef(printer);
1038 goto fail;
1039 }
1040
1041 if ((error = printer_register(pEntryPoints, printer)))
1042 {
1043 WLog_ERR(TAG, "printer_register failed with error %" PRIu32 "!", error);
1044 printer->ReleaseRef(printer);
1045 goto fail;
1046 }
1047 }
1048 else
1049 {
1050 rdpPrinter** printers = driver->EnumPrinters(driver);
1051 rdpPrinter** current = printers;
1052
1053 for (i = 0; current[i]; i++)
1054 {
1055 rdpPrinter* printer = current[i];
1056
1057 if ((error = printer_register(pEntryPoints, printer)))
1058 {
1059 WLog_ERR(TAG, "printer_register failed with error %" PRIu32 "!", error);
1060 break;
1061 }
1062 }
1063
1064 driver->ReleaseEnumPrinters(printers);
1065 }
1066
1067 fail:
1068 free(driver_name);
1069 if (driver)
1070 driver->ReleaseRef(driver);
1071
1072 return error;
1073 }
1074