windows-nt/Source/XPSP1/NT/windows/appcompat/shims/external/printergetprtl2.cpp

295 lines
8.7 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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