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.

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