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.

522 lines
13 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. prnsupp.c
  5. Abstract:
  6. This module contains routines for supporting printing in the NT
  7. server. Many of these routines are wrappers that send the request
  8. off to XACTSRV through LPC in order to issue a user-mode API.
  9. Author:
  10. David Treadwell (davidtr) 05-Nov-1991
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #include "prnsupp.tmh"
  15. #pragma hdrstop
  16. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text( PAGE, SrvOpenPrinter )
  18. #pragma alloc_text( PAGE, SrvAddPrintJob )
  19. #pragma alloc_text( PAGE, SrvSchedulePrintJob )
  20. #pragma alloc_text( PAGE, SrvClosePrinter )
  21. #endif
  22. NTSTATUS
  23. SrvOpenPrinter(
  24. IN PWCH PrinterName,
  25. OUT PHANDLE phPrinter,
  26. OUT PULONG Error
  27. )
  28. /*++
  29. Routine Description:
  30. This routine is a kernel-mode wrapper for the the user-mode API
  31. OpenPrinter( ). This packages up a call and sends it off to
  32. Xactsrv, which makes the actual API call.
  33. Arguments:
  34. Printer - a pointer to a Unicode string of the printer to open
  35. Handle - receives a handle, valid only in XACTSRV, that corresponds to
  36. the Printer open.
  37. Error - a Win32 error if one occurred, or NO_ERROR if the operation
  38. was successful.
  39. Return Value:
  40. NTSTATUS - result of operation.
  41. --*/
  42. {
  43. NTSTATUS status;
  44. XACTSRV_REQUEST_MESSAGE requestMessage;
  45. XACTSRV_REPLY_MESSAGE replyMessage;
  46. PSZ printerName;
  47. ULONG printerNameLength;
  48. PAGED_CODE( );
  49. printerNameLength = wcslen( PrinterName ) * sizeof(WCHAR) + sizeof(WCHAR);
  50. printerName = SrvXsAllocateHeap( printerNameLength, &status );
  51. if ( printerName == NULL ) {
  52. *Error = RtlNtStatusToDosErrorNoTeb( status );
  53. return status;
  54. }
  55. //
  56. // SrvXsResource is held at this point
  57. //
  58. //
  59. // Copy over the printer name to the new memory.
  60. //
  61. RtlCopyMemory( printerName, PrinterName, printerNameLength );
  62. //
  63. // Set up the message to send over the port.
  64. //
  65. requestMessage.PortMessage.u1.s1.DataLength =
  66. sizeof(requestMessage) - sizeof(PORT_MESSAGE);
  67. requestMessage.PortMessage.u1.s1.TotalLength = sizeof(requestMessage);
  68. requestMessage.PortMessage.u2.ZeroInit = 0;
  69. requestMessage.PortMessage.u2.s2.Type = LPC_KERNELMODE_MESSAGE;
  70. requestMessage.MessageType = XACTSRV_MESSAGE_OPEN_PRINTER;
  71. requestMessage.Message.OpenPrinter.PrinterName =
  72. (PCHAR)printerName + SrvXsPortMemoryDelta;
  73. //
  74. // Send the message to XACTSRV so it can call OpenPrinter( ).
  75. //
  76. // !!! We may want to put a timeout on this.
  77. IF_DEBUG(XACTSRV) {
  78. SrvPrint2( "SrvOpenPrinter: sending message at %p PrinterName %s\n",
  79. &requestMessage,
  80. (PCHAR)requestMessage.Message.OpenPrinter.PrinterName );
  81. }
  82. status = NtRequestWaitReplyPort(
  83. SrvXsPortHandle,
  84. (PPORT_MESSAGE)&requestMessage,
  85. (PPORT_MESSAGE)&replyMessage
  86. );
  87. if ( !NT_SUCCESS(status) ) {
  88. IF_DEBUG(ERRORS) {
  89. SrvPrint1( "SrvOpenPrinter: NtRequestWaitReplyPort failed: %X\n",
  90. status );
  91. }
  92. SrvLogServiceFailure( SRV_SVC_NT_REQ_WAIT_REPLY_PORT, status );
  93. *Error = ERROR_UNEXP_NET_ERR;
  94. goto exit;
  95. }
  96. IF_DEBUG(XACTSRV) {
  97. SrvPrint1( "SrvOpenPrinter: received response at %p\n", &replyMessage );
  98. }
  99. *phPrinter = replyMessage.Message.OpenPrinter.hPrinter;
  100. *Error = replyMessage.Message.OpenPrinter.Error;
  101. exit:
  102. SrvXsFreeHeap( printerName );
  103. return status;
  104. } // SrvOpenPrinter
  105. NTSTATUS
  106. SrvAddPrintJob (
  107. IN PWORK_CONTEXT WorkContext,
  108. IN HANDLE Handle,
  109. IN OUT PUNICODE_STRING FileName,
  110. OUT PULONG JobId,
  111. OUT PULONG Error
  112. )
  113. /*++
  114. Routine Description:
  115. This routine is a kernel-mode wrapper for the user-mode API AddJob( ).
  116. This API returns a filename to use as a disk spool file and a
  117. Job ID to identify the print job to the spooler subsystem.
  118. Arguments:
  119. Handle - the Printer handle.
  120. FileName - filled in with the Unicode name of the file to open as
  121. a spool filed. The MaximumLength and Buffer fields should
  122. be valid on input and are not changed. Length is changed to
  123. indicate the length of the NT path name of the file.
  124. JobId - filled in with the Job ID of the print job. This value
  125. is used to call ScheduleJob( ) when the writing of the spool
  126. file is complete and printing should begin.
  127. Error - if AddJob failed in XACTSRV, this is the error code.
  128. Return Value:
  129. NTSTATUS - result of operation. If AddJob( ) failed, NTSTATUS =
  130. STATUS_UNSUCCESSFUL and Error contains the real error code.
  131. --*/
  132. {
  133. NTSTATUS status;
  134. XACTSRV_REQUEST_MESSAGE requestMessage;
  135. XACTSRV_REPLY_MESSAGE replyMessage;
  136. ANSI_STRING fileName;
  137. PCONNECTION connection = WorkContext->Connection;
  138. PWCH destPtr, sourcePtr, sourceEndPtr;
  139. PAGED_CODE( );
  140. *Error = NO_ERROR;
  141. fileName.Buffer = NULL;
  142. //
  143. // Allocate space to hold the buffer for the file name that will be
  144. // returned.
  145. //
  146. fileName.Buffer = SrvXsAllocateHeap(
  147. MAXIMUM_FILENAME_LENGTH * sizeof(WCHAR),
  148. &status
  149. );
  150. if ( fileName.Buffer == NULL ) {
  151. *Error = RtlNtStatusToDosErrorNoTeb( status );
  152. return(status);
  153. }
  154. //
  155. // SrvXsResource is held at this point
  156. //
  157. //
  158. // Set up the message to send over the port.
  159. //
  160. requestMessage.PortMessage.u1.s1.DataLength =
  161. sizeof(requestMessage) - sizeof(PORT_MESSAGE);
  162. requestMessage.PortMessage.u1.s1.TotalLength = sizeof(requestMessage);
  163. requestMessage.PortMessage.u2.ZeroInit = 0;
  164. requestMessage.PortMessage.u2.s2.Type = LPC_KERNELMODE_MESSAGE;
  165. requestMessage.MessageType = XACTSRV_MESSAGE_ADD_JOB_PRINTER;
  166. requestMessage.Message.AddPrintJob.hPrinter = Handle;
  167. requestMessage.Message.AddPrintJob.Buffer =
  168. fileName.Buffer + SrvXsPortMemoryDelta;
  169. requestMessage.Message.AddPrintJob.BufferLength = MAXIMUM_FILENAME_LENGTH;
  170. // Add client machine name for notification
  171. //
  172. // Copy the client machine name for XACTSRV, skipping over the
  173. // initial "\\", and deleting trailing spaces.
  174. //
  175. destPtr = requestMessage.Message.AddPrintJob.ClientMachineName;
  176. sourcePtr =
  177. connection->ClientMachineNameString.Buffer + 2;
  178. sourceEndPtr = sourcePtr
  179. + min( connection->ClientMachineNameString.Length,
  180. sizeof(requestMessage.Message.AddPrintJob.ClientMachineName) /
  181. sizeof(WCHAR) - 1 );
  182. while ( sourcePtr < sourceEndPtr && *sourcePtr != UNICODE_NULL ) {
  183. *destPtr++ = *sourcePtr++;
  184. }
  185. *destPtr-- = UNICODE_NULL;
  186. while ( destPtr >= requestMessage.Message.AddPrintJob.ClientMachineName
  187. &&
  188. *destPtr == L' ' ) {
  189. *destPtr-- = UNICODE_NULL;
  190. }
  191. //
  192. // Send the message to XACTSRV so it can call AddJob( ).
  193. //
  194. // !!! We may want to put a timeout on this.
  195. IF_DEBUG(XACTSRV) {
  196. SrvPrint1( "SrvAddPrintJob: sending message at %p", &requestMessage );
  197. }
  198. status = IMPERSONATE( WorkContext );
  199. if( NT_SUCCESS( status ) ) {
  200. status = NtRequestWaitReplyPort(
  201. SrvXsPortHandle,
  202. (PPORT_MESSAGE)&requestMessage,
  203. (PPORT_MESSAGE)&replyMessage
  204. );
  205. REVERT( );
  206. }
  207. if ( !NT_SUCCESS(status) ) {
  208. IF_DEBUG(ERRORS) {
  209. SrvPrint1( "SrvAddPrintJob: NtRequestWaitReplyPort failed: %X\n",
  210. status );
  211. }
  212. SrvLogServiceFailure( SRV_SVC_NT_REQ_WAIT_REPLY_PORT, status );
  213. *Error = ERROR_UNEXP_NET_ERR;
  214. goto exit;
  215. }
  216. IF_DEBUG(XACTSRV) {
  217. SrvPrint1( "SrvAddPrintJob: received response at %p\n", &replyMessage );
  218. }
  219. if ( replyMessage.Message.AddPrintJob.Error != NO_ERROR ) {
  220. *Error = replyMessage.Message.AddPrintJob.Error;
  221. status = STATUS_UNSUCCESSFUL;
  222. goto exit;
  223. }
  224. //
  225. // Set up return information.
  226. //
  227. *JobId = replyMessage.Message.AddPrintJob.JobId;
  228. FileName->Length = MIN(replyMessage.Message.AddPrintJob.BufferLength, FileName->MaximumLength );
  229. RtlCopyMemory( FileName->Buffer, fileName.Buffer, FileName->Length );
  230. exit:
  231. SrvXsFreeHeap( fileName.Buffer );
  232. return status;
  233. } // SrvAddPrintJob
  234. NTSTATUS
  235. SrvSchedulePrintJob (
  236. IN HANDLE PrinterHandle,
  237. IN ULONG JobId
  238. )
  239. /*++
  240. Routine Description:
  241. This routine is a kernel-mode wrapper for the the user-mode API
  242. ScheduleJob( ).
  243. Arguments:
  244. PrinterHandle - a handle to a printer returned by OpenPrinter( ).
  245. JobId - the job ID returned to AddJob( ) that identifies this print
  246. job.
  247. Error - if ScheduleJob failed in XACTSRV, this is the error code.
  248. Return Value:
  249. NTSTATUS - result of operation. If ScheduleJob( ) failed, NTSTATUS =
  250. STATUS_UNSUCCESSFUL and Error contains the real error code.
  251. --*/
  252. {
  253. NTSTATUS status;
  254. XACTSRV_REQUEST_MESSAGE requestMessage;
  255. XACTSRV_REPLY_MESSAGE replyMessage;
  256. PAGED_CODE( );
  257. //
  258. // Grab the XsResource
  259. //
  260. (VOID) SrvXsAllocateHeap( 0, &status );
  261. if ( !NT_SUCCESS(status) ) {
  262. return status;
  263. }
  264. //
  265. // Set up the message to send over the port.
  266. //
  267. requestMessage.PortMessage.u1.s1.DataLength =
  268. sizeof(requestMessage) - sizeof(PORT_MESSAGE);
  269. requestMessage.PortMessage.u1.s1.TotalLength = sizeof(requestMessage);
  270. requestMessage.PortMessage.u2.ZeroInit = 0;
  271. requestMessage.PortMessage.u2.s2.Type = LPC_KERNELMODE_MESSAGE;
  272. requestMessage.MessageType = XACTSRV_MESSAGE_SCHD_JOB_PRINTER;
  273. requestMessage.Message.SchedulePrintJob.hPrinter = PrinterHandle;
  274. requestMessage.Message.SchedulePrintJob.JobId = JobId;
  275. //
  276. // Send the message to XACTSRV so it can call ScheduleJob( ).
  277. //
  278. // !!! We may want to put a timeout on this.
  279. IF_DEBUG(XACTSRV) {
  280. SrvPrint1( "SrvSchedulePrintJob: sending message at %p", &requestMessage );
  281. }
  282. status = NtRequestWaitReplyPort(
  283. SrvXsPortHandle,
  284. (PPORT_MESSAGE)&requestMessage,
  285. (PPORT_MESSAGE)&replyMessage
  286. );
  287. if ( !NT_SUCCESS(status) ) {
  288. IF_DEBUG(ERRORS) {
  289. SrvPrint1( "SrvSchedulePrintJob: NtRequestWaitReplyPort failed: %X\n",
  290. status );
  291. }
  292. SrvLogServiceFailure( SRV_SVC_NT_REQ_WAIT_REPLY_PORT, status );
  293. goto exit;
  294. }
  295. IF_DEBUG(XACTSRV) {
  296. SrvPrint1( "SrvSchedulePrintJob: received response at %p\n",
  297. &replyMessage );
  298. }
  299. exit:
  300. //
  301. // release the lock
  302. //
  303. SrvXsFreeHeap( NULL );
  304. return status;
  305. } // SrvSchedulePrintJob
  306. NTSTATUS
  307. SrvClosePrinter (
  308. IN HANDLE Handle
  309. )
  310. /*++
  311. Routine Description:
  312. This routine is a kernel-mode wrapper for the the user-mode API
  313. ClosePrinter( ).
  314. Arguments:
  315. Handle - the Printer handle to close.
  316. Return Value:
  317. NTSTATUS - result of operation.
  318. --*/
  319. {
  320. NTSTATUS status;
  321. XACTSRV_REQUEST_MESSAGE requestMessage;
  322. XACTSRV_REPLY_MESSAGE replyMessage;
  323. PAGED_CODE( );
  324. //
  325. // Grab the XsResource
  326. //
  327. (VOID) SrvXsAllocateHeap( 0, &status );
  328. if ( !NT_SUCCESS(status) ) {
  329. return status;
  330. }
  331. //
  332. // SrvXsResource is held at this point
  333. //
  334. //
  335. // Set up the message to send over the port.
  336. //
  337. requestMessage.PortMessage.u1.s1.DataLength =
  338. sizeof(requestMessage) - sizeof(PORT_MESSAGE);
  339. requestMessage.PortMessage.u1.s1.TotalLength = sizeof(requestMessage);
  340. requestMessage.PortMessage.u2.ZeroInit = 0;
  341. requestMessage.PortMessage.u2.s2.Type = LPC_KERNELMODE_MESSAGE;
  342. requestMessage.MessageType = XACTSRV_MESSAGE_CLOSE_PRINTER;
  343. requestMessage.Message.ClosePrinter.hPrinter = Handle;
  344. //
  345. // Send the message to XACTSRV so it can call ClosePrinter( ).
  346. //
  347. // !!! We may want to put a timeout on this.
  348. IF_DEBUG(XACTSRV) {
  349. SrvPrint1( "SrvClosePrinter: sending message at %p", &requestMessage );
  350. }
  351. status = NtRequestWaitReplyPort(
  352. SrvXsPortHandle,
  353. (PPORT_MESSAGE)&requestMessage,
  354. (PPORT_MESSAGE)&replyMessage
  355. );
  356. if ( !NT_SUCCESS(status) ) {
  357. IF_DEBUG(ERRORS) {
  358. SrvPrint1( "SrvClosePrinter: NtRequestWaitReplyPort failed: %X\n",
  359. status );
  360. }
  361. SrvLogServiceFailure( SRV_SVC_NT_REQ_WAIT_REPLY_PORT, status );
  362. goto exit;
  363. }
  364. IF_DEBUG(XACTSRV) {
  365. SrvPrint1( "SrvClosePrinter: received response at %p\n", &replyMessage );
  366. }
  367. exit:
  368. //
  369. // release the lock
  370. //
  371. SrvXsFreeHeap( NULL );
  372. return status;
  373. } // SrvClosePrinter