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.
This commit is contained in:
Simon Tatham 2017-03-13 21:28:36 +00:00
Родитель 73039b7831
Коммит 793ac87275
2 изменённых файлов: 52 добавлений и 15 удалений

2
Recipe
Просмотреть файл

@ -274,7 +274,7 @@ CHARSET = sbcsdat slookup sbcs utf8 toucs fromucs xenc mimeenc macenc localenc
# Standard libraries. # Standard libraries.
LIBS = advapi32.lib user32.lib gdi32.lib comctl32.lib comdlg32.lib 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 # Network backend sets. This also brings in the relevant attachment
# to proxy.c depending on whether we're crypto-avoidant or not. # to proxy.c depending on whether we're crypto-avoidant or not.

Просмотреть файл

@ -18,11 +18,46 @@ struct printer_job_tag {
HANDLE hprinter; 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, static int printer_add_enum(int param, DWORD level, char **buffer,
int offset, int *nprinters_ptr) int offset, int *nprinters_ptr)
{ {
DWORD needed = 0, nprinters = 0; DWORD needed = 0, nprinters = 0;
init_winfuncs();
*buffer = sresize(*buffer, offset+512, char); *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 * we'll need for the output. Discard the return value since it
* will almost certainly be a failure due to lack of space. * will almost certainly be a failure due to lack of space.
*/ */
EnumPrinters(param, NULL, level, (LPBYTE)((*buffer)+offset), 512, p_EnumPrinters(param, NULL, level, (LPBYTE)((*buffer)+offset), 512,
&needed, &nprinters); &needed, &nprinters);
if (needed < 512) if (needed < 512)
needed = 512; needed = 512;
*buffer = sresize(*buffer, offset+needed, char); *buffer = sresize(*buffer, offset+needed, char);
if (EnumPrinters(param, NULL, level, (LPBYTE)((*buffer)+offset), if (p_EnumPrinters(param, NULL, level, (LPBYTE)((*buffer)+offset),
needed, &needed, &nprinters) == 0) needed, &needed, &nprinters) == 0)
return FALSE; return FALSE;
*nprinters_ptr += nprinters; *nprinters_ptr += nprinters;
@ -131,19 +166,21 @@ printer_job *printer_start_job(char *printer)
DOC_INFO_1 docinfo; DOC_INFO_1 docinfo;
int jobstarted = 0, pagestarted = 0; int jobstarted = 0, pagestarted = 0;
init_winfuncs();
ret->hprinter = NULL; ret->hprinter = NULL;
if (!OpenPrinter(printer, &ret->hprinter, NULL)) if (!p_OpenPrinter(printer, &ret->hprinter, NULL))
goto error; goto error;
docinfo.pDocName = "PuTTY remote printer output"; docinfo.pDocName = "PuTTY remote printer output";
docinfo.pOutputFile = NULL; docinfo.pOutputFile = NULL;
docinfo.pDatatype = "RAW"; docinfo.pDatatype = "RAW";
if (!StartDocPrinter(ret->hprinter, 1, (LPBYTE)&docinfo)) if (!p_StartDocPrinter(ret->hprinter, 1, (LPBYTE)&docinfo))
goto error; goto error;
jobstarted = 1; jobstarted = 1;
if (!StartPagePrinter(ret->hprinter)) if (!p_StartPagePrinter(ret->hprinter))
goto error; goto error;
pagestarted = 1; pagestarted = 1;
@ -151,11 +188,11 @@ printer_job *printer_start_job(char *printer)
error: error:
if (pagestarted) if (pagestarted)
EndPagePrinter(ret->hprinter); p_EndPagePrinter(ret->hprinter);
if (jobstarted) if (jobstarted)
EndDocPrinter(ret->hprinter); p_EndDocPrinter(ret->hprinter);
if (ret->hprinter) if (ret->hprinter)
ClosePrinter(ret->hprinter); p_ClosePrinter(ret->hprinter);
sfree(ret); sfree(ret);
return NULL; return NULL;
} }
@ -167,7 +204,7 @@ void printer_job_data(printer_job *pj, void *data, int len)
if (!pj) if (!pj)
return; return;
WritePrinter(pj->hprinter, data, len, &written); p_WritePrinter(pj->hprinter, data, len, &written);
} }
void printer_finish_job(printer_job *pj) void printer_finish_job(printer_job *pj)
@ -175,8 +212,8 @@ void printer_finish_job(printer_job *pj)
if (!pj) if (!pj)
return; return;
EndPagePrinter(pj->hprinter); p_EndPagePrinter(pj->hprinter);
EndDocPrinter(pj->hprinter); p_EndDocPrinter(pj->hprinter);
ClosePrinter(pj->hprinter); p_ClosePrinter(pj->hprinter);
sfree(pj); sfree(pj);
} }