From 793ac872757667a87df4636b5b3eed61302dd837 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 13 Mar 2017 21:28:36 +0000 Subject: [PATCH] Load the Windows printing subsystem at run time. The printing functions are split between winspool.drv and spoolss.dll in a really weird way (who would have guessed that OpenPrinter and ClosePrinter don't live in the same dynamic library?!), but _neither_ of those counts as a system 'known DLL', so linking against either one of these at load time is again a potential DLL hijacking vector. --- Recipe | 2 +- windows/winprint.c | 65 ++++++++++++++++++++++++++++++++++++---------- 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/Recipe b/Recipe index e2cce9ae..0fb7bbb7 100644 --- a/Recipe +++ b/Recipe @@ -274,7 +274,7 @@ CHARSET = sbcsdat slookup sbcs utf8 toucs fromucs xenc mimeenc macenc localenc # Standard libraries. LIBS = advapi32.lib user32.lib gdi32.lib comctl32.lib comdlg32.lib - + shell32.lib imm32.lib winspool.lib ole32.lib + + shell32.lib imm32.lib ole32.lib # Network backend sets. This also brings in the relevant attachment # to proxy.c depending on whether we're crypto-avoidant or not. diff --git a/windows/winprint.c b/windows/winprint.c index c190e5fb..11587273 100644 --- a/windows/winprint.c +++ b/windows/winprint.c @@ -18,11 +18,46 @@ struct printer_job_tag { HANDLE hprinter; }; +DECL_WINDOWS_FUNCTION(static, BOOL, EnumPrinters, + (DWORD, LPTSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD)); +DECL_WINDOWS_FUNCTION(static, BOOL, OpenPrinter, + (LPTSTR, LPHANDLE, LPPRINTER_DEFAULTS)); +DECL_WINDOWS_FUNCTION(static, BOOL, ClosePrinter, (HANDLE)); +DECL_WINDOWS_FUNCTION(static, BOOL, StartDocPrinter, (HANDLE, DWORD, LPBYTE)); +DECL_WINDOWS_FUNCTION(static, BOOL, EndDocPrinter, (HANDLE)); +DECL_WINDOWS_FUNCTION(static, BOOL, StartPagePrinter, (HANDLE)); +DECL_WINDOWS_FUNCTION(static, BOOL, EndPagePrinter, (HANDLE)); +DECL_WINDOWS_FUNCTION(static, BOOL, WritePrinter, + (HANDLE, LPVOID, DWORD, LPDWORD)); + +static void init_winfuncs(void) +{ + static int initialised = FALSE; + char buf[4096]; + if (initialised) + return; + { + HMODULE winspool_module = load_system32_dll("winspool.drv"); + HMODULE spoolss_module = load_system32_dll("spoolss.dll"); + GET_WINDOWS_FUNCTION_PP(winspool_module, EnumPrinters); + GET_WINDOWS_FUNCTION_PP(winspool_module, OpenPrinter); + GET_WINDOWS_FUNCTION_PP(spoolss_module, ClosePrinter); + GET_WINDOWS_FUNCTION_PP(winspool_module, StartDocPrinter); + GET_WINDOWS_FUNCTION_PP(spoolss_module, EndDocPrinter); + GET_WINDOWS_FUNCTION_PP(spoolss_module, StartPagePrinter); + GET_WINDOWS_FUNCTION_PP(spoolss_module, EndPagePrinter); + GET_WINDOWS_FUNCTION_PP(spoolss_module, WritePrinter); + } + initialised = TRUE; +} + static int printer_add_enum(int param, DWORD level, char **buffer, int offset, int *nprinters_ptr) { DWORD needed = 0, nprinters = 0; + init_winfuncs(); + *buffer = sresize(*buffer, offset+512, char); /* @@ -30,16 +65,16 @@ static int printer_add_enum(int param, DWORD level, char **buffer, * we'll need for the output. Discard the return value since it * will almost certainly be a failure due to lack of space. */ - EnumPrinters(param, NULL, level, (LPBYTE)((*buffer)+offset), 512, - &needed, &nprinters); + p_EnumPrinters(param, NULL, level, (LPBYTE)((*buffer)+offset), 512, + &needed, &nprinters); if (needed < 512) needed = 512; *buffer = sresize(*buffer, offset+needed, char); - if (EnumPrinters(param, NULL, level, (LPBYTE)((*buffer)+offset), - needed, &needed, &nprinters) == 0) + if (p_EnumPrinters(param, NULL, level, (LPBYTE)((*buffer)+offset), + needed, &needed, &nprinters) == 0) return FALSE; *nprinters_ptr += nprinters; @@ -131,19 +166,21 @@ printer_job *printer_start_job(char *printer) DOC_INFO_1 docinfo; int jobstarted = 0, pagestarted = 0; + init_winfuncs(); + ret->hprinter = NULL; - if (!OpenPrinter(printer, &ret->hprinter, NULL)) + if (!p_OpenPrinter(printer, &ret->hprinter, NULL)) goto error; docinfo.pDocName = "PuTTY remote printer output"; docinfo.pOutputFile = NULL; docinfo.pDatatype = "RAW"; - if (!StartDocPrinter(ret->hprinter, 1, (LPBYTE)&docinfo)) + if (!p_StartDocPrinter(ret->hprinter, 1, (LPBYTE)&docinfo)) goto error; jobstarted = 1; - if (!StartPagePrinter(ret->hprinter)) + if (!p_StartPagePrinter(ret->hprinter)) goto error; pagestarted = 1; @@ -151,11 +188,11 @@ printer_job *printer_start_job(char *printer) error: if (pagestarted) - EndPagePrinter(ret->hprinter); + p_EndPagePrinter(ret->hprinter); if (jobstarted) - EndDocPrinter(ret->hprinter); + p_EndDocPrinter(ret->hprinter); if (ret->hprinter) - ClosePrinter(ret->hprinter); + p_ClosePrinter(ret->hprinter); sfree(ret); return NULL; } @@ -167,7 +204,7 @@ void printer_job_data(printer_job *pj, void *data, int len) if (!pj) return; - WritePrinter(pj->hprinter, data, len, &written); + p_WritePrinter(pj->hprinter, data, len, &written); } void printer_finish_job(printer_job *pj) @@ -175,8 +212,8 @@ void printer_finish_job(printer_job *pj) if (!pj) return; - EndPagePrinter(pj->hprinter); - EndDocPrinter(pj->hprinter); - ClosePrinter(pj->hprinter); + p_EndPagePrinter(pj->hprinter); + p_EndDocPrinter(pj->hprinter); + p_ClosePrinter(pj->hprinter); sfree(pj); }