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