Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

294 lines
9.0 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. PrinterGetPrtL2.cpp
  5. Abstract:
  6. This is a shim that can be applied to those applications who
  7. assumed false upper-limit on the size of PRINTER_INFO_2 buffer
  8. GetPrinter returns. What the shim does is that when it detects
  9. the spooler returned PRINTER_INFO_2 buffer is over a certain
  10. limit that could break those apps, it truncates the private
  11. devmode part in PRINTER_INFO_2's pDevMode to retain only the
  12. public devmode, and returns the truncated PRINTER_INFO_2 buffer.
  13. History:
  14. 10/29/2001 fengy Created
  15. --*/
  16. #include "precomp.h"
  17. #include <stddef.h>
  18. IMPLEMENT_SHIM_BEGIN(PrinterGetPrtL2)
  19. #include "ShimHookMacro.h"
  20. APIHOOK_ENUM_BEGIN
  21. APIHOOK_ENUM_ENTRY(GetPrinterA)
  22. APIHOOK_ENUM_END
  23. #define ALIGN_PTR_UP(addr) ((ULONG_PTR)((ULONG_PTR)(addr) + (sizeof(ULONG_PTR) - 1)) & ~(sizeof(ULONG_PTR) - 1))
  24. //
  25. // The PRINTER_INFO_2 buffer size limit over which this shim
  26. // will perform the devmode truncation. The default value is
  27. // set to 8K here. App-specific limit values can be specified
  28. // as decimal numbers in the XML database as following:
  29. //
  30. // <SHIM NAME="PrinterGetPrtL2" COMMAND_LINE="1024"/>
  31. //
  32. LONG g_lTruncateLimit = 0x2000;
  33. //
  34. // Table of offsets to each string field in PRINTER_INFO_2A
  35. //
  36. DWORD g_dwStringOffsets[] = {offsetof(PRINTER_INFO_2A, pServerName),
  37. offsetof(PRINTER_INFO_2A, pPrinterName),
  38. offsetof(PRINTER_INFO_2A, pShareName),
  39. offsetof(PRINTER_INFO_2A, pPortName),
  40. offsetof(PRINTER_INFO_2A, pDriverName),
  41. offsetof(PRINTER_INFO_2A, pComment),
  42. offsetof(PRINTER_INFO_2A, pLocation),
  43. offsetof(PRINTER_INFO_2A, pSepFile),
  44. offsetof(PRINTER_INFO_2A, pPrintProcessor),
  45. offsetof(PRINTER_INFO_2A, pDatatype),
  46. offsetof(PRINTER_INFO_2A, pParameters),
  47. 0xFFFFFFFF};
  48. /*++
  49. This stub function intercepts all level 2 calls to GetPrinterA and detects
  50. if the spooler returned PRINTER_INFO_2 buffer is over the app limit. If so,
  51. it will truncate the private devmode of PRINTER_INFO_2's pDevMode.
  52. --*/
  53. BOOL
  54. APIHOOK(GetPrinterA)(
  55. HANDLE hPrinter,
  56. DWORD Level,
  57. LPBYTE pPrinter,
  58. DWORD cbBuf,
  59. LPDWORD pcbNeeded
  60. )
  61. {
  62. BOOL bNoTruncation = TRUE;
  63. BOOL bRet;
  64. if (Level == 2 && pPrinter != NULL && cbBuf != 0)
  65. {
  66. PRINTER_INFO_2A *pInfo2Full = NULL;
  67. DWORD cbFullNeeded = 0;
  68. //
  69. // Call spooler to get the full PRINTER_INFO_2 buffer size
  70. //
  71. bRet = ORIGINAL_API(GetPrinterA)(
  72. hPrinter,
  73. 2,
  74. NULL,
  75. 0,
  76. &cbFullNeeded);
  77. if (!bRet &&
  78. GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
  79. cbFullNeeded > (DWORD)g_lTruncateLimit &&
  80. cbBuf >= cbFullNeeded &&
  81. (pInfo2Full = (PRINTER_INFO_2A *)malloc(cbFullNeeded)))
  82. {
  83. //
  84. // The full PRINTER_INFO_2 buffer size is over the app limit,
  85. // so we will first retrieve the full buffer into our internal
  86. // buffer.
  87. //
  88. // The condition "cbBuf >= cbFullNeeded" is here because if
  89. // that's not true, the original GetPrinterA's behavior is to
  90. // fail the call. We don't want to change that behavior.
  91. //
  92. bRet = ORIGINAL_API(GetPrinterA)(
  93. hPrinter,
  94. 2,
  95. (PBYTE)pInfo2Full,
  96. cbFullNeeded,
  97. &cbFullNeeded);
  98. if (bRet)
  99. {
  100. PRINTER_INFO_2A *pInfo2In;
  101. PBYTE pDest;
  102. INT i;
  103. //
  104. // Having the full PRINTER_INFO_2 structure in our internal
  105. // buffer, now we will copy it into app-allocated output buffer
  106. // by duplicating every thing except for the pDevMode. For
  107. // pDevMode we will only copy over the public devmode part,
  108. // because the bigger size of PRINTER_INFO_2 structure usually
  109. // are caused by big private devmode.
  110. //
  111. pInfo2In = (PRINTER_INFO_2A *)pPrinter;
  112. pDest = (PBYTE)pInfo2In + sizeof(PRINTER_INFO_2A);
  113. //
  114. // First copy over all the strings
  115. //
  116. i = 0;
  117. while (g_dwStringOffsets[i] != (-1))
  118. {
  119. PSTR pSrc;
  120. pSrc = *(PSTR *)((PBYTE)pInfo2Full + g_dwStringOffsets[i]);
  121. if (pSrc)
  122. {
  123. DWORD cbStrSize;
  124. cbStrSize = strlen(pSrc) + sizeof(CHAR);
  125. memcpy(pDest, pSrc, cbStrSize);
  126. *(PSTR *)((PBYTE)pInfo2In + g_dwStringOffsets[i]) = (PSTR)pDest;
  127. pDest += cbStrSize;
  128. }
  129. else
  130. {
  131. *(PSTR *)((PBYTE)pInfo2In + g_dwStringOffsets[i]) = NULL;
  132. }
  133. i++;
  134. }
  135. //
  136. // Then truncate the private devmode part by only copying over
  137. // public devmode
  138. //
  139. if (pInfo2Full->pDevMode)
  140. {
  141. pDest = (PBYTE)ALIGN_PTR_UP(pDest);
  142. memcpy(pDest, pInfo2Full->pDevMode, pInfo2Full->pDevMode->dmSize);
  143. pInfo2In->pDevMode = (DEVMODEA *)pDest;
  144. //
  145. // Set private devmode size to zero since it was just truncated
  146. //
  147. pInfo2In->pDevMode->dmDriverExtra = 0;
  148. pDest += pInfo2In->pDevMode->dmSize;
  149. }
  150. else
  151. {
  152. pInfo2In->pDevMode = NULL;
  153. }
  154. //
  155. // Then copy over the security descriptor
  156. //
  157. if (pInfo2Full->pSecurityDescriptor &&
  158. IsValidSecurityDescriptor(pInfo2Full->pSecurityDescriptor))
  159. {
  160. DWORD cbSDSize;
  161. cbSDSize = GetSecurityDescriptorLength(pInfo2Full->pSecurityDescriptor);
  162. pDest = (PBYTE)ALIGN_PTR_UP(pDest);
  163. memcpy(pDest, pInfo2Full->pSecurityDescriptor, cbSDSize);
  164. pInfo2In->pSecurityDescriptor = (PSECURITY_DESCRIPTOR)pDest;
  165. pDest += cbSDSize;
  166. }
  167. else
  168. {
  169. pInfo2In->pSecurityDescriptor = NULL;
  170. }
  171. //
  172. // Lastly copy over all the DWORD fields
  173. //
  174. pInfo2In->Attributes = pInfo2Full->Attributes;
  175. pInfo2In->Priority = pInfo2Full->Priority;
  176. pInfo2In->DefaultPriority = pInfo2Full->DefaultPriority;
  177. pInfo2In->StartTime = pInfo2Full->StartTime;
  178. pInfo2In->UntilTime = pInfo2Full->UntilTime;
  179. pInfo2In->Status = pInfo2Full->Status;
  180. pInfo2In->cJobs = pInfo2Full->cJobs;
  181. pInfo2In->AveragePPM = pInfo2Full->AveragePPM;
  182. //
  183. // We also need to set the correct return buffer size
  184. //
  185. if (pcbNeeded)
  186. {
  187. *pcbNeeded = pDest - pPrinter;
  188. }
  189. bNoTruncation = FALSE;
  190. DPFN(eDbgLevelInfo, "GetPrinterA truncated from %X to %X bytes",
  191. cbBuf, pDest - pPrinter);
  192. }
  193. }
  194. if (pInfo2Full)
  195. {
  196. free(pInfo2Full);
  197. pInfo2Full = NULL;
  198. }
  199. }
  200. if (bNoTruncation)
  201. {
  202. //
  203. // The shim doesn't need to do any truncation, or it has hit
  204. // an error when it was doing the truncation, so we will
  205. // just let the original API handle the call.
  206. //
  207. bRet = ORIGINAL_API(GetPrinterA)(
  208. hPrinter,
  209. Level,
  210. pPrinter,
  211. cbBuf,
  212. pcbNeeded);
  213. }
  214. return bRet;
  215. }
  216. /*++
  217. Handle DLL_PROCESS_ATTACH to retrieve command line parameter.
  218. --*/
  219. BOOL
  220. NOTIFY_FUNCTION(
  221. DWORD fdwReason
  222. )
  223. {
  224. if (fdwReason == DLL_PROCESS_ATTACH)
  225. {
  226. LONG lLimit = atol(COMMAND_LINE);
  227. if (lLimit > 0)
  228. {
  229. g_lTruncateLimit = lLimit;
  230. }
  231. }
  232. return TRUE;
  233. }
  234. /*++
  235. Register hooked functions
  236. --*/
  237. HOOK_BEGIN
  238. CALL_NOTIFY_FUNCTION
  239. APIHOOK_ENTRY(WINSPOOL.DRV, GetPrinterA);
  240. HOOK_END
  241. IMPLEMENT_SHIM_END