295 lines
8.7 KiB
C++
295 lines
8.7 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 2000-2001 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
PrinterGetPrtL2.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This is a shim that can be applied to those applications who
|
||
|
assumed false upper-limit on the size of PRINTER_INFO_2 buffer
|
||
|
GetPrinter returns. What the shim does is that when it detects
|
||
|
the spooler returned PRINTER_INFO_2 buffer is over a certain
|
||
|
limit that could break those apps, it truncates the private
|
||
|
devmode part in PRINTER_INFO_2's pDevMode to retain only the
|
||
|
public devmode, and returns the truncated PRINTER_INFO_2 buffer.
|
||
|
|
||
|
History:
|
||
|
|
||
|
10/29/2001 fengy Created
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "precomp.h"
|
||
|
#include <stddef.h>
|
||
|
|
||
|
IMPLEMENT_SHIM_BEGIN(PrinterGetPrtL2)
|
||
|
#include "ShimHookMacro.h"
|
||
|
|
||
|
APIHOOK_ENUM_BEGIN
|
||
|
APIHOOK_ENUM_ENTRY(GetPrinterA)
|
||
|
APIHOOK_ENUM_END
|
||
|
|
||
|
#define ALIGN_PTR_UP(addr) ((ULONG_PTR)((ULONG_PTR)(addr) + (sizeof(ULONG_PTR) - 1)) & ~(sizeof(ULONG_PTR) - 1))
|
||
|
|
||
|
//
|
||
|
// The PRINTER_INFO_2 buffer size limit over which this shim
|
||
|
// will perform the devmode truncation. The default value is
|
||
|
// set to 8K here. App-specific limit values can be specified
|
||
|
// as decimal numbers in the XML database as following:
|
||
|
//
|
||
|
// <SHIM NAME="PrinterGetPrtL2" COMMAND_LINE="1024"/>
|
||
|
//
|
||
|
LONG g_lTruncateLimit = 0x2000;
|
||
|
|
||
|
//
|
||
|
// Table of offsets to each string field in PRINTER_INFO_2A
|
||
|
//
|
||
|
DWORD g_dwStringOffsets[] = {offsetof(PRINTER_INFO_2A, pServerName),
|
||
|
offsetof(PRINTER_INFO_2A, pPrinterName),
|
||
|
offsetof(PRINTER_INFO_2A, pShareName),
|
||
|
offsetof(PRINTER_INFO_2A, pPortName),
|
||
|
offsetof(PRINTER_INFO_2A, pDriverName),
|
||
|
offsetof(PRINTER_INFO_2A, pComment),
|
||
|
offsetof(PRINTER_INFO_2A, pLocation),
|
||
|
offsetof(PRINTER_INFO_2A, pSepFile),
|
||
|
offsetof(PRINTER_INFO_2A, pPrintProcessor),
|
||
|
offsetof(PRINTER_INFO_2A, pDatatype),
|
||
|
offsetof(PRINTER_INFO_2A, pParameters),
|
||
|
0xFFFFFFFF};
|
||
|
|
||
|
/*++
|
||
|
|
||
|
This stub function intercepts all level 2 calls to GetPrinterA and detects
|
||
|
if the spooler returned PRINTER_INFO_2 buffer is over the app limit. If so,
|
||
|
it will truncate the private devmode of PRINTER_INFO_2's pDevMode.
|
||
|
|
||
|
--*/
|
||
|
BOOL
|
||
|
APIHOOK(GetPrinterA)(
|
||
|
HANDLE hPrinter,
|
||
|
DWORD Level,
|
||
|
LPBYTE pPrinter,
|
||
|
DWORD cbBuf,
|
||
|
LPDWORD pcbNeeded
|
||
|
)
|
||
|
{
|
||
|
BOOL bNoTruncation = TRUE;
|
||
|
BOOL bRet;
|
||
|
|
||
|
if (Level == 2 && pPrinter != NULL && cbBuf != 0)
|
||
|
{
|
||
|
PRINTER_INFO_2A *pInfo2Full = NULL;
|
||
|
DWORD cbFullNeeded = 0;
|
||
|
|
||
|
//
|
||
|
// Call spooler to get the full PRINTER_INFO_2 buffer size
|
||
|
//
|
||
|
bRet = ORIGINAL_API(GetPrinterA)(
|
||
|
hPrinter,
|
||
|
2,
|
||
|
NULL,
|
||
|
0,
|
||
|
&cbFullNeeded);
|
||
|
|
||
|
if (!bRet &&
|
||
|
GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
|
||
|
cbFullNeeded > (DWORD)g_lTruncateLimit &&
|
||
|
cbBuf >= cbFullNeeded &&
|
||
|
(pInfo2Full = (PRINTER_INFO_2A *)malloc(cbFullNeeded)))
|
||
|
{
|
||
|
//
|
||
|
// The full PRINTER_INFO_2 buffer size is over the app limit,
|
||
|
// so we will first retrieve the full buffer into our internal
|
||
|
// buffer.
|
||
|
//
|
||
|
// The condition "cbBuf >= cbFullNeeded" is here because if
|
||
|
// that's not true, the original GetPrinterA's behavior is to
|
||
|
// fail the call. We don't want to change that behavior.
|
||
|
//
|
||
|
bRet = ORIGINAL_API(GetPrinterA)(
|
||
|
hPrinter,
|
||
|
2,
|
||
|
(PBYTE)pInfo2Full,
|
||
|
cbFullNeeded,
|
||
|
&cbFullNeeded);
|
||
|
|
||
|
if (bRet)
|
||
|
{
|
||
|
PRINTER_INFO_2A *pInfo2In;
|
||
|
PBYTE pDest;
|
||
|
INT i;
|
||
|
|
||
|
//
|
||
|
// Having the full PRINTER_INFO_2 structure in our internal
|
||
|
// buffer, now we will copy it into app-allocated output buffer
|
||
|
// by duplicating every thing except for the pDevMode. For
|
||
|
// pDevMode we will only copy over the public devmode part,
|
||
|
// because the bigger size of PRINTER_INFO_2 structure usually
|
||
|
// are caused by big private devmode.
|
||
|
//
|
||
|
pInfo2In = (PRINTER_INFO_2A *)pPrinter;
|
||
|
pDest = (PBYTE)pInfo2In + sizeof(PRINTER_INFO_2A);
|
||
|
|
||
|
//
|
||
|
// First copy over all the strings
|
||
|
//
|
||
|
i = 0;
|
||
|
while (g_dwStringOffsets[i] != (-1))
|
||
|
{
|
||
|
PSTR pSrc;
|
||
|
|
||
|
pSrc = *(PSTR *)((PBYTE)pInfo2Full + g_dwStringOffsets[i]);
|
||
|
|
||
|
if (pSrc)
|
||
|
{
|
||
|
DWORD cbStrSize;
|
||
|
|
||
|
cbStrSize = strlen(pSrc) + sizeof(CHAR);
|
||
|
memcpy(pDest, pSrc, cbStrSize);
|
||
|
|
||
|
*(PSTR *)((PBYTE)pInfo2In + g_dwStringOffsets[i]) = (PSTR)pDest;
|
||
|
pDest += cbStrSize;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*(PSTR *)((PBYTE)pInfo2In + g_dwStringOffsets[i]) = NULL;
|
||
|
}
|
||
|
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Then truncate the private devmode part by only copying over
|
||
|
// public devmode
|
||
|
//
|
||
|
if (pInfo2Full->pDevMode)
|
||
|
{
|
||
|
pDest = (PBYTE)ALIGN_PTR_UP(pDest);
|
||
|
memcpy(pDest, pInfo2Full->pDevMode, pInfo2Full->pDevMode->dmSize);
|
||
|
pInfo2In->pDevMode = (DEVMODEA *)pDest;
|
||
|
|
||
|
//
|
||
|
// Set private devmode size to zero since it was just truncated
|
||
|
//
|
||
|
pInfo2In->pDevMode->dmDriverExtra = 0;
|
||
|
|
||
|
pDest += pInfo2In->pDevMode->dmSize;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pInfo2In->pDevMode = NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Then copy over the security descriptor
|
||
|
//
|
||
|
if (pInfo2Full->pSecurityDescriptor &&
|
||
|
IsValidSecurityDescriptor(pInfo2Full->pSecurityDescriptor))
|
||
|
{
|
||
|
DWORD cbSDSize;
|
||
|
|
||
|
cbSDSize = GetSecurityDescriptorLength(pInfo2Full->pSecurityDescriptor);
|
||
|
|
||
|
pDest = (PBYTE)ALIGN_PTR_UP(pDest);
|
||
|
memcpy(pDest, pInfo2Full->pSecurityDescriptor, cbSDSize);
|
||
|
pInfo2In->pSecurityDescriptor = (PSECURITY_DESCRIPTOR)pDest;
|
||
|
|
||
|
pDest += cbSDSize;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pInfo2In->pSecurityDescriptor = NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Lastly copy over all the DWORD fields
|
||
|
//
|
||
|
pInfo2In->Attributes = pInfo2Full->Attributes;
|
||
|
pInfo2In->Priority = pInfo2Full->Priority;
|
||
|
pInfo2In->DefaultPriority = pInfo2Full->DefaultPriority;
|
||
|
pInfo2In->StartTime = pInfo2Full->StartTime;
|
||
|
pInfo2In->UntilTime = pInfo2Full->UntilTime;
|
||
|
pInfo2In->Status = pInfo2Full->Status;
|
||
|
pInfo2In->cJobs = pInfo2Full->cJobs;
|
||
|
pInfo2In->AveragePPM = pInfo2Full->AveragePPM;
|
||
|
|
||
|
//
|
||
|
// We also need to set the correct return buffer size
|
||
|
//
|
||
|
if (pcbNeeded)
|
||
|
{
|
||
|
*pcbNeeded = pDest - pPrinter;
|
||
|
}
|
||
|
|
||
|
bNoTruncation = FALSE;
|
||
|
|
||
|
DPFN(eDbgLevelInfo, "GetPrinterA truncated from %X to %X bytes",
|
||
|
cbBuf, pDest - pPrinter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pInfo2Full)
|
||
|
{
|
||
|
free(pInfo2Full);
|
||
|
pInfo2Full = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (bNoTruncation)
|
||
|
{
|
||
|
//
|
||
|
// The shim doesn't need to do any truncation, or it has hit
|
||
|
// an error when it was doing the truncation, so we will
|
||
|
// just let the original API handle the call.
|
||
|
//
|
||
|
bRet = ORIGINAL_API(GetPrinterA)(
|
||
|
hPrinter,
|
||
|
Level,
|
||
|
pPrinter,
|
||
|
cbBuf,
|
||
|
pcbNeeded);
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Handle DLL_PROCESS_ATTACH to retrieve command line parameter.
|
||
|
|
||
|
--*/
|
||
|
BOOL
|
||
|
NOTIFY_FUNCTION(
|
||
|
DWORD fdwReason
|
||
|
)
|
||
|
{
|
||
|
if (fdwReason == DLL_PROCESS_ATTACH)
|
||
|
{
|
||
|
LONG lLimit = atol(COMMAND_LINE);
|
||
|
|
||
|
if (lLimit > 0)
|
||
|
{
|
||
|
g_lTruncateLimit = lLimit;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Register hooked functions
|
||
|
|
||
|
--*/
|
||
|
HOOK_BEGIN
|
||
|
|
||
|
CALL_NOTIFY_FUNCTION
|
||
|
APIHOOK_ENTRY(WINSPOOL.DRV, GetPrinterA);
|
||
|
|
||
|
HOOK_END
|
||
|
|
||
|
IMPLEMENT_SHIM_END
|