Source code of Windows XP (NT5)
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.

1280 lines
37 KiB

  1. /*++
  2. Copyright (c) 1991-1992 Microsoft Corporation
  3. Module Name:
  4. xsproc.c
  5. Abstract:
  6. This module contains the main processing loop for XACTSRV.
  7. Author:
  8. David Treadwell (davidtr) 05-Jan-1991
  9. Shanku Niyogi (w-shanku)
  10. Revision History:
  11. 02-Jun-1992 JohnRo
  12. RAID 9829: Avoid SERVICE_ equate conflicts.
  13. Chuck Lenzmeier (chuckl) 17-Jun-1992
  14. Moved from xssvc to srvsvc\server
  15. --*/
  16. //
  17. // Includes.
  18. //
  19. #include "srvsvcp.h"
  20. #include "xsdata.h"
  21. #include <netevent.h>
  22. #include <windows.h> // from sdk\inc
  23. #include <winspool.h> // Dynamically loaded as needed for perf
  24. #include <winsprlp.h> // addjob_info_2w, private spooler defs
  25. #include <apinums.h> // from net\inc
  26. #include <netlib.h> // from net\inc (NetpGetComputerName)
  27. #include <xactsrv2.h> // from private\inc
  28. #include <smbgtpt.h>
  29. #include <xsconst.h> // from xactsrv
  30. #include <lmsname.h> // from \sdk\inc
  31. #include <lmerr.h> // from \sdk\inc
  32. #include <lmapibuf.h> // from \sdk\inc (NetApiBufferFree)
  33. #include <lmmsg.h> // from \sdk\inc (NetMessageBufferSend)
  34. #include <winsvc.h> // from \sdk\inc
  35. #if DBG
  36. #include <stdio.h>
  37. #include <lmbrowsr.h>
  38. #endif
  39. #undef DEBUG
  40. #undef DEBUG_API_ERRORS
  41. #include <xsdebug.h>
  42. HMODULE hSpoolerLibrary = NULL;
  43. CRITICAL_SECTION SpoolerMutex;
  44. VOID
  45. ConvertApiStatusToDosStatus(
  46. LPXS_PARAMETER_HEADER header
  47. );
  48. BOOLEAN
  49. XsProcessApis (
  50. DWORD ThreadNum
  51. );
  52. BOOLEAN
  53. XsLoadPrintSpoolerFunctions(
  54. );
  55. BOOLEAN
  56. XsUnloadPrintSpoolerFunctions(
  57. );
  58. VOID
  59. XsProcessApisWrapper (
  60. LPVOID ThreadNumber
  61. )
  62. /*++
  63. Routine Description:
  64. This routine provides multithreaded capability for main processing
  65. routine, XsProcessApis.
  66. Arguments:
  67. ThreadNum - thread number for debugging purposes.
  68. --*/
  69. {
  70. XACTSRV_REQUEST_MESSAGE requestMessage;
  71. BOOLEAN LastThread;
  72. DWORD ThreadNum = PtrToInt( ThreadNumber );
  73. //
  74. // Increase the priority of this thread to just above foreground (the
  75. // same as the rest of the server).
  76. //
  77. SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL );
  78. //
  79. // Do the APIs
  80. //
  81. LastThread = XsProcessApis( ThreadNum );
  82. IF_DEBUG(THREADS) {
  83. SS_PRINT(( "Thread %ld exiting, active count %ld\n", ThreadNum,
  84. SsData.XsThreads ));
  85. }
  86. //
  87. // If the last thread has terminated, set the All Threads Terminated event.
  88. //
  89. if( LastThread ) {
  90. SetEvent( SsData.XsAllThreadsTerminatedEvent );
  91. } else if( SsData.XsTerminating ) {
  92. //
  93. // There are still threads left, and we are trying to terminate. Queue
  94. // another message to the queue so the next thread will get it and
  95. // notice that we're trying to quit.
  96. //
  97. RtlZeroMemory( &requestMessage, sizeof( requestMessage ));
  98. requestMessage.PortMessage.u1.s1.DataLength =
  99. (USHORT)( sizeof(requestMessage) - sizeof(PORT_MESSAGE) );
  100. requestMessage.PortMessage.u1.s1.TotalLength = sizeof(requestMessage);
  101. requestMessage.MessageType = XACTSRV_MESSAGE_WAKEUP;
  102. NtRequestPort(
  103. SsData.XsConnectionPortHandle,
  104. (PPORT_MESSAGE)&requestMessage
  105. );
  106. }
  107. ExitThread( NO_ERROR );
  108. } // XsProcessApisWrapper
  109. BOOLEAN
  110. XsProcessApis (
  111. DWORD ThreadNum
  112. )
  113. /*++
  114. Routine Description:
  115. This routine waits for messages to come through the LPC port to
  116. the server. When one does, it calls the appropriate routine to
  117. handle the API, then replies to the server indicating that the
  118. API has completed.
  119. Arguments:
  120. ThreadNum - thread number for debugging purposes.
  121. Return Value:
  122. TRUE if we are the last thread
  123. --*/
  124. {
  125. NTSTATUS status;
  126. NET_API_STATUS error;
  127. XACTSRV_REQUEST_MESSAGE request;
  128. XACTSRV_REPLY_MESSAGE reply;
  129. BOOL sendReply = FALSE;
  130. BOOL ValidationSuccessful = FALSE;
  131. LPTRANSACTION transaction;
  132. WORD apiNumber;
  133. LPXS_PARAMETER_HEADER header;
  134. LPVOID parameters;
  135. LPDESC structureDesc;
  136. LPDESC auxStructureDesc;
  137. LPDESC paramStructureDesc;
  138. LARGE_INTEGER timeout;
  139. #if 0
  140. LARGE_INTEGER XactSrvStartTime;
  141. LARGE_INTEGER XactSrvEndTime;
  142. LARGE_INTEGER PerformanceFrequency;
  143. #endif
  144. LONG availableThreads;
  145. LONG i;
  146. i = InterlockedIncrement( &SsData.XsThreads );
  147. //
  148. // Loop dispatching API requests.
  149. //
  150. while ( SsData.XsTerminating == FALSE ) {
  151. //
  152. // We're waiting to handle another API...
  153. //
  154. InterlockedIncrement( &SsData.XsWaitingApiThreads );
  155. //
  156. // Send the reply to the last message and wait for the next message.
  157. //
  158. // Wait for 30 seconds if there are many servicing threads. If there
  159. // is only one thread, we can wait without a timeout.
  160. //
  161. timeout.QuadPart = -1*10*1000*1000*30;
  162. status = NtReplyWaitReceivePortEx(
  163. SsData.XsCommunicationPortHandle,
  164. NULL, // PortContext
  165. sendReply ? (PPORT_MESSAGE)&reply : NULL,
  166. (PPORT_MESSAGE)&request,
  167. SsData.XsThreads > 1 ? &timeout : NULL
  168. );
  169. sendReply = TRUE;
  170. //
  171. // Set 'availableThreads' to the number of threads currently available to service
  172. // API requests
  173. //
  174. availableThreads = InterlockedDecrement( &SsData.XsWaitingApiThreads );
  175. IF_DEBUG(THREADS) {
  176. SS_PRINT(( "XsProcessApis: Thread %d: NtReplyWaitReceivePort %X, msg %X\n",
  177. ThreadNum, status, &request ));
  178. }
  179. if( status == STATUS_TIMEOUT ) {
  180. //
  181. // If this is the last thread, or we seem busy, then don't terminate.
  182. //
  183. if( InterlockedDecrement( &SsData.XsThreads ) == 0 ||
  184. availableThreads == 0 ) {
  185. //
  186. // Do not terminate.
  187. //
  188. InterlockedIncrement( &SsData.XsThreads );
  189. sendReply = FALSE;
  190. continue;
  191. }
  192. //
  193. // This thread can terminate, there isn't enough work to support it.
  194. //
  195. return FALSE;
  196. }
  197. if( !NT_SUCCESS( status ) ||
  198. SsData.XsTerminating ||
  199. request.PortMessage.u2.s2.Type == LPC_PORT_CLOSED ) {
  200. //
  201. // The port is no longer valid, or XACTSRV is terminating.
  202. //
  203. IF_DEBUG(THREADS) {
  204. SS_PRINT(( "XsProcessApis: %X\n", status ));
  205. SS_PRINT(( "XsProcessApis: %s. Thread %ld quitting\n",
  206. SsData.XsTerminating ?
  207. "XACTSRV terminating" : "Port invalid",
  208. ThreadNum ));
  209. }
  210. break;
  211. }
  212. //
  213. // If we have received anything other than a message, then something
  214. // strange is happening. Ignore it.
  215. //
  216. if( (request.PortMessage.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) == LPC_CONNECTION_REQUEST ) {
  217. //
  218. // Reject this connection attempt
  219. //
  220. IF_DEBUG(LPC) {
  221. SS_PRINT(( "XsProcessApis: unexpected LPC_CONNECTION_REQUEST rejected\n" ));
  222. }
  223. NtAcceptConnectPort( SsData.XsCommunicationPortHandle,
  224. NULL,
  225. (PPORT_MESSAGE)&request,
  226. FALSE,
  227. NULL,
  228. NULL
  229. );
  230. sendReply = FALSE;
  231. continue;
  232. } else if( !(request.PortMessage.u2.s2.Type & LPC_REQUEST) ) {
  233. //
  234. // This is not a request message. Reject it.
  235. //
  236. IF_DEBUG(LPC) {
  237. SS_PRINT(( "XsProcessApis: unexpected LPC type %X rejected\n",
  238. request.PortMessage.u2.s2.Type ));
  239. }
  240. sendReply = FALSE;
  241. continue;
  242. }
  243. IF_DEBUG(THREADS) {
  244. SS_PRINT(( "XsProcessApis: Thread %ld responding to request, "
  245. " MessageType %d, SsData.XsTerminating %d",
  246. ThreadNum, request.MessageType, SsData.XsTerminating ));
  247. }
  248. if( availableThreads == 0 ) {
  249. HANDLE threadHandle;
  250. DWORD threadId;
  251. //
  252. // Are there other threads ready to handle new requests? If not, then
  253. // we should spawn a new thread. Since the server synchronously sends
  254. // requests to xactsrv, we will never end up with more than
  255. // the maximum number of server worker threads + 1.
  256. //
  257. threadHandle = CreateThread(
  258. NULL,
  259. 0,
  260. (LPTHREAD_START_ROUTINE)XsProcessApisWrapper,
  261. IntToPtr(SsData.XsThreads),
  262. 0,
  263. &threadId
  264. );
  265. if ( threadHandle != 0 ) {
  266. IF_DEBUG(THREADS) {
  267. SS_PRINT(( "XsStartXactsrv: Created thread %ld for "
  268. "processing APIs\n", SsData.XsThreads ));
  269. }
  270. CloseHandle( threadHandle );
  271. } else {
  272. IF_DEBUG(THREADS) {
  273. SS_PRINT(( "XsStartXactsrv: Unable to create thread %ld for "
  274. "processing APIs\n", SsData.XsThreads ));
  275. }
  276. }
  277. }
  278. //
  279. // Set up the response message to be sent on the next call to
  280. // NtReplyWaitReceivePort.
  281. //
  282. reply.PortMessage.u1.s1.DataLength =
  283. sizeof(reply) - sizeof(PORT_MESSAGE);
  284. reply.PortMessage.u1.s1.TotalLength = sizeof(reply);
  285. reply.PortMessage.u2.ZeroInit = 0;
  286. reply.PortMessage.ClientId = request.PortMessage.ClientId;
  287. reply.PortMessage.MessageId = request.PortMessage.MessageId;
  288. switch ( request.MessageType ) {
  289. case XACTSRV_MESSAGE_DOWN_LEVEL_API:
  290. //
  291. // Get a pointer to the transaction block from the message.
  292. // It is the file server's responsibility to set up this
  293. // pointer correctly, and since he is a trusted entity, we
  294. // do no checking on the pointer value.
  295. //
  296. transaction = request.Message.DownLevelApi.Transaction;
  297. ASSERT( transaction != NULL );
  298. #if 0
  299. NtQueryPerformanceCounter(&XactSrvStartTime, &PerformanceFrequency);
  300. //
  301. // Convert frequency from ticks/second to ticks/millisecond
  302. //
  303. PerformanceFrequency = LiXDiv(PerformanceFrequency, 1000);
  304. if (LiGeq(XactSrvStartTime, transaction->XactSrvTime)) {
  305. CHAR Buffer[200];
  306. LARGE_INTEGER LpcTime = LiSub(XactSrvStartTime, transaction->XactSrvTime);
  307. LpcTime = LiDiv(LpcTime, PerformanceFrequency);
  308. sprintf(Buffer, "XactSrv: LPC Time: %ld milliseconds (%ld)\n", LpcTime.LowPart, LpcTime.HighPart);
  309. I_BrowserDebugTrace(NULL, Buffer);
  310. }
  311. #endif
  312. //
  313. // The API number is the first word in the parameters
  314. // section, and it is followed by the parameter descriptor
  315. // string. After that comes the data descriptor.
  316. //
  317. apiNumber = SmbGetUshort( (LPWORD)transaction->InParameters );
  318. paramStructureDesc = (LPDESC)( transaction->InParameters + 2 );
  319. try {
  320. structureDesc = paramStructureDesc
  321. + strlen( paramStructureDesc ) + 1;
  322. } except( EXCEPTION_EXECUTE_HANDLER ) {
  323. reply.Message.DownLevelApi.Status = GetExceptionCode();
  324. break;
  325. }
  326. //
  327. // Make sure the API number is in range.
  328. //
  329. if ( apiNumber >=
  330. (sizeof(XsApiTable) / sizeof(XS_API_TABLE_ENTRY)) ) {
  331. reply.Message.DownLevelApi.Status =
  332. STATUS_INVALID_SYSTEM_SERVICE;
  333. break;
  334. }
  335. //
  336. // Make sure xactsrv.dll is loaded, and a handler is available for this
  337. // request.
  338. //
  339. if( XsApiTable[ apiNumber ].Handler == NULL &&
  340. XsLoadXactLibrary( apiNumber ) == FALSE ) {
  341. reply.Message.DownLevelApi.Status = STATUS_INVALID_SYSTEM_SERVICE;
  342. break;
  343. }
  344. //
  345. // Check if the parameter descriptor is valid. If not,
  346. // there is obviously something very wrong about this
  347. // request.
  348. //
  349. ValidationSuccessful = FALSE;
  350. try {
  351. if (XsApiTable[apiNumber].Params == NULL &&
  352. *paramStructureDesc != '\0') {
  353. reply.Message.DownLevelApi.Status = STATUS_INVALID_PARAMETER;
  354. goto ValidationFailed;
  355. } else if ( !XsCheckSmbDescriptor(
  356. paramStructureDesc,
  357. XsApiTable[apiNumber].Params )) {
  358. reply.Message.DownLevelApi.Status = STATUS_INVALID_PARAMETER;
  359. goto ValidationFailed;
  360. }
  361. //
  362. // Capture the input parameters into a buffer. The API
  363. // handler will treat this data as passed-in parameters.
  364. //
  365. header = XsCaptureParameters( transaction, &auxStructureDesc );
  366. if ( header == NULL ) {
  367. reply.Message.DownLevelApi.Status = STATUS_NO_MEMORY;
  368. goto ValidationFailed;
  369. }
  370. ValidationSuccessful = TRUE;
  371. ValidationFailed:
  372. ;
  373. } except( EXCEPTION_EXECUTE_HANDLER ) {
  374. reply.Message.DownLevelApi.Status = GetExceptionCode();
  375. break;
  376. }
  377. if (!ValidationSuccessful) {
  378. break;
  379. }
  380. //
  381. // Initialize header to default values.
  382. //
  383. header->Converter = 0;
  384. header->Status = NO_ERROR;
  385. header->ClientMachineName =
  386. request.Message.DownLevelApi.ClientMachineName;
  387. header->ClientTransportName = request.Message.DownLevelApi.TransportName;
  388. header->EncryptionKey = request.Message.DownLevelApi.LanmanSessionKey;
  389. header->Flags = request.Message.DownLevelApi.Flags;
  390. header->ServerName = request.Message.DownLevelApi.ServerName;
  391. parameters = header + 1;
  392. IF_DEBUG(LPC) {
  393. SS_PRINT(( "XsProcessApis: received message from %ws at %lx, "
  394. "transaction %lx, API %ld on transport %ws\n",
  395. header->ClientMachineName, &request,
  396. transaction, apiNumber,
  397. header->ClientTransportName ));
  398. }
  399. IF_DEBUG(DESC_STRINGS) {
  400. SS_PRINT(( "XsProcessApis: API %ld, parameters %s, data %s\n",
  401. apiNumber, paramStructureDesc, structureDesc ));
  402. }
  403. //
  404. // Impersonate the client before calling the API.
  405. //
  406. if ( XsApiTable[apiNumber].ImpersonateClient ) {
  407. // NULL-session requests to impersonating API's are blocked by SRV.SYS (in xssupp.c),
  408. // otherwise NULL sessions could execute API's as privileged users.
  409. status = NtImpersonateClientOfPort(
  410. SsData.XsCommunicationPortHandle,
  411. (PPORT_MESSAGE)&request
  412. );
  413. if ( !NT_SUCCESS(status) ) {
  414. IF_DEBUG(ERRORS) {
  415. SS_PRINT(( "XsProcessApis: NtImpersonateClientOfPort "
  416. "failed: %X\n", status ));
  417. }
  418. reply.Message.DownLevelApi.Status = ERROR_ACCESS_DENIED;
  419. break;
  420. }
  421. }
  422. try {
  423. //
  424. // Call the API processing routine to perform the actual API call.
  425. // The called routine should set up parameters, make the actual API
  426. // call, and return the status to us.
  427. //
  428. reply.Message.DownLevelApi.Status =
  429. XsApiTable[apiNumber].Handler(
  430. header,
  431. parameters,
  432. structureDesc,
  433. auxStructureDesc
  434. );
  435. } except( EXCEPTION_EXECUTE_HANDLER ) {
  436. reply.Message.DownLevelApi.Status = GetExceptionCode();
  437. }
  438. //
  439. // Discontinue client impersonation.
  440. //
  441. if ( XsApiTable[apiNumber].ImpersonateClient ) {
  442. PVOID dummy = NULL;
  443. status = NtSetInformationThread(
  444. NtCurrentThread( ),
  445. ThreadImpersonationToken,
  446. &dummy, // discontinue impersonation
  447. sizeof(PVOID)
  448. );
  449. if ( !NT_SUCCESS(status)) {
  450. IF_DEBUG(ERRORS) {
  451. SS_PRINT(( "XsProcessApis: NtSetInformationThread "
  452. "(revert) failed: %X\n", status ));
  453. }
  454. // *** Ignore the error.
  455. }
  456. }
  457. //
  458. // Make sure we return the right error codes
  459. //
  460. if ( header->Status != NERR_Success ) {
  461. ConvertApiStatusToDosStatus( header );
  462. }
  463. //
  464. // Put the parameters in the transaction and free the parameter
  465. // buffer.
  466. //
  467. XsSetParameters( transaction, header, parameters );
  468. break;
  469. case XACTSRV_MESSAGE_OPEN_PRINTER: {
  470. UNICODE_STRING printerName;
  471. if( !pSpoolerOpenPrinterFunction )
  472. {
  473. if( !XsLoadPrintSpoolerFunctions() )
  474. {
  475. reply.Message.OpenPrinter.Error = GetLastError();
  476. break;
  477. }
  478. }
  479. RtlInitUnicodeString(
  480. &printerName,
  481. (PWCH)request.Message.OpenPrinter.PrinterName
  482. );
  483. if (!(*pSpoolerOpenPrinterFunction)( printerName.Buffer,
  484. &reply.Message.OpenPrinter.hPrinter, NULL)) {
  485. reply.Message.OpenPrinter.Error = GetLastError();
  486. SS_PRINT(( "XsProcessApis: OpenPrinter failed: %ld\n",
  487. reply.Message.OpenPrinter.Error ));
  488. break;
  489. }
  490. reply.Message.OpenPrinter.Error = NO_ERROR;
  491. break;
  492. }
  493. case XACTSRV_MESSAGE_ADD_JOB_PRINTER:
  494. {
  495. LPADDJOB_INFO_2W addJob;
  496. PRINTER_DEFAULTS prtDefault;
  497. DWORD bufferLength;
  498. UNICODE_STRING dosName;
  499. UNICODE_STRING ntName;
  500. BOOL ok;
  501. PVOID dummy = NULL;
  502. if( !(pSpoolerResetPrinterFunction || pSpoolerAddJobFunction) )
  503. {
  504. if( !XsLoadPrintSpoolerFunctions() )
  505. {
  506. reply.Message.OpenPrinter.Error = GetLastError();
  507. break;
  508. }
  509. }
  510. //
  511. // Allocate space for the add job structure. This buffer
  512. // will get the JobId and the spool file path name.
  513. //
  514. bufferLength = sizeof(ADDJOB_INFO_2W) +
  515. (MAXIMUM_FILENAME_LENGTH * sizeof(TCHAR));
  516. addJob = (LPADDJOB_INFO_2W) LocalAlloc( LPTR, bufferLength );
  517. if ( addJob == NULL ) {
  518. reply.Message.AddPrintJob.Error = ERROR_NOT_ENOUGH_MEMORY;
  519. break;
  520. }
  521. //
  522. // Impersonate the client before calling the API.
  523. //
  524. status = NtImpersonateClientOfPort(
  525. SsData.XsCommunicationPortHandle,
  526. (PPORT_MESSAGE)&request
  527. );
  528. if ( !NT_SUCCESS(status) ) {
  529. IF_DEBUG(ERRORS) {
  530. SS_PRINT(( "XsProcessApis: NtImpersonateClientOfPort "
  531. "failed: %X\n", status ));
  532. }
  533. LocalFree( addJob );
  534. reply.Message.DownLevelApi.Status = ERROR_ACCESS_DENIED;
  535. break;
  536. }
  537. //
  538. // call ResetJob so that we will pick up the new printer defaults
  539. //
  540. prtDefault.pDatatype = (LPWSTR)-1;
  541. prtDefault.pDevMode = (LPDEVMODEW)-1;
  542. prtDefault.DesiredAccess = 0;
  543. ok = (*pSpoolerResetPrinterFunction)(
  544. request.Message.AddPrintJob.hPrinter,
  545. &prtDefault
  546. );
  547. if ( !ok ) {
  548. //
  549. // *** Ignore the error. AddJob will use the old defaults
  550. // in this case.
  551. //
  552. IF_DEBUG(ERRORS) {
  553. DWORD error;
  554. error = GetLastError( );
  555. SS_PRINT(( "XsProcessApis: ResetPrinter "
  556. "failed: %ld\n", error ));
  557. }
  558. }
  559. // Setup IN arguments to AddJob buffer
  560. addJob->pData = request.Message.AddPrintJob.ClientMachineName;
  561. //
  562. // Call AddJob to set up the print job and get a job ID
  563. // and spool file name.
  564. //
  565. ok = (*pSpoolerAddJobFunction)(
  566. request.Message.AddPrintJob.hPrinter,
  567. 3,
  568. (LPBYTE)addJob,
  569. bufferLength,
  570. &bufferLength
  571. );
  572. if ( !ok ) {
  573. reply.Message.AddPrintJob.Error = GetLastError( );
  574. }
  575. //
  576. // Discontinue client impersonation.
  577. //
  578. status = NtSetInformationThread(
  579. NtCurrentThread( ),
  580. ThreadImpersonationToken,
  581. &dummy, // discontinue impersonation
  582. sizeof(PVOID)
  583. );
  584. if ( !NT_SUCCESS(status)) {
  585. IF_DEBUG(ERRORS) {
  586. SS_PRINT(( "XsProcessApis: NtSetInformationThread "
  587. "(revert) failed: %X\n", status ));
  588. }
  589. // *** Ignore the error.
  590. }
  591. if ( !ok ) {
  592. SS_PRINT(( "XsProcessApis: AddJob failed, %ld\n",
  593. reply.Message.AddPrintJob.Error ));
  594. LocalFree( addJob );
  595. break;
  596. }
  597. //
  598. // Set up the information in the return buffer.
  599. //
  600. reply.Message.AddPrintJob.JobId = addJob->JobId;
  601. RtlInitUnicodeString( &dosName, addJob->pData );
  602. status = RtlDosPathNameToNtPathName_U(
  603. dosName.Buffer,
  604. &ntName,
  605. NULL,
  606. NULL
  607. );
  608. if ( !NT_SUCCESS(status) ) {
  609. IF_DEBUG(ERRORS) {
  610. SS_PRINT(( "XsProcessApis: Dos-to-NT path failed: %X\n",
  611. status ));
  612. }
  613. ntName.Buffer = NULL;
  614. ntName.Length = 0;
  615. }
  616. //
  617. // Set up return data.
  618. //
  619. reply.Message.AddPrintJob.BufferLength = ntName.Length;
  620. reply.Message.AddPrintJob.Error = NO_ERROR;
  621. RtlCopyMemory(
  622. request.Message.AddPrintJob.Buffer,
  623. ntName.Buffer,
  624. ntName.Length
  625. );
  626. //
  627. // Free allocated resources.
  628. //
  629. LocalFree( addJob );
  630. if ( ntName.Buffer != NULL ) {
  631. RtlFreeHeap( RtlProcessHeap( ), 0, ntName.Buffer );
  632. }
  633. break;
  634. }
  635. case XACTSRV_MESSAGE_SCHD_JOB_PRINTER:
  636. if( !pSpoolerScheduleJobFunction )
  637. {
  638. if( !XsLoadPrintSpoolerFunctions() )
  639. {
  640. reply.Message.OpenPrinter.Error = GetLastError();
  641. break;
  642. }
  643. }
  644. //
  645. // Call ScheduleJob( ) to indicate that we're done writing to
  646. // the spool file.
  647. //
  648. if ( !(*pSpoolerScheduleJobFunction)(
  649. request.Message.SchedulePrintJob.hPrinter,
  650. request.Message.SchedulePrintJob.JobId ) ) {
  651. reply.Message.SchedulePrintJob.Error = GetLastError( );
  652. SS_PRINT(( "XsProcessApis: ScheduleJob failed, %ld\n",
  653. reply.Message.SchedulePrintJob.Error ));
  654. break;
  655. }
  656. reply.Message.SchedulePrintJob.Error = NO_ERROR;
  657. break;
  658. case XACTSRV_MESSAGE_CLOSE_PRINTER:
  659. if( !pSpoolerClosePrinterFunction )
  660. {
  661. if( !XsLoadPrintSpoolerFunctions() )
  662. {
  663. reply.Message.OpenPrinter.Error = GetLastError();
  664. break;
  665. }
  666. }
  667. if ( !(*pSpoolerClosePrinterFunction)( request.Message.ClosePrinter.hPrinter ) ) {
  668. reply.Message.ClosePrinter.Error = GetLastError( );
  669. SS_PRINT(( "XsProcessApis: ClosePrinter failed: %ld\n",
  670. reply.Message.ClosePrinter.Error ));
  671. break;
  672. }
  673. reply.Message.ClosePrinter.Error = NO_ERROR;
  674. break;
  675. case XACTSRV_MESSAGE_MESSAGE_SEND:
  676. {
  677. LPTSTR sender;
  678. error = NetpGetComputerName( &sender );
  679. if ( error != NO_ERROR ) {
  680. SS_PRINT(( "XsProcessApis: NetpGetComputerName failed: %ld\n",
  681. error ));
  682. reply.Message.MessageBufferSend.Error = error;
  683. break;
  684. }
  685. error = NetMessageBufferSend(
  686. NULL,
  687. //
  688. // the following LPTSTR typecast is not wrong, because the
  689. // ServerService will always be built for UNICODE. If you
  690. // want to rebuild it for ASCII, then
  691. // it must be fixed in ntos\srv\scavengr.c which
  692. // should pass in a LPWSTR if built for unicode or
  693. // convert the UNICODE_STRING to an OEM_STRING and
  694. // pass a pointer to the buffer field, as it does
  695. // now
  696. //
  697. (LPTSTR)request.Message.MessageBufferSend.Receipient,
  698. sender,
  699. request.Message.MessageBufferSend.Buffer,
  700. request.Message.MessageBufferSend.BufferLength
  701. );
  702. if ( error != NO_ERROR ) {
  703. SS_PRINT(( "XsProcessApis: NetMessageBufferSend failed: %ld\n",
  704. error ));
  705. }
  706. (void) NetApiBufferFree( sender );
  707. reply.Message.MessageBufferSend.Error = error;
  708. break;
  709. }
  710. case XACTSRV_MESSAGE_LSREQUEST:
  711. SS_PRINT(( "LSREQUEST User: %ws\n", request.Message.LSRequest.UserName ));
  712. {
  713. NT_LS_DATA NtLSData;
  714. //
  715. // Ensure we have loaded the license library. Or at least tried to!
  716. //
  717. if( SsData.SsLicenseRequest == NULL && !SsLoadLicenseLibrary() ) {
  718. //
  719. // Now what do we do? Let's be a kind and gentle server and let
  720. // the client in.
  721. //
  722. reply.Message.LSRequest.Status = STATUS_SUCCESS;
  723. reply.Message.LSRequest.hLicense = &SsData.SsFreeLicense;
  724. break;
  725. }
  726. NtLSData.DataType = NT_LS_USER_NAME;
  727. NtLSData.Data = request.Message.LSRequest.UserName;
  728. NtLSData.IsAdmin = request.Message.LSRequest.IsAdmin;
  729. reply.Message.LSRequest.Status = SsData.SsLicenseRequest (
  730. SsData.ServerProductName,
  731. SsData.szVersionNumber,
  732. (LS_HANDLE *)&reply.Message.LSRequest.hLicense,
  733. &NtLSData
  734. );
  735. if( !NT_SUCCESS( reply.Message.LSRequest.Status ) ) {
  736. //
  737. // We need to return the 'same old' error code that clients are used to
  738. // getting for when the server is full
  739. //
  740. SS_PRINT(("LSREQUEST returns status %X, mapping to %X\n",
  741. reply.Message.LSRequest.Status, STATUS_REQUEST_NOT_ACCEPTED ));
  742. reply.Message.LSRequest.Status = STATUS_REQUEST_NOT_ACCEPTED;
  743. }
  744. break;
  745. }
  746. case XACTSRV_MESSAGE_LSRELEASE:
  747. SS_PRINT(( "LSRELEASE Handle: %X\n", request.Message.LSRelease.hLicense ));
  748. if( SsData.SsFreeLicense != NULL &&
  749. request.Message.LSRelease.hLicense != &SsData.SsFreeLicense ) {
  750. SsData.SsFreeLicense( (LS_HANDLE)request.Message.LSRelease.hLicense );
  751. }
  752. break;
  753. case XACTSRV_MESSAGE_PNP:
  754. {
  755. PUNICODE_STRING transportName;
  756. BOOLEAN bind = request.Message.Pnp.Bind;
  757. //
  758. // Capture the parameters, release the server, and issue the bind or unbind
  759. //
  760. transportName = (PUNICODE_STRING)LocalAlloc(
  761. LPTR,
  762. sizeof( UNICODE_STRING ) +
  763. request.Message.Pnp.TransportName.MaximumLength
  764. );
  765. if( transportName == NULL ) {
  766. SS_PRINT(( "XACTSRV_MESSAGE_PNP: LocalAlloc failed!\n" ));
  767. break;
  768. }
  769. transportName->Buffer = (PUSHORT)(transportName+1);
  770. transportName->MaximumLength = request.Message.Pnp.TransportName.MaximumLength;
  771. RtlCopyUnicodeString(transportName, &request.Message.Pnp.TransportName );
  772. //
  773. // Now process the PNP command
  774. //
  775. if( bind == TRUE ) {
  776. //
  777. // If it is a bind, send the response now, and continue with the operation
  778. //
  779. sendReply = FALSE;
  780. status = NtReplyPort( SsData.XsCommunicationPortHandle, (PPORT_MESSAGE)&reply );
  781. //
  782. // Bind to the transport. First bind the primary server name, then bind all
  783. // of the secondary names. These calls will log errors as necessary.
  784. //
  785. BindToTransport( transportName->Buffer );
  786. BindOptionalNames( transportName->Buffer );
  787. } else {
  788. //
  789. // Unbind from the transport
  790. //
  791. I_NetServerTransportDel( transportName );
  792. }
  793. LocalFree( transportName );
  794. break;
  795. }
  796. default:
  797. SS_ASSERT( FALSE );
  798. }
  799. }
  800. return (InterlockedDecrement( &SsData.XsThreads ) == 0) ? TRUE : FALSE;
  801. } // XsProcessApis
  802. VOID
  803. ConvertApiStatusToDosStatus(
  804. LPXS_PARAMETER_HEADER Header
  805. )
  806. /*++
  807. Routine Description:
  808. This routine converts an api return status to status expected by
  809. downlevel.
  810. Arguments:
  811. Header - structure containing the status.
  812. Return Value:
  813. --*/
  814. {
  815. WORD dosStatus;
  816. switch ( Header->Status ) {
  817. case ERROR_SPECIAL_ACCOUNT:
  818. case ERROR_SPECIAL_GROUP:
  819. case ERROR_SPECIAL_USER:
  820. case ERROR_INVALID_LOGON_TYPE:
  821. dosStatus = ERROR_INVALID_PARAMETER;
  822. break;
  823. case ERROR_DEPENDENT_SERVICES_RUNNING:
  824. dosStatus = NERR_ServiceCtlNotValid;
  825. break;
  826. case ERROR_INVALID_DOMAINNAME:
  827. dosStatus = NERR_NotLocalDomain;
  828. break;
  829. case ERROR_NO_SUCH_USER:
  830. dosStatus = NERR_UserNotFound;
  831. break;
  832. case ERROR_ALIAS_EXISTS:
  833. dosStatus = NERR_GroupExists;
  834. break;
  835. case NERR_BadServiceName:
  836. dosStatus = NERR_ServiceNotInstalled;
  837. break;
  838. case ERROR_ILL_FORMED_PASSWORD:
  839. case NERR_PasswordTooRecent:
  840. dosStatus = ERROR_INVALID_PASSWORD;
  841. break;
  842. case ERROR_PASSWORD_RESTRICTION:
  843. dosStatus = NERR_PasswordHistConflict;
  844. break;
  845. case ERROR_ACCOUNT_RESTRICTION:
  846. dosStatus = NERR_PasswordTooRecent;
  847. break;
  848. case ERROR_PASSWORD_EXPIRED:
  849. case ERROR_PASSWORD_MUST_CHANGE:
  850. dosStatus = NERR_PasswordExpired;
  851. break;
  852. case ERROR_INVALID_PRINTER_NAME:
  853. dosStatus = NERR_QNotFound;
  854. break;
  855. case ERROR_UNKNOWN_PRINTER_DRIVER:
  856. dosStatus = NERR_DriverNotFound;
  857. break;
  858. case ERROR_NO_BROWSER_SERVERS_FOUND:
  859. //
  860. // Down level clients don't understand how to deal with
  861. // the "No browser server" error, so we turn it into success.
  862. //
  863. // This seems wrong to me, but it is what WfW does in the
  864. // same circumstance.
  865. //
  866. if ( !(Header->Flags & XS_FLAGS_NT_CLIENT) ) {
  867. dosStatus = NERR_Success;
  868. } else {
  869. dosStatus = Header->Status;
  870. }
  871. break;
  872. default:
  873. //
  874. // make sure it's a valid lm error code
  875. //
  876. if ( (Header->Status > ERROR_VC_DISCONNECTED) &&
  877. ((Header->Status < NERR_BASE) ||
  878. (Header->Status > MAX_NERR)) ) {
  879. NTSTATUS status;
  880. LPWSTR substring[1];
  881. WCHAR errorString[10];
  882. UNICODE_STRING unicodeString;
  883. substring[0] = errorString;
  884. unicodeString.MaximumLength = 10 * sizeof(WCHAR);
  885. unicodeString.Buffer = errorString;
  886. status = RtlIntegerToUnicodeString(
  887. (ULONG) Header->Status,
  888. 10,
  889. &unicodeString
  890. );
  891. if ( NT_SUCCESS( status ) ) {
  892. SsLogEvent(
  893. EVENT_SRV_CANT_MAP_ERROR,
  894. 1,
  895. substring,
  896. NO_ERROR
  897. );
  898. }
  899. dosStatus = ERROR_UNEXP_NET_ERR;
  900. SS_PRINT(( "srvsvc: unmapped error %d from xactsrv.\n",
  901. Header->Status )) ;
  902. } else {
  903. //
  904. // No change
  905. //
  906. return;
  907. }
  908. }
  909. Header->Status = dosStatus;
  910. return;
  911. } // ConvertApiStatusToDosStatus
  912. BOOLEAN
  913. XsLoadPrintSpoolerFunctions(
  914. )
  915. {
  916. BOOLEAN bReturn = TRUE;
  917. EnterCriticalSection( &SpoolerMutex );
  918. if( !hSpoolerLibrary )
  919. {
  920. hSpoolerLibrary = LoadLibrary( L"winspool.drv" );
  921. if( !hSpoolerLibrary )
  922. {
  923. bReturn = FALSE;
  924. goto finish;
  925. }
  926. pSpoolerOpenPrinterFunction = (PSPOOLER_OPEN_PRINTER)GetProcAddress( hSpoolerLibrary, "OpenPrinterW" );
  927. if( !pSpoolerOpenPrinterFunction )
  928. {
  929. bReturn = FALSE;
  930. goto finish;
  931. }
  932. pSpoolerResetPrinterFunction = (PSPOOLER_RESET_PRINTER)GetProcAddress( hSpoolerLibrary, "ResetPrinterW" );
  933. if( !pSpoolerResetPrinterFunction )
  934. {
  935. bReturn = FALSE;
  936. goto finish;
  937. }
  938. pSpoolerAddJobFunction = (PSPOOLER_ADD_JOB)GetProcAddress( hSpoolerLibrary, "AddJobW" );
  939. if( !pSpoolerAddJobFunction )
  940. {
  941. bReturn = FALSE;
  942. goto finish;
  943. }
  944. pSpoolerScheduleJobFunction = (PSPOOLER_SCHEDULE_JOB)GetProcAddress( hSpoolerLibrary, "ScheduleJob" );
  945. if( !pSpoolerScheduleJobFunction )
  946. {
  947. bReturn = FALSE;
  948. goto finish;
  949. }
  950. pSpoolerClosePrinterFunction = (PSPOOLER_CLOSE_PRINTER)GetProcAddress( hSpoolerLibrary, "ClosePrinter" );
  951. if( !pSpoolerClosePrinterFunction )
  952. {
  953. bReturn = FALSE;
  954. goto finish;
  955. }
  956. }
  957. finish:
  958. if( !bReturn )
  959. {
  960. pSpoolerOpenPrinterFunction = NULL;
  961. pSpoolerResetPrinterFunction = NULL;
  962. pSpoolerAddJobFunction = NULL;
  963. pSpoolerScheduleJobFunction = NULL;
  964. pSpoolerClosePrinterFunction = NULL;
  965. if( hSpoolerLibrary )
  966. {
  967. FreeLibrary( hSpoolerLibrary );
  968. hSpoolerLibrary = NULL;
  969. }
  970. }
  971. LeaveCriticalSection( &SpoolerMutex );
  972. return bReturn;
  973. }
  974. BOOLEAN
  975. XsUnloadPrintSpoolerFunctions(
  976. )
  977. {
  978. EnterCriticalSection( &SpoolerMutex );
  979. pSpoolerOpenPrinterFunction = NULL;
  980. pSpoolerResetPrinterFunction = NULL;
  981. pSpoolerAddJobFunction = NULL;
  982. pSpoolerScheduleJobFunction = NULL;
  983. pSpoolerClosePrinterFunction = NULL;
  984. if( hSpoolerLibrary )
  985. {
  986. FreeLibrary( hSpoolerLibrary );
  987. hSpoolerLibrary = NULL;
  988. }
  989. LeaveCriticalSection( &SpoolerMutex );
  990. return TRUE;
  991. }