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.

1435 lines
38 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1991 - 1992
  6. //
  7. // File: KLPC.C
  8. //
  9. // Contents: LPC Support for the KSEC device driver
  10. //
  11. // Functions: CreateLpcPort
  12. // AcceptConnection
  13. // LPCServerThread
  14. // HandleLPCError
  15. // ShutdownServerThread
  16. // StartLPCThread
  17. // StopLPCThread
  18. //
  19. // History: 20 May 92 RichardW Created
  20. //
  21. //------------------------------------------------------------------------
  22. #include <lsapch.hxx>
  23. extern "C" {
  24. #include "klpcstub.h"
  25. }
  26. //
  27. // Module variables:
  28. //
  29. WCHAR szPortName[] = SPM_PORTNAME;
  30. HANDLE hListenThread;
  31. HANDLE hLpcPort; // This port ID is used for everything.
  32. SECURITY_STATUS LsapTrapStatusCode ;
  33. DSA_THSave * GetDsaThreadState ;
  34. DSA_THRestore * RestoreDsaThreadState ;
  35. PLSAP_API_LOG LpcApiLog ;
  36. #define DBG_CONNECT ((ULONG) 0xFFFFFFFF)
  37. #define DBG_DISCONNECT ((ULONG) 0xFFFFFFFE)
  38. //
  39. // Local Prototypes:
  40. //
  41. NTSTATUS CreateLpcPort(HANDLE *, PWSTR, DWORD, DWORD, DWORD);
  42. DWORD LpcHandler(PVOID pMsg);
  43. DWORD RundownConnection(PVOID pMessage);
  44. DWORD RundownConnectionNoFree(PVOID pMsg);
  45. PLSAP_API_LOG
  46. ApiLogCreate(
  47. ULONG Entries
  48. )
  49. {
  50. PLSAP_API_LOG ApiLog ;
  51. ULONG Size ;
  52. if ( Entries == 0 )
  53. {
  54. Entries = DEFAULT_LOG_SIZE;
  55. }
  56. DsysAssert( ((Entries & (Entries - 1) ) == 0 ) );
  57. if ( Entries & (Entries - 1 ))
  58. {
  59. return NULL ;
  60. }
  61. Size = sizeof( LSAP_API_LOG ) + ( sizeof( LSAP_API_LOG_ENTRY ) * (Entries - 1) ) ;
  62. ApiLog = (PLSAP_API_LOG) LsapAllocatePrivateHeap( Size );
  63. if ( ApiLog )
  64. {
  65. ApiLog->TotalSize = Entries ;
  66. ApiLog->ModSize = Entries - 1;
  67. }
  68. return ApiLog ;
  69. }
  70. PLSAP_API_LOG_ENTRY
  71. ApiLogAlloc(
  72. PLSAP_API_LOG Log
  73. )
  74. {
  75. ULONG WatchDog ;
  76. PLSAP_API_LOG_ENTRY Entry = NULL ;
  77. if ( !Log )
  78. {
  79. return NULL ;
  80. }
  81. WatchDog = Log->TotalSize * 2 ;
  82. while ( ( Log->Entries[ Log->Current ].ThreadId != 0 ) &&
  83. ( Log->Entries[ Log->Current ].ThreadId != 0xFFFFFFFF ) &&
  84. ( WatchDog ) )
  85. {
  86. Log->Current++ ;
  87. Log->Current &= Log->ModSize ;
  88. WatchDog-- ;
  89. }
  90. if ( WatchDog )
  91. {
  92. Entry = & Log->Entries[ Log->Current ] ;
  93. Entry->ThreadId = 0 ;
  94. Log->Current ++ ;
  95. Log->Current &= Log->ModSize;
  96. }
  97. return Entry ;
  98. }
  99. PLSAP_API_LOG_ENTRY
  100. ApiLogLocate(
  101. PLSAP_API_LOG Log,
  102. ULONG MessageId
  103. )
  104. {
  105. ULONG i ;
  106. PLSAP_API_LOG_ENTRY Entry = NULL ;
  107. for ( i = 0 ; i < Log->TotalSize ; i++ )
  108. {
  109. if ( Log->Entries[ i ].MessageId == MessageId )
  110. {
  111. Entry = &Log->Entries[ i ];
  112. break;
  113. }
  114. }
  115. return Entry ;
  116. }
  117. //+-------------------------------------------------------------------------
  118. //
  119. // Function: SetKsecEvent
  120. //
  121. // Synopsis: Triggers the event releasing the KSecDD
  122. //
  123. // Effects: Better be ready for LPC by when this call is executed
  124. //
  125. //--------------------------------------------------------------------------
  126. NTSTATUS
  127. SetKsecEvent(void)
  128. {
  129. HANDLE hEvent;
  130. hEvent = SpmOpenEvent(EVENT_ALL_ACCESS,FALSE, SPM_EVENTNAME);
  131. if (!hEvent)
  132. {
  133. DebugLog((DEB_WARN, "Could not open %ws, %d\n", SPM_EVENTNAME, GetLastError()));
  134. return(STATUS_INVALID_HANDLE);
  135. }
  136. if (!SetEvent(hEvent))
  137. {
  138. DebugLog((DEB_ERROR, "Failed to set ksec event, %d\n", GetLastError()));
  139. (void) CloseHandle(hEvent);
  140. return(STATUS_INVALID_HANDLE);
  141. }
  142. (void) CloseHandle(hEvent);
  143. return(STATUS_SUCCESS);
  144. }
  145. //+-------------------------------------------------------------------------
  146. //
  147. // Function: LsapBuildSD
  148. //
  149. // Synopsis: Shared code to build the SD for either the KsecEvent or
  150. // the LPC port. For the KsecEvent, give everybody
  151. // GENERIC_EXECUTE access. For the LPC port, give everybody
  152. // access to call in on it.
  153. //
  154. // Effects: For KsecEvent, sets the security on the event.
  155. // For LPC port, returns the SD as an OUT parameter
  156. //
  157. //--------------------------------------------------------------------------
  158. NTSTATUS
  159. LsapBuildSD(
  160. IN ULONG dwType,
  161. OUT PSECURITY_DESCRIPTOR *ppSD OPTIONAL
  162. )
  163. {
  164. HANDLE hEvent = NULL;
  165. NTSTATUS Status;
  166. ULONG SDLength;
  167. PACL pEventDacl = NULL;
  168. PSECURITY_DESCRIPTOR pEventSD = NULL;
  169. ULONG ulWorldAccess = 0;
  170. ULONG ulAdminAccess = 0;
  171. if (dwType == BUILD_KSEC_SD)
  172. {
  173. hEvent = SpmOpenEvent(EVENT_ALL_ACCESS,FALSE, SPM_EVENTNAME);
  174. if (!hEvent)
  175. {
  176. DebugLog((DEB_WARN, "Could not open %ws, %d\n", SPM_EVENTNAME, GetLastError()));
  177. return(STATUS_INVALID_HANDLE);
  178. }
  179. //
  180. // The default DACL is the same as SePublicDefaultDacl in ntos\se
  181. //
  182. // World gets GENERIC_EXECUTE
  183. // Admin gets GENERIC_READ, GENERIC_EXECUTE, READ_CONTROL
  184. // System gets GENERIC_ALL
  185. //
  186. ulWorldAccess = GENERIC_EXECUTE | GENERIC_READ;
  187. ulAdminAccess = GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL;
  188. }
  189. else
  190. {
  191. //
  192. // ppSD is an OUT parameter for BUILD_LPC_SD
  193. //
  194. ASSERT(ppSD != NULL);
  195. ulWorldAccess = SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE;
  196. ulAdminAccess = GENERIC_ALL;
  197. }
  198. SDLength = sizeof(SECURITY_DESCRIPTOR) +
  199. (ULONG) sizeof(ACL) +
  200. (3 * ((ULONG) sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG))) +
  201. RtlLengthSid( LsapLocalSystemSid ) +
  202. RtlLengthSid( LsapAliasAdminsSid ) +
  203. RtlLengthSid( LsapWorldSid );
  204. pEventSD = (PSECURITY_DESCRIPTOR) LsapAllocateLsaHeap(SDLength);
  205. if (pEventSD == NULL)
  206. {
  207. if (dwType == BUILD_KSEC_SD)
  208. {
  209. CloseHandle(hEvent);
  210. }
  211. return(STATUS_INSUFFICIENT_RESOURCES);
  212. }
  213. pEventDacl = (PACL) ((PBYTE) pEventSD + sizeof(SECURITY_DESCRIPTOR));
  214. Status = RtlCreateAcl( pEventDacl,
  215. SDLength - sizeof(SECURITY_DESCRIPTOR),
  216. ACL_REVISION);
  217. ASSERT( NT_SUCCESS(Status) );
  218. //
  219. // WORLD access
  220. //
  221. Status = RtlAddAccessAllowedAce (
  222. pEventDacl,
  223. ACL_REVISION,
  224. ulWorldAccess,
  225. LsapWorldSid
  226. );
  227. ASSERT( NT_SUCCESS(Status) );
  228. //
  229. // SYSTEM access
  230. //
  231. Status = RtlAddAccessAllowedAce (
  232. pEventDacl,
  233. ACL_REVISION,
  234. GENERIC_ALL,
  235. LsapLocalSystemSid
  236. );
  237. ASSERT( NT_SUCCESS(Status) );
  238. //
  239. // ADMINISTRATORS access
  240. //
  241. Status = RtlAddAccessAllowedAce (
  242. pEventDacl,
  243. ACL_REVISION,
  244. ulAdminAccess,
  245. LsapAliasAdminsSid
  246. );
  247. ASSERT( NT_SUCCESS(Status) );
  248. //
  249. // Now initialize security descriptors
  250. // that export this protection
  251. //
  252. Status = RtlCreateSecurityDescriptor(
  253. pEventSD,
  254. SECURITY_DESCRIPTOR_REVISION1
  255. );
  256. ASSERT( NT_SUCCESS(Status) );
  257. Status = RtlSetDaclSecurityDescriptor(
  258. pEventSD,
  259. TRUE, // DaclPresent
  260. pEventDacl,
  261. FALSE // DaclDefaulted
  262. );
  263. ASSERT( NT_SUCCESS(Status) );
  264. if (dwType == BUILD_KSEC_SD)
  265. {
  266. Status = NtSetSecurityObject(
  267. hEvent,
  268. DACL_SECURITY_INFORMATION,
  269. pEventSD
  270. );
  271. CloseHandle(hEvent);
  272. LsapFreeLsaHeap(pEventSD);
  273. if (!NT_SUCCESS(Status))
  274. {
  275. DebugLog((DEB_ERROR,"Failed to set event SD: 0x%x\n",Status));
  276. }
  277. }
  278. else
  279. {
  280. ASSERT(hEvent == NULL);
  281. if (NT_SUCCESS(Status))
  282. {
  283. *ppSD = pEventSD;
  284. }
  285. else
  286. {
  287. DebugLog((DEB_ERROR, "Failed to create LPC SD: 0x%x\n", Status));
  288. LsapFreeLsaHeap(pEventSD);
  289. }
  290. }
  291. return(Status);
  292. }
  293. //+-------------------------------------------------------------------------
  294. //
  295. // Function: CreateLpcPort
  296. //
  297. // Synopsis: Creates an LPC port and returns a handle to it.
  298. //
  299. // Effects:
  300. //
  301. // Arguments: phPort - receives port handle
  302. // pszPortName - Unicode name of port
  303. // cbConnect - Size of the connect message data
  304. // cbMessage - Size of the messages
  305. // cMessages - Max number of messages queued
  306. //
  307. // Requires:
  308. //
  309. // Returns:
  310. //
  311. // Notes:
  312. //
  313. //--------------------------------------------------------------------------
  314. NTSTATUS
  315. CreateLpcPort( HANDLE * phPort,
  316. PWSTR pszPortName,
  317. DWORD cbConnect,
  318. DWORD cbMessage,
  319. DWORD cMessages)
  320. {
  321. NTSTATUS nsReturn;
  322. OBJECT_ATTRIBUTES PortObjAttr;
  323. UNICODE_STRING ucsPortName;
  324. PSECURITY_DESCRIPTOR psdPort;
  325. //
  326. // Create a security descriptor for the port we are about to create
  327. //
  328. nsReturn = LsapBuildSD(BUILD_LPC_SD, &psdPort);
  329. if (!NT_SUCCESS(nsReturn))
  330. {
  331. return nsReturn;
  332. }
  333. //
  334. // Create the name
  335. //
  336. RtlInitUnicodeString(&ucsPortName, pszPortName);
  337. InitializeObjectAttributes(&PortObjAttr, &ucsPortName, 0, NULL, psdPort);
  338. //
  339. // Create the port
  340. nsReturn = NtCreatePort(phPort, // returned handle
  341. &PortObjAttr, // name, etc.
  342. cbConnect, // size of a connect msg
  343. cbMessage, // size of a normal msg
  344. cMessages * cbMessage // number of msgs to buffer
  345. ); // communication
  346. LsapFreeLsaHeap(psdPort);
  347. return nsReturn;
  348. }
  349. //+---------------------------------------------------------------------------
  350. //
  351. // Function: AcceptConnection
  352. //
  353. // Synopsis: Accepts a connection from a client.
  354. //
  355. // Effects:
  356. //
  357. // Arguments: [ConnectReq] --
  358. //
  359. // Requires:
  360. //
  361. // Returns:
  362. //
  363. // Signals:
  364. //
  365. // Modifies:
  366. //
  367. // Algorithm:
  368. //
  369. // History: 7-22-93 RichardW Created
  370. //
  371. // Notes:
  372. //
  373. //----------------------------------------------------------------------------
  374. DWORD
  375. AcceptConnection(
  376. PVOID pvConnect
  377. )
  378. {
  379. PSession pSession = NULL ;
  380. HANDLE hCommPort;
  381. PHANDLE phPort;
  382. NTSTATUS scRet;
  383. BOOLEAN bAccept = TRUE;
  384. NTSTATUS Status;
  385. PSPM_LPC_MESSAGE ConnectReq = (PSPM_LPC_MESSAGE) pvConnect;
  386. WCHAR LogonProcessName[LSAP_MAX_PACKAGE_NAME_LENGTH+1];
  387. CHAR NarrowLogonName[ LSAP_MAX_PACKAGE_NAME_LENGTH + 1 ];
  388. LUID LogonId;
  389. ULONG Flags = 0;
  390. LSA_CALL_INFO CallInfo ;
  391. DBG_DISPATCH_PROLOGUE( LpcApiLog, pvConnect, CallInfo );
  392. scRet = LsapValidLogonProcess(
  393. &ConnectReq->ConnectionRequest,
  394. ConnectReq->pmMessage.u1.s1.DataLength,
  395. &ConnectReq->pmMessage.ClientId,
  396. &LogonId,
  397. &Flags
  398. );
  399. if (NT_SUCCESS(scRet))
  400. {
  401. //
  402. // Create a session to represent the client.
  403. //
  404. strncpy(
  405. NarrowLogonName,
  406. ConnectReq->ConnectionRequest.LogonProcessName,
  407. LSAP_MAX_PACKAGE_NAME_LENGTH
  408. );
  409. NarrowLogonName[ LSAP_MAX_PACKAGE_NAME_LENGTH ] = '\0';
  410. mbstowcs(
  411. LogonProcessName,
  412. NarrowLogonName,
  413. LSAP_MAX_PACKAGE_NAME_LENGTH+1
  414. );
  415. scRet = CreateSession( &ConnectReq->pmMessage.ClientId,
  416. TRUE,
  417. LogonProcessName,
  418. Flags,
  419. &pSession);
  420. }
  421. if (!NT_SUCCESS(scRet))
  422. {
  423. bAccept = FALSE;
  424. phPort = &hCommPort;
  425. if ( pSession )
  426. {
  427. SpmpDereferenceSession( pSession );
  428. pSession = NULL ;
  429. }
  430. }
  431. else
  432. {
  433. PLSAP_AU_REGISTER_CONNECT_RESP Response;
  434. phPort = &pSession->hPort;
  435. //
  436. // Fill in the complete connection info:
  437. //
  438. Response = (PLSAP_AU_REGISTER_CONNECT_RESP) &ConnectReq->ConnectionRequest;
  439. if ( pSession->dwProcessID == pDefaultSession->dwProcessID )
  440. {
  441. //
  442. // We're connecting to us. Set a flag:
  443. //
  444. Response->SecurityMode |= LSA_MODE_SAME_PROCESS ;
  445. }
  446. Response->CompletionStatus = STATUS_SUCCESS;
  447. Response->PackageCount = SpmpCurrentPackageCount();
  448. }
  449. //
  450. // Accept the connection
  451. //
  452. DebugLog((DEB_TRACE, "LpcListen: %sing connection from %x.%x\n",
  453. (bAccept ? "Accept" : "Reject"),
  454. ConnectReq->pmMessage.ClientId.UniqueProcess,
  455. ConnectReq->pmMessage.ClientId.UniqueThread ));
  456. Status = NtAcceptConnectPort(phPort, // Save the port handle
  457. pSession, // Associate the session
  458. (PPORT_MESSAGE) ConnectReq,
  459. // Connection request to accept
  460. bAccept, // Accept the connection
  461. NULL, // Server view (none)
  462. NULL // Client view (none)
  463. );
  464. if ( !NT_SUCCESS( Status ) )
  465. {
  466. //
  467. // Failed to respond appropriately. If we had
  468. // set things up for this session, tear them down
  469. //
  470. if ( NT_SUCCESS( scRet ) )
  471. {
  472. SpmpDereferenceSession( pSession );
  473. pSession = NULL ;
  474. goto Cleanup ;
  475. }
  476. }
  477. if ((!NT_SUCCESS(scRet)) || (!bAccept))
  478. {
  479. if ( scRet == STATUS_INVALID_CID )
  480. {
  481. PPORT_MESSAGE Message = (PPORT_MESSAGE) ConnectReq ;
  482. DebugLog((DEB_ERROR,
  483. "LSA: Failed to %s client [%x.%x, Message %x] because of invalid clientid\n",
  484. ( bAccept ? "accept" : "reject" ),
  485. Message->ClientId.UniqueProcess,
  486. Message->ClientId.UniqueThread,
  487. Message->MessageId));
  488. }
  489. DebugLog((DEB_ERROR, "Failed to accept 0x%08x\n", scRet));
  490. //
  491. // Delete the session we just created:
  492. //
  493. if ( pSession )
  494. {
  495. SpmpDereferenceSession( pSession );
  496. }
  497. goto Cleanup;
  498. }
  499. //
  500. // Must complete the session record *BEFORE* calling CompleteConnectPort,
  501. // since as soon as that happens, the other guy could send another message
  502. // and we might hit an assert.
  503. //
  504. if (bAccept)
  505. {
  506. Status = NtCompleteConnectPort(pSession->hPort);
  507. }
  508. Cleanup:
  509. DBG_DISPATCH_POSTLOGUE( (NT_SUCCESS(Status) ? ULongToPtr(scRet) : ULongToPtr(Status)),
  510. LongToPtr(DBG_CONNECT) );
  511. LsapFreePrivateHeap( ConnectReq );
  512. return( 0 );
  513. }
  514. //+---------------------------------------------------------------------------
  515. //
  516. // Function: LpcServerThread
  517. //
  518. // Synopsis: Handles all requests from clients
  519. //
  520. // Arguments: [pvIgnored] --
  521. //
  522. // History: 7-23-93 RichardW Created
  523. //
  524. // Notes:
  525. //
  526. //----------------------------------------------------------------------------
  527. ULONG
  528. LpcServerThread(PVOID pvIgnored)
  529. {
  530. PSession pSession;
  531. PSession pMySession = GetCurrentSession();
  532. NTSTATUS scRet;
  533. PSPM_LPC_MESSAGE pMessage;
  534. CSHORT sMessageType;
  535. NTSTATUS Status;
  536. UCHAR PanicBuffer[sizeof(SPM_LPC_MESSAGE)];
  537. BOOLEAN OutOfMemory;
  538. HANDLE hDummy;
  539. PVOID TaskPointer ;
  540. LPTHREAD_START_ROUTINE TaskFunction ;
  541. BOOL ScheduleUrgent ;
  542. BOOL ExecNow ;
  543. #if DBG_TRACK_API
  544. PLSAP_API_LOG_ENTRY Entry ;
  545. #endif
  546. //
  547. // First, create the port:
  548. //
  549. DebugLog((DEB_TRACE_INIT, "LpcServerThread starting up, creating port\n"));
  550. scRet = CreateLpcPort( &hLpcPort, // Handle that stores the port
  551. szPortName, // Name of the port.
  552. sizeof(SPM_LPC_MESSAGE), // Size of a connect message
  553. sizeof(SPM_LPC_MESSAGE), // Size of a request message
  554. 16); // Number of messages to queue
  555. if (FAILED(scRet))
  556. {
  557. DebugLog((DEB_ERROR, "CreateLpcPort returned 0x%08x\n", scRet));
  558. return((ULONG) scRet);
  559. }
  560. DebugLog((DEB_TRACE, "LPCServerThread started on port %ws\n", szPortName));
  561. DebugLog((DEB_TRACE_INIT, "LpcServerThread starting up: setting event\n"));
  562. //
  563. // Trigger the KSec event that will cause the device driver to allow
  564. // connections
  565. //
  566. scRet = SetKsecEvent();
  567. #if DBG
  568. if (FAILED(scRet))
  569. {
  570. DebugLog((DEB_ERROR, "Error setting event, %x\n", scRet));
  571. }
  572. #endif
  573. #if DBG_TRACK_API
  574. LpcApiLog = ApiLogCreate( 0 );
  575. if ( !LpcApiLog )
  576. {
  577. NtClose( hLpcPort );
  578. return STATUS_NO_MEMORY ;
  579. }
  580. #endif
  581. //
  582. // All we do is wait here:
  583. //
  584. for (; ; )
  585. {
  586. //
  587. // Allocate memory for the message
  588. //
  589. pMessage = (PSPM_LPC_MESSAGE) LsapAllocatePrivateHeap(
  590. sizeof( SPM_LPC_MESSAGE ) );
  591. if (pMessage)
  592. {
  593. OutOfMemory = FALSE;
  594. }
  595. else
  596. {
  597. OutOfMemory = TRUE;
  598. pMessage = (PSPM_LPC_MESSAGE) PanicBuffer;
  599. }
  600. //
  601. // Wait for a message from one of the critters
  602. //
  603. pSession = NULL;
  604. ExecNow = FALSE ;
  605. Status = NtReplyWaitReceivePort(hLpcPort, // Port
  606. (void **)&pSession, // Get session
  607. NULL, // No reply
  608. (PPORT_MESSAGE) pMessage); // Recvd msg
  609. if ( !NT_SUCCESS( Status ) )
  610. {
  611. DebugLog(( DEB_ERROR, "LpcServer: ReplyWaitReceive returned %x\n",
  612. Status ));
  613. if ( !OutOfMemory )
  614. {
  615. LsapFreePrivateHeap( pMessage );
  616. }
  617. continue;
  618. }
  619. DebugLog((DEB_TRACE_WAPI, "LpcServer: Received msg from %x.%x\n",
  620. pMessage->pmMessage.ClientId.UniqueProcess,
  621. pMessage->pmMessage.ClientId.UniqueThread));
  622. if (pSession)
  623. {
  624. DsysAssert(pSession->hPort);
  625. }
  626. else
  627. {
  628. DsysAssert(pMessage->pmMessage.u2.s2.Type == LPC_CONNECTION_REQUEST);
  629. }
  630. if (OutOfMemory)
  631. {
  632. //
  633. // Generate a fail
  634. //
  635. DebugLog((DEB_ERROR, "KLPC: out of memory, failing request %x\n",
  636. pMessage->pmMessage.MessageId));
  637. if (pMessage->pmMessage.u2.s2.Type == LPC_CONNECTION_REQUEST)
  638. {
  639. Status = NtAcceptConnectPort(
  640. &hDummy,
  641. NULL,
  642. (PPORT_MESSAGE) pMessage,
  643. FALSE,
  644. NULL,
  645. NULL);
  646. }
  647. else if (pMessage->pmMessage.u2.s2.Type == LPC_REQUEST)
  648. {
  649. pMessage->ApiMessage.Args.SpmArguments.fAPI |= SPMAPI_FLAG_ERROR_RET;
  650. pMessage->ApiMessage.scRet = STATUS_INSUFFICIENT_RESOURCES;
  651. while (TRUE)
  652. {
  653. Status = NtReplyPort(pSession->hPort, (PPORT_MESSAGE) pMessage);
  654. if (Status == STATUS_INSUFFICIENT_RESOURCES ||
  655. Status == STATUS_NO_MEMORY)
  656. {
  657. Sleep(125);
  658. }
  659. else
  660. {
  661. break;
  662. }
  663. }
  664. }
  665. else if (pMessage->pmMessage.u2.s2.Type == LPC_PORT_CLOSED)
  666. {
  667. SetCurrentSession( pSession );
  668. RundownConnectionNoFree( pMessage );
  669. SetCurrentSession( pMySession );
  670. }
  671. else
  672. {
  673. DebugLog((DEB_ERROR, "Unknown Message received, punting\n"));
  674. }
  675. continue;
  676. }
  677. if (!NT_SUCCESS(Status))
  678. {
  679. DebugLog((DEB_ERROR, "Discarding message, %x\n", scRet));
  680. LsapFreePrivateHeap( pMessage );
  681. continue;
  682. }
  683. //
  684. // Check message for LPC errors
  685. //
  686. #if DBG_TRACK_API
  687. Entry = ApiLogAlloc( LpcApiLog );
  688. if ( Entry )
  689. {
  690. Entry->MessageId = pMessage->pmMessage.MessageId ;
  691. Entry->pvMessage = pMessage ;
  692. GetSystemTimeAsFileTime( (LPFILETIME) &Entry->QueueTime );
  693. }
  694. #endif
  695. sMessageType = pMessage->pmMessage.u2.s2.Type;
  696. switch(sMessageType & ~LPC_KERNELMODE_MESSAGE)
  697. {
  698. case LPC_REQUEST:
  699. case LPC_REPLY:
  700. case LPC_DATAGRAM:
  701. //
  702. // "Normal" API requests. Route to the standard
  703. // handler, non urgent:
  704. //
  705. TaskFunction = LpcHandler ;
  706. ScheduleUrgent = FALSE ;
  707. if ((pMessage->ApiMessage.dwAPI > LsapAuMaxApiNumber) &&
  708. (pMessage->ApiMessage.dwAPI < SPMAPI_MaxApiNumber) &&
  709. (pMessage->ApiMessage.Args.SpmArguments.fAPI & SPMAPI_FLAG_EXEC_NOW) )
  710. {
  711. ExecNow = TRUE ;
  712. }
  713. break;
  714. case LPC_CONNECTION_REQUEST:
  715. //
  716. // New connection request. Handle with some priority
  717. //
  718. TaskFunction = AcceptConnection ;
  719. ScheduleUrgent = TRUE ;
  720. pSession = pMySession ;
  721. break;
  722. case LPC_PORT_CLOSED:
  723. //
  724. // Client has gone away. Make sure we clean up
  725. //
  726. TaskFunction = RundownConnection ;
  727. ScheduleUrgent = FALSE ;
  728. DebugLog((DEB_TRACE, "Client %d.%d died, running down session\n",
  729. pMessage->pmMessage.ClientId.UniqueProcess,
  730. pMessage->pmMessage.ClientId.UniqueThread));
  731. break ;
  732. case LPC_LOST_REPLY:
  733. case LPC_CLIENT_DIED:
  734. case LPC_EXCEPTION:
  735. case LPC_DEBUG_EVENT:
  736. case LPC_ERROR_EVENT:
  737. default:
  738. //
  739. // These are debugger messages, so we should never see them.
  740. //
  741. DebugLog((DEB_WARN,"Discarding message type %d\n",sMessageType));
  742. LsapFreePrivateHeap( pMessage );
  743. continue;
  744. }
  745. //
  746. // If the message has the EXEC_NOW flag on, that means that the caller
  747. // deemed this urgent, and not to be spawned to another thread.
  748. //
  749. if ( ExecNow )
  750. {
  751. TlsSetValue(dwSession, pSession);
  752. LpcHandler(pMessage);
  753. TlsSetValue(dwSession, pMySession);
  754. continue;
  755. }
  756. //
  757. // Assign a thread to handle the request, and
  758. // then loop back and wait again.
  759. //
  760. TaskPointer = LsapAssignThread(
  761. TaskFunction,
  762. pMessage,
  763. pSession,
  764. ScheduleUrgent != 0);
  765. if ( !TaskPointer )
  766. {
  767. //
  768. // Generate a fail
  769. //
  770. DebugLog((DEB_ERROR, "KLPC: out of memory, failing request %x\n",
  771. pMessage->pmMessage.MessageId));
  772. //
  773. // For connection requests, there is no reply. In fact, using Reply
  774. // will cause lots of problems since the client will be stalled waiting
  775. // for the reply.
  776. //
  777. if ( sMessageType == LPC_CONNECTION_REQUEST )
  778. {
  779. Status = NtAcceptConnectPort(
  780. &hDummy,
  781. NULL,
  782. (PPORT_MESSAGE) pMessage,
  783. FALSE,
  784. NULL,
  785. NULL);
  786. DBG_DISPATCH_POSTLOGUE( UlongToPtr( STATUS_INSUFFICIENT_RESOURCES ),
  787. LongToPtr(DBG_CONNECT) );
  788. }
  789. else
  790. {
  791. pMessage->ApiMessage.Args.SpmArguments.fAPI |= SPMAPI_FLAG_ERROR_RET;
  792. pMessage->ApiMessage.scRet = STATUS_INSUFFICIENT_RESOURCES;
  793. while (TRUE)
  794. {
  795. Status = NtReplyPort(pSession->hPort, (PPORT_MESSAGE) pMessage);
  796. if (Status == STATUS_INSUFFICIENT_RESOURCES ||
  797. Status == STATUS_NO_MEMORY)
  798. {
  799. Sleep(125);
  800. }
  801. else
  802. {
  803. break;
  804. }
  805. }
  806. DBG_DISPATCH_POSTLOGUE( ULongToPtr( STATUS_INSUFFICIENT_RESOURCES ),
  807. pMessage->ApiMessage.dwAPI );
  808. }
  809. LsapFreePrivateHeap( pMessage );
  810. }
  811. #if DBG_TRACK_API
  812. if ( Entry )
  813. {
  814. Entry->WorkItem = TaskPointer ;
  815. }
  816. #endif
  817. }
  818. return((ULONG) scRet);
  819. }
  820. //+---------------------------------------------------------------------------
  821. //
  822. // Function: LpcHandler
  823. //
  824. // Synopsis: Generic threadpool function called to handle an LPC request
  825. //
  826. // Arguments: [pMsg] -- Message to process
  827. //
  828. // History: 7-23-93 RichardW Created
  829. //
  830. // Notes:
  831. //
  832. //----------------------------------------------------------------------------
  833. DWORD
  834. LpcHandler(
  835. PVOID pMsg
  836. )
  837. {
  838. PSPM_LPC_MESSAGE pApi = (PSPM_LPC_MESSAGE) pMsg ;
  839. PSession pSession = (PSession) TlsGetValue(dwSession);
  840. NTSTATUS Status = STATUS_SUCCESS;
  841. DWORD i;
  842. LSA_CALL_INFO CallInfo ;
  843. PULONG_PTR Where ;
  844. BOOL BreakOnCall = FALSE;
  845. BOOL IsCallInfoSet = FALSE;
  846. ZeroMemory( &CallInfo, sizeof(CallInfo) );
  847. DBG_DISPATCH_PROLOGUE( LpcApiLog, pApi, CallInfo );
  848. DsysAssert( pSession != pDefaultSession );
  849. //
  850. // Verify that if the caller claimed to be from Kernel mode
  851. // that they still are. If the session is still indefinite,
  852. // fix that up now:
  853. //
  854. if ( ( pSession->fSession & SESFLAG_MAYBEKERNEL ) != 0 )
  855. {
  856. if ( ( pApi->pmMessage.u2.s2.Type & LPC_KERNELMODE_MESSAGE ) != 0 )
  857. {
  858. pSession->fSession &= ~(SESFLAG_MAYBEKERNEL | SESFLAG_WOW_PROCESS) ;
  859. pSession->fSession |= SESFLAG_KERNEL ;
  860. if ( pEfsSession )
  861. {
  862. if ( (pEfsSession->fSession & SESFLAG_EFS) == 0 )
  863. {
  864. LsapUpdateEfsSession( pSession );
  865. }
  866. }
  867. }
  868. else
  869. {
  870. //
  871. // This was a very bad caller. They set the flag that it
  872. // was going to be a kernel mode session, but then they turned
  873. // out not to be in kernel mode. Kill this session
  874. //
  875. LockSession( pSession );
  876. if ( pSession->hPort )
  877. {
  878. NtClose( pSession->hPort );
  879. pSession->hPort = NULL ;
  880. }
  881. UnlockSession( pSession );
  882. goto Cleanup;
  883. }
  884. }
  885. if ((pApi->ApiMessage.dwAPI > LsapAuMaxApiNumber) &&
  886. ((pSession->fSession & SESFLAG_KERNEL) != 0))
  887. {
  888. if ((pApi->pmMessage.u2.s2.Type & LPC_KERNELMODE_MESSAGE) == 0)
  889. {
  890. DebugLog((DEB_ERROR, "Caller claimed to be from kernelmode but sent non-kernelmode message\n"));
  891. pApi->ApiMessage.scRet = STATUS_ACCESS_DENIED ;
  892. Status = STATUS_ACCESS_DENIED;
  893. }
  894. }
  895. CallInfo.Message = pApi ;
  896. CallInfo.CallInfo.ProcessId = HandleToUlong(pApi->pmMessage.ClientId.UniqueProcess);
  897. CallInfo.CallInfo.ThreadId = HandleToUlong(pApi->pmMessage.ClientId.UniqueThread);
  898. CallInfo.CallInfo.Attributes = 0 ;
  899. CallInfo.InProcCall = FALSE ;
  900. CallInfo.Session = pSession ;
  901. if (((pSession->fSession & SESFLAG_TCB_PRIV) != 0) ||
  902. ((pSession->fSession & SESFLAG_KERNEL) != 0))
  903. {
  904. CallInfo.CallInfo.Attributes |= SECPKG_CALL_IS_TCB ;
  905. }
  906. if ( pApi->ApiMessage.Args.SpmArguments.fAPI & SPMAPI_FLAG_ANSI_CALL)
  907. {
  908. CallInfo.CallInfo.Attributes |= SECPKG_CALL_ANSI ;
  909. }
  910. if ( pApi->pmMessage.u2.s2.Type & LPC_KERNELMODE_MESSAGE )
  911. {
  912. CallInfo.CallInfo.Attributes |= SECPKG_CALL_KERNEL_MODE ;
  913. if ( pApi->ApiMessage.Args.SpmArguments.fAPI & SPMAPI_FLAG_KMAP_MEM )
  914. {
  915. CallInfo.Flags |= CALL_FLAG_KERNEL_POOL ;
  916. CallInfo.KMap = (PKSEC_LSA_MEMORY_HEADER) pApi->ApiMessage.Args.SpmArguments.ContextPointer;
  917. }
  918. }
  919. //
  920. // If the kernel driver has set the error-ret flag, then we have
  921. // been asked to break in by the driver. If we're allowed to take
  922. // breakpoints (checked later), we'll break in. For now, set the flag
  923. // that we should check:
  924. //
  925. if ( pApi->ApiMessage.Args.SpmArguments.fAPI & SPMAPI_FLAG_ERROR_RET )
  926. {
  927. if ( CallInfo.CallInfo.Attributes & SECPKG_CALL_KERNEL_MODE )
  928. {
  929. BreakOnCall = TRUE ;
  930. }
  931. }
  932. if ( pSession->fSession & SESFLAG_WOW_PROCESS )
  933. {
  934. CallInfo.CallInfo.Attributes |= SECPKG_CALL_WOWCLIENT ;
  935. }
  936. CallInfo.Allocs = 0 ;
  937. //
  938. // Only copy out the IP address from "new" clients (vs. clients compiled using a version
  939. // of lsadll.lib from a previous OS release that didn't have this field).
  940. //
  941. if ( pApi->ApiMessage.dwAPI == LsapAuLogonUserApi
  942. &&
  943. pApi->pmMessage.u1.s1.DataLength == LSAP_AU_DATA_LENGTH(sizeof(LSAP_LOGON_USER_ARGS)))
  944. {
  945. RtlCopyMemory(CallInfo.IpAddress,
  946. pApi->ApiMessage.Args.LsaArguments.LogonUser.IpAddress,
  947. LSAP_ADDRESS_LENGTH);
  948. }
  949. else if ( pApi->ApiMessage.dwAPI == SPMAPI_AcceptContext )
  950. {
  951. RtlCopyMemory(CallInfo.IpAddress,
  952. pApi->ApiMessage.Args.SpmArguments.API.AcceptContext.IpAddress,
  953. LSAP_ADDRESS_LENGTH);
  954. }
  955. if (NT_SUCCESS(Status))
  956. {
  957. DebugLog((DEB_TRACE_WAPI, "[%x.%x] Dispatching API (Message %x)\n",
  958. pApi->pmMessage.ClientId.UniqueProcess,
  959. pApi->pmMessage.ClientId.UniqueThread,
  960. pApi->pmMessage.MessageId));
  961. LsapSetCurrentCall( &CallInfo );
  962. IsCallInfoSet = TRUE;
  963. //
  964. // Call the dispatcher, and have the request routed to the security package
  965. //
  966. DsysAssert( pSession->hPort );
  967. //
  968. // If we need a breakpoint, this will do it. Note that this
  969. // will return immediately if we weren't started under a debugger.
  970. //
  971. if ( BreakOnCall )
  972. {
  973. LsapInternalBreak();
  974. }
  975. Status = DispatchAPI( pApi );
  976. #if DBG
  977. if ( ( LsapTrapStatusCode != 0 ) )
  978. {
  979. DsysAssert( LsapTrapStatusCode != pApi->ApiMessage.scRet );
  980. }
  981. #endif
  982. }
  983. //
  984. // Done. Send the message back to the caller, and return to the
  985. // thread pool.
  986. //
  987. if ( ( pApi->ApiMessage.dwAPI > LsapAuMaxApiNumber ) &&
  988. ( pApi->ApiMessage.Args.SpmArguments.fAPI & SPMAPI_FLAG_ALLOCS ) )
  989. {
  990. if ( CallInfo.Allocs )
  991. {
  992. DsysAssert( CallInfo.Allocs <= MAX_BUFFERS_IN_CALL );
  993. Where = (PULONG_PTR) pApi->ApiMessage.bData ;
  994. *Where++ = CallInfo.Allocs ;
  995. for ( i = 0 ; i < CallInfo.Allocs ; i++ )
  996. {
  997. *Where++ = (ULONG_PTR) CallInfo.Buffers[ i ];
  998. }
  999. }
  1000. else
  1001. {
  1002. pApi->ApiMessage.Args.SpmArguments.fAPI &= ~(SPMAPI_FLAG_ALLOCS) ;
  1003. }
  1004. }
  1005. DsysAssert(pSession->hPort);
  1006. do
  1007. {
  1008. Status = NtReplyPort( pSession->hPort,
  1009. (PPORT_MESSAGE) pApi);
  1010. if ( ! NT_SUCCESS( Status ) )
  1011. {
  1012. if (Status == STATUS_NO_MEMORY)
  1013. {
  1014. Sleep(125); // Sleep for an eighth of a second, and retry
  1015. continue;
  1016. }
  1017. if (Status == STATUS_INVALID_CID)
  1018. {
  1019. //
  1020. // Already received the CLIENT_DIED and has been run down,
  1021. // and the session has been deref'd, so when we go, it will
  1022. // be closed completely.
  1023. //
  1024. break ;
  1025. }
  1026. //
  1027. // All other errors, until we have something more sensible to
  1028. // do,
  1029. //
  1030. LsapLpcContextCleanup(pApi);
  1031. break;
  1032. }
  1033. } while ( !NT_SUCCESS(Status) );
  1034. Cleanup:
  1035. if (IsCallInfoSet)
  1036. {
  1037. LsapSetCurrentCall( NULL );
  1038. }
  1039. DBG_DISPATCH_POSTLOGUE(
  1040. (NT_SUCCESS( Status ) ? ULongToPtr(pApi->ApiMessage.scRet) : ULongToPtr(Status)),
  1041. LongToPtr(pApi->ApiMessage.dwAPI) );
  1042. LsapFreePrivateHeap( pApi );
  1043. //
  1044. // We're out of here.
  1045. //
  1046. return(0);
  1047. }
  1048. //+---------------------------------------------------------------------------
  1049. //
  1050. // Function: RundownConnection
  1051. //
  1052. // Synopsis: Handles running down a closed connection
  1053. //
  1054. // Arguments: [pMsg] -- Message
  1055. //
  1056. // History: 4-01-94 RichardW Created
  1057. //
  1058. // Notes:
  1059. //
  1060. //----------------------------------------------------------------------------
  1061. DWORD
  1062. RundownConnectionNoFree(PVOID pMsg)
  1063. {
  1064. NTSTATUS scRet;
  1065. PSession pSession;
  1066. LSA_CALL_INFO CallInfo ;
  1067. DBG_DISPATCH_PROLOGUE( LpcApiLog, pMsg, CallInfo );
  1068. pSession = GetCurrentSession();
  1069. DebugLog((DEB_TRACE, "[%x] Process Detach\n", pSession->dwProcessID));
  1070. //
  1071. // Call the session manager to do preliminary cleanup:
  1072. //
  1073. LsapSessionDisconnect( pSession );
  1074. //
  1075. // Deref the session. Note that a client may have died while we were
  1076. // processing one or more requests in other threads. So, this is a
  1077. // safe (possibly deferred) dereference operation.
  1078. //
  1079. SpmpDereferenceSession(pSession);
  1080. //
  1081. // Use the default, spmgr session.
  1082. //
  1083. TlsSetValue(dwSession, pDefaultSession);
  1084. //
  1085. // Clean up and we're out of here...
  1086. //
  1087. DBG_DISPATCH_POSTLOGUE( ULongToPtr(STATUS_SUCCESS), LongToPtr(DBG_DISCONNECT) );
  1088. return(0);
  1089. }
  1090. DWORD
  1091. RundownConnection(
  1092. PVOID pMessage
  1093. )
  1094. {
  1095. RundownConnectionNoFree( pMessage );
  1096. LsapFreePrivateHeap( pMessage );
  1097. return 0 ;
  1098. }
  1099. //+---------------------------------------------------------------------------
  1100. //
  1101. // Function: CatchLpcDeath
  1102. //
  1103. // Synopsis: This function is invoked when the LPC thread dies
  1104. //
  1105. // Arguments: [PVOID] --
  1106. //
  1107. // History: 9-13-95 RichardW Created
  1108. //
  1109. // Notes:
  1110. //
  1111. //----------------------------------------------------------------------------
  1112. DWORD
  1113. CatchLpcDeath(
  1114. PVOID pvIgnored)
  1115. {
  1116. DsysAssertMsg(FALSE, "LPC Thread died");
  1117. return(0);
  1118. }
  1119. //+---------------------------------------------------------------------------
  1120. //
  1121. // Function: StartLpcThread
  1122. //
  1123. // Synopsis: Initializes the LPC server.
  1124. //
  1125. // Arguments: (none)
  1126. //
  1127. // History: 7-23-93 RichardW Created
  1128. //
  1129. // Notes:
  1130. //
  1131. //----------------------------------------------------------------------------
  1132. NTSTATUS
  1133. StartLpcThread(void)
  1134. {
  1135. DWORD tid;
  1136. hListenThread = LsapCreateThread(
  1137. NULL,
  1138. 0,
  1139. LpcServerThread,
  1140. 0,
  1141. 0,
  1142. &tid
  1143. );
  1144. if (!hListenThread)
  1145. {
  1146. return(STATUS_UNSUCCESSFUL);
  1147. }
  1148. LsaIRegisterNotification(
  1149. CatchLpcDeath,
  1150. NULL,
  1151. NOTIFIER_TYPE_HANDLE_WAIT,
  1152. 0,
  1153. NOTIFIER_FLAG_ONE_SHOT,
  1154. 0,
  1155. hListenThread
  1156. );
  1157. return(STATUS_SUCCESS);
  1158. }