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.

689 lines
18 KiB

  1. /*++
  2. Copyright (c) 1991-1992 Microsoft Corporation
  3. Module Name:
  4. xsinit.c
  5. Abstract:
  6. This module contains the initialization and termination code for
  7. the XACTSRV component of the server service.
  8. Author:
  9. David Treadwell (davidtr) 05-Jan-1991
  10. Shanku Niyogi (w-shanku)
  11. Revision History:
  12. Chuck Lenzmeier (chuckl) 17-Jun-1992
  13. Merged xactsrv.c into xsinit.c and moved from xssvc to
  14. srvsvc\server
  15. --*/
  16. //
  17. // Includes.
  18. //
  19. #include "srvsvcp.h"
  20. #include "xsdata.h"
  21. #include <windows.h> // from sdk\inc
  22. #include <xactsrv2.h> // from private\inc
  23. #include <srvfsctl.h>
  24. #include <xsconst.h> // from xactsrv
  25. #undef DEBUG
  26. #undef DEBUG_API_ERRORS
  27. #include <xsdebug.h>
  28. extern CRITICAL_SECTION SpoolerMutex;
  29. BOOLEAN
  30. XsUnloadPrintSpoolerFunctions(
  31. );
  32. DWORD
  33. XsStartXactsrv (
  34. VOID
  35. )
  36. {
  37. NTSTATUS status;
  38. DWORD error;
  39. DWORD i;
  40. HANDLE threadHandle;
  41. DWORD threadId;
  42. HANDLE eventHandle;
  43. HANDLE serverHandle;
  44. ANSI_STRING ansiName;
  45. UNICODE_STRING unicodeName;
  46. IO_STATUS_BLOCK ioStatusBlock;
  47. OBJECT_ATTRIBUTES objectAttributes;
  48. PORT_MESSAGE connectionRequest;
  49. REMOTE_PORT_VIEW clientView;
  50. BOOL waitForEvent;
  51. //
  52. // Set up variables so that we'll know how to shut down in case of
  53. // an error.
  54. //
  55. serverHandle = NULL;
  56. eventHandle = NULL;
  57. waitForEvent = FALSE;
  58. try {
  59. RtlInitializeResource( &SsData.LibraryResource );
  60. InitializeCriticalSection( &SpoolerMutex );
  61. } except( EXCEPTION_EXECUTE_HANDLER ) {
  62. return RtlNtStatusToDosError( GetExceptionCode() );
  63. }
  64. SsData.LibraryResourceInitialized = TRUE;
  65. //
  66. // Create a event that will be set by the last thread to exit.
  67. //
  68. IF_DEBUG(INIT) {
  69. SS_PRINT(( "XsStartXactsrv: Creating termination event.\n" ));
  70. }
  71. SS_ASSERT( SsData.XsAllThreadsTerminatedEvent == NULL );
  72. status = NtCreateEvent(
  73. &SsData.XsAllThreadsTerminatedEvent,
  74. EVENT_ALL_ACCESS,
  75. NULL,
  76. NotificationEvent,
  77. FALSE
  78. );
  79. if ( !NT_SUCCESS(status) ) {
  80. IF_DEBUG(ERRORS) {
  81. SS_PRINT(( "XsStartXactsrv: NtCreateEvent failed: %X\n",
  82. status ));
  83. }
  84. SsData.XsAllThreadsTerminatedEvent = NULL;
  85. goto exit;
  86. }
  87. //
  88. // Open the server device. Note that we need this handle because
  89. // the handle used by the main server service is synchronous. We
  90. // need to to do the XACTSRV_CONNECT FSCTL asynchronously.
  91. //
  92. RtlInitUnicodeString( &unicodeName, XS_SERVER_DEVICE_NAME_W );
  93. InitializeObjectAttributes(
  94. &objectAttributes,
  95. &unicodeName,
  96. OBJ_CASE_INSENSITIVE,
  97. NULL,
  98. NULL
  99. );
  100. status = NtOpenFile(
  101. &serverHandle,
  102. FILE_READ_DATA, // DesiredAccess
  103. &objectAttributes,
  104. &ioStatusBlock,
  105. 0L, // ShareAccess
  106. 0L // OpenOptions
  107. );
  108. if ( NT_SUCCESS(status) ) {
  109. status = ioStatusBlock.Status;
  110. }
  111. if ( !NT_SUCCESS(status) ) {
  112. IF_DEBUG(ERRORS) {
  113. SS_PRINT(( "XsStartXactsrv: NtOpenFile (server device object) "
  114. "failed: %X\n", status ));
  115. }
  116. goto exit;
  117. }
  118. //
  119. // Create the LPC port.
  120. //
  121. // !!! Right now this only tries a single port name. If, for some
  122. // bizarre reason, somebody already has a port by this name,
  123. // then this will fail. It might make sense to try different
  124. // names if this fails.
  125. //
  126. // !!! We might want to make the port name somewhat random for
  127. // slightly enhanced security.
  128. RtlInitUnicodeString( &unicodeName, XS_PORT_NAME_W );
  129. RtlInitAnsiString( &ansiName, XS_PORT_NAME_A );
  130. InitializeObjectAttributes(
  131. &objectAttributes,
  132. &unicodeName,
  133. 0,
  134. NULL,
  135. NULL
  136. );
  137. IF_DEBUG(LPC) {
  138. SS_PRINT(( "XsInitialize: creating port %Z\n", &ansiName ));
  139. }
  140. SS_ASSERT( SsData.XsConnectionPortHandle == NULL );
  141. status = NtCreatePort(
  142. &SsData.XsConnectionPortHandle,
  143. &objectAttributes,
  144. 0,
  145. XS_PORT_MAX_MESSAGE_LENGTH,
  146. XS_PORT_MAX_MESSAGE_LENGTH * 32
  147. );
  148. if ( ! NT_SUCCESS(status) ) {
  149. IF_DEBUG(ERRORS) {
  150. if ( status == STATUS_OBJECT_NAME_COLLISION ) {
  151. SS_PRINT(( "XsStartXactsrv: The XACTSRV port already "
  152. "exists\n"));
  153. } else {
  154. SS_PRINT(( "XsStartXactsrv: Failed to create port %Z: %X\n",
  155. &ansiName, status ));
  156. }
  157. }
  158. SsData.XsConnectionPortHandle = NULL;
  159. goto exit;
  160. }
  161. //
  162. // Set up an event so that we'll know when IO completes, then send
  163. // the FSCTL to the server indicating that it should now connect to
  164. // us. We'll set up the port while the IO is outstanding, then wait
  165. // on the event when the port setup is complete.
  166. //
  167. status = NtCreateEvent(
  168. &eventHandle,
  169. EVENT_ALL_ACCESS,
  170. NULL, // ObjectAttributes
  171. NotificationEvent,
  172. FALSE
  173. );
  174. if ( !NT_SUCCESS(status) ) {
  175. IF_DEBUG(ERRORS) {
  176. SS_PRINT(( "XsStartXactsrv: NtCreateEvent failed: %X\n",
  177. status ));
  178. }
  179. goto exit;
  180. }
  181. IF_DEBUG(LPC) {
  182. SS_PRINT(( "XsStartXactsrv: sending FSCTL_SRV_XACTSRV_CONNECT.\n" ));
  183. }
  184. status = NtFsControlFile(
  185. serverHandle,
  186. eventHandle,
  187. NULL, // ApcRoutine
  188. NULL, // ApcContext
  189. &ioStatusBlock,
  190. FSCTL_SRV_XACTSRV_CONNECT,
  191. ansiName.Buffer,
  192. ansiName.Length,
  193. NULL, // OutputBuffer
  194. 0L // OutputBufferLength
  195. );
  196. if ( !NT_SUCCESS(status) ) {
  197. IF_DEBUG(ERRORS) {
  198. SS_PRINT(( "XsStartXactsrv: NtFsControlFile failed: %X\n",
  199. status ));
  200. }
  201. goto exit;
  202. }
  203. waitForEvent = TRUE;
  204. //
  205. // Start listening for the server's connection to the port. Note
  206. // that it is OK if the server happens to call NtConnectPort
  207. // first--it will simply block until this call to NtListenPort
  208. // occurs.
  209. //
  210. IF_DEBUG(LPC) {
  211. SS_PRINT(( "XsStartXactsrv: listening to port.\n" ));
  212. }
  213. connectionRequest.u1.s1.TotalLength = sizeof(connectionRequest);
  214. connectionRequest.u1.s1.DataLength = (CSHORT)0;
  215. status = NtListenPort(
  216. SsData.XsConnectionPortHandle,
  217. &connectionRequest
  218. );
  219. if ( !NT_SUCCESS(status) ) {
  220. IF_DEBUG(ERRORS) {
  221. SS_PRINT(( "XsStartXactsrv: NtListenPort failed: %X\n", status ));
  222. }
  223. goto exit;
  224. }
  225. //
  226. // The server has initiated the connection. Accept the connection.
  227. //
  228. // !!! We probably need some security check here.
  229. //
  230. clientView.Length = sizeof(clientView);
  231. clientView.ViewSize = 0;
  232. clientView.ViewBase = 0;
  233. IF_DEBUG(LPC) {
  234. SS_PRINT(( "XsStartXactsrv: Accepting connection to port.\n" ));
  235. }
  236. SS_ASSERT( SsData.XsCommunicationPortHandle == NULL );
  237. status = NtAcceptConnectPort(
  238. &SsData.XsCommunicationPortHandle,
  239. NULL, // PortContext
  240. &connectionRequest,
  241. TRUE, // AcceptConnection
  242. NULL, // ServerView
  243. &clientView
  244. );
  245. if ( !NT_SUCCESS(status) ) {
  246. IF_DEBUG(ERRORS) {
  247. SS_PRINT(( "XsStartXactsrv: NtAcceptConnectPort failed: %X\n",
  248. status ));
  249. }
  250. SsData.XsCommunicationPortHandle = NULL;
  251. goto exit;
  252. }
  253. IF_DEBUG(LPC) {
  254. SS_PRINT(( "XsStartXactsrv: client view size: %ld, base: %lx\n",
  255. clientView.ViewSize, clientView.ViewBase ));
  256. }
  257. //
  258. // Complete the connection to the port, thereby releasing the server
  259. // thread waiting in NtConnectPort.
  260. //
  261. IF_DEBUG(LPC) {
  262. SS_PRINT(( "XsStartXactsrv: Completing connection to port.\n" ));
  263. }
  264. status = NtCompleteConnectPort( SsData.XsCommunicationPortHandle );
  265. if ( !NT_SUCCESS(status) ) {
  266. IF_DEBUG(ERRORS) {
  267. SS_PRINT(( "XsStartXactsrv: NtCompleteConnectPort failed: %X\n",
  268. status ));
  269. }
  270. goto exit;
  271. }
  272. status = STATUS_SUCCESS;
  273. exit:
  274. //
  275. // Wait for the IO to complete, then close the event handle.
  276. //
  277. if ( waitForEvent ) {
  278. NTSTATUS waitStatus;
  279. SS_ASSERT( eventHandle != NULL );
  280. waitStatus = NtWaitForSingleObject( eventHandle, FALSE, NULL );
  281. if ( !NT_SUCCESS(waitStatus) ) {
  282. IF_DEBUG(ERRORS) {
  283. SS_PRINT(( "XsStartXactsrv: NtWaitForSingleObject failed: "
  284. "%X\n", waitStatus ));
  285. }
  286. //
  287. // If another error has already occurred, don't report this
  288. // one.
  289. //
  290. if ( NT_SUCCESS(status) ) {
  291. status = waitStatus;
  292. }
  293. }
  294. //
  295. // Check the status in the IO status block. If it is bad, then
  296. // there was some problem on the server side of the port setup.
  297. //
  298. if ( !NT_SUCCESS(ioStatusBlock.Status) ) {
  299. IF_DEBUG(ERRORS) {
  300. SS_PRINT(( "XsStartXactsrv: bad status in IO status block: "
  301. "%X\n", ioStatusBlock.Status ));
  302. }
  303. //
  304. // If another error has already occurred, don't report this
  305. // one.
  306. //
  307. if ( NT_SUCCESS(status) ) {
  308. status = ioStatusBlock.Status;
  309. }
  310. }
  311. CloseHandle( eventHandle );
  312. }
  313. //
  314. // Close the handle to the server.
  315. //
  316. if ( serverHandle != NULL ) {
  317. CloseHandle( serverHandle );
  318. }
  319. //
  320. // If the above failed, return to caller now.
  321. //
  322. if ( !NT_SUCCESS(status) ) {
  323. return RtlNtStatusToDosError( status );
  324. }
  325. //
  326. // Start one API processing thread. It will spawn others if needed
  327. //
  328. threadHandle = CreateThread(
  329. NULL,
  330. 0,
  331. (LPTHREAD_START_ROUTINE)XsProcessApisWrapper,
  332. 0,
  333. 0,
  334. &threadId
  335. );
  336. if ( threadHandle != 0 ) {
  337. IF_DEBUG(THREADS) {
  338. SS_PRINT(( "XsStartXactsrv: Created thread %ld for "
  339. "processing APIs\n", SsData.XsThreads ));
  340. }
  341. CloseHandle( threadHandle );
  342. SsData.ApiThreadsStarted = TRUE;
  343. } else {
  344. //
  345. // Thread creation failed. Return an error to the caller.
  346. // It is the responsibility of the caller to call
  347. // XsStopXactsrv to clean up.
  348. //
  349. error = GetLastError( );
  350. return error;
  351. }
  352. //
  353. // Initialization succeeded.
  354. //
  355. return NO_ERROR;
  356. } // XsStartXactsrv
  357. /*
  358. * This routine is called to stop the transaction processor once the
  359. * server driver has terminated.
  360. */
  361. VOID
  362. XsStopXactsrv (
  363. VOID
  364. )
  365. {
  366. NTSTATUS status;
  367. static XACTSRV_REQUEST_MESSAGE requestMessage;
  368. LONG i;
  369. BOOL ok;
  370. //
  371. // Stop all the xs worker threads, and release resources
  372. //
  373. if ( SsData.XsConnectionPortHandle != NULL ) {
  374. //
  375. // Indicate that XACTSRV is terminating.
  376. //
  377. SsData.XsTerminating = TRUE;
  378. IF_DEBUG(TERMINATION) {
  379. SS_PRINT(("XsStopXactsrv: queueing termination messages\n"));
  380. }
  381. if( SsData.ApiThreadsStarted == TRUE ) {
  382. //
  383. // Queue a message to kill off the worker thereads
  384. //
  385. RtlZeroMemory( &requestMessage, sizeof( requestMessage ));
  386. requestMessage.PortMessage.u1.s1.DataLength =
  387. (USHORT)( sizeof(requestMessage) - sizeof(PORT_MESSAGE) );
  388. requestMessage.PortMessage.u1.s1.TotalLength = sizeof(requestMessage);
  389. requestMessage.MessageType = XACTSRV_MESSAGE_WAKEUP;
  390. status = NtRequestPort(
  391. SsData.XsConnectionPortHandle,
  392. (PPORT_MESSAGE)&requestMessage
  393. );
  394. IF_DEBUG(ERRORS) {
  395. if ( !NT_SUCCESS(status) ) {
  396. SS_PRINT(( "SrvXsDisconnect: NtRequestPort failed: %X\n",
  397. status ));
  398. }
  399. }
  400. //
  401. // The above will cause all worker threads to wake up then die.
  402. //
  403. ok = WaitForSingleObject( SsData.XsAllThreadsTerminatedEvent, (DWORD)-1 );
  404. IF_DEBUG(ERRORS) {
  405. if ( !ok ) {
  406. SS_PRINT(( "XsStopXactsrv: WaitForSingleObject failed: "
  407. "%ld\n", GetLastError() ));
  408. }
  409. }
  410. SsData.ApiThreadsStarted = FALSE;
  411. }
  412. CloseHandle( SsData.XsConnectionPortHandle );
  413. }
  414. if( SsData.XsCommunicationPortHandle != NULL ) {
  415. CloseHandle( SsData.XsCommunicationPortHandle );
  416. SsData.XsCommunicationPortHandle = NULL;
  417. }
  418. //
  419. // Unload the xactsrv libaray
  420. //
  421. if( SsData.XsXactsrvLibrary != NULL ) {
  422. PXS_API_TABLE_ENTRY entry = XsApiTable;
  423. //
  424. // Null out all of the entry points
  425. //
  426. for( entry = XsApiTable;
  427. entry < &XsApiTable[ XS_SIZE_OF_API_TABLE ];
  428. entry++ ) {
  429. entry->Handler = NULL;
  430. }
  431. XsSetParameters = NULL;
  432. XsCaptureParameters = NULL;
  433. XsCheckSmbDescriptor = NULL;
  434. FreeLibrary( SsData.XsXactsrvLibrary );
  435. SsData.XsXactsrvLibrary = NULL;
  436. }
  437. //
  438. // Unload the license library
  439. //
  440. if( SsData.XsLicenseLibrary != NULL ) {
  441. SsData.SsLicenseRequest = NULL;
  442. SsData.SsFreeLicense = NULL;
  443. FreeLibrary( SsData.XsLicenseLibrary );
  444. SsData.XsLicenseLibrary = NULL;
  445. }
  446. if( SsData.LibraryResourceInitialized == TRUE ) {
  447. // Unload the spooler library if necessary
  448. XsUnloadPrintSpoolerFunctions();
  449. DeleteCriticalSection( &SpoolerMutex );
  450. // Delete the library resource
  451. RtlDeleteResource( &SsData.LibraryResource );
  452. SsData.LibraryResourceInitialized = FALSE;
  453. }
  454. //
  455. // Close the termination event.
  456. //
  457. if ( SsData.XsAllThreadsTerminatedEvent != NULL ) {
  458. CloseHandle( SsData.XsAllThreadsTerminatedEvent );
  459. SsData.XsAllThreadsTerminatedEvent = NULL;
  460. }
  461. return;
  462. } // XsStopXactsrv
  463. /*
  464. * This routine is called to dynamically load the transaction library for
  465. * downlevel clients. It fills in the entry points for the library
  466. */
  467. BOOLEAN
  468. XsLoadXactLibrary( WORD FunctionNumber )
  469. {
  470. PXS_API_TABLE_ENTRY entry = &XsApiTable[ FunctionNumber ];
  471. if( SsData.XsXactsrvLibrary == NULL ) {
  472. RtlAcquireResourceExclusive( &SsData.LibraryResource, TRUE );
  473. if( SsData.XsXactsrvLibrary == NULL ) {
  474. SsData.XsXactsrvLibrary = LoadLibrary( L"xactsrv.dll" );
  475. }
  476. RtlReleaseResource( &SsData.LibraryResource );
  477. if( SsData.XsXactsrvLibrary == NULL ) {
  478. DbgPrint( "SRVSVC: Unable to load xactsrv.dll, error %u\n",
  479. GetLastError() );
  480. return FALSE;
  481. }
  482. }
  483. if( XsSetParameters == NULL &&
  484. (XsSetParameters = (XS_SET_PARAMETERS_FUNCTION)GetProcAddress(
  485. SsData.XsXactsrvLibrary, "XsSetParameters" )) == NULL ) {
  486. DbgPrint( "SRVSVC: XsSetParameters entry missing from xactsrv.dll, err %u\n",
  487. GetLastError() );
  488. return FALSE;
  489. }
  490. if( XsCaptureParameters == NULL &&
  491. (XsCaptureParameters = (XS_CAPTURE_PARAMETERS_FUNCTION)GetProcAddress(
  492. SsData.XsXactsrvLibrary, "XsCaptureParameters" )) == NULL ) {
  493. DbgPrint( "SRVSVC: XsCaptureParameters entry missing from xactsrv.dll, err %u\n",
  494. GetLastError() );
  495. return FALSE;
  496. }
  497. if( XsCheckSmbDescriptor == NULL &&
  498. (XsCheckSmbDescriptor = (XS_CHECK_SMB_DESCRIPTOR_FUNCTION)GetProcAddress(
  499. SsData.XsXactsrvLibrary, "XsCheckSmbDescriptor" )) == NULL ) {
  500. DbgPrint( "SRVSVC: XsCheckSmbDescriptor entry missing from xactsrv.dll, err %u\n",
  501. GetLastError() );
  502. return FALSE;
  503. }
  504. //
  505. // Fetch the requested entry point
  506. //
  507. entry->Handler =
  508. (PXACTSRV_API_HANDLER)GetProcAddress( SsData.XsXactsrvLibrary, entry->HandlerName );
  509. if( entry->Handler == NULL ) {
  510. DbgPrint( "SRVSVC: %s entry missing from xactsrv.dll, err %u\n",
  511. entry->HandlerName, GetLastError() );
  512. return FALSE;
  513. }
  514. return TRUE;
  515. }
  516. BOOLEAN
  517. SsLoadLicenseLibrary()
  518. {
  519. if( SsData.XsLicenseLibrary == NULL ) {
  520. RtlAcquireResourceExclusive( &SsData.LibraryResource, TRUE );
  521. if( SsData.XsLicenseLibrary == NULL ) {
  522. SsData.XsLicenseLibrary = LoadLibrary( L"ntlsapi.dll" );
  523. }
  524. RtlReleaseResource( &SsData.LibraryResource );
  525. if( SsData.XsLicenseLibrary == NULL ) {
  526. return FALSE;
  527. }
  528. }
  529. SsData.SsLicenseRequest = (PNT_LICENSE_REQUEST_W)GetProcAddress( SsData.XsLicenseLibrary, "NtLicenseRequestW" );
  530. SsData.SsFreeLicense = (PNT_LS_FREE_HANDLE)GetProcAddress( SsData.XsLicenseLibrary, "NtLSFreeHandle" );
  531. return( SsData.SsLicenseRequest != NULL && SsData.SsFreeLicense != NULL );
  532. }