зеркало из https://github.com/github/putty.git
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:
Родитель
73039b7831
Коммит
793ac87275
2
Recipe
2
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.
|
||||
|
|
|
@ -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,7 +65,7 @@ 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,
|
||||
p_EnumPrinters(param, NULL, level, (LPBYTE)((*buffer)+offset), 512,
|
||||
&needed, &nprinters);
|
||||
|
||||
if (needed < 512)
|
||||
|
@ -38,7 +73,7 @@ static int printer_add_enum(int param, DWORD level, char **buffer,
|
|||
|
||||
*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)
|
||||
return FALSE;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче