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.

1116 lines
29 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. xssupp.c
  5. Abstract:
  6. This module contains the code necessary to support XACTSRV for down-level
  7. remote APIs.
  8. Author:
  9. David Treadwell (davidtr) 05-Jan-1991
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #include "xssupp.tmh"
  14. #pragma hdrstop
  15. //
  16. // Xs forward declarations
  17. //
  18. VOID
  19. SrvXsFreeSharedMemory (
  20. VOID
  21. );
  22. #ifdef ALLOC_PRAGMA
  23. #pragma alloc_text( PAGE, SrvXsConnect )
  24. #pragma alloc_text( PAGE, SrvXsRequest )
  25. #pragma alloc_text( PAGE, SrvXsLSOperation )
  26. #pragma alloc_text( PAGE, SrvXsDisconnect )
  27. #pragma alloc_text( PAGE, SrvXsFreeSharedMemory )
  28. #pragma alloc_text( PAGE, SrvXsAllocateHeap )
  29. #pragma alloc_text( PAGE, SrvXsFreeHeap )
  30. #pragma alloc_text( PAGE, SrvXsPnpOperation )
  31. #endif
  32. //
  33. // Xs internal Globals
  34. //
  35. //
  36. // This count indicates how many outstanding transactions are using
  37. // the XS shared memory. This prevents us from deleting the shared
  38. // memory while it is still being accessed.
  39. //
  40. ULONG SrvXsSharedMemoryReference = 0;
  41. NTSTATUS
  42. SrvXsConnect (
  43. IN PUNICODE_STRING PortName
  44. )
  45. /*++
  46. Routine Description:
  47. This routine performs all the work necessary to connect the server
  48. to XACTSRV. It creates a section of shared memory to use, then
  49. calls NtConnectPort to connect to the port that XACTSRV has already
  50. created.
  51. Arguments:
  52. PortName - Name of the port XACTSRV has opened.
  53. Return Value:
  54. NTSTATUS - result of operation.
  55. --*/
  56. {
  57. NTSTATUS status;
  58. PORT_VIEW clientView;
  59. SECURITY_QUALITY_OF_SERVICE dynamicQos;
  60. PAGED_CODE( );
  61. //
  62. // Initialize variables so that we know what to close on exit.
  63. //
  64. SrvXsSectionHandle = NULL;
  65. SrvXsPortHandle = NULL;
  66. SrvXsPortMemoryHeap = NULL;
  67. //
  68. // Create the section to be used as unnamed shared memory for
  69. // communication between the server and XACTSRV.
  70. //
  71. status = NtCreateSection(
  72. &SrvXsSectionHandle,
  73. SECTION_ALL_ACCESS,
  74. NULL, // ObjectAttributes
  75. &SrvXsSectionSize,
  76. PAGE_READWRITE,
  77. SEC_RESERVE,
  78. NULL // FileHandle
  79. );
  80. if ( !NT_SUCCESS(status) ) {
  81. IF_DEBUG(ERRORS) {
  82. KdPrint(( "SrvXsConnect: NtCreateSection failed: %X\n", status ));
  83. }
  84. goto exit;
  85. }
  86. IF_DEBUG(XACTSRV) {
  87. KdPrint(( "SrvXsConnect: created section of %ld bytes, handle %p\n",
  88. SrvXsSectionSize.LowPart, SrvXsSectionHandle ));
  89. }
  90. //
  91. // Set up for a call to NtConnectPort and connect to XACTSRV. This
  92. // includes a description of the port memory section so that the
  93. // LPC connection logic can make the section visible to both the
  94. // client and server processes.
  95. //
  96. clientView.Length = sizeof(clientView);
  97. clientView.SectionHandle = SrvXsSectionHandle;
  98. clientView.SectionOffset = 0;
  99. clientView.ViewSize = SrvXsSectionSize.LowPart;
  100. clientView.ViewBase = 0;
  101. clientView.ViewRemoteBase = 0;
  102. //
  103. // Set up the security quality of service parameters to use over the
  104. // port. Use dynamic tracking so that XACTSRV will impersonate the
  105. // user that we are impersonating when we call NtRequestWaitReplyPort.
  106. // If we used static tracking, XACTSRV would impersonate the context
  107. // when the connection is made.
  108. //
  109. dynamicQos.ImpersonationLevel = SecurityImpersonation;
  110. dynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  111. dynamicQos.EffectiveOnly = TRUE;
  112. // !!! We might want to use a timeout value.
  113. status = NtConnectPort(
  114. &SrvXsPortHandle,
  115. PortName,
  116. &dynamicQos,
  117. &clientView,
  118. NULL, // ServerView
  119. NULL, // MaxMessageLength
  120. NULL, // ConnectionInformation
  121. NULL // ConnectionInformationLength
  122. );
  123. if ( !NT_SUCCESS(status) ) {
  124. IF_DEBUG(ERRORS) {
  125. KdPrint(( "SrvXsConnect: NtConnectPort for port %wZ failed: %X\n",
  126. PortName, status ));
  127. }
  128. goto exit;
  129. }
  130. IF_DEBUG(XACTSRV) {
  131. KdPrint(( "SrvXsConnect: conected to port %wZ, handle %p\n",
  132. PortName, SrvXsPortHandle ));
  133. }
  134. //
  135. // Store information about the section so that we can create pointers
  136. // meaningful to XACTSRV.
  137. //
  138. SrvXsPortMemoryBase = clientView.ViewBase;
  139. SrvXsPortMemoryDelta = PTR_DIFF_FULLPTR( clientView.ViewRemoteBase,
  140. clientView.ViewBase );
  141. IF_DEBUG(XACTSRV) {
  142. KdPrint(( "SrvXsConnect: port mem base %p, port mem delta %p\n",
  143. SrvXsPortMemoryBase, (PVOID)SrvXsPortMemoryDelta ));
  144. }
  145. //
  146. // Set up the port memory as heap.
  147. //
  148. // *** Note that we do our own heap serialization using
  149. // SrvXsResource.
  150. //
  151. SrvXsPortMemoryHeap = RtlCreateHeap(
  152. HEAP_NO_SERIALIZE, // Flags
  153. SrvXsPortMemoryBase, // HeapBase
  154. SrvXsSectionSize.LowPart, // ReserveSize
  155. PAGE_SIZE, // CommitSize
  156. NULL, // Lock
  157. 0 // Reserved
  158. );
  159. SrvXsActive = TRUE;
  160. //
  161. // Test it out to ensure everything is working right
  162. //
  163. SrvXsFreeHeap( SrvXsAllocateHeap( 100, &status ) );
  164. return status;
  165. exit:
  166. if ( SrvXsSectionHandle != NULL ) {
  167. SrvNtClose( SrvXsSectionHandle, FALSE );
  168. }
  169. if ( SrvXsPortHandle != NULL ) {
  170. SrvNtClose( SrvXsPortHandle, FALSE );
  171. }
  172. return status;
  173. } // SrvXsConnect
  174. SMB_TRANS_STATUS
  175. SrvXsRequest (
  176. IN OUT PWORK_CONTEXT WorkContext
  177. )
  178. /*++
  179. Routine Description:
  180. This routine sends a remote API request to XACTSRV. It first
  181. updates all the pointers in the transaction block so that they
  182. are meaningful to XACTSRV, then sends a message over the port
  183. indicating that there is a request in the shared memory ready to
  184. be serviced. It then fixes all the pointers in the transaction
  185. block.
  186. Arguments:
  187. WorkContext - a pointer to a work context block that has a pointer to
  188. transaction block to use.
  189. Return Value:
  190. NTSTATUS - result of operation.
  191. --*/
  192. {
  193. NTSTATUS status;
  194. PCONNECTION connection = WorkContext->Connection;
  195. PSESSION session = WorkContext->Session;
  196. SMB_TRANS_STATUS returnStatus;
  197. PTRANSACTION transaction;
  198. XACTSRV_REQUEST_MESSAGE requestMessage;
  199. XACTSRV_REPLY_MESSAGE replyMessage;
  200. PWCH destPtr, sourcePtr, sourceEndPtr;
  201. PAGED_CODE( );
  202. //
  203. // If this call is made on the NULL session, make sure it's one of
  204. // the authorized apis.
  205. //
  206. transaction = WorkContext->Parameters.Transaction;
  207. if ( session->IsNullSession && SrvRestrictNullSessionAccess ) {
  208. USHORT apiNumber;
  209. apiNumber = SmbGetUshort( (PSMB_USHORT)transaction->InParameters );
  210. if ( apiNumber != API_WUserPasswordSet2 &&
  211. apiNumber != API_WUserGetGroups &&
  212. apiNumber != API_NetServerEnum2 &&
  213. apiNumber != API_WNetServerReqChallenge &&
  214. apiNumber != API_WNetServerAuthenticate &&
  215. apiNumber != API_WNetServerPasswordSet &&
  216. apiNumber != API_WNetAccountDeltas &&
  217. apiNumber != API_WNetAccountSync &&
  218. apiNumber != API_WWkstaUserLogoff &&
  219. apiNumber != API_WNetWriteUpdateLog &&
  220. apiNumber != API_WNetAccountUpdate &&
  221. apiNumber != API_SamOEMChgPasswordUser2_P &&
  222. apiNumber != API_NetServerEnum3 &&
  223. apiNumber != API_WNetAccountConfirmUpdate ) {
  224. IF_DEBUG(ERRORS) {
  225. KdPrint(( "SrvXsRequest: Null session tried to call api.%d\n",
  226. apiNumber ));
  227. }
  228. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  229. return SmbTransStatusErrorWithoutData;
  230. }
  231. }
  232. //
  233. // Initialize the transport name pointer to make sure we can know if
  234. // it has been allocated.
  235. //
  236. requestMessage.Message.DownLevelApi.TransportName = NULL;
  237. //
  238. // Convert the relevant pointers in the transaction block to the base
  239. // in XACTSRV.
  240. //
  241. transaction->TransactionName.Buffer += SrvXsPortMemoryDelta;
  242. transaction->InSetup += SrvXsPortMemoryDelta;
  243. transaction->OutSetup += SrvXsPortMemoryDelta;
  244. transaction->InParameters += SrvXsPortMemoryDelta;
  245. transaction->OutParameters += SrvXsPortMemoryDelta;
  246. transaction->InData += SrvXsPortMemoryDelta;
  247. transaction->OutData += SrvXsPortMemoryDelta;
  248. //
  249. // Build the transport name in the message.
  250. //
  251. requestMessage.Message.DownLevelApi.TransportName =
  252. SrvXsAllocateHeap(
  253. WorkContext->Endpoint->TransportName.Length + sizeof(WCHAR),
  254. &status
  255. );
  256. if ( requestMessage.Message.DownLevelApi.TransportName == NULL ) {
  257. SrvSetSmbError( WorkContext, status );
  258. returnStatus = SmbTransStatusErrorWithoutData;
  259. goto exit;
  260. }
  261. requestMessage.Message.DownLevelApi.TransportNameLength =
  262. WorkContext->Endpoint->TransportName.Length;
  263. RtlCopyMemory(
  264. requestMessage.Message.DownLevelApi.TransportName,
  265. WorkContext->Endpoint->TransportName.Buffer,
  266. WorkContext->Endpoint->TransportName.Length
  267. );
  268. //
  269. // Null terminate the transport name.
  270. //
  271. requestMessage.Message.DownLevelApi.TransportName[ WorkContext->Endpoint->TransportName.Length / sizeof(WCHAR) ] = UNICODE_NULL;
  272. //
  273. // Adjust the transport name to be self relative within the buffer.
  274. //
  275. requestMessage.Message.DownLevelApi.TransportName =
  276. (PWSTR)((PUCHAR)requestMessage.Message.DownLevelApi.TransportName +
  277. SrvXsPortMemoryDelta);
  278. //
  279. // Build the server name in the message
  280. //
  281. RtlCopyMemory(
  282. requestMessage.Message.DownLevelApi.ServerName,
  283. WorkContext->Endpoint->TransportAddress.Buffer,
  284. MIN( sizeof(requestMessage.Message.DownLevelApi.ServerName),
  285. WorkContext->Endpoint->TransportAddress.Length )
  286. );
  287. requestMessage.Message.DownLevelApi.Transaction =
  288. (PTRANSACTION)( (PCHAR)transaction + SrvXsPortMemoryDelta );
  289. //
  290. // Set up the message to send over the port.
  291. //
  292. requestMessage.PortMessage.u1.s1.DataLength =
  293. (USHORT)( sizeof(requestMessage) - sizeof(PORT_MESSAGE) );
  294. requestMessage.PortMessage.u1.s1.TotalLength = sizeof(requestMessage);
  295. requestMessage.PortMessage.u2.ZeroInit = 0;
  296. requestMessage.PortMessage.u2.s2.Type = LPC_KERNELMODE_MESSAGE;
  297. requestMessage.MessageType = XACTSRV_MESSAGE_DOWN_LEVEL_API;
  298. //
  299. // Copy the client machine name for XACTSRV, skipping over the
  300. // initial "\\", and deleting trailing spaces.
  301. //
  302. destPtr = requestMessage.Message.DownLevelApi.ClientMachineName;
  303. sourcePtr =
  304. connection->PagedConnection->ClientMachineNameString.Buffer + 2;
  305. sourceEndPtr = sourcePtr
  306. + min( connection->PagedConnection->ClientMachineNameString.Length,
  307. sizeof(requestMessage.Message.DownLevelApi.ClientMachineName) /
  308. sizeof(WCHAR) - 1 );
  309. while ( sourcePtr < sourceEndPtr && *sourcePtr != UNICODE_NULL ) {
  310. *destPtr++ = *sourcePtr++;
  311. }
  312. *destPtr-- = UNICODE_NULL;
  313. while ( destPtr >= requestMessage.Message.DownLevelApi.ClientMachineName
  314. &&
  315. *destPtr == L' ' ) {
  316. *destPtr-- = UNICODE_NULL;
  317. }
  318. //
  319. // Copy the lanman session key. This will be used to decrypt doubly
  320. // encrypted passwords.
  321. //
  322. RtlCopyMemory(
  323. requestMessage.Message.DownLevelApi.LanmanSessionKey,
  324. session->LanManSessionKey,
  325. MSV1_0_LANMAN_SESSION_KEY_LENGTH
  326. );
  327. //
  328. // Set the flags
  329. //
  330. requestMessage.Message.DownLevelApi.Flags = 0;
  331. if ( IS_NT_DIALECT( connection->SmbDialect ) ) {
  332. requestMessage.Message.DownLevelApi.Flags |= XS_FLAGS_NT_CLIENT;
  333. }
  334. //
  335. // Send the message to XACTSRV and wait for a response message.
  336. //
  337. // !!! We may want to put a timeout on this.
  338. //
  339. IF_DEBUG(XACTSRV) {
  340. KdPrint(( "SrvXsRequest: Sending message at %p, port mem %p.\n",
  341. &requestMessage, transaction ));
  342. }
  343. status = IMPERSONATE( WorkContext );
  344. if( NT_SUCCESS( status ) ) {
  345. status = NtRequestWaitReplyPort(
  346. SrvXsPortHandle,
  347. (PPORT_MESSAGE)&requestMessage,
  348. (PPORT_MESSAGE)&replyMessage
  349. );
  350. REVERT( );
  351. }
  352. if ( !NT_SUCCESS(status) ) {
  353. IF_DEBUG(ERRORS) {
  354. KdPrint(( "SrvXsRequest: NtRequestWaitReplyPort failed: %X\n",
  355. status ));
  356. }
  357. SrvSetSmbError( WorkContext, status );
  358. returnStatus = SmbTransStatusErrorWithoutData;
  359. goto exit;
  360. }
  361. IF_DEBUG(XACTSRV) {
  362. KdPrint(( "SrvXsRequest: Received response at %p\n", &replyMessage ));
  363. }
  364. //
  365. // Check the status returned in the reply.
  366. //
  367. status = replyMessage.Message.DownLevelApi.Status;
  368. if ( !NT_SUCCESS(status) ) {
  369. IF_DEBUG(SMB_ERRORS) {
  370. KdPrint(( "SrvXsRequest: XACTSRV reply had status %X\n", status ));
  371. }
  372. SrvSetSmbError( WorkContext, status );
  373. returnStatus = SmbTransStatusErrorWithoutData;
  374. goto exit;
  375. }
  376. returnStatus = SmbTransStatusSuccess;
  377. exit:
  378. //
  379. // We're done with the API. Free up the buffer containing the
  380. // transport name.
  381. //
  382. if ( requestMessage.Message.DownLevelApi.TransportName != NULL ) {
  383. requestMessage.Message.DownLevelApi.TransportName =
  384. (PWSTR)((PUCHAR)requestMessage.Message.DownLevelApi.TransportName -
  385. SrvXsPortMemoryDelta);
  386. SrvXsFreeHeap( requestMessage.Message.DownLevelApi.TransportName );
  387. }
  388. //
  389. // Convert the relevant pointers in the transaction block back to
  390. // the server base.
  391. //
  392. transaction->TransactionName.Buffer -= SrvXsPortMemoryDelta;
  393. transaction->InSetup -= SrvXsPortMemoryDelta;
  394. transaction->OutSetup -= SrvXsPortMemoryDelta;
  395. transaction->InParameters -= SrvXsPortMemoryDelta;
  396. transaction->OutParameters -= SrvXsPortMemoryDelta;
  397. transaction->InData -= SrvXsPortMemoryDelta;
  398. transaction->OutData -= SrvXsPortMemoryDelta;
  399. return returnStatus;
  400. } // SrvXsRequest
  401. NTSTATUS
  402. SrvXsLSOperation (
  403. IN PSESSION Session,
  404. IN ULONG Type
  405. )
  406. /*++
  407. Routine Description:
  408. This routine causes the Xact service to do an NtLSRequest call
  409. Arguments:
  410. Session - a pointer to the session structure involved in the request
  411. Type - either XACTSRV_MESSAGE_LSREQUEST or XACTSRV_MESSAGE_LSRELEASE
  412. depending on whether a license is being requested or being
  413. released.
  414. Return Value:
  415. STATUS_SUCCESS if the license was granted
  416. Notes:
  417. Once a license is granted for a particular session, it is never released
  418. until the session is deallocated. Therefore, it is only necessary to
  419. hold the Session->Connection->LicenseLock when we are checking for
  420. acquisition of the license.
  421. We don't need licenses if we are running on a workstation.
  422. We don't try for licenses over NULL sessions
  423. --*/
  424. {
  425. XACTSRV_REQUEST_MESSAGE requestMessage;
  426. XACTSRV_REPLY_MESSAGE replyMessage;
  427. NTSTATUS status;
  428. ULONG requestLength;
  429. UNICODE_STRING userName, userDomain;
  430. PAGED_CODE( );
  431. if( SrvProductTypeServer == FALSE || !SrvXsActive ) {
  432. return STATUS_SUCCESS;
  433. }
  434. switch( Type ) {
  435. case XACTSRV_MESSAGE_LSREQUEST:
  436. if( Session->IsNullSession ||
  437. Session->IsLSNotified ) {
  438. return STATUS_SUCCESS;
  439. }
  440. ACQUIRE_LOCK( &Session->Connection->LicenseLock );
  441. if( Session->IsLSNotified == TRUE ) {
  442. RELEASE_LOCK( &Session->Connection->LicenseLock );
  443. return STATUS_SUCCESS;
  444. }
  445. //
  446. // Put domainname\username in the message
  447. //
  448. status = SrvGetUserAndDomainName( Session, &userName, &userDomain );
  449. if( !NT_SUCCESS( status ) ) {
  450. RELEASE_LOCK( &Session->Connection->LicenseLock );
  451. return status;
  452. }
  453. requestMessage.Message.LSRequest.UserName =
  454. SrvXsAllocateHeap( userDomain.Length + sizeof(WCHAR)
  455. + userName.Length + sizeof(WCHAR), &status
  456. );
  457. if ( requestMessage.Message.LSRequest.UserName == NULL ) {
  458. RELEASE_LOCK( &Session->Connection->LicenseLock );
  459. SrvReleaseUserAndDomainName( Session, &userName, &userDomain );
  460. return status;
  461. }
  462. if( userDomain.Length ) {
  463. RtlCopyMemory(
  464. requestMessage.Message.LSRequest.UserName,
  465. userDomain.Buffer,
  466. userDomain.Length
  467. );
  468. }
  469. requestMessage.Message.LSRequest.UserName[ userDomain.Length / sizeof(WCHAR) ] = L'\\';
  470. RtlCopyMemory(
  471. requestMessage.Message.LSRequest.UserName + (userDomain.Length / sizeof( WCHAR )) + 1,
  472. userName.Buffer,
  473. userName.Length
  474. );
  475. requestMessage.Message.LSRequest.UserName[ (userDomain.Length
  476. + userName.Length) / sizeof( WCHAR )
  477. + 1 ]
  478. = UNICODE_NULL;
  479. requestMessage.Message.LSRequest.IsAdmin = SrvIsAdmin( Session->UserHandle );
  480. IF_DEBUG(LICENSE) {
  481. KdPrint(("XACTSRV_MESSAGE_LSREQUEST: %ws, IsAdmin: %d\n",
  482. requestMessage.Message.LSRequest.UserName,
  483. requestMessage.Message.LSRequest.IsAdmin ));
  484. }
  485. // Adjust the buffer pointers to be self relative within the buffer.
  486. requestMessage.Message.LSRequest.UserName =
  487. (PWSTR)((PUCHAR)requestMessage.Message.LSRequest.UserName + SrvXsPortMemoryDelta);
  488. SrvReleaseUserAndDomainName( Session, &userName, &userDomain );
  489. break;
  490. case XACTSRV_MESSAGE_LSRELEASE:
  491. if( Session->IsLSNotified == FALSE )
  492. return STATUS_SUCCESS;
  493. IF_DEBUG(LICENSE) {
  494. KdPrint(("XACTSRV_MESSAGE_LSRELEASE: Handle %p\n", Session->hLicense ));
  495. }
  496. requestMessage.Message.LSRelease.hLicense = Session->hLicense;
  497. break;
  498. default:
  499. ASSERT( !"Bad Type" );
  500. return STATUS_INVALID_PARAMETER;
  501. }
  502. requestMessage.PortMessage.u1.s1.DataLength =
  503. (USHORT)( sizeof(requestMessage) - sizeof(PORT_MESSAGE) );
  504. requestMessage.PortMessage.u1.s1.TotalLength = sizeof(requestMessage);
  505. requestMessage.PortMessage.u2.ZeroInit = 0;
  506. requestMessage.PortMessage.u2.s2.Type = LPC_KERNELMODE_MESSAGE;
  507. requestMessage.MessageType = Type;
  508. //
  509. // Send the message to XACTSRV and wait for a response message.
  510. //
  511. // !!! We may want to put a timeout on this.
  512. //
  513. status = NtRequestWaitReplyPort(
  514. SrvXsPortHandle,
  515. (PPORT_MESSAGE)&requestMessage,
  516. (PPORT_MESSAGE)&replyMessage
  517. );
  518. IF_DEBUG( ERRORS ) {
  519. if( !NT_SUCCESS( status ) ) {
  520. KdPrint(( "SrvXsLSOperation: NtRequestWaitReplyPort failed: %X\n", status ));
  521. }
  522. }
  523. if( NT_SUCCESS( status ) )
  524. status = replyMessage.Message.LSRequest.Status;
  525. switch( Type ) {
  526. case XACTSRV_MESSAGE_LSREQUEST:
  527. requestMessage.Message.LSRequest.UserName =
  528. (PWSTR)((PUCHAR)requestMessage.Message.LSRequest.UserName - SrvXsPortMemoryDelta);
  529. SrvXsFreeHeap( requestMessage.Message.LSRequest.UserName );
  530. if( NT_SUCCESS( status ) ) {
  531. Session->IsLSNotified = TRUE;
  532. Session->hLicense = replyMessage.Message.LSRequest.hLicense;
  533. IF_DEBUG( LICENSE ) {
  534. KdPrint((" hLicense = %p\n", Session->hLicense ));
  535. }
  536. }
  537. RELEASE_LOCK( &Session->Connection->LicenseLock );
  538. break;
  539. case XACTSRV_MESSAGE_LSRELEASE:
  540. Session->IsLSNotified = FALSE;
  541. break;
  542. }
  543. IF_DEBUG( LICENSE ) {
  544. if( !NT_SUCCESS( status ) ) {
  545. KdPrint(( " SrvXsLSOperation returning status %X\n", status ));
  546. }
  547. }
  548. return status;
  549. } // SrvXsLSOperation
  550. VOID
  551. SrvXsPnpOperation(
  552. PUNICODE_STRING DeviceName,
  553. BOOLEAN Bind
  554. )
  555. /*++
  556. Routine Description:
  557. This routine sends the Xact service a PNP notification
  558. --*/
  559. {
  560. PXACTSRV_REQUEST_MESSAGE requestMessage;
  561. PXACTSRV_REQUEST_MESSAGE responseMessage;
  562. ULONG len;
  563. NTSTATUS status;
  564. PAGED_CODE( );
  565. if( SrvXsPortHandle == NULL ) {
  566. IF_DEBUG( PNP ) {
  567. KdPrint(( "SRV: SrvXsPnpOperation no SRVSVC handle!\n" ));
  568. }
  569. return;
  570. }
  571. len = (sizeof( XACTSRV_REQUEST_MESSAGE ) * 2) + DeviceName->Length + sizeof( WCHAR );
  572. requestMessage = SrvXsAllocateHeap( len, &status );
  573. if( requestMessage == NULL ) {
  574. IF_DEBUG( PNP ) {
  575. KdPrint(( "SRV: SrvXsPnpOperation unable to allocate memory: %X\n", status ));
  576. }
  577. return;
  578. }
  579. RtlZeroMemory( requestMessage, len );
  580. responseMessage = requestMessage + 1;
  581. requestMessage->Message.Pnp.TransportName.Buffer = (PWCHAR)(responseMessage + 1);
  582. requestMessage->Message.Pnp.Bind = Bind;
  583. //
  584. // Send the name of the transport of interest to Xactsrv
  585. //
  586. requestMessage->Message.Pnp.TransportName.Length = DeviceName->Length;
  587. requestMessage->Message.Pnp.TransportName.MaximumLength = DeviceName->Length + sizeof( WCHAR );
  588. RtlCopyMemory( requestMessage->Message.Pnp.TransportName.Buffer,
  589. DeviceName->Buffer,
  590. DeviceName->Length
  591. );
  592. //
  593. // Normalize the buffer pointer so xactsrv can rebase it
  594. //
  595. requestMessage->Message.Pnp.TransportName.Buffer =
  596. (PWSTR)((PUCHAR)requestMessage->Message.Pnp.TransportName.Buffer + SrvXsPortMemoryDelta);
  597. requestMessage->PortMessage.u1.s1.DataLength =
  598. (USHORT)( sizeof(*requestMessage) - sizeof(PORT_MESSAGE) );
  599. requestMessage->PortMessage.u1.s1.TotalLength = sizeof(*requestMessage);
  600. requestMessage->PortMessage.u2.ZeroInit = 0;
  601. requestMessage->PortMessage.u2.s2.Type = LPC_KERNELMODE_MESSAGE;
  602. requestMessage->MessageType = XACTSRV_MESSAGE_PNP;
  603. //
  604. // Send the message to XACTSRV
  605. //
  606. IF_DEBUG( PNP ) {
  607. KdPrint(( "SRV: Sending PNP %sbind request for %wZ to SRVSVC\n",
  608. requestMessage->Message.Pnp.Bind ? "" : "un", DeviceName
  609. ));
  610. }
  611. status = NtRequestWaitReplyPort(
  612. SrvXsPortHandle,
  613. (PPORT_MESSAGE)requestMessage,
  614. (PPORT_MESSAGE)responseMessage
  615. );
  616. IF_DEBUG( PNP ) {
  617. if( !NT_SUCCESS( status ) ) {
  618. KdPrint(( "SRV: PNP response from xactsrv status %X\n", status ));
  619. }
  620. }
  621. SrvXsFreeHeap( requestMessage );
  622. }
  623. VOID
  624. SrvXsDisconnect ( )
  625. {
  626. NTSTATUS status;
  627. PAGED_CODE( );
  628. //
  629. // Acquire exclusive access to the port resource, to prevent new
  630. // requests from being started.
  631. //
  632. IF_DEBUG(XACTSRV) {
  633. KdPrint(( "SrvXsDisconnect: Xactsrv disconnect called.\n"));
  634. }
  635. ExAcquireResourceExclusiveLite( &SrvXsResource, TRUE );
  636. SrvXsActive = FALSE;
  637. SrvXsFreeSharedMemory();
  638. ExReleaseResourceLite( &SrvXsResource );
  639. IF_DEBUG(XACTSRV) {
  640. KdPrint(( "SrvXsDisconnect: SrvXsResource released.\n"));
  641. }
  642. return;
  643. } // SrvXsDisconnect
  644. VOID
  645. SrvXsFreeSharedMemory (
  646. VOID
  647. )
  648. /*++
  649. Routine Description:
  650. This routine frees the xactsrv shared memory. SrvXsResource assumed
  651. held exclusive.
  652. Arguments:
  653. none.
  654. Return Value:
  655. TRUE if xactsrv memory was freed, FALSE otherwise.
  656. --*/
  657. {
  658. PAGED_CODE( );
  659. //
  660. // Free up memory only if we don't have any transactions using the
  661. // shared memory.
  662. //
  663. if ( SrvXsSharedMemoryReference == 0 ) {
  664. if ( SrvXsPortMemoryHeap != NULL ) {
  665. RtlDestroyHeap( SrvXsPortMemoryHeap );
  666. SrvXsPortMemoryHeap = NULL;
  667. }
  668. if ( SrvXsSectionHandle != NULL ) {
  669. SrvNtClose( SrvXsSectionHandle, FALSE );
  670. SrvXsSectionHandle = NULL;
  671. }
  672. if ( SrvXsPortHandle != NULL ) {
  673. SrvNtClose( SrvXsPortHandle, FALSE );
  674. SrvXsPortHandle = NULL;
  675. }
  676. IF_DEBUG(XACTSRV) {
  677. KdPrint(( "SrvXsFreeSharedMemory: Xactsrv memory freed.\n" ));
  678. }
  679. } else {
  680. IF_DEBUG(XACTSRV) {
  681. KdPrint(( "SrvXsFreeSharedMemory: Active transactions %d.\n",
  682. SrvXsSharedMemoryReference ));
  683. }
  684. }
  685. return;
  686. } // SrvXsFreeSharedMemory
  687. PVOID
  688. SrvXsAllocateHeap (
  689. IN ULONG SizeOfAllocation OPTIONAL,
  690. OUT PNTSTATUS Status
  691. )
  692. /*++
  693. Routine Description:
  694. This routine allocates heap from the Xs shared memory.
  695. Arguments:
  696. SizeOfAllocation - if specified, the number of bytes to allocate.
  697. if zero, no memory will be allocated.
  698. Status - the status of the request.
  699. Return Value:
  700. Address of the allocated memory. NULL, if no memory is allocated.
  701. --*/
  702. {
  703. PVOID heapAllocated = NULL;
  704. PAGED_CODE( );
  705. *Status = STATUS_SUCCESS;
  706. //
  707. // Check that XACTSRV is active. This must be done while holding
  708. // the resource.
  709. //
  710. ExAcquireResourceExclusiveLite( &SrvXsResource, TRUE );
  711. IF_DEBUG(XACTSRV) {
  712. KdPrint(( "SrvXsAllocateHeap: SrvXsResource acquired.\n"));
  713. }
  714. if ( !SrvXsActive ) {
  715. IF_DEBUG(ERRORS) {
  716. KdPrint(( "SrvXsAllocateHeap: XACTSRV is not active.\n" ));
  717. }
  718. ExReleaseResourceLite( &SrvXsResource );
  719. IF_DEBUG(XACTSRV) {
  720. KdPrint(( "SrvXsAllocateHeap: SrvXsResource released.\n"));
  721. }
  722. *Status = STATUS_NOT_SUPPORTED;
  723. return NULL;
  724. }
  725. //
  726. // Increment reference to our shared memory.
  727. //
  728. SrvXsSharedMemoryReference++;
  729. IF_DEBUG(XACTSRV) {
  730. KdPrint(( "SrvXsAllocateHeap: Incremented transaction count = %d.\n",
  731. SrvXsSharedMemoryReference
  732. ));
  733. }
  734. //
  735. // If SizeOfAllocation == 0, then the caller does not want any heap
  736. // allocated and only wants to have the lock held.
  737. //
  738. IF_DEBUG(XACTSRV) {
  739. KdPrint(( "SrvXsAllocateHeap: Heap to allocate %d bytes.\n",
  740. SizeOfAllocation
  741. ));
  742. }
  743. if ( SizeOfAllocation > 0 ) {
  744. heapAllocated = RtlAllocateHeap(
  745. SrvXsPortMemoryHeap,
  746. HEAP_NO_SERIALIZE,
  747. SizeOfAllocation
  748. );
  749. if ( heapAllocated == NULL ) {
  750. IF_DEBUG(ERRORS) {
  751. KdPrint(( "SrvXsAllocateHeap: RtlAllocateHeap failed "
  752. "to allocate %d bytes.\n",
  753. SizeOfAllocation
  754. ));
  755. }
  756. *Status = STATUS_INSUFF_SERVER_RESOURCES;
  757. }
  758. }
  759. //
  760. // Release the resource.
  761. //
  762. ExReleaseResourceLite( &SrvXsResource );
  763. IF_DEBUG(XACTSRV) {
  764. KdPrint(( "SrvXsAllocateHeap: SrvXsResource released.\n"));
  765. }
  766. return heapAllocated;
  767. } // SrvXsAllocateHeap
  768. VOID
  769. SrvXsFreeHeap (
  770. IN PVOID MemoryToFree OPTIONAL
  771. )
  772. /*++
  773. Routine Description:
  774. This routine frees heap allocated through SrvXsAllocateHeap.
  775. Arguments:
  776. MemoryToFree - pointer to the memory to be freed. If NULL, no memory
  777. is freed.
  778. Return Value:
  779. none.
  780. --*/
  781. {
  782. PAGED_CODE( );
  783. //
  784. // We need exclusive access to the resource in order to free
  785. // heap and decrement the reference count.
  786. //
  787. ExAcquireResourceExclusiveLite( &SrvXsResource, TRUE );
  788. IF_DEBUG(XACTSRV) {
  789. KdPrint(( "SrvXsFreeHeap: SrvXsResource acquired.\n"));
  790. }
  791. //
  792. // Free the allocated heap (if any).
  793. //
  794. if ( MemoryToFree != NULL ) {
  795. RtlFreeHeap( SrvXsPortMemoryHeap, 0, MemoryToFree );
  796. IF_DEBUG(XACTSRV) {
  797. KdPrint(( "SrvXsFreeHeap: Heap %p freed.\n", MemoryToFree ));
  798. }
  799. }
  800. //
  801. // Decrement the shared memory reference count, and check whether XS
  802. // shutdown is in progress. If so, complete XS cleanup if the
  803. // reference count reaches 0.
  804. //
  805. ASSERT( SrvXsSharedMemoryReference > 0 );
  806. SrvXsSharedMemoryReference--;
  807. IF_DEBUG(XACTSRV) {
  808. KdPrint(( "SrvXsFreeHeap: Decrement transaction count = %d.\n",
  809. SrvXsSharedMemoryReference
  810. ));
  811. }
  812. //
  813. // If SrvXsActive is FALSE, XACTSRV cleanup is in progress.
  814. //
  815. if ( !SrvXsActive ) {
  816. SrvXsFreeSharedMemory( );
  817. }
  818. //
  819. // Release the resource.
  820. //
  821. ExReleaseResourceLite( &SrvXsResource );
  822. IF_DEBUG(XACTSRV) {
  823. KdPrint(( "SrvXsFreeHeap: SrvXsResource released.\n"));
  824. }
  825. return;
  826. } // SrvXsFreeHeap