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.

7065 lines
188 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1992 - 1999
  3. Module Name:
  4. lpcsvr.cxx
  5. Abstract:
  6. Implementation of the RPC on LPC protocol engine for the server.
  7. Revision History:
  8. Mazhar Mohammed: Code fork from spcsvr.cxx, 08/02/95
  9. 05-06-96: Merged WMSG and LRPC into a single protocol
  10. Mazhar Mohammed Added Pipes Support
  11. Mazhar Mohammed Added support for Async RPC 08-14-96
  12. Mazhar Mohammed No more WMSG 9/22/97
  13. Kamen Moutafov (kamenm) Jan-2000 Support for multiple transfer syntaxes
  14. Kamen Moutafov (KamenM) Dec 99 - Feb 2000 - Support for cell debugging stuff
  15. Kamen Moutafov (KamenM) Mar-2000 Support for extended error info
  16. --*/
  17. #include <precomp.hxx>
  18. #include <queue.hxx>
  19. #include <hndlsvr.hxx>
  20. #include <lpcpack.hxx>
  21. #include <lpcsvr.hxx>
  22. #include <ProtBind.hxx>
  23. #include <lpcclnt.hxx>
  24. #include <CharConv.hxx>
  25. inline BOOL
  26. RecvLotsaCallsWrapper(
  27. LRPC_ADDRESS * Address
  28. )
  29. {
  30. Address->ReceiveLotsaCalls();
  31. return(FALSE);
  32. }
  33. inline RPC_STATUS
  34. InitializeLrpcIfNecessary(
  35. )
  36. /*++
  37. Routine Description:
  38. description
  39. Arguments:
  40. arg1 - description
  41. --*/
  42. {
  43. int nIndex ;
  44. RPC_STATUS Status ;
  45. if (GlobalLrpcServer == 0)
  46. {
  47. if ((Status = InitializeLrpcServer()) != RPC_S_OK)
  48. {
  49. return Status ;
  50. }
  51. }
  52. return (RPC_S_OK) ;
  53. }
  54. LRPC_SERVER::LRPC_SERVER(
  55. IN OUT RPC_STATUS *Status
  56. ) : ServerMutex(Status,
  57. TRUE // pre-allocate semaphore
  58. )
  59. {
  60. Address = NULL ;
  61. EndpointInitialized = 0 ;
  62. }
  63. RPC_STATUS
  64. LRPC_SERVER::InitializeAsync (
  65. )
  66. {
  67. RPC_CHAR Endpoint[20];
  68. RPC_STATUS Status = RPC_S_OK ;
  69. if (EndpointInitialized == 0)
  70. {
  71. swprintf(Endpoint, RPC_CONST_STRING("MSAsyncRPC_%d"),
  72. GetCurrentProcessId()) ;
  73. Status = RpcServerUseProtseqEpW (
  74. RPC_STRING_LITERAL("ncalrpc"), 100, Endpoint, NULL) ;
  75. if (Status != RPC_S_OK)
  76. {
  77. return Status ;
  78. }
  79. Status = GlobalRpcServer->ServerListen(1, 100, 1) ;
  80. if (Status == RPC_S_OK)
  81. {
  82. Status = SetEndpoint(Endpoint) ;
  83. }
  84. }
  85. return Status ;
  86. }
  87. RPC_STATUS
  88. InitializeLrpcServer (
  89. )
  90. /*++
  91. Routine Description:
  92. description
  93. Arguments:
  94. arg1 - description
  95. Return Value:
  96. RPC_S_OK - Function succeeded
  97. RPC_S_OUT_OF_MEMORY - we ran out of memory
  98. --*/
  99. {
  100. RPC_STATUS Status = RPC_S_OK ;
  101. GlobalMutexRequest() ;
  102. if (GlobalLrpcServer == 0)
  103. {
  104. GlobalLrpcServer = new LRPC_SERVER(&Status) ;
  105. if (GlobalLrpcServer == 0)
  106. {
  107. #if DBG
  108. PrintToDebugger("LRPC: LRPC_SERVER initialization failed\n") ;
  109. #endif
  110. GlobalMutexClear() ;
  111. return (RPC_S_OUT_OF_MEMORY) ;
  112. }
  113. if (Status != RPC_S_OK)
  114. {
  115. GlobalMutexClear() ;
  116. delete GlobalLrpcServer ;
  117. GlobalLrpcServer = 0 ;
  118. return Status ;
  119. }
  120. }
  121. GlobalMutexClear() ;
  122. return (RPC_S_OK) ;
  123. }
  124. void
  125. SetCommonFaultFields (
  126. IN LRPC_MESSAGE *LrpcMessage,
  127. IN RPC_STATUS Status,
  128. IN int Flags,
  129. IN int AdditionalLength
  130. )
  131. {
  132. LrpcMessage->Fault.RpcHeader.MessageType = LRPC_MSG_FAULT;
  133. LrpcMessage->Fault.RpcStatus = Status;
  134. LrpcMessage->LpcHeader.u1.s1.DataLength =
  135. sizeof(LRPC_FAULT_MESSAGE) - sizeof(PORT_MESSAGE)
  136. - sizeof(LrpcMessage->Fault.Buffer) + (CSHORT)AdditionalLength;
  137. LrpcMessage->LpcHeader.u1.s1.TotalLength =
  138. sizeof(LRPC_FAULT_MESSAGE) - sizeof(LrpcMessage->Fault.Buffer)
  139. + (CSHORT)AdditionalLength;
  140. if ((Flags & LRPC_SYNC_CLIENT) == 0)
  141. {
  142. LrpcMessage->LpcHeader.u2.ZeroInit = 0;
  143. LrpcMessage->LpcHeader.CallbackId = 0 ;
  144. LrpcMessage->LpcHeader.MessageId = 0 ;
  145. LrpcMessage->LpcHeader.u2.s2.DataInfoOffset = 0;
  146. }
  147. }
  148. void
  149. SetCommonFault2Fields (
  150. IN LRPC_MESSAGE *LrpcMessage,
  151. IN RPC_STATUS Status,
  152. IN unsigned int Length,
  153. IN void *Buffer
  154. )
  155. {
  156. LrpcMessage->Fault2.RpcHeader.MessageType = LRPC_MSG_FAULT2;
  157. LrpcMessage->Fault2.RpcStatus = Status;
  158. LrpcMessage->LpcHeader.u1.s1.DataLength =
  159. sizeof(LRPC_FAULT2_MESSAGE) - sizeof(PORT_MESSAGE);
  160. LrpcMessage->LpcHeader.u1.s1.TotalLength =
  161. sizeof(LRPC_FAULT2_MESSAGE);
  162. // the Server/DataEntries must have been set in GetBuffer - no
  163. // need to reset them here
  164. LrpcMessage->Fault2.RpcHeader.Flags |= LRPC_EEINFO_PRESENT;
  165. }
  166. void
  167. TrimIfNecessaryAndSetImmediateBuffer (
  168. IN LRPC_MESSAGE *LrpcMessage,
  169. IN RPC_STATUS Status,
  170. IN int Flags,
  171. IN size_t EstimatedEEInfoSize,
  172. IN BOOL fTrimEEInfo,
  173. IN ExtendedErrorInfo *CurrentEEInfo
  174. )
  175. {
  176. size_t NeededLength;
  177. RPC_STATUS RpcStatus;
  178. if (fTrimEEInfo)
  179. {
  180. ASSERT(MAXIMUM_FAULT_MESSAGE >= MinimumTransportEEInfoLength);
  181. TrimEEInfoToLength (MAXIMUM_FAULT_MESSAGE, &NeededLength);
  182. if (NeededLength == 0)
  183. {
  184. SetCommonFaultFields(LrpcMessage, Status, Flags, 0);
  185. return;
  186. }
  187. ASSERT(NeededLength <= MAXIMUM_FAULT_MESSAGE);
  188. EstimatedEEInfoSize = NeededLength;
  189. // fall through to the next if - it will succeed
  190. // as we know the length is trimmed.
  191. }
  192. else
  193. {
  194. ASSERT(EstimatedEEInfoSize <= MAXIMUM_FAULT_MESSAGE);
  195. }
  196. RpcStatus = PickleEEInfo(CurrentEEInfo,
  197. LrpcMessage->Fault.Buffer,
  198. MAXIMUM_FAULT_MESSAGE);
  199. if (RpcStatus != RPC_S_OK)
  200. {
  201. SetCommonFaultFields(LrpcMessage, Status, Flags, 0);
  202. return;
  203. }
  204. SetCommonFaultFields(LrpcMessage, Status, Flags, EstimatedEEInfoSize);
  205. LrpcMessage->Fault.RpcHeader.Flags |= LRPC_EEINFO_PRESENT;
  206. }
  207. void
  208. SetFaultPacket (
  209. IN LRPC_MESSAGE *LrpcMessage,
  210. IN RPC_STATUS Status,
  211. IN int Flags,
  212. IN LRPC_SCALL *CurrentCall OPTIONAL
  213. )
  214. /*++
  215. Routine Description:
  216. Initialize a fault packet
  217. Arguments:
  218. LrpcMessage - Fault message
  219. Status - Fault status
  220. Flags - Flags from the request message
  221. --*/
  222. {
  223. THREAD *Thread;
  224. ExtendedErrorInfo *CurrentEEInfo;
  225. size_t EstimatedEEInfoSize;
  226. RPC_STATUS RpcStatus;
  227. RPC_MESSAGE RpcMessage;
  228. // we will see whether there is extended error information here
  229. // and try to send it. If we run in out-of-memory, or there is
  230. // no EEInfo, send plain old fault.
  231. Thread = ThreadSelf();
  232. if (Thread && g_fSendEEInfo)
  233. {
  234. CurrentEEInfo = Thread->GetEEInfo();
  235. if (CurrentEEInfo)
  236. {
  237. // if this function runs in out-of-memory, it will
  238. // return 0.
  239. EstimatedEEInfoSize = EstimateSizeOfEEInfo();
  240. if (EstimatedEEInfoSize == 0)
  241. {
  242. SetCommonFaultFields(LrpcMessage, Status, Flags, 0);
  243. return;
  244. }
  245. // if there is no current call, we cannot send arbitrary length
  246. // data, so we must trim the EEInfo
  247. if (CurrentCall == NULL)
  248. {
  249. TrimIfNecessaryAndSetImmediateBuffer(LrpcMessage,
  250. Status,
  251. Flags,
  252. EstimatedEEInfoSize,
  253. TRUE,
  254. CurrentEEInfo);
  255. return;
  256. }
  257. if (EstimatedEEInfoSize <= MAXIMUM_FAULT_MESSAGE)
  258. {
  259. TrimIfNecessaryAndSetImmediateBuffer(LrpcMessage,
  260. Status,
  261. Flags,
  262. EstimatedEEInfoSize,
  263. FALSE,
  264. CurrentEEInfo);
  265. return;
  266. }
  267. ASSERT(CurrentCall != NULL);
  268. // here, the estimated EEInfo size is larger that the available
  269. // space in the fault packet. We have a call, so we must try
  270. // sending a fault2 packet.
  271. RpcMessage.Handle = CurrentCall;
  272. RpcMessage.RpcFlags = CurrentCall->RpcMessage.RpcFlags;
  273. // increase the buffer lenght in case we fall in the window
  274. // b/n MAXIMUM_MESSAGE_BUFFER and the EstimatedEEInfoSize. If we
  275. // do, GetBuffer will return us an immediate buffer, and this is
  276. // not something we want
  277. RpcMessage.BufferLength = max(EstimatedEEInfoSize, MAXIMUM_MESSAGE_BUFFER + 4);
  278. RpcStatus = CurrentCall->LRPC_SCALL::GetBuffer(&RpcMessage, NULL);
  279. if (RpcStatus != RPC_S_OK)
  280. {
  281. // can't send the full data - trim and send
  282. TrimIfNecessaryAndSetImmediateBuffer(LrpcMessage,
  283. Status,
  284. Flags,
  285. EstimatedEEInfoSize,
  286. TRUE,
  287. CurrentEEInfo);
  288. return;
  289. }
  290. ASSERT(CurrentCall->LrpcReplyMessage->Rpc.RpcHeader.Flags != LRPC_BUFFER_IMMEDIATE);
  291. // on success, GetBuffer has allocated a buffer in RpcMessage.Buffer
  292. // and has setup CurrentCall->LrpcReplyMessage for sending to
  293. // the client.
  294. // Fill in the EEInfo
  295. RpcStatus = PickleEEInfo(CurrentEEInfo,
  296. (unsigned char *)RpcMessage.Buffer,
  297. EstimatedEEInfoSize);
  298. if (RpcStatus != RPC_S_OK)
  299. {
  300. if (!CurrentCall->IsClientAsync())
  301. CurrentCall->Association->Buffers.DeleteItemByBruteForce(RpcMessage.Buffer);
  302. RpcpFarFree(RpcMessage.Buffer);
  303. // can't send the full data - trim and send
  304. TrimIfNecessaryAndSetImmediateBuffer(LrpcMessage,
  305. Status,
  306. Flags,
  307. EstimatedEEInfoSize,
  308. TRUE,
  309. CurrentEEInfo);
  310. return;
  311. }
  312. // Send to the client
  313. if (CurrentCall->IsClientAsync())
  314. {
  315. if (!CurrentCall->IsSyncCall())
  316. {
  317. ASSERT(CurrentCall->LrpcAsyncReplyMessage == CurrentCall->LrpcReplyMessage);
  318. }
  319. SetCommonFault2Fields(CurrentCall->LrpcReplyMessage,
  320. Status,
  321. RpcMessage.BufferLength,
  322. RpcMessage.Buffer);
  323. }
  324. else
  325. {
  326. // send the data for sync client
  327. // set fault2 fields
  328. SetCommonFault2Fields(CurrentCall->LrpcReplyMessage,
  329. Status,
  330. RpcMessage.BufferLength,
  331. RpcMessage.Buffer);
  332. // our caller will do the sending
  333. }
  334. return;
  335. }
  336. }
  337. SetCommonFaultFields(LrpcMessage, Status, Flags, 0);
  338. }
  339. void
  340. SetBindAckFault (
  341. IN LRPC_MESSAGE *LrpcMessage,
  342. IN RPC_STATUS Status
  343. )
  344. /*++
  345. Routine Description:
  346. Initialize a fault bind ack packet (bind_nak). It will add extended
  347. error info if there is some, and sending of eeinfo is enabled.
  348. Arguments:
  349. LrpcMessage - Bind message
  350. Status - Fault status
  351. --*/
  352. {
  353. size_t NeededLength;
  354. ExtendedErrorInfo *EEInfo;
  355. ASSERT(IsBufferAligned(LrpcMessage->Bind.BindExchange.Buffer));
  356. ASSERT(MAX_BIND_NAK >= MinimumTransportEEInfoLength);
  357. LrpcMessage->Bind.BindExchange.RpcStatus = Status;
  358. if (g_fSendEEInfo)
  359. {
  360. EEInfo = RpcpGetEEInfo();
  361. if (EEInfo)
  362. {
  363. TrimEEInfoToLength (MAX_BIND_NAK, &NeededLength);
  364. if (NeededLength != 0)
  365. {
  366. Status = PickleEEInfo(EEInfo,
  367. LrpcMessage->Bind.BindExchange.Buffer,
  368. MAX_BIND_NAK);
  369. if (Status == RPC_S_OK)
  370. {
  371. LrpcMessage->Bind.BindExchange.Flags |= EXTENDED_ERROR_INFO_PRESENT;
  372. LrpcMessage->LpcHeader.u1.s1.DataLength = (CSHORT)NeededLength +
  373. BIND_NAK_PICKLE_BUFFER_OFFSET
  374. - sizeof(PORT_MESSAGE);
  375. }
  376. }
  377. }
  378. }
  379. if (!(LrpcMessage->Bind.BindExchange.Flags & EXTENDED_ERROR_INFO_PRESENT))
  380. {
  381. LrpcMessage->LpcHeader.u1.s1.DataLength = sizeof(LRPC_BIND_MESSAGE)
  382. - sizeof(PORT_MESSAGE);
  383. }
  384. }
  385. LRPC_ADDRESS::LRPC_ADDRESS (
  386. OUT RPC_STATUS * Status
  387. ) : RPC_ADDRESS(Status),
  388. ThreadsDoingLongWait(0)
  389. /*++
  390. --*/
  391. {
  392. ObjectType = LRPC_ADDRESS_TYPE;
  393. LpcAddressPort = 0;
  394. CallThreadCount = 0;
  395. ActiveCallCount = 0;
  396. ServerListeningFlag = 0;
  397. AssociationCount = 0;
  398. fServerThreadsStarted = 0;
  399. SequenceNumber = 1;
  400. fTickleMessageAvailable = FALSE;
  401. TickleMessage = NULL;
  402. if (IsServerSideDebugInfoEnabled())
  403. {
  404. DebugCell = (DebugEndpointInfo *)AllocateCell(&DebugCellTag);
  405. if (DebugCell == NULL)
  406. {
  407. *Status = RPC_S_OUT_OF_MEMORY;
  408. }
  409. else
  410. {
  411. DebugCell->TypeHeader = 0;
  412. DebugCell->Type = dctEndpointInfo;
  413. DebugCell->ProtseqType = (UCHAR)LRPC_TOWER_ID;
  414. DebugCell->Status = desAllocated;
  415. memset(DebugCell->EndpointName, 0, sizeof(DebugCell->EndpointName));
  416. }
  417. }
  418. else
  419. DebugCell = NULL;
  420. }
  421. RPC_STATUS
  422. LRPC_ADDRESS::ServerStartingToListen (
  423. IN unsigned int MinimumCallThreads,
  424. IN unsigned int MaximumConcurrentCalls
  425. )
  426. /*++
  427. Routine Description:
  428. This routine gets called when RpcServerListen is called by the application.
  429. We need to create the threads we need to receive remote procedure calls.
  430. Arguments:
  431. MinimumCallThreads - Supplies the minimum number of threads which we
  432. must create.
  433. MaximumConcurrentCalls - Unused.
  434. Return Value:
  435. RPC_S_OK - Ok, this address is all ready to start listening for remote
  436. procedure calls.
  437. RPC_S_OUT_OF_THREADS - We could not create enough threads so that we
  438. have at least the minimum number of call threads required (as
  439. specified by the MinimumCallThreads argument).
  440. --*/
  441. {
  442. RPC_STATUS Status;
  443. UNUSED(MaximumConcurrentCalls);
  444. if (fServerThreadsStarted == 0)
  445. {
  446. Status = InitializeServerSideCellHeapIfNecessary();
  447. if (Status != RPC_S_OK)
  448. return Status;
  449. this->MinimumCallThreads = MinimumCallThreads;
  450. AddressMutex.Request();
  451. if (CallThreadCount < this->MinimumCallThreads)
  452. {
  453. Status = Server->CreateThread((THREAD_PROC)&RecvLotsaCallsWrapper,
  454. this);
  455. if (Status != RPC_S_OK)
  456. {
  457. AddressMutex.Clear();
  458. VALIDATE(Status)
  459. {
  460. RPC_S_OUT_OF_THREADS,
  461. RPC_S_OUT_OF_MEMORY
  462. } END_VALIDATE;
  463. return(Status);
  464. }
  465. CallThreadCount += 1;
  466. }
  467. AddressMutex.Clear();
  468. fServerThreadsStarted = 1;
  469. }
  470. ServerListeningFlag = 1;
  471. return(RPC_S_OK);
  472. }
  473. void
  474. LRPC_ADDRESS::ServerStoppedListening (
  475. )
  476. /*++
  477. Routine Description:
  478. We just need to indicate that the server is no longer listening, and
  479. set the minimum call thread count to one.
  480. --*/
  481. {
  482. ServerListeningFlag = 0;
  483. MinimumCallThreads = 1;
  484. }
  485. #ifdef DEBUGRPC
  486. // Hard coded world (aka EveryOne) SID
  487. const SID World = { 1, 1, { 0, 0, 0, 0, 0, 1}, 0};
  488. // Hard coded anonymous SID
  489. const SID AnonymousLogonSid = { 1, 1, SECURITY_NT_AUTHORITY, SECURITY_ANONYMOUS_LOGON_RID};
  490. SECURITY_DESCRIPTOR *DefaultPortSD = NULL;
  491. RPC_STATUS
  492. CreateAndGetDefaultPortSDIfNecessary (
  493. OUT SECURITY_DESCRIPTOR **PortSD
  494. )
  495. /*++
  496. Function Name: CreateAndGetDefaultPortSDIfNecessary
  497. Parameters:
  498. PortSD - receives the default port SD on success.
  499. Undefined on failure
  500. Description:
  501. If the default port SD is not created, creates it,
  502. and returns it. If it is already created, it simply
  503. returns it. The function is thread-safe.
  504. Returns:
  505. RPC_S_OK or other codes for error.
  506. --*/
  507. {
  508. DWORD DaclSize;
  509. PACL Dacl;
  510. ULONG LengthOfDacl;
  511. SECURITY_DESCRIPTOR *LocalDefaultSD; // we work on a local copy to make
  512. // this thread safe
  513. if (DefaultPortSD)
  514. {
  515. *PortSD = DefaultPortSD;
  516. return RPC_S_OK;
  517. }
  518. LocalDefaultSD = new SECURITY_DESCRIPTOR;
  519. if ( LocalDefaultSD == 0
  520. || !InitializeSecurityDescriptor(LocalDefaultSD,
  521. SECURITY_DESCRIPTOR_REVISION) )
  522. {
  523. return(RPC_S_OUT_OF_MEMORY);
  524. }
  525. ASSERT(GetSidLengthRequired(SID_MAX_SUB_AUTHORITIES) <= 0x44);
  526. DaclSize = 2 * sizeof(ACCESS_ALLOWED_ACE) + sizeof(World) + sizeof(AnonymousLogonSid) + 0x44;
  527. LengthOfDacl = DaclSize + sizeof(ACL);
  528. Dacl = (ACL *) new char[LengthOfDacl];
  529. if (NULL == Dacl)
  530. {
  531. return(RPC_S_OUT_OF_MEMORY);
  532. }
  533. ASSERT(IsValidSid((PVOID)&World));
  534. ASSERT(IsValidSid((PVOID)&AnonymousLogonSid));
  535. InitializeAcl(Dacl, LengthOfDacl, ACL_REVISION);
  536. if (!AddAccessAllowedAce(Dacl, ACL_REVISION,
  537. PORT_ALL_ACCESS,
  538. (PVOID)&World))
  539. {
  540. // this should never fail unless we messed up the
  541. // parameters or there is a version mismatch
  542. ASSERT(0);
  543. delete Dacl;
  544. delete LocalDefaultSD;
  545. return(RPC_S_OUT_OF_RESOURCES);
  546. }
  547. if (!AddAccessAllowedAce(Dacl, ACL_REVISION,
  548. PORT_ALL_ACCESS,
  549. (PVOID)&AnonymousLogonSid ))
  550. {
  551. // this should never fail unless we messed up the
  552. // parameters or there is a version mismatch
  553. ASSERT(0);
  554. delete Dacl;
  555. delete LocalDefaultSD;
  556. return(RPC_S_OUT_OF_RESOURCES);
  557. }
  558. if (!SetSecurityDescriptorDacl(LocalDefaultSD, TRUE, Dacl, FALSE))
  559. {
  560. delete Dacl;
  561. delete LocalDefaultSD;
  562. return(RPC_S_OUT_OF_RESOURCES);
  563. }
  564. if (InterlockedCompareExchangePointer((PVOID *)&DefaultPortSD,
  565. LocalDefaultSD,
  566. NULL) != NULL)
  567. {
  568. // somebody beat us to the punch - free our local copy
  569. delete Dacl;
  570. delete LocalDefaultSD;
  571. }
  572. *PortSD = DefaultPortSD;
  573. return RPC_S_OK;
  574. }
  575. #endif
  576. RPC_STATUS
  577. LRPC_ADDRESS::ActuallySetupAddress (
  578. IN RPC_CHAR * Endpoint,
  579. IN void * SecurityDescriptor OPTIONAL
  580. )
  581. /*++
  582. Function Name:ActuallySetupAddress
  583. Parameters:
  584. Description:
  585. Returns:
  586. --*/
  587. {
  588. NTSTATUS NtStatus;
  589. RPC_CHAR * LpcPortName;
  590. UNICODE_STRING UnicodeString;
  591. OBJECT_ATTRIBUTES ObjectAttributes;
  592. RPC_STATUS Status;
  593. #ifdef DEBUGRPC
  594. BOOL Result;
  595. BOOL DaclPresent;
  596. PACL Dacl;
  597. BOOL Ignored;
  598. #endif
  599. // Allocate and initialize the port name. We need to stick the
  600. // LRPC_DIRECTORY_NAME on the front of the endpoint. This is for
  601. // security reasons (so that anyone can create LRPC endpoints).
  602. LpcPortName = new RPC_CHAR[RpcpStringLength(Endpoint)
  603. + RpcpStringLength(LRPC_DIRECTORY_NAME) + 1];
  604. if (LpcPortName == 0)
  605. {
  606. return(RPC_S_OUT_OF_MEMORY);
  607. }
  608. RpcpMemoryCopy(
  609. LpcPortName,
  610. LRPC_DIRECTORY_NAME,
  611. RpcpStringLength(LRPC_DIRECTORY_NAME) *sizeof(RPC_CHAR));
  612. RpcpMemoryCopy(
  613. LpcPortName + RpcpStringLength(LRPC_DIRECTORY_NAME),
  614. Endpoint,
  615. (RpcpStringLength(Endpoint) + 1) *sizeof(RPC_CHAR));
  616. RtlInitUnicodeString(&UnicodeString, LpcPortName);
  617. #ifdef DEBUGRPC
  618. // in checked builds we check the security descriptor for NULL Dacl,
  619. // and if present, we replace it with a default "allow everyone"
  620. // Dacl. This was requested by ChrisW (12/14/2000) from the Security
  621. // Team so that they can get LPC ports out of the picture, and then
  622. // ASSERT on NULL Dacls for other objects
  623. if (SecurityDescriptor)
  624. {
  625. Result = GetSecurityDescriptorDacl(SecurityDescriptor,
  626. &DaclPresent,
  627. &Dacl,
  628. &Ignored // lpbDaclDefaulted
  629. );
  630. if (!Result)
  631. {
  632. // invalid security descriptor is the only reason this could fail
  633. delete LpcPortName;
  634. return RPC_S_INVALID_ENDPOINT_FORMAT;
  635. }
  636. if (DaclPresent && (Dacl == NULL))
  637. {
  638. Status = CreateAndGetDefaultPortSDIfNecessary((SECURITY_DESCRIPTOR **)&SecurityDescriptor);
  639. if (Status != RPC_S_OK)
  640. {
  641. delete LpcPortName;
  642. return Status;
  643. }
  644. // We were able to grab a default port SD - just let it through
  645. }
  646. // else
  647. // {
  648. // the security descriptor supplied by caller has non NULL Dacl - let
  649. // it through
  650. // }
  651. }
  652. #endif
  653. InitializeObjectAttributes(
  654. &ObjectAttributes,
  655. &UnicodeString,
  656. OBJ_CASE_INSENSITIVE,
  657. 0,
  658. SecurityDescriptor);
  659. NtStatus = NtCreatePort(
  660. &LpcAddressPort,
  661. &ObjectAttributes,
  662. sizeof(LRPC_BIND_EXCHANGE),
  663. PORT_MAXIMUM_MESSAGE_LENGTH,
  664. 0);
  665. delete LpcPortName;
  666. if (NT_SUCCESS(NtStatus))
  667. {
  668. Status = LrpcSetEndpoint(Endpoint);
  669. return(Status);
  670. }
  671. if (NtStatus == STATUS_NO_MEMORY)
  672. {
  673. return(RPC_S_OUT_OF_MEMORY);
  674. }
  675. if ((NtStatus == STATUS_INSUFFICIENT_RESOURCES)
  676. || (NtStatus == STATUS_QUOTA_EXCEEDED))
  677. {
  678. return(RPC_S_OUT_OF_RESOURCES);
  679. }
  680. if ((NtStatus == STATUS_OBJECT_PATH_INVALID)
  681. || (NtStatus == STATUS_OBJECT_PATH_NOT_FOUND)
  682. || (NtStatus == STATUS_OBJECT_NAME_INVALID)
  683. || (NtStatus == STATUS_OBJECT_TYPE_MISMATCH)
  684. || (NtStatus == STATUS_INVALID_OWNER))
  685. {
  686. return(RPC_S_INVALID_ENDPOINT_FORMAT);
  687. }
  688. #if DBG
  689. if (NtStatus != STATUS_OBJECT_NAME_COLLISION)
  690. {
  691. PrintToDebugger("RPC : NtCreatePort : %lx\n", NtStatus);
  692. }
  693. #endif // DBG
  694. ASSERT(NtStatus == STATUS_OBJECT_NAME_COLLISION);
  695. return(RPC_S_DUPLICATE_ENDPOINT);
  696. }
  697. extern RPC_CHAR *
  698. ULongToHexString (
  699. IN RPC_CHAR * String,
  700. IN unsigned long Number
  701. );
  702. RPC_STATUS
  703. LRPC_ADDRESS::ServerSetupAddress (
  704. IN RPC_CHAR * NetworkAddress,
  705. IN RPC_CHAR * *Endpoint,
  706. IN unsigned int PendingQueueSize,
  707. IN void * SecurityDescriptor, OPTIONAL
  708. IN unsigned long EndpointFlags,
  709. IN unsigned long NICFlags,
  710. OUT NETWORK_ADDRESS_VECTOR **ppNetworkAddressVector
  711. )
  712. /*++
  713. Routine Description:
  714. We need to setup the connection port and get ready to receive remote
  715. procedure calls. We will use the name of this machine as the network
  716. address.
  717. Arguments:
  718. Endpoint - Supplies the endpoint to be used will this address.
  719. NetworkAddress - Returns the network address for this server. The
  720. ownership of the buffer allocated to contain the network address
  721. passes to the caller.
  722. SecurityDescriptor - Optionally supplies a security descriptor to
  723. be placed on this address.
  724. PendingQueueSize - Unused.
  725. RpcProtocolSequence - Unused.
  726. Return Value:
  727. RPC_S_OK - We successfully setup this address.
  728. RPC_S_INVALID_SECURITY_DESC - The supplied security descriptor is
  729. invalid.
  730. RPC_S_CANT_CREATE_ENDPOINT - The endpoint format is correct, but
  731. the endpoint can not be created.
  732. RPC_S_INVALID_ENDPOINT_FORMAT - The endpoint is not a valid
  733. endpoint for this particular transport interface.
  734. RPC_S_OUT_OF_RESOURCES - Insufficient resources are available to
  735. setup the address.
  736. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to setup
  737. the address.
  738. --*/
  739. {
  740. BOOL Boolean;
  741. RPC_CHAR * String;
  742. RPC_STATUS Status ;
  743. RPC_CHAR DynamicEndpoint[64];
  744. static unsigned int DynamicEndpointCount = 0;
  745. DWORD NetworkAddressLength = MAX_COMPUTERNAME_LENGTH + 1;
  746. ULONG EndpointLength;
  747. UNUSED(PendingQueueSize);
  748. if (*Endpoint)
  749. {
  750. // the maximum allowed length in bytes is the
  751. // string length in bytes (string length * 2) + the NULL
  752. // terminator
  753. EndpointLength = RpcpStringLength(*Endpoint) * 2 + 2;
  754. if (EndpointLength > BIND_BACK_PORT_NAME_LEN)
  755. {
  756. RpcpErrorAddRecord(EEInfoGCRuntime,
  757. RPC_S_INVALID_ENDPOINT_FORMAT,
  758. EEInfoDLLRPC_ADDRESS__ServerSetupAddress10,
  759. *Endpoint,
  760. EndpointLength,
  761. BIND_BACK_PORT_NAME_LEN);
  762. return RPC_S_INVALID_ENDPOINT_FORMAT;
  763. }
  764. }
  765. Status = InitializeLrpcIfNecessary() ;
  766. if (Status != RPC_S_OK)
  767. {
  768. return Status ;
  769. }
  770. ASSERT(GlobalLrpcServer != 0) ;
  771. *ppNetworkAddressVector = (NETWORK_ADDRESS_VECTOR *)
  772. new char[ sizeof(NETWORK_ADDRESS_VECTOR) + sizeof(RPC_CHAR *) + sizeof(RPC_CHAR) * (MAX_COMPUTERNAME_LENGTH + 1)];
  773. if (*ppNetworkAddressVector == NULL)
  774. {
  775. return RPC_S_OUT_OF_MEMORY;
  776. }
  777. (*ppNetworkAddressVector)->Count = 1;
  778. (*ppNetworkAddressVector)->NetworkAddresses[0] = (RPC_CHAR *)
  779. (((char *) *ppNetworkAddressVector) + sizeof(NETWORK_ADDRESS_VECTOR) + sizeof(RPC_CHAR *));
  780. Boolean = GetComputerNameW(
  781. (*ppNetworkAddressVector)->NetworkAddresses[0],
  782. &NetworkAddressLength);
  783. if (Boolean != TRUE)
  784. {
  785. Status = GetLastError();
  786. #if DBG
  787. PrintToDebugger("RPC : GetComputerNameW : %d\n", Status);
  788. #endif // DBG
  789. if (Status == ERROR_NOT_ENOUGH_MEMORY)
  790. {
  791. Status = RPC_S_OUT_OF_MEMORY;
  792. }
  793. else if ((Status == ERROR_NOT_ENOUGH_QUOTA)
  794. || (Status == ERROR_NO_SYSTEM_RESOURCES))
  795. {
  796. Status = RPC_S_OUT_OF_RESOURCES;
  797. }
  798. else
  799. {
  800. ASSERT(0);
  801. Status = RPC_S_OUT_OF_MEMORY;
  802. }
  803. goto Cleanup;
  804. }
  805. if (*Endpoint)
  806. {
  807. Status = ActuallySetupAddress(*Endpoint, SecurityDescriptor);
  808. }
  809. else
  810. {
  811. for (;;)
  812. {
  813. String = DynamicEndpoint;
  814. *String++ = RPC_CONST_CHAR('L');
  815. *String++ = RPC_CONST_CHAR('R');
  816. *String++ = RPC_CONST_CHAR('P');
  817. *String++ = RPC_CONST_CHAR('C');
  818. String = ULongToHexString(String,
  819. PtrToUlong(NtCurrentTeb()->ClientId.UniqueProcess));
  820. DynamicEndpointCount += 1;
  821. *String++ = RPC_CONST_CHAR('.');
  822. String = ULongToHexString(String, DynamicEndpointCount);
  823. *String = 0;
  824. Status = ActuallySetupAddress(DynamicEndpoint, SecurityDescriptor);
  825. if (Status != RPC_S_DUPLICATE_ENDPOINT)
  826. {
  827. break;
  828. }
  829. }
  830. if (Status == RPC_S_OK)
  831. {
  832. *Endpoint = DuplicateString(DynamicEndpoint);
  833. if (*Endpoint == 0)
  834. {
  835. Status = RPC_S_OUT_OF_MEMORY;
  836. }
  837. else
  838. {
  839. return(RPC_S_OK);
  840. }
  841. }
  842. }
  843. Cleanup:
  844. if (Status != RPC_S_OK)
  845. {
  846. delete *ppNetworkAddressVector;
  847. *ppNetworkAddressVector = 0;
  848. }
  849. return Status;
  850. }
  851. RPC_STATUS
  852. LRPC_ADDRESS::CompleteListen (
  853. )
  854. /*++
  855. Function Name:CompleteListen
  856. Parameters:
  857. Description:
  858. Returns:
  859. --*/
  860. {
  861. LRPC_ADDRESS *LocalAddress;
  862. if (DebugCell)
  863. {
  864. CStackAnsi AnsiEndpoint;
  865. int i;
  866. RPC_STATUS RpcStatus;
  867. i = RpcpStringLength(InqEndpoint()) + 1;
  868. *(AnsiEndpoint.GetPAnsiString()) = (char *)_alloca(i);
  869. RpcStatus = AnsiEndpoint.Attach(InqEndpoint(), i, i * 2);
  870. // note that effectively we ignore the result. That's ok - we don't
  871. // want servers to be unable to start because of code page issues
  872. // in the debug path. If this fails and we ignore it, the worse
  873. // that can happen is to have empty endpoint in the debug cell
  874. // - not a big deal.
  875. if (RpcStatus == RPC_S_OK)
  876. {
  877. strncpy(DebugCell->EndpointName, AnsiEndpoint, sizeof(DebugCell->EndpointName));
  878. }
  879. DebugCell->Status = desActive;
  880. }
  881. do
  882. {
  883. AddressChain = LrpcAddressList;
  884. }
  885. while (InterlockedCompareExchangePointer((PVOID *)&LrpcAddressList, this, LrpcAddressList) != AddressChain);
  886. return(RPC_S_OK);
  887. }
  888. inline LRPC_SASSOCIATION *
  889. LRPC_ADDRESS::ReferenceAssociation (
  890. IN unsigned long AssociationKey
  891. )
  892. /*++
  893. Routine Description:
  894. Given an assocation key, we need to map it into an association. The
  895. association may already have been deleted, in which case, we need to
  896. return zero.
  897. Arguments:
  898. AssociationKey - Supplies the key to be used to map into an association.
  899. Return Value:
  900. If the association still exists, it will be returned; otherwise, zero
  901. will be returned.
  902. --*/
  903. {
  904. LRPC_SASSOCIATION * Association;
  905. LPC_KEY *LpcKey = (LPC_KEY *) &AssociationKey;
  906. USHORT MySequenceNumber;
  907. ASSERT(SERVERKEY(AssociationKey));
  908. MySequenceNumber = LpcKey->SeqNumber & ~SERVER_KEY_MASK;
  909. AddressMutex.Request();
  910. Association = AssociationDictionary.Find(LpcKey->AssocKey);
  911. if (Association == 0
  912. || Association->SequenceNumber != MySequenceNumber)
  913. {
  914. AddressMutex.Clear();
  915. return(0);
  916. }
  917. Association->AssociationReferenceCount++;
  918. LogEvent(SU_SASSOC, EV_INC, Association, 0,
  919. Association->AssociationReferenceCount, 1, 1);
  920. AddressMutex.Clear();
  921. return(Association);
  922. }
  923. inline LRPC_CASSOCIATION *
  924. LRPC_ADDRESS::ReferenceClientAssoc (
  925. IN unsigned long AssociationKey
  926. )
  927. /*++
  928. Routine Description:
  929. Given an assocation key, we need to map it into an association. The
  930. association may already have been deleted, in which case, we need to
  931. return zero.
  932. Arguments:
  933. AssociationKey - Supplies the key to be used to map into an association.
  934. Return Value:
  935. If the association still exists, it will be returned; otherwise, zero
  936. will be returned.
  937. --*/
  938. {
  939. LRPC_CASSOCIATION * Association;
  940. LPC_KEY *LpcKey = (LPC_KEY *) &AssociationKey;
  941. LrpcMutexRequest();
  942. Association = LrpcAssociationDict->Find(LpcKey->AssocKey);
  943. if (Association == 0
  944. || Association->SequenceNumber != LpcKey->SeqNumber)
  945. {
  946. LrpcMutexClear();
  947. return(0);
  948. }
  949. Association->AddReference();
  950. LrpcMutexClear();
  951. return(Association);
  952. }
  953. #if defined(_WIN64)
  954. #define BAD_HANDLE_CONST ((HANDLE)0xbaaaaaadbaaaaaad)
  955. #else
  956. #define BAD_HANDLE_CONST (ULongToHandle(0xbaaaaaad))
  957. #endif
  958. inline void
  959. LRPC_ADDRESS::DereferenceAssociation (
  960. IN LRPC_SASSOCIATION * Association
  961. )
  962. /*++
  963. Routine Description:
  964. We are done using this address, so the reference count can be decremented.
  965. If no one is referencing this association, then we can go ahead and
  966. delete it.
  967. Arguments:
  968. Association - Supplies the association whose reference count should be
  969. decremented.
  970. --*/
  971. {
  972. NTSTATUS NtStatus;
  973. AddressMutex.Request();
  974. Association->AssociationReferenceCount -= 1;
  975. ASSERT(Association->AssociationReferenceCount >= 0);
  976. LogEvent(SU_SASSOC, EV_DEC, Association, 0,
  977. Association->AssociationReferenceCount, 1, 1);
  978. if (Association->AssociationReferenceCount <= 0)
  979. {
  980. AssociationDictionary.Delete(Association->DictionaryKey);
  981. AssociationCount--;
  982. AddressMutex.Clear();
  983. if (Association->LpcServerPort)
  984. {
  985. NtStatus = NtClose(Association->LpcServerPort);
  986. Association->LpcServerPort = BAD_HANDLE_CONST;
  987. LogEvent(SU_SASSOC, EV_STOP, Association, Association->LpcServerPort,
  988. Association->AssociationReferenceCount, 1, 1);
  989. #if DBG
  990. if (!NT_SUCCESS(NtStatus))
  991. {
  992. PrintToDebugger("RPC : NtClose : %lx\n", NtStatus);
  993. ASSERT(0) ;
  994. }
  995. #endif // DBG
  996. }
  997. if (Association->LpcReplyPort)
  998. {
  999. NtStatus = NtClose(Association->LpcReplyPort);
  1000. #if DBG
  1001. if (!NT_SUCCESS(NtStatus))
  1002. {
  1003. PrintToDebugger("RPC : NtClose : %lx\n", NtStatus);
  1004. ASSERT(0) ;
  1005. }
  1006. #endif // DBG
  1007. }
  1008. delete Association;
  1009. }
  1010. else
  1011. {
  1012. AddressMutex.Clear();
  1013. }
  1014. }
  1015. BOOL
  1016. LRPC_ADDRESS::DealWithLRPCRequest (
  1017. IN LRPC_MESSAGE * LrpcMessage,
  1018. IN LRPC_MESSAGE * LrpcReply,
  1019. IN LRPC_SASSOCIATION *Association,
  1020. OUT LRPC_MESSAGE **LrpcResponse
  1021. )
  1022. /*++
  1023. Routine Description:
  1024. Deal with a new LRPC request.
  1025. Arguments:
  1026. LrpcMessage - request message
  1027. LrpcReply - the reply is placed here
  1028. Association - the association on which the request arrived
  1029. Return Value:
  1030. FALSE if the thread should stay, or !FALSE if the thread should go
  1031. --*/
  1032. {
  1033. int retval ;
  1034. LRPC_SCALL *SCall;
  1035. NTSTATUS NtStatus ;
  1036. RPC_STATUS Status;
  1037. LRPC_SCALL *NewSCall ;
  1038. int Flags = LrpcMessage->Rpc.RpcHeader.Flags ;
  1039. if (ServerListeningFlag == 0
  1040. && GlobalRpcServer->InqNumAutoListenInterfaces() == 0)
  1041. {
  1042. *LrpcResponse = LrpcMessage ;
  1043. RpcpErrorAddRecord(EEInfoGCRuntime,
  1044. RPC_S_SERVER_TOO_BUSY,
  1045. EEInfoDLDealWithLRPCRequest10,
  1046. (ULONG)ServerListeningFlag,
  1047. (ULONG)GlobalRpcServer->InqNumAutoListenInterfaces());
  1048. SetFaultPacket(*LrpcResponse,
  1049. RPC_S_SERVER_TOO_BUSY, Flags, NULL);
  1050. return 0;
  1051. }
  1052. Status = Association->AllocateSCall(LrpcMessage,
  1053. LrpcReply,
  1054. Flags,
  1055. &SCall) ;
  1056. if (Status != RPC_S_OK)
  1057. {
  1058. *LrpcResponse = LrpcMessage ;
  1059. RpcpErrorAddRecord(EEInfoGCRuntime,
  1060. Status,
  1061. EEInfoDLDealWithLRPCRequest20);
  1062. SetFaultPacket(*LrpcResponse, Status, Flags, NULL);
  1063. return 0 ;
  1064. }
  1065. ASSERT(SCall);
  1066. Status = SCall->LrpcMessageToRpcMessage(LrpcMessage,
  1067. &(SCall->RpcMessage));
  1068. if (Status != RPC_S_OK)
  1069. {
  1070. #if DBG
  1071. PrintToDebugger("LRPC: LrpcMessageToRpcMessage failed: %d\n",
  1072. Status) ;
  1073. #endif
  1074. *LrpcResponse = LrpcMessage ;
  1075. SetFaultPacket(*LrpcResponse, Status, Flags, NULL);
  1076. Association->FreeSCall (SCall) ;
  1077. return 0;
  1078. }
  1079. AddressMutex.Request();
  1080. if (SCall->Flags & LRPC_CAUSAL)
  1081. {
  1082. retval = Association->MaybeQueueSCall(SCall) ;
  1083. switch (retval)
  1084. {
  1085. case 0:
  1086. break;
  1087. case 1:
  1088. AddressMutex.Clear();
  1089. *LrpcResponse = NULL ;
  1090. return 0;
  1091. case -1:
  1092. AddressMutex.Clear();
  1093. *LrpcResponse = LrpcMessage ;
  1094. RpcpErrorAddRecord(EEInfoGCRuntime,
  1095. RPC_S_OUT_OF_MEMORY,
  1096. EEInfoDLDealWithLRPCRequest30);
  1097. SetFaultPacket(*LrpcResponse, LRPC_MSG_FAULT, Flags, NULL);
  1098. Association->FreeSCall (SCall) ;
  1099. return 0;
  1100. }
  1101. }
  1102. ActiveCallCount += 1;
  1103. if (ActiveCallCount >= CallThreadCount)
  1104. {
  1105. Status = Server->CreateThread(
  1106. (THREAD_PROC)&RecvLotsaCallsWrapper,
  1107. this);
  1108. if (Status == RPC_S_OK)
  1109. {
  1110. CallThreadCount += 1;
  1111. }
  1112. else
  1113. {
  1114. // If the above SCall is causal and creating the thread has failed
  1115. // then the call has been put into the dictionary and needs
  1116. // to be removed. It will be the only scall for the key.
  1117. if (SCall->Flags & LRPC_CAUSAL)
  1118. Association->ClientThreadDict.Delete(MsgClientIdToClientId(SCall->LrpcRequestMessage->Rpc.LpcHeader.ClientId).UniqueThread) ;
  1119. ActiveCallCount -= 1;
  1120. ASSERT((int)ActiveCallCount >= 0);
  1121. AddressMutex.Clear();
  1122. *LrpcResponse = LrpcMessage ;
  1123. RpcpErrorAddRecord(EEInfoGCRuntime,
  1124. Status,
  1125. EEInfoDLDealWithLRPCRequest40);
  1126. SetFaultPacket(*LrpcResponse,
  1127. RPC_S_SERVER_TOO_BUSY, Flags, NULL);
  1128. Association->FreeSCall(SCall) ;
  1129. return 0;
  1130. }
  1131. }
  1132. AddressMutex.Clear();
  1133. while (1)
  1134. {
  1135. LrpcReply->Rpc.RpcHeader.Flags = 0;
  1136. SCall->DealWithRequestMessage();
  1137. if ((SCall->Flags & LRPC_CAUSAL) == 0)
  1138. {
  1139. break;
  1140. }
  1141. NewSCall = Association->GetNextSCall(SCall) ;
  1142. if (NewSCall)
  1143. {
  1144. SCall->SendReply();
  1145. SCall = NewSCall ;
  1146. while (SCall->Deleted)
  1147. {
  1148. FreeMessage(SCall->LrpcRequestMessage) ;
  1149. NewSCall = Association->GetNextSCall(SCall) ;
  1150. AddressMutex.Request();
  1151. //
  1152. // N.B. If a causally ordered call fails
  1153. // in DealWithRequestMessage, this is fine, because
  1154. // in SendReply, if we send back a fault,
  1155. // we will mark all calls in the SCallDict with Deleted,
  1156. // and in this loop, we will skip them.
  1157. //
  1158. if (NewSCall == 0)
  1159. {
  1160. if (fKeepThread())
  1161. {
  1162. retval = 0;
  1163. }
  1164. else
  1165. {
  1166. CallThreadCount -= 1;
  1167. retval = 1;
  1168. }
  1169. ActiveCallCount -= 1;
  1170. ASSERT((int)ActiveCallCount >= 0);
  1171. AddressMutex.Clear();
  1172. Association->FreeSCall(SCall) ;
  1173. DereferenceAssociation(Association) ;
  1174. *LrpcResponse = NULL ;
  1175. return retval;
  1176. }
  1177. AddressMutex.Clear();
  1178. Association->FreeSCall(SCall) ;
  1179. DereferenceAssociation(Association) ;
  1180. SCall = NewSCall ;
  1181. }
  1182. RpcpPurgeEEInfo();
  1183. }
  1184. else
  1185. {
  1186. break;
  1187. }
  1188. // Make sure that the LrpcReplyMessage is always pointing to the
  1189. // one located on this thread's stack. It is possible that we
  1190. // will pick up a queued scall that was put into the queue on
  1191. // another thread. In this case, the LrpcReplyMessage may point to
  1192. // that thread's stack - a recepie for disaster.
  1193. // Note that LrpcReply is located on the stack for the current thread.
  1194. LrpcReply->Rpc.RpcHeader.CallId = SCall->CallId ;
  1195. SCall->LrpcReplyMessage = LrpcReply;
  1196. }
  1197. AddressMutex.Request();
  1198. if (fKeepThread())
  1199. {
  1200. if (SCall->IsSyncCall() && SCall->IsClientAsync() == 0)
  1201. {
  1202. ActiveCallCount -= 1;
  1203. ASSERT((int)ActiveCallCount >= 0);
  1204. AddressMutex.Clear();
  1205. *LrpcResponse = SCall->InitMsg();
  1206. Association->FreeSCall(SCall) ;
  1207. }
  1208. else
  1209. {
  1210. AddressMutex.Clear();
  1211. *LrpcResponse = NULL;
  1212. SCall->SendReply();
  1213. AddressMutex.Request();
  1214. ActiveCallCount -= 1;
  1215. ASSERT((int)ActiveCallCount >= 0);
  1216. AddressMutex.Clear();
  1217. }
  1218. return 0 ;
  1219. }
  1220. //
  1221. // This thread is extraneous, reply and return this
  1222. // thread to the system.
  1223. //
  1224. ActiveCallCount -= 1;
  1225. ASSERT((int)ActiveCallCount >= 0);
  1226. CallThreadCount -= 1;
  1227. AddressMutex.Clear();
  1228. SCall->SendReply();
  1229. return 1 ;
  1230. }
  1231. #define LRPC_LISTEN_TIMEOUT 5*60*1000
  1232. inline void
  1233. FormatTimeOut(
  1234. OUT PLARGE_INTEGER TimeOut,
  1235. IN DWORD Milliseconds
  1236. )
  1237. {
  1238. ASSERT(Milliseconds != -1);
  1239. TimeOut->QuadPart = UInt32x32To64( Milliseconds, 10000 );
  1240. TimeOut->QuadPart *= -1;
  1241. }
  1242. RPC_STATUS
  1243. LRPC_ADDRESS::BeginLongCall(
  1244. void
  1245. )
  1246. {
  1247. RPC_STATUS Status = RPC_S_OK;
  1248. AddressMutex.Request();
  1249. if (ActiveCallCount + 1 >= CallThreadCount)
  1250. {
  1251. AddressMutex.Clear();
  1252. Status = Server->CreateThread(
  1253. (THREAD_PROC)&RecvLotsaCallsWrapper,
  1254. this);
  1255. AddressMutex.Request();
  1256. // N.B. We increase the active call count
  1257. // regrdless of Status. This is OK, because
  1258. // if we return failure, the caller of this function
  1259. // is responsible to decrease it
  1260. ActiveCallCount ++;
  1261. if (Status == RPC_S_OK)
  1262. {
  1263. CallThreadCount += 1;
  1264. }
  1265. }
  1266. else
  1267. {
  1268. ActiveCallCount ++;
  1269. }
  1270. AddressMutex.Clear();
  1271. return Status;
  1272. }
  1273. void LRPC_ADDRESS::HandleInvalidAssociationReference (
  1274. IN LRPC_MESSAGE *RequestMessage,
  1275. IN OUT LRPC_MESSAGE **ReplyMessage,
  1276. IN ULONG AssociationKey
  1277. )
  1278. {
  1279. ASSERT(RequestMessage != NULL);
  1280. ASSERT(ReplyMessage != NULL);
  1281. // we handle only binds, requests and copies
  1282. if ((RequestMessage->Bind.MessageType != LRPC_MSG_REQUEST)
  1283. && (RequestMessage->Bind.MessageType != LRPC_MSG_BIND)
  1284. && (RequestMessage->Bind.MessageType != LRPC_MSG_COPY))
  1285. {
  1286. *ReplyMessage = NULL;
  1287. return;
  1288. }
  1289. RpcpErrorAddRecord(EEInfoGCRuntime,
  1290. RPC_S_CALL_FAILED_DNE,
  1291. EEInfoDLLRPC_ADDRESS__HandleInvalidAssociationReference10,
  1292. AssociationKey);
  1293. if (RequestMessage->Bind.MessageType == LRPC_MSG_BIND)
  1294. {
  1295. SetBindAckFault(RequestMessage, RPC_S_CALL_FAILED_DNE);
  1296. // if this is bind, patch up the fields a bit, as SetFaultPacket
  1297. // does not set everything right for the bind case
  1298. RequestMessage->Bind.MessageType = LRPC_BIND_ACK;
  1299. }
  1300. else
  1301. {
  1302. SetFaultPacket(RequestMessage,
  1303. RPC_S_CALL_FAILED_DNE,
  1304. RequestMessage->Rpc.RpcHeader.Flags,
  1305. NULL);
  1306. }
  1307. *ReplyMessage = RequestMessage;
  1308. }
  1309. BOOL
  1310. LRPC_ADDRESS::EndLongCall(
  1311. void
  1312. )
  1313. {
  1314. AddressMutex.Request();
  1315. ActiveCallCount -= 1;
  1316. int SpareThreads = CallThreadCount -
  1317. (ActiveCallCount + MinimumCallThreads);
  1318. if (SpareThreads > 0)
  1319. {
  1320. ASSERT(CallThreadCount > ActiveCallCount);
  1321. AddressMutex.Clear();
  1322. return TRUE;
  1323. }
  1324. AddressMutex.Clear();
  1325. return FALSE;
  1326. }
  1327. void
  1328. LRPC_ADDRESS::ReceiveLotsaCalls (
  1329. )
  1330. /*++
  1331. Routine Description:
  1332. Here is where we receive remote procedure calls to this address. One
  1333. more threads will be executing this routine at once.
  1334. --*/
  1335. {
  1336. NTSTATUS NtStatus;
  1337. LRPC_SASSOCIATION * Association;
  1338. LRPC_CASSOCIATION *CAssociation;
  1339. unsigned long AssociationKey;
  1340. char *PaddedMessage;
  1341. LRPC_MESSAGE * Reply ;
  1342. LRPC_MESSAGE * LrpcMessage = 0;
  1343. LRPC_MESSAGE * LrpcReplyMessage = 0;
  1344. int AssociationType = 0;
  1345. int Flags = 0;
  1346. BOOL PartialFlag ;
  1347. BOOL fStatus ;
  1348. RPC_STATUS Status;
  1349. unsigned long ReplyKey = -1;
  1350. LARGE_INTEGER LongTimeout;
  1351. LARGE_INTEGER ShortTimeout;
  1352. PLARGE_INTEGER pliTimeout = &ShortTimeout;
  1353. ULONG_PTR Key;
  1354. THREAD *ThisThread;
  1355. DebugThreadInfo *DebugCell;
  1356. FormatTimeOut(&ShortTimeout, gThreadTimeout);
  1357. FormatTimeOut(&LongTimeout, LRPC_LISTEN_TIMEOUT);
  1358. pliTimeout = &ShortTimeout;
  1359. PaddedMessage = (char *) _alloca(PadToNaturalBoundary(sizeof(LRPC_MESSAGE) + 1) + sizeof(LRPC_MESSAGE));
  1360. Reply = (LRPC_MESSAGE *) AlignOnNaturalBoundary(PaddedMessage) ;
  1361. ThisThread = RpcpGetThreadPointer();
  1362. ASSERT(ThisThread);
  1363. DebugCell = ThisThread->DebugCell;
  1364. if (DebugCell)
  1365. {
  1366. if (this->DebugCell)
  1367. {
  1368. GetDebugCellIDFromDebugCell(
  1369. (DebugCellUnion *)this->DebugCell,
  1370. &this->DebugCellTag,
  1371. &ThisThread->DebugCell->Endpoint);
  1372. }
  1373. }
  1374. for (;;)
  1375. {
  1376. if (LrpcMessage == 0)
  1377. {
  1378. while ((LrpcMessage = AllocateMessage()) == 0)
  1379. {
  1380. Sleep(100) ;
  1381. }
  1382. }
  1383. ASSERT(LrpcReplyMessage == 0
  1384. || LrpcReplyMessage->Rpc.RpcHeader.MessageType <= MAX_LRPC_MSG);
  1385. if (DebugCell)
  1386. {
  1387. DebugCell->Status = dtsIdle;
  1388. DebugCell->LastUpdateTime = NtGetTickCount();
  1389. }
  1390. RpcpPurgeEEInfoFromThreadIfNecessary(ThisThread);
  1391. NtStatus = NtReplyWaitReceivePortEx(LpcAddressPort,
  1392. (PVOID *) &Key,
  1393. (PORT_MESSAGE *) LrpcReplyMessage,
  1394. (PORT_MESSAGE *) LrpcMessage,
  1395. pliTimeout);
  1396. AssociationKey = (ULONG) Key; // need this for 64bit
  1397. if (NtStatus != STATUS_TIMEOUT
  1398. && NT_SUCCESS(NtStatus))
  1399. {
  1400. if (pliTimeout != &ShortTimeout)
  1401. {
  1402. #if defined (RPC_GC_AUDIT)
  1403. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) LPC Thread %X: coming back from long wait\n",
  1404. GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId());
  1405. #endif
  1406. ASSERT((pliTimeout == NULL) || (pliTimeout == &LongTimeout));
  1407. ThreadsDoingLongWait.Decrement();
  1408. pliTimeout = &ShortTimeout;
  1409. }
  1410. if (DebugCell)
  1411. {
  1412. DebugCell->Status = dtsProcessing;
  1413. DebugCell->LastUpdateTime = NtGetTickCount();
  1414. }
  1415. #if 0
  1416. if (LrpcMessage->LpcHeader.u2.s2.Type == LPC_CONNECTION_REQUEST)
  1417. LogEvent(SU_PACKET, EV_PKT_IN, (void *) LrpcMessage->LpcHeader.u2.ZeroInit,
  1418. (void *)LrpcMessage->Connect.BindExchange.ConnectType, AssociationKey);
  1419. else
  1420. LogEvent(SU_PACKET, EV_PKT_IN, (void *) LrpcMessage->LpcHeader.u2.ZeroInit,
  1421. 0, AssociationKey);
  1422. #endif
  1423. if (LrpcMessage->LpcHeader.u2.s2.Type == LPC_DATAGRAM
  1424. || LrpcMessage->LpcHeader.u2.s2.Type == LPC_REQUEST)
  1425. {
  1426. if (!SERVERKEY(AssociationKey))
  1427. {
  1428. VALIDATE(LrpcMessage->Bind.MessageType)
  1429. {
  1430. LRPC_MSG_FAULT,
  1431. LRPC_MSG_FAULT2,
  1432. LRPC_MSG_RESPONSE,
  1433. LRPC_CLIENT_SEND_MORE
  1434. } END_VALIDATE;
  1435. //
  1436. // response or fault on the back connection.
  1437. // we are using async rpc or pipes
  1438. //
  1439. CAssociation = ReferenceClientAssoc(AssociationKey);
  1440. if (CAssociation)
  1441. {
  1442. BeginLongCall();
  1443. LrpcReplyMessage = 0;
  1444. CAssociation->ProcessResponse(LrpcMessage, &LrpcReplyMessage);
  1445. //
  1446. // the receive thread needs to allocate a new message
  1447. //
  1448. LrpcMessage = 0 ;
  1449. CAssociation->RemoveReference() ;
  1450. EndLongCall();
  1451. }
  1452. else
  1453. {
  1454. HandleInvalidAssociationReference(LrpcMessage,
  1455. &LrpcReplyMessage,
  1456. AssociationKey);
  1457. }
  1458. continue;
  1459. }
  1460. Association = ReferenceAssociation(AssociationKey);
  1461. if (Association == 0)
  1462. {
  1463. HandleInvalidAssociationReference(LrpcMessage,
  1464. &LrpcReplyMessage,
  1465. AssociationKey);
  1466. continue;
  1467. }
  1468. ReplyKey = AssociationKey;
  1469. Flags = LrpcMessage->Rpc.RpcHeader.Flags ;
  1470. PartialFlag = FALSE ;
  1471. if (LrpcMessage->Bind.MessageType == LRPC_MSG_REQUEST)
  1472. {
  1473. //
  1474. // Optimize the common case
  1475. //
  1476. fStatus = DealWithLRPCRequest (
  1477. LrpcMessage,
  1478. Reply,
  1479. Association,
  1480. &LrpcReplyMessage) ;
  1481. if (fStatus)
  1482. {
  1483. // this is the first of two exits from the loop
  1484. // (the second is below)
  1485. if (DebugCell)
  1486. {
  1487. DebugCell->Status = dtsAllocated;
  1488. DebugCell->LastUpdateTime = NtGetTickCount();
  1489. }
  1490. return;
  1491. }
  1492. if (LrpcReplyMessage == 0)
  1493. {
  1494. LrpcMessage = 0;
  1495. }
  1496. else
  1497. {
  1498. DereferenceAssociation(Association);
  1499. }
  1500. }
  1501. else
  1502. {
  1503. switch (LrpcMessage->Bind.MessageType)
  1504. {
  1505. case LRPC_PARTIAL_REQUEST:
  1506. case LRPC_SERVER_SEND_MORE:
  1507. case LRPC_MSG_CANCEL:
  1508. LrpcReplyMessage = Association->
  1509. DealWithPartialRequest(&LrpcMessage) ;
  1510. break;
  1511. case LRPC_MSG_COPY:
  1512. LrpcReplyMessage = Association->DealWithCopyMessage(
  1513. (LRPC_COPY_MESSAGE *)LrpcMessage);
  1514. break;
  1515. case LRPC_MSG_BIND :
  1516. Association->DealWithBindMessage(LrpcMessage);
  1517. LrpcReplyMessage = 0 ;
  1518. break;
  1519. case LRPC_MSG_BIND_BACK:
  1520. BeginLongCall();
  1521. LrpcReplyMessage = Association->
  1522. DealWithBindBackMessage(LrpcMessage);
  1523. EndLongCall();
  1524. break;
  1525. default:
  1526. #if DBG
  1527. PrintToDebugger("RPC : Bad Message Type (%d) - %d\n",
  1528. LrpcMessage->Bind.MessageType,
  1529. LrpcMessage->LpcHeader.u2.s2.Type);
  1530. #endif // DBG
  1531. ASSERT(0) ;
  1532. LrpcReplyMessage = 0 ;
  1533. Association->Delete();
  1534. break;
  1535. }
  1536. DereferenceAssociation(Association);
  1537. }
  1538. }
  1539. else
  1540. {
  1541. switch (LrpcMessage->LpcHeader.u2.s2.Type)
  1542. {
  1543. case LPC_CONNECTION_REQUEST:
  1544. if (LrpcMessage->Connect.BindExchange.ConnectType
  1545. == LRPC_CONNECT_REQUEST)
  1546. {
  1547. BeginLongCall();
  1548. DealWithNewClient(LrpcMessage) ;
  1549. EndLongCall();
  1550. }
  1551. else if (LrpcMessage->Connect.BindExchange.ConnectType
  1552. == LRPC_CONNECT_RESPONSE)
  1553. {
  1554. DealWithConnectResponse(LrpcMessage) ;
  1555. }
  1556. else if (LrpcMessage->Connect.BindExchange.ConnectType
  1557. == LRPC_CONNECT_TICKLE)
  1558. {
  1559. HANDLE Ignore;
  1560. // always reject - this just has the purpose of tickling
  1561. // a thread on a long wait
  1562. NtStatus = NtAcceptConnectPort(&Ignore,
  1563. NULL,
  1564. (PORT_MESSAGE *) LrpcMessage,
  1565. FALSE,
  1566. NULL,
  1567. NULL);
  1568. #if defined (RPC_GC_AUDIT)
  1569. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) LPC Thread %X: tickled\n",
  1570. GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId());
  1571. #endif
  1572. }
  1573. else
  1574. {
  1575. ASSERT(0) ;
  1576. }
  1577. LrpcReplyMessage = 0;
  1578. break;
  1579. case LPC_CLIENT_DIED:
  1580. LrpcReplyMessage = 0;
  1581. break;
  1582. case LPC_PORT_CLOSED:
  1583. if (SERVERKEY(AssociationKey))
  1584. {
  1585. Association = ReferenceAssociation(AssociationKey);
  1586. if (Association == 0)
  1587. {
  1588. LrpcReplyMessage = 0;
  1589. continue;
  1590. }
  1591. BeginLongCall();
  1592. Association->Delete();
  1593. DereferenceAssociation(Association);
  1594. LrpcReplyMessage = 0;
  1595. EndLongCall();
  1596. }
  1597. else
  1598. {
  1599. CAssociation = ReferenceClientAssoc(AssociationKey);
  1600. if (CAssociation)
  1601. {
  1602. BeginLongCall();
  1603. CAssociation->AbortAssociation(1) ;
  1604. CAssociation->RemoveReference() ;
  1605. EndLongCall();
  1606. }
  1607. LrpcReplyMessage = 0;
  1608. }
  1609. continue;
  1610. default:
  1611. LrpcReplyMessage = 0 ;
  1612. ASSERT(0);
  1613. } // switch
  1614. } // else
  1615. } // if
  1616. else
  1617. {
  1618. switch (NtStatus)
  1619. {
  1620. case STATUS_NO_MEMORY:
  1621. case STATUS_INSUFFICIENT_RESOURCES:
  1622. case STATUS_UNSUCCESSFUL:
  1623. PauseExecution(500L);
  1624. break;
  1625. case STATUS_TIMEOUT:
  1626. #if defined (RPC_GC_AUDIT)
  1627. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) LPC Thread %X: timed out - gc\n",
  1628. GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId());
  1629. #endif
  1630. PerformGarbageCollection();
  1631. if (pliTimeout == &ShortTimeout)
  1632. {
  1633. // be conservative and presume we will
  1634. // be doing long wait. If later we find out
  1635. // we won't, we'll reverse that. Also, this must
  1636. // be done nefore we check for
  1637. // GarbageCollectedRequested - this allows other
  1638. // threads to safely count the number of threads
  1639. // on short wait without taking a mutex
  1640. ThreadsDoingLongWait.Increment();
  1641. LrpcReplyMessage = 0;
  1642. // if there is garbage collection
  1643. // requested, don't switch to long
  1644. // wait
  1645. if (GarbageCollectionRequested)
  1646. {
  1647. #if defined (RPC_GC_AUDIT)
  1648. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) LPC Thread %X: gc requested - can't do long wait\n",
  1649. GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId());
  1650. #endif
  1651. ThreadsDoingLongWait.Decrement();
  1652. }
  1653. else
  1654. {
  1655. #if defined (RPC_GC_AUDIT)
  1656. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) LPC Thread %X: going to long wait\n",
  1657. GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId());
  1658. #endif
  1659. // there is no garbage collection requested
  1660. // switch to longer wait (but not infinite yet)
  1661. pliTimeout = &LongTimeout;
  1662. }
  1663. }
  1664. else if (pliTimeout == &LongTimeout)
  1665. {
  1666. // if this is a long wait, and we're a spare
  1667. // thread, we can go
  1668. AddressMutex.Request();
  1669. if (CallThreadCount - ActiveCallCount > 1)
  1670. {
  1671. CallThreadCount -= 1;
  1672. ASSERT(CallThreadCount > ActiveCallCount);
  1673. AddressMutex.Clear();
  1674. // decrease the counter of threads doing long
  1675. // listen after we decrease the CallThreadCount
  1676. // This allows other threads to use the number
  1677. // of threads doing short wait without taking
  1678. // a mutex
  1679. ThreadsDoingLongWait.Decrement();
  1680. FreeMessage(LrpcMessage);
  1681. // N.B. This is the second exit from the loop (see above)
  1682. if (DebugCell)
  1683. {
  1684. DebugCell->Status = dtsAllocated;
  1685. DebugCell->LastUpdateTime = NtGetTickCount();
  1686. }
  1687. return ;
  1688. }
  1689. else
  1690. {
  1691. //
  1692. // We are assuming that if the call has timed out, the reply has
  1693. // been sent
  1694. //
  1695. LrpcReplyMessage = 0;
  1696. pliTimeout = NULL;
  1697. #if defined (RPC_GC_AUDIT)
  1698. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) LPC Thread %X: going to infinite wait\n",
  1699. GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId());
  1700. #endif
  1701. }
  1702. AddressMutex.Clear();
  1703. }
  1704. else
  1705. {
  1706. ASSERT(!"We cannot get a timeout on wait with infinite timeout");
  1707. }
  1708. if (DebugCell)
  1709. {
  1710. RelocateCellIfPossible((void **) &DebugCell, &ThisThread->DebugCellTag);
  1711. ThisThread->DebugCell = DebugCell;
  1712. }
  1713. break;
  1714. default:
  1715. if (LrpcReplyMessage)
  1716. {
  1717. LrpcReplyMessage = 0;
  1718. if (ReplyKey != -1)
  1719. {
  1720. Association = ReferenceAssociation(ReplyKey);
  1721. if (Association == 0)
  1722. {
  1723. continue;
  1724. }
  1725. }
  1726. else
  1727. continue;
  1728. BeginLongCall();
  1729. Association->Delete();
  1730. DereferenceAssociation(Association);
  1731. EndLongCall();
  1732. }
  1733. break;
  1734. } // switch
  1735. } // else
  1736. } // for
  1737. }
  1738. #define DEFAULT_PORT_DIR "\\RPC Control\\"
  1739. #define DEFAULT_PORT_NAME "ARPC Port1"
  1740. #define DEFAULT_REPLY_NAME "ARPC Reply Port"
  1741. void
  1742. LRPC_ADDRESS::DealWithNewClient (
  1743. IN LRPC_MESSAGE * ConnectionRequest
  1744. )
  1745. /*++
  1746. Routine Description:
  1747. A new client has connected with our address port. We need to take
  1748. care of the new client and send a response.
  1749. Arguments:
  1750. ConnectionRequest - Supplies information need by LPC to abort the
  1751. connect request. Includes the bind request from the client.
  1752. This contains the information about which interface the client
  1753. wants to bind with. and which we use to send the status code
  1754. back in.
  1755. --*/
  1756. {
  1757. LRPC_SASSOCIATION * Association;
  1758. NTSTATUS NtStatus;
  1759. RPC_STATUS Status = RPC_S_OK;
  1760. DWORD Key;
  1761. LPC_KEY *LpcKey = (LPC_KEY *) &Key;
  1762. Association = new LRPC_SASSOCIATION(this,
  1763. &Status);
  1764. if (Association == 0)
  1765. {
  1766. RejectNewClient(ConnectionRequest, RPC_S_OUT_OF_MEMORY);
  1767. return;
  1768. }
  1769. if (Status != RPC_S_OK)
  1770. {
  1771. delete Association ;
  1772. RejectNewClient(ConnectionRequest, RPC_S_OUT_OF_MEMORY);
  1773. return ;
  1774. }
  1775. AddressMutex.Request();
  1776. Association->DictionaryKey = (unsigned short)
  1777. AssociationDictionary.Insert(Association);
  1778. AssociationCount++;
  1779. SequenceNumber = (SequenceNumber+1) % (0x7FFF);
  1780. Association->SequenceNumber = SequenceNumber;
  1781. AddressMutex.Clear();
  1782. if (Association->DictionaryKey == -1)
  1783. {
  1784. AddressMutex.Request();
  1785. AssociationCount-- ;
  1786. AddressMutex.Clear();
  1787. delete Association ;
  1788. RejectNewClient(ConnectionRequest, RPC_S_OUT_OF_MEMORY);
  1789. return;
  1790. }
  1791. if (ConnectionRequest->Connect.BindExchange.Flags & BIND_BACK_FLAG)
  1792. {
  1793. ConnectionRequest->Connect.BindExchange.szPortName[PORT_NAME_LEN-1] = NULL;
  1794. Status = Association->BindBack(
  1795. (RPC_CHAR *)ConnectionRequest->Connect.BindExchange.szPortName,
  1796. ConnectionRequest->Connect.BindExchange.AssocKey) ;
  1797. if (Status != RPC_S_OK)
  1798. {
  1799. RejectNewClient(ConnectionRequest, RPC_S_OUT_OF_MEMORY);
  1800. Association->Delete() ;
  1801. return;
  1802. }
  1803. }
  1804. ConnectionRequest->Connect.BindExchange.RpcStatus = RPC_S_OK;
  1805. ASSERT(sizeof(unsigned long) <= sizeof(PVOID));
  1806. ASSERT((Association->SequenceNumber & SERVER_KEY_MASK) == 0);
  1807. LpcKey->SeqNumber = Association->SequenceNumber | SERVER_KEY_MASK;
  1808. LpcKey->AssocKey = Association->DictionaryKey;
  1809. // After the call to NtAcceptConnectPort, the client will become unblocked
  1810. // the association will be in the dictionary and will have refcount 1. If the client quits
  1811. // or closes port the association will be deleted. Then NtCompleteConnectPort
  1812. // may touch invalid memory or operate on a bad handle. To prevent that we
  1813. // need to hold an extra count between the two calls.
  1814. //
  1815. // Since this thread is the only one playing with the association up to now,
  1816. // there is no need for a lock.
  1817. Association->AssociationReferenceCount++;
  1818. NtStatus = NtAcceptConnectPort(&(Association->LpcServerPort),
  1819. ULongToPtr(Key),
  1820. (PORT_MESSAGE *) ConnectionRequest,
  1821. TRUE,
  1822. NULL,
  1823. NULL);
  1824. if (NT_ERROR(NtStatus))
  1825. {
  1826. Association->Delete();
  1827. // We just have to dereference the association to remove the extra
  1828. // count added above. This should cause its deletion.
  1829. DereferenceAssociation(Association);
  1830. #if DBG
  1831. PrintToDebugger("RPC : NtAcceptConnectPort : %lx\n", NtStatus);
  1832. #endif // DBG
  1833. return;
  1834. }
  1835. NtStatus = NtCompleteConnectPort(Association->LpcServerPort);
  1836. if (NT_ERROR(NtStatus))
  1837. {
  1838. #if DBG
  1839. PrintToDebugger("RPC : NtCompleteConnectPort : %lx\n", NtStatus);
  1840. #endif // DBG
  1841. // If Association->Delete() has already been called on a different
  1842. // theread due to a closed client port, this call will be ignored...
  1843. Association->Delete();
  1844. // and the final reference will be removed here causing a deletion.
  1845. DereferenceAssociation(Association);
  1846. return;
  1847. }
  1848. // Remove the extra-reference.
  1849. DereferenceAssociation(Association);
  1850. }
  1851. void
  1852. LRPC_ADDRESS::DealWithConnectResponse (
  1853. IN LRPC_MESSAGE * ConnectResponse
  1854. )
  1855. /*++
  1856. Routine Description:
  1857. Just received a connect response from the remove server,
  1858. need to handle that.
  1859. Arguments:
  1860. ConnectionRequest -
  1861. Needed to get the pAssoc
  1862. --*/
  1863. {
  1864. NTSTATUS NtStatus;
  1865. HANDLE temp ;
  1866. LRPC_CASSOCIATION * Association ;
  1867. DWORD Key;
  1868. Key = ConnectResponse->Connect.BindExchange.AssocKey;
  1869. Association = ReferenceClientAssoc(Key);
  1870. if (Association == 0)
  1871. {
  1872. RejectNewClient(ConnectResponse, RPC_S_PROTOCOL_ERROR);
  1873. return;
  1874. }
  1875. NtStatus = NtAcceptConnectPort(&temp,
  1876. ULongToPtr(Key),
  1877. (PPORT_MESSAGE) ConnectResponse,
  1878. TRUE,
  1879. NULL,
  1880. NULL);
  1881. if (NT_SUCCESS(NtStatus))
  1882. {
  1883. Association->SetReceivePort(temp) ;
  1884. NtStatus = NtCompleteConnectPort(temp);
  1885. if (!NT_SUCCESS(NtStatus))
  1886. {
  1887. #if DBG
  1888. PrintToDebugger("LRPC: NtCompleteConnectPort(1) failed: %lx\n",
  1889. NtStatus) ;
  1890. #endif
  1891. Association->Delete();
  1892. }
  1893. }
  1894. else
  1895. {
  1896. #if DBG
  1897. PrintToDebugger("LRPC: NtAcceptConnectionPort(1) failed: %lx\n",
  1898. NtStatus) ;
  1899. #endif
  1900. Association->Delete();
  1901. }
  1902. //
  1903. // Remove the reference we added above
  1904. //
  1905. Association->RemoveReference() ;
  1906. }
  1907. void
  1908. LRPC_ADDRESS::RejectNewClient (
  1909. IN LRPC_MESSAGE * ConnectionRequest,
  1910. IN RPC_STATUS Status
  1911. )
  1912. /*++
  1913. Routine Description:
  1914. A new client has connected with our address port. We need to reject
  1915. the client.
  1916. Arguments:
  1917. ConnectionRequest - Supplies information need by LPC to abort the
  1918. connect request. Includes the bind request from the client,
  1919. which we use to send the status code back in.
  1920. Status - Supplies the reason the client is being rejected.
  1921. --*/
  1922. {
  1923. NTSTATUS NtStatus;
  1924. HANDLE Ignore;
  1925. ASSERT(Status != RPC_S_OK);
  1926. ConnectionRequest->Connect.BindExchange.RpcStatus = Status;
  1927. ConnectionRequest->Connect.BindExchange.Flags |= SERVER_BIND_EXCH_RESP;
  1928. NtStatus = NtAcceptConnectPort(&Ignore,
  1929. NULL,
  1930. (PORT_MESSAGE *) ConnectionRequest,
  1931. FALSE,
  1932. NULL,
  1933. NULL);
  1934. #if DBG
  1935. if (!NT_SUCCESS(NtStatus))
  1936. {
  1937. PrintToDebugger("RPC : NtAcceptConnectPort : %lx\n", NtStatus);
  1938. // if the client thread dies for whatever reason, NtAcceptConnectPort
  1939. // can return STATUS_REPLY_MESSAGE_MISMATCH
  1940. VALIDATE(NtStatus)
  1941. {
  1942. STATUS_INVALID_CID,
  1943. STATUS_REPLY_MESSAGE_MISMATCH
  1944. } END_VALIDATE;
  1945. }
  1946. #endif // DBG
  1947. }
  1948. void
  1949. LRPC_ADDRESS::EnumerateAndCallEachAssociation (
  1950. IN AssociationCallbackType asctType,
  1951. IN OUT void *Context OPTIONAL
  1952. )
  1953. /*++
  1954. Function Name: EnumerateAndCallEachAssociation
  1955. Parameters:
  1956. asctType - type of callback to make
  1957. Context - opaque memory block specific for the callback
  1958. type.
  1959. Description:
  1960. Common infrastructure for calling into each association
  1961. Returns:
  1962. --*/
  1963. {
  1964. LRPC_SASSOCIATION *CurrentAssociation;
  1965. BOOL CopyOfDictionaryUsed;
  1966. LRPC_SASSOCIATION_DICT AssocDictCopy;
  1967. LRPC_SASSOCIATION_DICT *AssocDictToUse;
  1968. BOOL Res;
  1969. DictionaryCursor cursor;
  1970. DestroyContextHandleCallbackContext *CallbackContext;
  1971. AddressMutex.Request();
  1972. CopyOfDictionaryUsed = AssocDictCopy.ExpandToSize(AssociationDictionary.Size());
  1973. if (CopyOfDictionaryUsed)
  1974. {
  1975. AssociationDictionary.Reset(cursor);
  1976. while ( (CurrentAssociation = AssociationDictionary.Next(cursor)) != 0 )
  1977. {
  1978. Res = AssocDictCopy.Insert(CurrentAssociation);
  1979. ASSERT(Res != -1);
  1980. // artifically add a count to keep it alive
  1981. // while we destroy the contexts
  1982. CurrentAssociation->AssociationReferenceCount++;
  1983. }
  1984. AddressMutex.Clear();
  1985. AssocDictToUse = &AssocDictCopy;
  1986. }
  1987. else
  1988. {
  1989. AssocDictToUse = &AssociationDictionary;
  1990. }
  1991. AssocDictToUse->Reset(cursor);
  1992. while ( (CurrentAssociation = AssocDictToUse->Next(cursor)) != 0 )
  1993. {
  1994. switch (asctType)
  1995. {
  1996. case asctDestroyContextHandle:
  1997. CallbackContext = (DestroyContextHandleCallbackContext *)Context;
  1998. // call into the association to destroy the context handles
  1999. CurrentAssociation->DestroyContextHandlesForInterface(
  2000. CallbackContext->RpcInterfaceInformation,
  2001. CallbackContext->RundownContextHandles);
  2002. break;
  2003. case asctCleanupIdleSContext:
  2004. CurrentAssociation->CleanupIdleSContexts();
  2005. break;
  2006. default:
  2007. ASSERT(0);
  2008. }
  2009. }
  2010. if (CopyOfDictionaryUsed)
  2011. {
  2012. while ( (CurrentAssociation = AssocDictCopy.Next(cursor)) != 0 )
  2013. {
  2014. // remove the extra refcounts
  2015. DereferenceAssociation(CurrentAssociation);
  2016. }
  2017. }
  2018. else
  2019. {
  2020. AddressMutex.Clear();
  2021. }
  2022. }
  2023. void
  2024. LRPC_ADDRESS::DestroyContextHandlesForInterface (
  2025. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
  2026. IN BOOL RundownContextHandles
  2027. )
  2028. /*++
  2029. Function Name: DestroyContextHandlesForInterface
  2030. Parameters:
  2031. RpcInterfaceInformation - the interface for which context handles
  2032. are to be unregistered
  2033. RundownContextHandles - if non-zero, rundown the context handles. If
  2034. FALSE, destroy the runtime portion of the context handle resource,
  2035. but don't call the user rundown routine.
  2036. Description:
  2037. The implementation for context handle destruction for the local RPC
  2038. (LRPC). Using the callback infrastructure it will walk the list of
  2039. associations, and for each one it will ask the association to
  2040. destroy the context handles for that interface.
  2041. Returns:
  2042. --*/
  2043. {
  2044. DestroyContextHandleCallbackContext CallbackContext;
  2045. CallbackContext.RpcInterfaceInformation = RpcInterfaceInformation;
  2046. CallbackContext.RundownContextHandles = RundownContextHandles;
  2047. EnumerateAndCallEachAssociation(asctDestroyContextHandle,
  2048. &CallbackContext);
  2049. }
  2050. void
  2051. LRPC_ADDRESS::CleanupIdleSContexts (
  2052. void
  2053. )
  2054. /*++
  2055. Function Name: CleanupIdleSContexts
  2056. Parameters:
  2057. Description:
  2058. The implementation for idle SContext cleanup for the local RPC
  2059. (LRPC). Using the callback infrastructure it will walk the list of
  2060. associations, and for each one it will ask the association to
  2061. destroy the idle scontexts
  2062. Returns:
  2063. --*/
  2064. {
  2065. LogEvent(SU_GC, EV_PRUNE, this, 0, 0, 0, 0);
  2066. EnumerateAndCallEachAssociation(asctCleanupIdleSContext,
  2067. NULL);
  2068. }
  2069. BOOL
  2070. LRPC_ADDRESS::PrepareForLoopbackTickling (
  2071. void
  2072. )
  2073. {
  2074. RPC_CHAR * LpcPortName;
  2075. int DirectoryNameLength;
  2076. int EndpointLength;
  2077. LrpcMutexVerifyOwned();
  2078. DirectoryNameLength = RpcpStringLength(LRPC_DIRECTORY_NAME);
  2079. EndpointLength = RpcpStringLength(InqEndpoint());
  2080. LpcPortName = new RPC_CHAR[
  2081. EndpointLength
  2082. + DirectoryNameLength + 1];
  2083. if (LpcPortName == 0)
  2084. {
  2085. return FALSE;
  2086. }
  2087. TickleMessage = new LRPC_BIND_EXCHANGE;
  2088. if (TickleMessage == NULL)
  2089. {
  2090. delete LpcPortName;
  2091. return FALSE;
  2092. }
  2093. RpcpMemoryCopy(LpcPortName, LRPC_DIRECTORY_NAME,
  2094. DirectoryNameLength * sizeof(RPC_CHAR));
  2095. RpcpMemoryCopy(LpcPortName + DirectoryNameLength,
  2096. InqEndpoint(),
  2097. (EndpointLength + 1) * sizeof(RPC_CHAR));
  2098. RtlInitUnicodeString(&ThisAddressLoopbackString, LpcPortName);
  2099. return TRUE;
  2100. }
  2101. BOOL
  2102. LRPC_ADDRESS::LoopbackTickle (
  2103. void
  2104. )
  2105. {
  2106. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  2107. HANDLE LoopbackPort;
  2108. ULONG TickleMessageLength = sizeof(LRPC_BIND_EXCHANGE);
  2109. NTSTATUS NtStatus;
  2110. ASSERT (IsPreparedForLoopbackTickling());
  2111. SecurityQualityOfService.EffectiveOnly = FALSE;
  2112. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  2113. SecurityQualityOfService.ImpersonationLevel = SecurityAnonymous;
  2114. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  2115. TickleMessage->ConnectType = LRPC_CONNECT_TICKLE ;
  2116. // TickleMessage->AssocKey = Key;
  2117. TickleMessage->Flags = 0;
  2118. NtStatus = NtConnectPort(
  2119. &LoopbackPort,
  2120. &ThisAddressLoopbackString,
  2121. &SecurityQualityOfService,
  2122. NULL,
  2123. NULL,
  2124. NULL,
  2125. TickleMessage,
  2126. &TickleMessageLength);
  2127. if (NtStatus == STATUS_PORT_CONNECTION_REFUSED)
  2128. return TRUE;
  2129. else
  2130. {
  2131. ASSERT(NtStatus != RPC_S_OK);
  2132. return FALSE;
  2133. }
  2134. }
  2135. LRPC_SASSOCIATION::LRPC_SASSOCIATION (
  2136. IN LRPC_ADDRESS * Address,
  2137. IN RPC_STATUS *Status
  2138. ) : AssociationMutex(Status)
  2139. /*++
  2140. --*/
  2141. {
  2142. ObjectType = LRPC_SASSOCIATION_TYPE;
  2143. LpcServerPort = 0;
  2144. LpcReplyPort = 0 ;
  2145. this->Address = Address;
  2146. AssociationReferenceCount = 1;
  2147. Aborted = 0 ;
  2148. Deleted = -1 ;
  2149. if (*Status == RPC_S_OK)
  2150. {
  2151. CachedSCall = new LRPC_SCALL(Status);
  2152. if (CachedSCall == 0)
  2153. {
  2154. *Status = RPC_S_OUT_OF_MEMORY;
  2155. }
  2156. }
  2157. else
  2158. {
  2159. CachedSCall = NULL;
  2160. }
  2161. CachedSCallAvailable = 0;
  2162. fFirstCall = 0;
  2163. }
  2164. LRPC_SASSOCIATION::~LRPC_SASSOCIATION (
  2165. )
  2166. /*++
  2167. Routine Description:
  2168. We will call this routine when the client has notified us that this port
  2169. has closed, and there are no calls outstanding on it.
  2170. --*/
  2171. {
  2172. PVOID Buffer;
  2173. LRPC_SBINDING * Binding;
  2174. LRPC_SCALL *SCall ;
  2175. unsigned int Length ;
  2176. LRPC_SCONTEXT *SContext;
  2177. DictionaryCursor cursor;
  2178. while (SCall = (LRPC_SCALL *) FreeSCallQueue.TakeOffQueue(&Length))
  2179. {
  2180. delete SCall;
  2181. }
  2182. Bindings.Reset(cursor);
  2183. while ((Binding = Bindings.Next(cursor)) != 0)
  2184. {
  2185. delete Binding;
  2186. }
  2187. if (CachedSCall)
  2188. {
  2189. delete CachedSCall;
  2190. }
  2191. SContextDict.Reset(cursor);
  2192. while ((SContext = SContextDict.Next(cursor)) != 0)
  2193. {
  2194. delete SContext;
  2195. }
  2196. }
  2197. RPC_STATUS
  2198. LRPC_SASSOCIATION::AllocateSCall (
  2199. IN LRPC_MESSAGE * LrpcMessage,
  2200. IN LRPC_MESSAGE * LrpcReplyMessage,
  2201. IN unsigned int Flags,
  2202. IN LRPC_SCALL **SCall
  2203. )
  2204. /*++
  2205. Routine Description:
  2206. Allocate an SCall
  2207. Arguments:
  2208. LrpcMessage - Request message
  2209. LrpcReplyMessage - Reply message
  2210. Flags - Request flags
  2211. Return Value:
  2212. Pointer to the SCall
  2213. --*/
  2214. {
  2215. unsigned int Length ;
  2216. RPC_STATUS Status ;
  2217. LRPC_SCALL *NewSCall;
  2218. *SCall = NULL;
  2219. if (InterlockedIncrement(&CachedSCallAvailable) == 1)
  2220. {
  2221. NewSCall = CachedSCall;
  2222. }
  2223. else
  2224. {
  2225. AssociationMutex.Request() ;
  2226. NewSCall = (LRPC_SCALL *) FreeSCallQueue.TakeOffQueue(&Length) ;
  2227. AssociationMutex.Clear() ;
  2228. if (NewSCall == 0)
  2229. {
  2230. NewSCall = new LRPC_SCALL(&Status) ;
  2231. if (NewSCall == 0)
  2232. {
  2233. return RPC_S_OUT_OF_MEMORY;
  2234. }
  2235. if (Status != RPC_S_OK)
  2236. {
  2237. delete NewSCall;
  2238. return Status;
  2239. }
  2240. }
  2241. }
  2242. Status = NewSCall->ActivateCall(this,
  2243. LrpcMessage,
  2244. LrpcReplyMessage,
  2245. Flags) ;
  2246. if ((Flags & LRPC_BUFFER_PARTIAL)
  2247. || NewSCall->IsClientAsync())
  2248. {
  2249. Status = NewSCall->SetupCall() ;
  2250. if (Status != RPC_S_OK)
  2251. {
  2252. if (NewSCall != CachedSCall)
  2253. {
  2254. delete NewSCall ;
  2255. }
  2256. return RPC_S_OUT_OF_MEMORY ;
  2257. }
  2258. }
  2259. LogEvent(SU_SCALL, EV_CREATE, NewSCall, 0, Flags, 1);
  2260. *SCall = NewSCall;
  2261. return RPC_S_OK;
  2262. }
  2263. void
  2264. LRPC_SASSOCIATION::FreeSCall (
  2265. IN LRPC_SCALL *SCall
  2266. )
  2267. /*++
  2268. Routine Description:
  2269. Free the SCall
  2270. Arguments:
  2271. SCall - Pointer to the SCall object
  2272. --*/
  2273. {
  2274. ASSERT(SCall->pAsync != (PRPC_ASYNC_STATE) -1);
  2275. if (SCall->pAsync)
  2276. {
  2277. SCall->DoPostDispatchProcessing();
  2278. }
  2279. if (SCall->SBinding
  2280. && SCall->SBinding->RpcInterface->IsAutoListenInterface())
  2281. {
  2282. SCall->SBinding->RpcInterface->EndAutoListenCall() ;
  2283. }
  2284. if (SCall->ReceiveEvent)
  2285. {
  2286. AssociationMutex.Request() ;
  2287. SCallDict.Delete(ULongToPtr(SCall->CallId));
  2288. AssociationMutex.Clear() ;
  2289. }
  2290. LogEvent(SU_SCALL, EV_DELETE, SCall, SCall->pAsync, SCall->Flags, 1);
  2291. SCall->pAsync = (PRPC_ASYNC_STATE) -1;
  2292. if (SCall->SContext)
  2293. {
  2294. SCall->SContext->RemoveReference();
  2295. }
  2296. if (SCall->ClientPrincipalName != NULL)
  2297. {
  2298. delete SCall->ClientPrincipalName;
  2299. SCall->ClientPrincipalName = NULL;
  2300. }
  2301. SCall->DeactivateCall();
  2302. if (SCall == CachedSCall)
  2303. {
  2304. CachedSCallAvailable = 0;
  2305. }
  2306. else
  2307. {
  2308. AssociationMutex.Request() ;
  2309. SCall->pAsync = (PRPC_ASYNC_STATE) -1;
  2310. if (FreeSCallQueue.PutOnQueue(SCall, 0))
  2311. delete SCall ;
  2312. AssociationMutex.Clear() ;
  2313. }
  2314. }
  2315. int
  2316. LRPC_SASSOCIATION::MaybeQueueSCall (
  2317. IN LRPC_SCALL *SCall
  2318. )
  2319. /*++
  2320. Routine Description:
  2321. if the thread is currently executing a call, the call
  2322. is queued up, otherwise it is signalled to be dispatched.
  2323. Arguments:
  2324. SCall - the SCall to be dispatched.
  2325. Return Value:
  2326. 0: dispatch the call
  2327. 1: don't dispatch the call
  2328. -1: error
  2329. --*/
  2330. {
  2331. LRPC_SCALL *FirstSCall ;
  2332. int Status ;
  2333. AssociationMutex.Request() ;
  2334. FirstSCall = ClientThreadDict.Find(
  2335. MsgClientIdToClientId(SCall->LrpcRequestMessage->Rpc.LpcHeader.ClientId).UniqueThread) ;
  2336. if (FirstSCall == 0)
  2337. {
  2338. Status = ClientThreadDict.Insert(
  2339. MsgClientIdToClientId(SCall->LrpcRequestMessage->Rpc.LpcHeader.ClientId).UniqueThread,
  2340. SCall) ;
  2341. SCall->LastSCall = SCall ;
  2342. AssociationMutex.Clear() ;
  2343. VALIDATE(Status)
  2344. {
  2345. 0,
  2346. -1
  2347. } END_VALIDATE;
  2348. return Status ;
  2349. }
  2350. ASSERT(FirstSCall->LastSCall);
  2351. FirstSCall->LastSCall->NextSCall = SCall ;
  2352. FirstSCall->LastSCall = SCall ;
  2353. AssociationMutex.Clear() ;
  2354. return 1 ;
  2355. }
  2356. LRPC_SCALL *
  2357. LRPC_SASSOCIATION::GetNextSCall (
  2358. IN LRPC_SCALL *SCall
  2359. )
  2360. /*++
  2361. Routine Description:
  2362. description
  2363. Arguments:
  2364. SCall - description
  2365. Return Value:
  2366. --*/
  2367. {
  2368. LRPC_SCALL *NextSCall ;
  2369. ASSERT(SCall) ;
  2370. AssociationMutex.Request() ;
  2371. NextSCall = SCall->NextSCall ;
  2372. if (NextSCall != 0)
  2373. {
  2374. ASSERT(SCall->LastSCall);
  2375. NextSCall->LastSCall = SCall->LastSCall ;
  2376. ClientThreadDict.Update (
  2377. MsgClientIdToClientId(SCall->LrpcRequestMessage->Rpc.LpcHeader.ClientId).UniqueThread,
  2378. NextSCall) ;
  2379. }
  2380. else
  2381. {
  2382. ClientThreadDict.Delete (
  2383. MsgClientIdToClientId(SCall->LrpcRequestMessage->Rpc.LpcHeader.ClientId).UniqueThread) ;
  2384. }
  2385. AssociationMutex.Clear() ;
  2386. return NextSCall ;
  2387. }
  2388. void
  2389. LRPC_SASSOCIATION::Delete(
  2390. )
  2391. /*++
  2392. Routine Description:
  2393. description
  2394. Arguments:
  2395. arg1 - description
  2396. Return Value:
  2397. RPC_S_OK - Function succeeded
  2398. RPC_S_OUT_OF_MEMORY - we ran out of memory
  2399. --*/
  2400. {
  2401. LRPC_SCALL *SCall ;
  2402. DictionaryCursor cursor;
  2403. if (InterlockedIncrement(&Deleted) == 0)
  2404. {
  2405. AssociationMutex.Request() ;
  2406. SCallDict.Reset(cursor) ;
  2407. while ((SCall = SCallDict.Next(cursor)) != 0)
  2408. {
  2409. SCall->Deleted = 1;
  2410. if (SCall->ReceiveEvent)
  2411. {
  2412. SCall->ReceiveEvent->Raise();
  2413. }
  2414. }
  2415. AssociationMutex.Clear() ;
  2416. LogEvent(SU_SASSOC, EV_DELETE,
  2417. this, 0, AssociationReferenceCount, 1, 1);
  2418. Address->DereferenceAssociation(this);
  2419. }
  2420. }
  2421. RPC_STATUS
  2422. LRPC_SASSOCIATION::BindBack (
  2423. IN RPC_CHAR *Endpoint,
  2424. IN DWORD AssocKey
  2425. )
  2426. /*++
  2427. Routine Description:
  2428. Create a back connection to the client.
  2429. Arguments:
  2430. LrpcThread - LrpcThread to connect to.
  2431. pAssoc - Pointer to client association.
  2432. Return Value:
  2433. RPC_S_OK - Function succeeded
  2434. RPC_S_OUT_OF_MEMORY - we ran out of memory
  2435. --*/
  2436. {
  2437. NTSTATUS NtStatus;
  2438. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  2439. RPC_CHAR * LpcPortName ;
  2440. UNICODE_STRING unicodePortName;
  2441. LRPC_BIND_EXCHANGE BindExchange;
  2442. unsigned long BindExchangeLength = sizeof(LRPC_BIND_EXCHANGE);
  2443. LpcPortName = new RPC_CHAR[RpcpStringLength(Endpoint)
  2444. + RpcpStringLength(LRPC_DIRECTORY_NAME) + 1];
  2445. if (LpcPortName == 0)
  2446. {
  2447. #if DBG
  2448. PrintToDebugger("LRPC: Out of memory in DealWithNewClient\n") ;
  2449. #endif
  2450. return RPC_S_OUT_OF_MEMORY ;
  2451. }
  2452. RpcpMemoryCopy(LpcPortName,
  2453. LRPC_DIRECTORY_NAME,
  2454. RpcpStringLength(LRPC_DIRECTORY_NAME) * sizeof(RPC_CHAR));
  2455. RpcpMemoryCopy(LpcPortName + RpcpStringLength(LRPC_DIRECTORY_NAME),
  2456. Endpoint,
  2457. (RpcpStringLength(Endpoint) + 1) * sizeof(RPC_CHAR));
  2458. RtlInitUnicodeString(&unicodePortName, LpcPortName);
  2459. // Hack Hack, where do I get the real QOS values from ??
  2460. SecurityQualityOfService.EffectiveOnly = TRUE;
  2461. SecurityQualityOfService.ContextTrackingMode = SECURITY_STATIC_TRACKING;
  2462. SecurityQualityOfService.ImpersonationLevel = SecurityAnonymous;
  2463. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  2464. BindExchange.ConnectType = LRPC_CONNECT_RESPONSE ;
  2465. BindExchange.AssocKey = AssocKey ;
  2466. NtStatus = NtConnectPort(&LpcReplyPort,
  2467. &unicodePortName,
  2468. &SecurityQualityOfService,
  2469. 0,
  2470. 0,
  2471. 0,
  2472. &BindExchange,
  2473. &BindExchangeLength);
  2474. delete LpcPortName ;
  2475. if (!NT_SUCCESS(NtStatus))
  2476. {
  2477. #if DBG
  2478. PrintToDebugger("LRPC: NtConnectPort : %lx\n", NtStatus);
  2479. #endif // DBG
  2480. return RPC_S_OUT_OF_MEMORY ;
  2481. }
  2482. return RPC_S_OK ;
  2483. }
  2484. LRPC_MESSAGE *
  2485. LRPC_SASSOCIATION::DealWithBindBackMessage (
  2486. IN LRPC_MESSAGE *BindBackMessage
  2487. )
  2488. /*++
  2489. Routine Description:
  2490. Used in conjuction with Async RPC. This function
  2491. creates a back connection to the client so that two asynchronous
  2492. flow of data can occur.
  2493. Arguments:
  2494. BindBackMessage - The message receive from the client
  2495. Return Value:
  2496. reply message.
  2497. --*/
  2498. {
  2499. RPC_STATUS Status ;
  2500. BindBackMessage->BindBack.szPortName[PORT_NAME_LEN-1] = NULL;
  2501. Status = BindBack((RPC_CHAR *) BindBackMessage->BindBack.szPortName,
  2502. BindBackMessage->BindBack.AssocKey) ;
  2503. BindBackMessage->Ack.MessageType = LRPC_MSG_ACK ;
  2504. BindBackMessage->Ack.RpcStatus = Status ;
  2505. BindBackMessage->LpcHeader.u1.s1.DataLength =
  2506. sizeof(LRPC_BIND_MESSAGE) - sizeof(PORT_MESSAGE);
  2507. BindBackMessage->LpcHeader.u1.s1.TotalLength =
  2508. sizeof(LRPC_BIND_MESSAGE);
  2509. if (Status != RPC_S_OK)
  2510. {
  2511. Delete() ;
  2512. }
  2513. return BindBackMessage ;
  2514. }
  2515. RPC_STATUS
  2516. LRPC_SASSOCIATION::AddBinding (
  2517. IN OUT LRPC_BIND_EXCHANGE * BindExchange
  2518. )
  2519. /*++
  2520. Routine Description:
  2521. We will attempt to add a new binding to this association.
  2522. Arguments:
  2523. BindExchange - Supplies a description of the interface to which the
  2524. client wish to bind.
  2525. Return Value:
  2526. --*/
  2527. {
  2528. RPC_STATUS Status;
  2529. RPC_SYNTAX_IDENTIFIER TransferSyntax;
  2530. RPC_INTERFACE * RpcInterface;
  2531. LRPC_SBINDING * Binding;
  2532. BOOL fIgnored;
  2533. int DictKey;
  2534. RPC_SYNTAX_IDENTIFIER ProposedSyntaxes[MaximumNumberOfTransferSyntaxes];
  2535. int PresentationContexts[MaximumNumberOfTransferSyntaxes];
  2536. int TransferSyntaxFlagSettings[MaximumNumberOfTransferSyntaxes];
  2537. int NextProposedSyntax;
  2538. int ChosenProposedTransferSyntax;
  2539. int ChosenAvailableTransferSyntax;
  2540. NextProposedSyntax = 0;
  2541. if (BindExchange->TransferSyntaxSet & TS_NDR20_FLAG)
  2542. {
  2543. RpcpMemoryCopy(&ProposedSyntaxes[NextProposedSyntax],
  2544. NDR20TransferSyntax, sizeof(RPC_SYNTAX_IDENTIFIER));
  2545. PresentationContexts[NextProposedSyntax] = (int)BindExchange->PresentationContext[0];
  2546. TransferSyntaxFlagSettings[NextProposedSyntax] = TS_NDR20_FLAG;
  2547. NextProposedSyntax ++;
  2548. }
  2549. if (BindExchange->TransferSyntaxSet & TS_NDR64_FLAG)
  2550. {
  2551. RpcpMemoryCopy(&ProposedSyntaxes[NextProposedSyntax],
  2552. NDR64TransferSyntax, sizeof(RPC_SYNTAX_IDENTIFIER));
  2553. PresentationContexts[NextProposedSyntax] = (int)BindExchange->PresentationContext[1];
  2554. TransferSyntaxFlagSettings[NextProposedSyntax] = TS_NDR64_FLAG;
  2555. NextProposedSyntax ++;
  2556. }
  2557. if (BindExchange->TransferSyntaxSet & TS_NDRTEST_FLAG)
  2558. {
  2559. RpcpMemoryCopy(&ProposedSyntaxes[NextProposedSyntax],
  2560. NDRTestTransferSyntax, sizeof(RPC_SYNTAX_IDENTIFIER));
  2561. PresentationContexts[NextProposedSyntax] = (int)BindExchange->PresentationContext[2];
  2562. TransferSyntaxFlagSettings[NextProposedSyntax] = TS_NDRTEST_FLAG;
  2563. NextProposedSyntax ++;
  2564. }
  2565. if (NextProposedSyntax == 0)
  2566. {
  2567. // no syntaxes proposed - protocol error
  2568. ASSERT(0);
  2569. return RPC_S_PROTOCOL_ERROR;
  2570. }
  2571. ASSERT(NextProposedSyntax <= MaximumNumberOfTransferSyntaxes);
  2572. Status = Address->FindInterfaceTransfer(&(BindExchange->InterfaceId),
  2573. ProposedSyntaxes,
  2574. NextProposedSyntax,
  2575. &TransferSyntax,
  2576. &RpcInterface,
  2577. &fIgnored,
  2578. &ChosenProposedTransferSyntax,
  2579. &ChosenAvailableTransferSyntax);
  2580. if (Status != RPC_S_OK)
  2581. {
  2582. return(Status);
  2583. }
  2584. ASSERT (ChosenProposedTransferSyntax < NextProposedSyntax);
  2585. Binding = new LRPC_SBINDING(RpcInterface,
  2586. ChosenAvailableTransferSyntax);
  2587. if (Binding == 0)
  2588. {
  2589. return(RPC_S_OUT_OF_MEMORY);
  2590. }
  2591. Binding->SetPresentationContext(PresentationContexts[ChosenProposedTransferSyntax]);
  2592. DictKey = (unsigned char) Bindings.Insert(Binding);
  2593. if (DictKey == -1)
  2594. {
  2595. delete Binding;
  2596. return(RPC_S_OUT_OF_MEMORY);
  2597. }
  2598. BindExchange->TransferSyntaxSet = TransferSyntaxFlagSettings[ChosenProposedTransferSyntax];
  2599. return(RPC_S_OK);
  2600. }
  2601. RPC_STATUS
  2602. LRPC_SASSOCIATION::SaveToken (
  2603. IN LRPC_MESSAGE *LrpcMessage,
  2604. OUT HANDLE *pTokenHandle,
  2605. IN BOOL fRestoreToken
  2606. )
  2607. /*++
  2608. Routine Description:
  2609. Impersonate the client and save away the token.
  2610. Arguments:
  2611. LrpcMessage - request message
  2612. Return Value:
  2613. RPC_S_OK - Function succeeded
  2614. RPC_S_OUT_OF_MEMORY - we ran out of memory
  2615. --*/
  2616. {
  2617. NTSTATUS NtStatus ;
  2618. HANDLE ImpersonationToken = 0;
  2619. RPC_STATUS Status;
  2620. if (fRestoreToken)
  2621. {
  2622. //
  2623. // Save away the old token
  2624. //
  2625. if (OpenThreadToken (GetCurrentThread(),
  2626. TOKEN_IMPERSONATE | TOKEN_QUERY,
  2627. TRUE,
  2628. &ImpersonationToken) == FALSE)
  2629. {
  2630. ImpersonationToken = 0;
  2631. #if DBG
  2632. if (GetLastError() != ERROR_NO_TOKEN)
  2633. {
  2634. PrintToDebugger("LRPC: OpenThreadToken failed %d\n", GetLastError());
  2635. }
  2636. #endif
  2637. }
  2638. }
  2639. NtStatus = NtImpersonateClientOfPort(LpcServerPort,
  2640. (PORT_MESSAGE *) LrpcMessage);
  2641. if (NT_ERROR(NtStatus))
  2642. {
  2643. #if DBG
  2644. PrintToDebugger("LRPC: NtImpersonateClientOfPort failed: 0x%lX\n",
  2645. NtStatus) ;
  2646. #endif
  2647. return RPC_S_INVALID_AUTH_IDENTITY ;
  2648. }
  2649. Status = RPC_S_OK;
  2650. if (OpenThreadToken (GetCurrentThread(),
  2651. TOKEN_IMPERSONATE | TOKEN_QUERY,
  2652. TRUE,
  2653. pTokenHandle) == FALSE)
  2654. {
  2655. *pTokenHandle = 0;
  2656. if (GetLastError() == ERROR_CANT_OPEN_ANONYMOUS)
  2657. {
  2658. Status = ERROR_CANT_OPEN_ANONYMOUS;
  2659. }
  2660. else
  2661. {
  2662. #if DBG
  2663. PrintToDebugger("LRPC: OpenThreadToken failed\n") ;
  2664. #endif
  2665. }
  2666. }
  2667. if (fRestoreToken)
  2668. {
  2669. //
  2670. // Restore the token
  2671. //
  2672. NtStatus = NtSetInformationThread(NtCurrentThread(),
  2673. ThreadImpersonationToken,
  2674. &ImpersonationToken,
  2675. sizeof(HANDLE));
  2676. #if DBG
  2677. if (!NT_SUCCESS(NtStatus))
  2678. {
  2679. PrintToDebugger("RPC : NtSetInformationThread : %lx\n", NtStatus);
  2680. }
  2681. #endif // DBG
  2682. if (ImpersonationToken)
  2683. {
  2684. CloseHandle(ImpersonationToken);
  2685. }
  2686. }
  2687. return Status;
  2688. }
  2689. RPC_STATUS
  2690. LRPC_SASSOCIATION::GetClientName (
  2691. IN LRPC_SCALL *SCall,
  2692. IN OUT ULONG *ClientPrincipalNameBufferLength OPTIONAL, // in bytes
  2693. OUT RPC_CHAR **ClientPrincipalName
  2694. )
  2695. /*++
  2696. Routine Description:
  2697. Gets the client name for the given scall
  2698. Arguments:
  2699. SCall - the SCall for which to get the client name
  2700. ClientPrincipalNameBufferLength - if present, *ClientPrincipalName must
  2701. point to a caller supplied buffer, which if big enough,
  2702. will be filled with the client principal name. If not present,
  2703. *ClientPrincipalName must be NULL.
  2704. ClientPrincipalName - see ClientPrincipalNameBufferLength
  2705. Return Value:
  2706. RPC_S_OK for success, or RPC_S_* / Win32 error code for error.
  2707. --*/
  2708. {
  2709. RPC_STATUS Status = RPC_S_OK;
  2710. BOOL Result;
  2711. unsigned long Size;
  2712. HANDLE TokenHandle = 0;
  2713. LRPC_SCONTEXT *SContext = 0;
  2714. TOKEN_STATISTICS TokenStatisticsInformation;
  2715. DictionaryCursor cursor;
  2716. BOOL fAnonymous;
  2717. BOOL fMutexHeld = FALSE;
  2718. BOOL fAssociationSContextUsed = FALSE;
  2719. RPC_CHAR *CurrentUserName;
  2720. ULONG CurrentUserNameLength;
  2721. if (SCall->SContext == NULL)
  2722. {
  2723. // take the lock opportunistically
  2724. AssociationMutex.Request();
  2725. fMutexHeld = TRUE;
  2726. if (SCall->SContext == NULL)
  2727. {
  2728. Status = SaveToken(
  2729. SCall->LrpcRequestMessage,
  2730. &TokenHandle, 1);
  2731. if ((Status != RPC_S_OK) && (Status != ERROR_CANT_OPEN_ANONYMOUS))
  2732. {
  2733. goto Cleanup;
  2734. }
  2735. if (Status == RPC_S_OK)
  2736. {
  2737. Result = GetTokenInformation(
  2738. TokenHandle,
  2739. TokenStatistics,
  2740. &TokenStatisticsInformation,
  2741. sizeof(TokenStatisticsInformation),
  2742. &Size
  2743. );
  2744. if (Result != TRUE)
  2745. {
  2746. Status = RPC_S_INVALID_AUTH_IDENTITY;
  2747. goto Cleanup;
  2748. }
  2749. fAnonymous = FALSE;
  2750. }
  2751. else
  2752. {
  2753. ASSERT(Status == ERROR_CANT_OPEN_ANONYMOUS);
  2754. fAnonymous = TRUE;
  2755. TokenHandle = 0;
  2756. }
  2757. SContextDict.Reset(cursor);
  2758. while ((SContext = SContextDict.Next(cursor)) != 0)
  2759. {
  2760. // if either input and found are anonymous, or the modified
  2761. // ids match, we have found it
  2762. if ((fAnonymous && SContext->GetAnonymousFlag())
  2763. ||
  2764. FastCompareLUIDAligned(&SContext->ClientLuid,
  2765. &TokenStatisticsInformation.ModifiedId))
  2766. {
  2767. break;
  2768. }
  2769. }
  2770. if (SContext == 0)
  2771. {
  2772. SContext = new LRPC_SCONTEXT(NULL,
  2773. fAnonymous ? NULL : ((LUID *) &TokenStatisticsInformation.ModifiedId),
  2774. this,
  2775. FALSE, // fDefaultLogonId
  2776. fAnonymous
  2777. );
  2778. if (SContext == 0)
  2779. {
  2780. Status = RPC_S_OUT_OF_MEMORY;
  2781. goto Cleanup;
  2782. }
  2783. if (SContextDict.Insert(SContext) == -1)
  2784. {
  2785. delete SContext;
  2786. Status = RPC_S_OUT_OF_MEMORY;
  2787. goto Cleanup;
  2788. }
  2789. // mark the context as server side only
  2790. SContext->SetServerSideOnlyFlag();
  2791. // record that we have used this recently to prevent it from being
  2792. // garbage collected
  2793. SContext->UpdateLastAccessTime();
  2794. EnableIdleLrpcSContextsCleanup();
  2795. // tell the garbage collector that we have something to be
  2796. // collected
  2797. GarbageCollectionNeeded(FALSE, // fOneTimeCleanup
  2798. LRPC_SCONTEXT::CONTEXT_IDLE_TIMEOUT);
  2799. }
  2800. else
  2801. {
  2802. // record that we have used this recently to prevent it from being
  2803. // garbage collected
  2804. SContext->UpdateLastAccessTime();
  2805. }
  2806. // we have taken or created the current SContext in the association
  2807. // we need to prevent the garbage collection thread from destroying
  2808. // it underneath us. We add one refcount for the purpose and record
  2809. // this
  2810. SContext->AddReference();
  2811. fAssociationSContextUsed = TRUE;
  2812. }
  2813. else
  2814. {
  2815. SContext = SCall->SContext;
  2816. // record that we have used this recently to prevent it from being
  2817. // garbage collected
  2818. SContext->UpdateLastAccessTime();
  2819. }
  2820. AssociationMutex.Clear() ;
  2821. fMutexHeld = FALSE;
  2822. }
  2823. else
  2824. {
  2825. SContext = SCall->SContext;
  2826. // record that we have used this recently to prevent it from being
  2827. // garbage collected
  2828. SContext->UpdateLastAccessTime();
  2829. }
  2830. ASSERT(SContext);
  2831. // if we go through the path where the token is retrieved from
  2832. // the SContext, passing NULL TokenHandle to get user name is Ok
  2833. // as it will retrieve the token from the SContext
  2834. Status = SContext->GetUserName(ClientPrincipalNameBufferLength, ClientPrincipalName, TokenHandle);
  2835. // If ARGUMENT_PRESENT(ClientPrincipalNameBufferLength), Status may be
  2836. // ERROR_MORE_DATA, which is a success error code.
  2837. if (fAssociationSContextUsed)
  2838. {
  2839. if ((Status == RPC_S_OK)
  2840. && (!ARGUMENT_PRESENT(ClientPrincipalNameBufferLength)))
  2841. {
  2842. // we weren't supplied a user buffer. Copy the principal
  2843. // name to a call variable to avoid the garbage collector
  2844. // collecting this under the feet of our caller. Then
  2845. // we can release the refcount
  2846. if (SCall->ClientPrincipalName == NULL)
  2847. {
  2848. CurrentUserNameLength = (RpcpStringLength(*ClientPrincipalName) + 1) * sizeof(RPC_CHAR);
  2849. // CurrentUserNameLength is in bytes. Allocate chars for it and cast it back
  2850. CurrentUserName = (RPC_CHAR *) new char [CurrentUserNameLength];
  2851. if (CurrentUserName != NULL)
  2852. {
  2853. RpcpMemoryCopy(CurrentUserName,
  2854. *ClientPrincipalName,
  2855. CurrentUserNameLength);
  2856. SCall->ClientPrincipalName = CurrentUserName;
  2857. *ClientPrincipalName = CurrentUserName;
  2858. }
  2859. else
  2860. {
  2861. Status = RPC_S_OUT_OF_MEMORY;
  2862. // fall through in cleanup path
  2863. }
  2864. }
  2865. else
  2866. {
  2867. *ClientPrincipalName = SCall->ClientPrincipalName;
  2868. }
  2869. }
  2870. // succeeded or not, drop the refcount
  2871. SContext->RemoveReference();
  2872. }
  2873. if (Status != RPC_S_OK)
  2874. {
  2875. // N.B. failure of this function doesn't mean we have
  2876. // to delete a newly created scontext. scontexts without
  2877. // names are perfectly valid, and since we know the only
  2878. // missing part from this scontext is the name, we can
  2879. // leave it alone, return failure, and attempt to get the
  2880. // name next time
  2881. goto Cleanup;
  2882. }
  2883. Cleanup:
  2884. if (fMutexHeld)
  2885. {
  2886. AssociationMutex.Clear() ;
  2887. }
  2888. if (TokenHandle)
  2889. {
  2890. CloseHandle(TokenHandle);
  2891. }
  2892. return Status;
  2893. }
  2894. #if defined(_WIN64)
  2895. C_ASSERT((FIELD_OFFSET(TOKEN_STATISTICS, ModifiedId) % 8) == 0);
  2896. C_ASSERT((FIELD_OFFSET(LRPC_SCONTEXT, ClientLuid) % 8) == 0);
  2897. #endif
  2898. void
  2899. LRPC_SASSOCIATION::DealWithBindMessage (
  2900. IN LRPC_MESSAGE * LrpcMessage
  2901. )
  2902. /*++
  2903. Routine Description:
  2904. LRPC_ADDRESS::ReceiveLotsaCalls will call this routine when the client
  2905. sends a bind message. We need to process the bind message, and send
  2906. a response to the client.
  2907. Arguments:
  2908. LrpcMessage - Supplies the bind message. We will also use this to send
  2909. the response.
  2910. Return Value:
  2911. The reply message to be sent to the client will be returned.
  2912. --*/
  2913. {
  2914. RPC_STATUS Status = RPC_S_OK;
  2915. NTSTATUS NtStatus ;
  2916. HANDLE ImpersonationToken = 0;
  2917. HANDLE TokenHandle;
  2918. unsigned long Size;
  2919. BOOL Result;
  2920. LRPC_SCONTEXT *SContext;
  2921. ULONG SecurityContextId = -1;
  2922. DictionaryCursor cursor;
  2923. BOOL fBindDefaultLogonId;
  2924. BOOL fAnonymous;
  2925. if (LrpcMessage->Bind.BindExchange.Flags & NEW_SECURITY_CONTEXT_FLAG)
  2926. {
  2927. TOKEN_STATISTICS TokenStatisticsInformation;
  2928. //
  2929. // If SaveToken succeeds, as a side-effect, it will
  2930. // fill in the SecurityContextId field of the BindExchange
  2931. //
  2932. Status = SaveToken(
  2933. LrpcMessage,
  2934. &TokenHandle) ;
  2935. if ((Status != RPC_S_OK) && (Status != ERROR_CANT_OPEN_ANONYMOUS))
  2936. {
  2937. RpcpErrorAddRecord(EEInfoGCRuntime,
  2938. Status,
  2939. EEInfoDLDealWithBindMessage10);
  2940. goto Cleanup;
  2941. }
  2942. if (TokenHandle || (Status == ERROR_CANT_OPEN_ANONYMOUS))
  2943. {
  2944. if (TokenHandle)
  2945. {
  2946. Result = GetTokenInformation(
  2947. TokenHandle,
  2948. TokenStatistics,
  2949. &TokenStatisticsInformation,
  2950. sizeof(TokenStatisticsInformation),
  2951. &Size
  2952. );
  2953. if (Result != TRUE)
  2954. {
  2955. RpcpErrorAddRecord(EEInfoGCRuntime,
  2956. RPC_S_INVALID_AUTH_IDENTITY,
  2957. EEInfoDLDealWithBindMessage20,
  2958. GetLastError());
  2959. CloseHandle(TokenHandle);
  2960. Status = RPC_S_INVALID_AUTH_IDENTITY;
  2961. goto Cleanup;
  2962. }
  2963. fAnonymous = FALSE;
  2964. }
  2965. else
  2966. {
  2967. fAnonymous = TRUE;
  2968. Status = RPC_S_OK;
  2969. }
  2970. AssociationMutex.Request();
  2971. int Key = 0;
  2972. fBindDefaultLogonId =
  2973. (LrpcMessage->Bind.BindExchange.Flags & DEFAULT_LOGONID_FLAG)
  2974. ? TRUE : FALSE;
  2975. SContextDict.Reset(cursor);
  2976. while ((SContext = SContextDict.NextWithKey(cursor, &Key)) != 0)
  2977. {
  2978. if ((fAnonymous && SContext->GetAnonymousFlag())
  2979. ||
  2980. (FastCompareLUIDAligned(&SContext->ClientLuid,
  2981. &TokenStatisticsInformation.ModifiedId)
  2982. &&
  2983. (SContext->GetDefaultLogonIdFlag() == fBindDefaultLogonId)))
  2984. {
  2985. SecurityContextId = Key;
  2986. SContext->ClearServerSideOnlyFlag();
  2987. break;
  2988. }
  2989. }
  2990. if (SContext == 0)
  2991. {
  2992. if (fAnonymous)
  2993. {
  2994. SContext = new LRPC_SCONTEXT(TokenHandle,
  2995. (LUID *) NULL,
  2996. this,
  2997. 0,
  2998. fAnonymous);
  2999. }
  3000. else
  3001. {
  3002. SContext = new LRPC_SCONTEXT(TokenHandle,
  3003. (LUID *) &TokenStatisticsInformation.ModifiedId,
  3004. this,
  3005. fBindDefaultLogonId,
  3006. 0 // fAnonymousToken
  3007. );
  3008. }
  3009. if (SContext == 0)
  3010. {
  3011. RpcpErrorAddRecord(EEInfoGCRuntime,
  3012. RPC_S_OUT_OF_MEMORY,
  3013. EEInfoDLDealWithBindMessage30,
  3014. sizeof(LRPC_SCONTEXT));
  3015. CloseHandle(TokenHandle);
  3016. Status = RPC_S_OUT_OF_MEMORY;
  3017. AssociationMutex.Clear();
  3018. goto Cleanup;
  3019. }
  3020. if ((SecurityContextId = SContextDict.Insert(SContext)) == -1)
  3021. {
  3022. RpcpErrorAddRecord(EEInfoGCRuntime,
  3023. RPC_S_OUT_OF_MEMORY,
  3024. EEInfoDLDealWithBindMessage40);
  3025. delete SContext;
  3026. Status = RPC_S_OUT_OF_MEMORY;
  3027. AssociationMutex.Clear();
  3028. goto Cleanup;
  3029. }
  3030. }
  3031. else if (SContext->hToken == NULL)
  3032. {
  3033. // if the context had no token, add one. This can happen
  3034. // if previous callers for this modified id just queried
  3035. // the user name. In this case, we won't cache the token
  3036. SContext->hToken = TokenHandle;
  3037. }
  3038. else
  3039. {
  3040. CloseHandle(TokenHandle);
  3041. }
  3042. AssociationMutex.Clear();
  3043. }
  3044. Cleanup:
  3045. //
  3046. // Revert
  3047. //
  3048. NtStatus = NtSetInformationThread(NtCurrentThread(),
  3049. ThreadImpersonationToken,
  3050. &ImpersonationToken,
  3051. sizeof(HANDLE));
  3052. #if DBG
  3053. if (!NT_SUCCESS(NtStatus))
  3054. {
  3055. PrintToDebugger("RPC : NtSetInformationThread : %lx\n", NtStatus);
  3056. }
  3057. #endif // DBG
  3058. }
  3059. if (Status == RPC_S_OK
  3060. && LrpcMessage->Bind.BindExchange.Flags & NEW_PRESENTATION_CONTEXT_FLAG)
  3061. {
  3062. Status = AddBinding(&(LrpcMessage->Bind.BindExchange));
  3063. if (Status != RPC_S_OK)
  3064. {
  3065. RpcpErrorAddRecord(EEInfoGCRuntime,
  3066. Status,
  3067. EEInfoDLDealWithBindMessage50);
  3068. }
  3069. }
  3070. LrpcMessage->Bind.BindExchange.RpcStatus = Status ;
  3071. if (LrpcMessage->Bind.OldSecurityContexts.NumContexts > 0)
  3072. {
  3073. DWORD i;
  3074. LRPC_SCONTEXT *SContext;
  3075. DWORD NumContexts = LrpcMessage->Bind.OldSecurityContexts.NumContexts;
  3076. DWORD CalculatedSize = ((NumContexts-1) * sizeof(DWORD))+sizeof(LRPC_BIND_MESSAGE);
  3077. if (NumContexts > MAX_LRPC_CONTEXTS
  3078. || CalculatedSize > (DWORD) LrpcMessage->LpcHeader.u1.s1.TotalLength)
  3079. {
  3080. //
  3081. // Bogus request
  3082. //
  3083. LrpcMessage->Bind.BindExchange.RpcStatus = RPC_S_PROTOCOL_ERROR;
  3084. RpcpErrorAddRecord(EEInfoGCRuntime,
  3085. RPC_S_PROTOCOL_ERROR,
  3086. EEInfoDLDealWithBindMessage60,
  3087. NumContexts,
  3088. CalculatedSize,
  3089. (DWORD) LrpcMessage->LpcHeader.u1.s1.TotalLength);
  3090. goto Reply;
  3091. }
  3092. AssociationMutex.Request();
  3093. for (i = 0; i < NumContexts; i++)
  3094. {
  3095. SContext = SContextDict.Delete(
  3096. LrpcMessage->Bind.OldSecurityContexts.SecurityContextId[i]);
  3097. if (SContext)
  3098. {
  3099. SContext->Destroy();
  3100. }
  3101. else
  3102. {
  3103. ASSERT(0);
  3104. }
  3105. }
  3106. AssociationMutex.Clear();
  3107. }
  3108. Reply:
  3109. // if failure, check out of EEInfo
  3110. if ((LrpcMessage->Bind.BindExchange.RpcStatus != RPC_S_OK) && (g_fSendEEInfo))
  3111. {
  3112. SetBindAckFault(LrpcMessage,
  3113. LrpcMessage->Bind.BindExchange.RpcStatus);
  3114. }
  3115. LrpcMessage->Bind.MessageType = LRPC_BIND_ACK ;
  3116. LrpcMessage->Bind.BindExchange.SecurityContextId = SecurityContextId;
  3117. if (!(LrpcMessage->Bind.BindExchange.Flags & EXTENDED_ERROR_INFO_PRESENT))
  3118. {
  3119. LrpcMessage->LpcHeader.u1.s1.DataLength = sizeof(LRPC_BIND_MESSAGE)
  3120. - sizeof(PORT_MESSAGE);
  3121. }
  3122. ReplyMessage(LrpcMessage);
  3123. }
  3124. RPC_STATUS LRPC_SASSOCIATION::CreateThread(void)
  3125. {
  3126. RPC_STATUS status;
  3127. status = Address->BeginLongCall();
  3128. if (status != RPC_S_OK)
  3129. {
  3130. Address->EndLongCall();
  3131. }
  3132. return status;
  3133. }
  3134. void LRPC_SASSOCIATION::RundownNotificationCompleted(void)
  3135. {
  3136. Address->EndLongCall();
  3137. }
  3138. RPC_STATUS
  3139. LRPC_SBINDING::CheckSecurity (
  3140. SCALL * Context
  3141. )
  3142. {
  3143. if ( (RpcInterface->SequenceNumber == SequenceNumber)
  3144. || (RpcInterface->IsSecurityCallbackReqd() == 0))
  3145. {
  3146. return (RPC_S_OK);
  3147. }
  3148. RPC_STATUS Status = RpcInterface->CheckSecurityIfNecessary(Context);
  3149. NukeStaleEEInfoIfNecessary(Status);
  3150. Context->RevertToSelf();
  3151. if (Status == RPC_S_OK)
  3152. {
  3153. SequenceNumber = RpcInterface->SequenceNumber ;
  3154. return (RPC_S_OK);
  3155. }
  3156. else
  3157. {
  3158. SequenceNumber = 0;
  3159. RpcpErrorAddRecord(EEInfoGCApplication,
  3160. RPC_S_ACCESS_DENIED,
  3161. EEInfoDLCheckSecurity10,
  3162. Status);
  3163. return (RPC_S_ACCESS_DENIED);
  3164. }
  3165. }
  3166. void
  3167. LRPC_SCALL::DealWithRequestMessage (
  3168. )
  3169. /*++
  3170. Routine Description:
  3171. We will process the original request message in this routine, dispatch
  3172. the remote procedure call to the stub, and then send the response
  3173. message.
  3174. Arguments:
  3175. RpcMessage - Contains the request buffer
  3176. Return Value:
  3177. none
  3178. --*/
  3179. {
  3180. RPC_STATUS Status, ExceptionCode;
  3181. int Flags = LrpcRequestMessage->Rpc.RpcHeader.Flags ;
  3182. LRPC_SBINDING *LrpcBinding ;
  3183. THREAD *ThisThread;
  3184. DebugThreadInfo *ThreadDebugCell;
  3185. DebugCallInfo *CallDebugCell;
  3186. ULONG TickCount;
  3187. PRPC_DISPATCH_TABLE DispatchTableToUse;
  3188. RuntimeInfo.Length = sizeof(RPC_RUNTIME_INFO) ;
  3189. ClientId = MsgClientIdToClientId(LrpcRequestMessage->LpcHeader.ClientId);
  3190. MessageId = LrpcRequestMessage->LpcHeader.MessageId;
  3191. CallbackId = LrpcRequestMessage->LpcHeader.CallbackId;
  3192. LrpcBinding = LookupBinding(
  3193. LrpcRequestMessage->Rpc.RpcHeader.PresentContext);
  3194. if (LrpcBinding == 0)
  3195. {
  3196. COPYMSG(LrpcReplyMessage, LrpcRequestMessage) ;
  3197. FreeBuffer(&RpcMessage);
  3198. RpcpErrorAddRecord(EEInfoGCRuntime,
  3199. RPC_S_UNKNOWN_IF,
  3200. EEInfoDLDealWithRequestMessage10,
  3201. LrpcRequestMessage->Rpc.RpcHeader.PresentContext);
  3202. SetFaultPacket(LrpcReplyMessage, RPC_S_UNKNOWN_IF, Flags, NULL);
  3203. return;
  3204. }
  3205. SBinding = LrpcBinding;
  3206. if (SBinding->RpcInterface->IsAutoListenInterface())
  3207. {
  3208. LrpcBinding->RpcInterface->BeginAutoListenCall() ;
  3209. }
  3210. LrpcBinding->GetSelectedTransferSyntaxAndDispatchTable(&RpcMessage.TransferSyntax,
  3211. &DispatchTableToUse);
  3212. RpcMessage.ProcNum = LrpcRequestMessage->Rpc.RpcHeader.ProcedureNumber;
  3213. RpcMessage.Handle = this;
  3214. RpcMessage.ReservedForRuntime = &RuntimeInfo ;
  3215. // NDR_DREP_ASCII | NDR_DREP_LITTLE_ENDIAN | NDR_DREP_IEEE
  3216. RpcMessage.DataRepresentation = 0x00 | 0x10 | 0x0000;
  3217. if ((LrpcRequestMessage->Rpc.RpcHeader.Flags & LRPC_OBJECT_UUID))
  3218. {
  3219. ObjectUuidFlag = 1;
  3220. RpcpMemoryCopy(&ObjectUuid,
  3221. &(LrpcRequestMessage->Rpc.RpcHeader.ObjectUuid), sizeof(UUID));
  3222. }
  3223. ThisThread = RpcpGetThreadPointer();
  3224. ASSERT(ThisThread);
  3225. RpcpSetThreadContextWithThread(ThisThread, this);
  3226. ThreadDebugCell = ThisThread->DebugCell;
  3227. //
  3228. // Check IF Level Security
  3229. //
  3230. if (LrpcBinding->RpcInterface->IsSecurityCallbackReqd() != 0)
  3231. {
  3232. Status = LrpcBinding->CheckSecurity(this);
  3233. if (Status != RPC_S_OK)
  3234. {
  3235. COPYMSG(LrpcReplyMessage, LrpcRequestMessage) ;
  3236. FreeBuffer(&RpcMessage);
  3237. // the error record (if any) was already added
  3238. // by CheckSecurity
  3239. SetFaultPacket(LrpcReplyMessage,
  3240. RPC_S_ACCESS_DENIED,
  3241. Flags,
  3242. NULL) ;
  3243. RpcpSetThreadContextWithThread(ThisThread, 0) ;
  3244. return;
  3245. }
  3246. }
  3247. if (ThreadDebugCell)
  3248. {
  3249. TickCount = NtGetTickCount();
  3250. ThreadDebugCell->Status = dtsDispatched;
  3251. ThreadDebugCell->LastUpdateTime = TickCount;
  3252. CallDebugCell = DebugCell;
  3253. CallDebugCell->InterfaceUUIDStart = LrpcBinding->RpcInterface->GetInterfaceFirstDWORD();
  3254. CallDebugCell->CallID = CallId;
  3255. CallDebugCell->LastUpdateTime = TickCount;
  3256. // shoehorn the PID and TID into shorts - most of the time
  3257. // it doesn't actually truncate important information
  3258. CallDebugCell->PID = (USHORT)ClientId.UniqueProcess;
  3259. CallDebugCell->TID = (USHORT)ClientId.UniqueThread;
  3260. CallDebugCell->ProcNum = (unsigned short)RpcMessage.ProcNum;
  3261. CallDebugCell->Status = csDispatched;
  3262. GetDebugCellIDFromDebugCell((DebugCellUnion *)ThreadDebugCell,
  3263. &ThisThread->DebugCellTag, &CallDebugCell->ServicingTID);
  3264. if (LrpcBinding->RpcInterface->IsPipeInterface())
  3265. CallDebugCell->CallFlags |= DBGCELL_PIPE_CALL;
  3266. }
  3267. if (ObjectUuidFlag != 0)
  3268. {
  3269. Status = LrpcBinding->RpcInterface->DispatchToStubWithObject(
  3270. &RpcMessage,
  3271. &ObjectUuid,
  3272. 0,
  3273. DispatchTableToUse,
  3274. &ExceptionCode);
  3275. }
  3276. else
  3277. {
  3278. Status = LrpcBinding->RpcInterface->DispatchToStub(
  3279. &RpcMessage,
  3280. 0,
  3281. DispatchTableToUse,
  3282. &ExceptionCode);
  3283. }
  3284. RpcpSetThreadContextWithThread(ThisThread, 0);
  3285. LRPC_SCALL::RevertToSelf();
  3286. if (ThreadDebugCell)
  3287. {
  3288. ThreadDebugCell->Status = dtsProcessing;
  3289. ThreadDebugCell->LastUpdateTime = NtGetTickCount();
  3290. }
  3291. if (Status != RPC_S_OK)
  3292. {
  3293. if (Status == RPC_P_EXCEPTION_OCCURED)
  3294. {
  3295. SetFaultPacket(LrpcReplyMessage,
  3296. LrpcMapRpcStatus(ExceptionCode),
  3297. Flags,
  3298. this) ;
  3299. }
  3300. else
  3301. {
  3302. VALIDATE(Status)
  3303. {
  3304. RPC_S_PROCNUM_OUT_OF_RANGE,
  3305. RPC_S_UNKNOWN_IF,
  3306. RPC_S_NOT_LISTENING,
  3307. RPC_S_SERVER_TOO_BUSY,
  3308. RPC_S_UNSUPPORTED_TYPE
  3309. } END_VALIDATE;
  3310. if (Status == RPC_S_NOT_LISTENING)
  3311. {
  3312. RpcpErrorAddRecord(EEInfoGCRuntime,
  3313. Status,
  3314. EEInfoDLDealWithRequestMessage20);
  3315. Status = RPC_S_SERVER_TOO_BUSY;
  3316. }
  3317. RpcpErrorAddRecord(EEInfoGCRuntime,
  3318. Status,
  3319. EEInfoDLDealWithRequestMessage30);
  3320. SetFaultPacket(LrpcReplyMessage,
  3321. LrpcMapRpcStatus(Status),
  3322. Flags,
  3323. this);
  3324. }
  3325. if (IsSyncCall())
  3326. {
  3327. INITMSG(LrpcReplyMessage,
  3328. ClientId,
  3329. CallbackId,
  3330. MessageId) ;
  3331. }
  3332. else
  3333. {
  3334. if (Flags & LRPC_NON_PIPE)
  3335. {
  3336. INITMSG(LrpcReplyMessage,
  3337. ClientId,
  3338. CallbackId,
  3339. MessageId) ;
  3340. Association->ReplyMessage(LrpcReplyMessage);
  3341. }
  3342. else
  3343. {
  3344. if ((LrpcReplyMessage->Rpc.RpcHeader.MessageType != LRPC_MSG_FAULT2)
  3345. || (!IsClientAsync()))
  3346. {
  3347. SendDGReply(LrpcReplyMessage);
  3348. }
  3349. }
  3350. RemoveReference();
  3351. }
  3352. }
  3353. else
  3354. {
  3355. //
  3356. // The rest of the response headers are set in ::GetBuffer.
  3357. //
  3358. LrpcReplyMessage->Rpc.RpcHeader.MessageType = LRPC_MSG_RESPONSE;
  3359. }
  3360. }
  3361. void
  3362. LRPC_SCALL::SendReply (
  3363. )
  3364. {
  3365. RPC_STATUS Status;
  3366. BOOL Shutup ;
  3367. LRPC_SASSOCIATION *LocalAssociation;
  3368. if (IsSyncCall())
  3369. {
  3370. if (IsClientAsync())
  3371. {
  3372. if (LrpcReplyMessage->Fault.RpcHeader.MessageType == LRPC_MSG_FAULT)
  3373. {
  3374. SendDGReply(LrpcReplyMessage);
  3375. }
  3376. else
  3377. {
  3378. RpcMessage.RpcFlags = 0;
  3379. Status = SendRequest(&RpcMessage, &Shutup) ;
  3380. if (Status != RPC_S_OK)
  3381. {
  3382. #if DBG
  3383. PrintToDebugger("RPC: SendRequest failed: %d\n", Status);
  3384. #endif
  3385. Association->Delete();
  3386. }
  3387. }
  3388. }
  3389. else
  3390. {
  3391. INITMSG(LrpcReplyMessage,
  3392. ClientId,
  3393. CallbackId,
  3394. MessageId) ;
  3395. Association->ReplyMessage(LrpcReplyMessage);
  3396. }
  3397. FreeMessage(LrpcRequestMessage) ;
  3398. LocalAssociation = Association;
  3399. Association->FreeSCall(this) ;
  3400. // don't touch the this pointer after FreeSCall - it may be freed
  3401. LocalAssociation->Address->DereferenceAssociation(LocalAssociation);
  3402. }
  3403. else
  3404. {
  3405. if ((LrpcReplyMessage->Rpc.RpcHeader.MessageType != LRPC_MSG_FAULT2)
  3406. || (!IsClientAsync()))
  3407. {
  3408. RemoveReference();
  3409. }
  3410. else
  3411. {
  3412. BOOL Shutup;
  3413. RpcMessage.RpcFlags = 0;
  3414. Status = SendRequest(&RpcMessage, &Shutup) ;
  3415. if (Status != RPC_S_OK)
  3416. {
  3417. #if DBG
  3418. PrintToDebugger("RPC: SendRequest failed: %d\n", Status);
  3419. #endif
  3420. Association->Delete();
  3421. }
  3422. }
  3423. }
  3424. }
  3425. LRPC_MESSAGE *
  3426. LRPC_SASSOCIATION::DealWithCopyMessage (
  3427. IN LRPC_COPY_MESSAGE * LrpcMessage
  3428. )
  3429. /*++
  3430. Routine Description:
  3431. We will process a copy message in this routine; this means that we need
  3432. to copy a buffer of data from the server into the client's address
  3433. space.
  3434. Arguments:
  3435. LrpcMessage - Supplies the copy message which was received from
  3436. the client.
  3437. Return Value:
  3438. The reply message to be sent to the client will be returned.
  3439. --*/
  3440. {
  3441. NTSTATUS NtStatus;
  3442. SIZE_T NumberOfBytesWritten;
  3443. PVOID Buffer;
  3444. ASSERT(LrpcMessage->IsPartial == 0);
  3445. AssociationMutex.Request() ;
  3446. // We need this only to prevent an attack
  3447. // Also, the pointer is to a server address. It is ok to just cast it
  3448. // to the server's pointer type and it won't hurt anything in the case
  3449. // of 32/64 bit LRPC.
  3450. Buffer = Buffers.DeleteItemByBruteForce(MsgPtrToPtr(LrpcMessage->Server.Buffer));
  3451. AssociationMutex.Clear() ;
  3452. if (LrpcMessage->RpcStatus == RPC_S_OK)
  3453. {
  3454. if (Buffer == 0)
  3455. {
  3456. LrpcMessage->RpcStatus = RPC_S_PROTOCOL_ERROR;
  3457. }
  3458. else
  3459. {
  3460. NtStatus = NtWriteRequestData(LpcServerPort,
  3461. (PORT_MESSAGE *) LrpcMessage,
  3462. 0,
  3463. (PVOID) Buffer,
  3464. LrpcMessage->Server.Length,
  3465. &NumberOfBytesWritten);
  3466. if (NT_ERROR(NtStatus))
  3467. {
  3468. LrpcMessage->RpcStatus = RPC_S_OUT_OF_MEMORY;
  3469. }
  3470. else
  3471. {
  3472. ASSERT(LrpcMessage->Server.Length == NumberOfBytesWritten);
  3473. LrpcMessage->RpcStatus = RPC_S_OK;
  3474. }
  3475. }
  3476. }
  3477. LrpcMessage->LpcHeader.u1.s1.DataLength = sizeof(LRPC_COPY_MESSAGE)
  3478. - sizeof(PORT_MESSAGE);
  3479. LrpcMessage->LpcHeader.u1.s1.TotalLength = sizeof(LRPC_COPY_MESSAGE);
  3480. if (Buffer != 0)
  3481. {
  3482. RpcpFarFree(Buffer);
  3483. }
  3484. return((LRPC_MESSAGE *) LrpcMessage);
  3485. }
  3486. LRPC_MESSAGE *
  3487. LRPC_SASSOCIATION::DealWithPartialRequest (
  3488. IN LRPC_MESSAGE **LrpcMessage
  3489. )
  3490. /*++
  3491. Routine Description:
  3492. Deal with more data on a dispatched call. This
  3493. only happens when you have pipes. Pipe data on
  3494. async calls is handled differently from sync calls.
  3495. Arguments:
  3496. LrpcMessage - the LRPC message. For pipe data, we always
  3497. take the slow path (ie: NtReadRequestData).
  3498. Return Value:
  3499. NULL: if the request was processed.
  3500. not NULL: if there was a problem. the return value contains the
  3501. reply message.
  3502. --*/
  3503. {
  3504. LRPC_SCALL *SCall ;
  3505. RPC_STATUS Status ;
  3506. AssociationMutex.Request() ;
  3507. SCall = SCallDict.Find(ULongToPtr((*LrpcMessage)->Rpc.RpcHeader.CallId));
  3508. AssociationMutex.Clear() ;
  3509. // we have to wait until the server either calls
  3510. // Receive or calls Register. If it Calls Receive,
  3511. // we know that it is synchronous. If it calls
  3512. // Register, we know that it is async.
  3513. if (SCall)
  3514. {
  3515. Status = SCall->ProcessResponse(LrpcMessage) ;
  3516. }
  3517. else
  3518. {
  3519. #if DBG
  3520. PrintToDebugger("LRPC: No call corresponding the the pipe request\n");
  3521. #endif
  3522. Status = RPC_S_OUT_OF_MEMORY ;
  3523. }
  3524. if (Status != RPC_S_OK)
  3525. {
  3526. SetFaultPacket(*LrpcMessage,
  3527. Status,
  3528. LRPC_SYNC_CLIENT,
  3529. NULL) ;
  3530. return *LrpcMessage ;
  3531. }
  3532. return NULL ;
  3533. }
  3534. void
  3535. LRPC_SASSOCIATION::CleanupIdleSContexts (
  3536. void
  3537. )
  3538. /*++
  3539. Routine Description:
  3540. Walks the list of SContexts, finds the ones
  3541. that are idle and server side only, and cleans
  3542. them up.
  3543. Arguments:
  3544. Return Value:
  3545. --*/
  3546. {
  3547. LRPC_SCONTEXT *SContext;
  3548. DictionaryCursor cursor;
  3549. SContextDict.Reset(cursor);
  3550. AssociationMutex.Request();
  3551. while ((SContext = SContextDict.Next(cursor)) != 0)
  3552. {
  3553. if (SContext->GetServerSideOnlyFlag())
  3554. {
  3555. if (SContext->IsIdle())
  3556. {
  3557. SContext = (LRPC_SCONTEXT *)SContextDict.DeleteItemByBruteForce(SContext);
  3558. ASSERT(SContext);
  3559. SContext->Destroy();
  3560. }
  3561. }
  3562. }
  3563. AssociationMutex.Clear();
  3564. }
  3565. RPC_STATUS
  3566. LRPC_SCALL::SetupCall(
  3567. )
  3568. /*++
  3569. Routine Description:
  3570. Helper function that does the setup needed to use the
  3571. call in conjuction with Pipes or Async RPC.
  3572. Return Value:
  3573. RPC_S_OK - Function succeeded
  3574. RPC_S_OUT_OF_MEMORY - we ran out of memory
  3575. --*/
  3576. {
  3577. RPC_STATUS Status = RPC_S_OK ;
  3578. //
  3579. // Stuff from ActivateCall
  3580. //
  3581. RcvBufferLength = 0;
  3582. CallId = LrpcRequestMessage->Rpc.RpcHeader.CallId ;
  3583. ReceiveComplete = 0;
  3584. AsyncReply = 0;
  3585. CachedAPCInfoAvailable = 1;
  3586. Choked = 0;
  3587. AsyncStatus = RPC_S_OK ;
  3588. NeededLength = 0;
  3589. NotificationIssued = -1;
  3590. if (ReceiveEvent == 0)
  3591. {
  3592. ReceiveEvent = new EVENT(&Status, 0);
  3593. if (ReceiveEvent == 0 || Status)
  3594. {
  3595. delete ReceiveEvent;
  3596. ReceiveEvent = 0;
  3597. return RPC_S_OUT_OF_MEMORY ;
  3598. }
  3599. CallMutex = new MUTEX(&Status) ;
  3600. if (CallMutex == 0 || Status)
  3601. {
  3602. Association->SCallDict.Delete(ULongToPtr(CallId));
  3603. goto Cleanup;
  3604. }
  3605. }
  3606. else
  3607. {
  3608. ReceiveEvent->Lower();
  3609. }
  3610. Association->AssociationMutex.Request() ;
  3611. if (Association->SCallDict.Insert(ULongToPtr(CallId), this) == -1)
  3612. {
  3613. Association->AssociationMutex.Clear() ;
  3614. goto Cleanup;
  3615. }
  3616. Association->AssociationMutex.Clear() ;
  3617. LrpcReplyMessage->Rpc.RpcHeader.CallId = CallId ;
  3618. return (RPC_S_OK) ;
  3619. Cleanup:
  3620. delete CallMutex ;
  3621. delete ReceiveEvent;
  3622. CallMutex = 0;
  3623. ReceiveEvent = 0;
  3624. return RPC_S_OUT_OF_MEMORY ;
  3625. }
  3626. RPC_STATUS
  3627. LRPC_SCALL::NegotiateTransferSyntax (
  3628. IN OUT PRPC_MESSAGE Message
  3629. )
  3630. {
  3631. // this can happen in the callback case only.
  3632. // Just return the already negotiated transfer syntax
  3633. PRPC_DISPATCH_TABLE Ignored;
  3634. SBinding->GetSelectedTransferSyntaxAndDispatchTable(&Message->TransferSyntax,
  3635. &Ignored);
  3636. return RPC_S_OK;
  3637. }
  3638. RPC_STATUS
  3639. LRPC_SCALL::GetBuffer (
  3640. IN OUT PRPC_MESSAGE Message,
  3641. IN UUID *
  3642. )
  3643. /*++
  3644. Routine Description:
  3645. We will allocate a buffer which will be used to either send a request
  3646. or receive a response.
  3647. Arguments:
  3648. Message - Supplies the length of the buffer that is needed. The buffer
  3649. will be returned.
  3650. Return Value:
  3651. RPC_S_OK - A buffer has been successfully allocated. It will be of at
  3652. least the required length.
  3653. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate that
  3654. large a buffer.
  3655. --*/
  3656. {
  3657. int BufferKey ;
  3658. ASSERT(LrpcReplyMessage != 0) ;
  3659. if (PARTIAL(Message))
  3660. {
  3661. CurrentBufferLength =
  3662. (Message->BufferLength < MINIMUM_PARTIAL_BUFFLEN)
  3663. ? MINIMUM_PARTIAL_BUFFLEN:Message->BufferLength ;
  3664. Message->Buffer = RpcpFarAllocate(CurrentBufferLength) ;
  3665. if (Message->Buffer == 0)
  3666. {
  3667. CurrentBufferLength = 0;
  3668. return (RPC_S_OUT_OF_MEMORY) ;
  3669. }
  3670. }
  3671. else if (Message->BufferLength <= MAXIMUM_MESSAGE_BUFFER)
  3672. {
  3673. ASSERT(((ULONG_PTR) LrpcReplyMessage->Rpc.Buffer) % 8 == 0);
  3674. // uncomment this to check for 16 byte alignment on 64 bits
  3675. // ASSERT(IsBufferAligned(LrpcReplyMessage->Rpc.Buffer));
  3676. Message->Buffer = LrpcReplyMessage->Rpc.Buffer;
  3677. LrpcReplyMessage->LpcHeader.u2.ZeroInit = 0;
  3678. LrpcReplyMessage->Rpc.RpcHeader.Flags = LRPC_BUFFER_IMMEDIATE;
  3679. LrpcReplyMessage->LpcHeader.u1.s1.DataLength = (USHORT)
  3680. (Align4(Message->BufferLength) + sizeof(LRPC_RPC_HEADER));
  3681. return (RPC_S_OK) ;
  3682. }
  3683. else
  3684. {
  3685. Message->Buffer = RpcpFarAllocate(Message->BufferLength);
  3686. if (Message->Buffer == 0)
  3687. {
  3688. return(RPC_S_OUT_OF_MEMORY);
  3689. }
  3690. }
  3691. LrpcReplyMessage->Rpc.RpcHeader.Flags = LRPC_BUFFER_SERVER;
  3692. LrpcReplyMessage->LpcHeader.u2.ZeroInit = 0;
  3693. if (PARTIAL(Message) || IsClientAsync())
  3694. {
  3695. LrpcReplyMessage->Rpc.Request.CountDataEntries = 1;
  3696. LrpcReplyMessage->LpcHeader.MessageId = 0;
  3697. LrpcReplyMessage->LpcHeader.CallbackId = 0;
  3698. LrpcReplyMessage->LpcHeader.u2.s2.DataInfoOffset =
  3699. sizeof(PORT_MESSAGE) + sizeof(LRPC_RPC_HEADER);
  3700. LrpcReplyMessage->LpcHeader.u1.s1.DataLength =
  3701. sizeof(LRPC_RPC_HEADER) + sizeof(PORT_DATA_INFORMATION);
  3702. LrpcReplyMessage->Rpc.Request.DataEntries[0].Base = PtrToMsgPtr(Message->Buffer);
  3703. LrpcReplyMessage->Rpc.Request.DataEntries[0].Size = Message->BufferLength;
  3704. }
  3705. else
  3706. {
  3707. Association->AssociationMutex.Request() ;
  3708. BufferKey = Association->Buffers.Insert((LRPC_CLIENT_BUFFER *) Message->Buffer) ;
  3709. Association->AssociationMutex.Clear() ;
  3710. if (BufferKey == -1)
  3711. {
  3712. RpcpFarFree(Message->Buffer) ;
  3713. return RPC_S_OUT_OF_MEMORY ;
  3714. }
  3715. LrpcReplyMessage->LpcHeader.u1.s1.DataLength =
  3716. sizeof(LRPC_RPC_HEADER) + sizeof(LRPC_SERVER_BUFFER) ;
  3717. ASSERT(Message->BufferLength < 0x80000000);
  3718. LrpcReplyMessage->Rpc.Server.Length = Message->BufferLength ;
  3719. LrpcReplyMessage->Rpc.Server.Buffer = PtrToMsgPtr(Message->Buffer) ;
  3720. }
  3721. return(RPC_S_OK);
  3722. }
  3723. void
  3724. LRPC_SCALL::FreeBuffer (
  3725. IN PRPC_MESSAGE Message
  3726. )
  3727. /*++
  3728. Routine Description:
  3729. We will free the supplied buffer.
  3730. Arguments:
  3731. Message - Supplies the buffer to be freed.
  3732. --*/
  3733. {
  3734. ASSERT(LrpcReplyMessage != NULL) ;
  3735. if (!(Message->Buffer == LrpcRequestMessage->Rpc.Buffer
  3736. || Message->Buffer == LrpcReplyMessage->Rpc.Buffer))
  3737. {
  3738. if (!PARTIAL(Message) && !IsClientAsync())
  3739. {
  3740. Association->AssociationMutex.Request() ;
  3741. Association->Buffers.DeleteItemByBruteForce((LRPC_CLIENT_BUFFER *) Message->Buffer);
  3742. Association->AssociationMutex.Clear() ;
  3743. }
  3744. RpcpFarFree(Message->Buffer);
  3745. }
  3746. }
  3747. void
  3748. LRPC_SCALL::FreePipeBuffer (
  3749. IN PRPC_MESSAGE Message
  3750. )
  3751. /*++
  3752. Routine Description:
  3753. description
  3754. Arguments:
  3755. arg1 - description
  3756. Return Value:
  3757. RPC_S_OK - Function succeeded
  3758. RPC_S_OUT_OF_MEMORY - we ran out of memory
  3759. --*/
  3760. {
  3761. RpcpFarFree(Message->Buffer) ;
  3762. }
  3763. RPC_STATUS
  3764. LRPC_SCALL::ReallocPipeBuffer (
  3765. IN PRPC_MESSAGE Message,
  3766. IN unsigned int NewSize
  3767. )
  3768. /*++
  3769. Routine Description:
  3770. description
  3771. Arguments:
  3772. arg1 - description
  3773. Return Value:
  3774. RPC_S_OK - Function succeeded
  3775. RPC_S_OUT_OF_MEMORY - we ran out of memory
  3776. --*/
  3777. {
  3778. int BufferKey;
  3779. PVOID Buffer ;
  3780. void *NewBuffer ;
  3781. BOOL BufferChanged = FALSE ;
  3782. if (NewSize > CurrentBufferLength)
  3783. {
  3784. NewBuffer = RpcpFarAllocate(NewSize) ;
  3785. if (NewBuffer == 0)
  3786. {
  3787. RpcpFarFree(Message->Buffer) ;
  3788. return (RPC_S_OUT_OF_MEMORY) ;
  3789. }
  3790. if (CurrentBufferLength > 0)
  3791. {
  3792. RpcpMemoryCopy(NewBuffer, Message->Buffer, Message->BufferLength) ;
  3793. FreePipeBuffer(Message) ;
  3794. }
  3795. Message->Buffer = NewBuffer ;
  3796. CurrentBufferLength = NewSize ;
  3797. BufferChanged = TRUE ;
  3798. }
  3799. Message->BufferLength = NewSize ;
  3800. LrpcReplyMessage->Rpc.RpcHeader.Flags = LRPC_BUFFER_SERVER;
  3801. ASSERT(Message->BufferLength < 0x80000000);
  3802. LrpcReplyMessage->Rpc.Request.DataEntries[0].Base = PtrToMsgPtr(Message->Buffer);
  3803. LrpcReplyMessage->Rpc.Request.DataEntries[0].Size = Message->BufferLength;
  3804. return (RPC_S_OK) ;
  3805. }
  3806. RPC_STATUS
  3807. LRPC_SCALL::AbortAsyncCall (
  3808. IN PRPC_ASYNC_STATE pAsync,
  3809. IN unsigned long ExceptionCode
  3810. )
  3811. {
  3812. NTSTATUS NtStatus;
  3813. RPC_STATUS Status = RPC_S_OK;
  3814. NukeStaleEEInfoIfNecessary(ExceptionCode);
  3815. RpcpErrorAddRecord(EEInfoGCApplication,
  3816. ExceptionCode,
  3817. EEInfoDLAbortCall,
  3818. SBinding->GetInterfaceFirstDWORD(),
  3819. (short)RpcMessage.ProcNum,
  3820. RpcMessage.RpcFlags);
  3821. SetFaultPacket(LrpcReplyMessage, ExceptionCode, Flags, this);
  3822. if (IsClientAsync())
  3823. {
  3824. if (LrpcReplyMessage->Rpc.RpcHeader.MessageType != LRPC_MSG_FAULT2)
  3825. {
  3826. NtStatus = SendDGReply(LrpcReplyMessage) ;
  3827. }
  3828. else
  3829. {
  3830. BOOL Ignored;
  3831. RpcMessage.RpcFlags = 0;
  3832. RpcMessage.Buffer = NULL;
  3833. Status = SendRequest(&RpcMessage,
  3834. &Ignored // shutup parameter - it is not relevant for us
  3835. );
  3836. if (Status != RPC_S_OK)
  3837. {
  3838. #if DBG
  3839. PrintToDebugger("RPC: SendRequest failed: %d\n", Status);
  3840. #endif
  3841. Association->Delete();
  3842. }
  3843. }
  3844. }
  3845. else
  3846. {
  3847. INITMSG(LrpcReplyMessage,
  3848. ClientId,
  3849. CallbackId,
  3850. MessageId);
  3851. NtStatus = Association->ReplyMessage(LrpcReplyMessage);
  3852. }
  3853. if (NT_ERROR(NtStatus))
  3854. {
  3855. Status = RPC_S_CALL_FAILED ;
  3856. }
  3857. RemoveReference();
  3858. return Status ;
  3859. }
  3860. RPC_STATUS
  3861. LRPC_SCALL::Receive (
  3862. IN PRPC_MESSAGE Message,
  3863. IN unsigned int Size
  3864. )
  3865. /*++
  3866. Routine Description:
  3867. Receive routine used by pipes
  3868. Arguments:
  3869. Message - contains to buffer to receive in
  3870. pSize - pointer to a size value that contains the minimum amount of
  3871. data that needs to be received.
  3872. Return Value:
  3873. RPC_S_OK - We have successfully converted the message.
  3874. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to do the
  3875. conversion.
  3876. --*/
  3877. {
  3878. int RequestedSize;
  3879. unsigned long Extra = IsExtraMessage(Message) ;
  3880. ASSERT(ReceiveEvent) ;
  3881. Message->DataRepresentation = 0x00 | 0x10 | 0x0000;
  3882. if (!Extra && Message->Buffer)
  3883. {
  3884. ASSERT(LrpcRequestMessage->Rpc.RpcHeader.Flags & LRPC_BUFFER_REQUEST);
  3885. RpcpFarFree(Message->Buffer);
  3886. Message->Buffer = 0;
  3887. Message->BufferLength = 0;
  3888. }
  3889. //
  3890. // It is ok for us to find out that the buffer is complete
  3891. // before SavedBuffer is set,
  3892. // we need to take the CallMutex in GetCoalescedBuffer
  3893. //
  3894. while (!BufferComplete && (!PARTIAL(Message) || RcvBufferLength < Size))
  3895. {
  3896. if (ReceiveEvent->Wait() == WAIT_FAILED)
  3897. {
  3898. return RPC_S_CALL_FAILED;
  3899. }
  3900. if (AsyncStatus != RPC_S_OK)
  3901. {
  3902. return AsyncStatus;
  3903. }
  3904. }
  3905. return GetCoalescedBuffer(Message, Extra) ;
  3906. }
  3907. RPC_STATUS
  3908. LRPC_SCALL::Send (
  3909. IN OUT PRPC_MESSAGE Message
  3910. )
  3911. {
  3912. BOOL Shutup ;
  3913. Message->RpcFlags |= RPC_BUFFER_PARTIAL;
  3914. return SendRequest(Message, &Shutup) ;
  3915. }
  3916. RPC_STATUS
  3917. LRPC_SCALL::SendRequest (
  3918. IN OUT PRPC_MESSAGE Message,
  3919. OUT BOOL *Shutup
  3920. )
  3921. /*++
  3922. Routine Description:
  3923. description
  3924. Arguments:
  3925. arg1 - description
  3926. Return Value:
  3927. RPC_S_OK - Function succeeded
  3928. RPC_S_OUT_OF_MEMORY - we ran out of memory
  3929. --*/
  3930. {
  3931. RPC_STATUS Status;
  3932. NTSTATUS NtStatus ;
  3933. int RemainingLength = 0;
  3934. LRPC_MESSAGE ReplyMessage ;
  3935. *Shutup = 0;
  3936. if (PARTIAL(Message))
  3937. {
  3938. if (Message->BufferLength < MINIMUM_PARTIAL_BUFFLEN)
  3939. {
  3940. return (RPC_S_SEND_INCOMPLETE) ;
  3941. }
  3942. if (NOT_MULTIPLE_OF_EIGHT(Message->BufferLength))
  3943. {
  3944. RemainingLength = Message->BufferLength & LOW_BITS ;
  3945. Message->BufferLength &= ~LOW_BITS ;
  3946. }
  3947. LrpcReplyMessage->Rpc.RpcHeader.Flags |= LRPC_BUFFER_PARTIAL ;
  3948. }
  3949. if (FirstSend)
  3950. {
  3951. // this code will get executed only in
  3952. // the non async case
  3953. FirstSend = 0;
  3954. if (ReceiveEvent == 0)
  3955. {
  3956. Status = SetupCall() ;
  3957. if (Status != RPC_S_OK)
  3958. {
  3959. if (PARTIAL(Message)
  3960. && LrpcReplyMessage->Rpc.RpcHeader.Flags & LRPC_BUFFER_SERVER)
  3961. {
  3962. RpcpFarFree(Message->Buffer);
  3963. }
  3964. return Status ;
  3965. }
  3966. }
  3967. }
  3968. if (LrpcReplyMessage->Rpc.RpcHeader.Flags & LRPC_BUFFER_SERVER)
  3969. {
  3970. ASSERT((Message->Buffer == NULL)
  3971. || (PtrToMsgPtr(Message->Buffer) == LrpcReplyMessage->Rpc.Request.DataEntries[0].Base));
  3972. LrpcReplyMessage->LpcHeader.u1.s1.TotalLength =
  3973. LrpcReplyMessage->LpcHeader.u1.s1.DataLength
  3974. + sizeof(PORT_MESSAGE);
  3975. if (LrpcReplyMessage->Rpc.RpcHeader.Flags & LRPC_EEINFO_PRESENT)
  3976. {
  3977. LrpcReplyMessage->Rpc.RpcHeader.MessageType = LRPC_MSG_FAULT2;
  3978. // for FAULT2, the length has already been set
  3979. }
  3980. else
  3981. {
  3982. LrpcReplyMessage->Rpc.RpcHeader.MessageType = LRPC_MSG_RESPONSE;
  3983. LrpcReplyMessage->Rpc.Request.DataEntries[0].Size =
  3984. Message->BufferLength ;
  3985. }
  3986. LrpcReplyMessage->Rpc.RpcHeader.CallId = CallId;
  3987. NtStatus = NtRequestWaitReplyPort(Association->LpcReplyPort,
  3988. (PORT_MESSAGE *) LrpcReplyMessage,
  3989. (PORT_MESSAGE *) &ReplyMessage) ;
  3990. if (NT_ERROR(NtStatus))
  3991. {
  3992. if (Message->Buffer)
  3993. {
  3994. RpcpFarFree(Message->Buffer);
  3995. }
  3996. return RPC_S_CALL_FAILED ;
  3997. }
  3998. else
  3999. {
  4000. ASSERT((ReplyMessage.Rpc.RpcHeader.MessageType == LRPC_MSG_ACK)
  4001. ||
  4002. (ReplyMessage.Rpc.RpcHeader.MessageType == LRPC_MSG_FAULT));
  4003. if (!PARTIAL(Message) &&
  4004. (LrpcReplyMessage->Rpc.RpcHeader.MessageType != LRPC_MSG_FAULT2) &&
  4005. (LrpcReplyMessage->Rpc.RpcHeader.MessageType != LRPC_MSG_FAULT))
  4006. {
  4007. if (Message->Buffer)
  4008. {
  4009. RpcpFarFree(Message->Buffer);
  4010. }
  4011. }
  4012. if (ReplyMessage.Rpc.RpcHeader.MessageType == LRPC_MSG_ACK)
  4013. {
  4014. *Shutup = ReplyMessage.Ack.Shutup;
  4015. }
  4016. else
  4017. {
  4018. Status = ReplyMessage.Fault.RpcStatus;
  4019. return Status;
  4020. }
  4021. }
  4022. }
  4023. else
  4024. {
  4025. ASSERT(!PARTIAL(Message)) ;
  4026. LrpcReplyMessage->Rpc.RpcHeader.MessageType = LRPC_MSG_RESPONSE;
  4027. NtStatus = SendDGReply(LrpcReplyMessage) ;
  4028. if (NT_ERROR(NtStatus))
  4029. {
  4030. return RPC_S_CALL_FAILED ;
  4031. }
  4032. }
  4033. if (RemainingLength)
  4034. {
  4035. ASSERT(PARTIAL(Message)) ;
  4036. RpcpMemoryMove(Message->Buffer,
  4037. (char *) Message->Buffer + Message->BufferLength,
  4038. RemainingLength) ;
  4039. Message->BufferLength = RemainingLength ;
  4040. return (RPC_S_SEND_INCOMPLETE) ;
  4041. }
  4042. return RPC_S_OK ;
  4043. }
  4044. inline RPC_STATUS
  4045. LRPC_SCALL::GetBufferDo(
  4046. IN OUT PRPC_MESSAGE Message,
  4047. IN unsigned long NewSize,
  4048. IN BOOL fDataValid
  4049. )
  4050. /*++
  4051. Routine Description:
  4052. description
  4053. Arguments:
  4054. arg1 - description
  4055. Return Value:
  4056. RPC_S_OK - Function succeeded
  4057. RPC_S_OUT_OF_MEMORY - we ran out of memory
  4058. --*/
  4059. {
  4060. void *NewBuffer ;
  4061. if (NewSize < CurrentBufferLength)
  4062. {
  4063. Message->BufferLength = NewSize ;
  4064. }
  4065. else
  4066. {
  4067. NewBuffer = RpcpFarAllocate(NewSize) ;
  4068. if (NewBuffer == 0)
  4069. {
  4070. RpcpFarFree(Message->Buffer) ;
  4071. Message->BufferLength = 0;
  4072. return RPC_S_OUT_OF_MEMORY ;
  4073. }
  4074. if (fDataValid && Message->BufferLength > 0)
  4075. {
  4076. RpcpMemoryCopy(NewBuffer,
  4077. Message->Buffer,
  4078. Message->BufferLength) ;
  4079. }
  4080. if (EXTRA(Message))
  4081. {
  4082. ASSERT(Message->ReservedForRuntime) ;
  4083. ((PRPC_RUNTIME_INFO)Message->ReservedForRuntime)->OldBuffer =
  4084. NewBuffer;
  4085. }
  4086. RpcpFarFree(Message->Buffer) ;
  4087. Message->Buffer = NewBuffer ;
  4088. Message->BufferLength = NewSize ;
  4089. }
  4090. return RPC_S_OK ;
  4091. }
  4092. RPC_STATUS
  4093. LRPC_SCALL::SendReceive (
  4094. IN OUT PRPC_MESSAGE Message
  4095. )
  4096. /*++
  4097. Routine Description:
  4098. Arguments:
  4099. Message - Supplies the request and returns the response of a remote
  4100. procedure call.
  4101. Return Value:
  4102. RPC_S_OK - The remote procedure call completed successful.
  4103. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to perform the
  4104. remote procedure call.
  4105. RPC_S_OUT_OF_RESOURCES - Insufficient resources are available to complete
  4106. the remote procedure call.
  4107. --*/
  4108. {
  4109. NTSTATUS NtStatus;
  4110. RPC_STATUS ExceptionCode, Status;
  4111. LRPC_MESSAGE *LrpcSavedMessage;
  4112. SIZE_T NumberOfBytesRead;
  4113. RPC_MESSAGE RpcMessage ;
  4114. RPC_RUNTIME_INFO RuntimeInfo ;
  4115. PRPC_DISPATCH_TABLE DispatchTableToUse;
  4116. // The LrpcMessage must be saved, it is in use by the stub. The current
  4117. // LrpcReplyMessage can be used for the callback request message and reply.
  4118. //
  4119. // We must:
  4120. // Save the current LrpcRequestMessage
  4121. // Make the current LrpcReplyMessage the LrpcRequestMessage
  4122. // Allocate a new LrpcReplyMessage.
  4123. LrpcSavedMessage = LrpcRequestMessage;
  4124. LrpcRequestMessage = LrpcReplyMessage;
  4125. LrpcReplyMessage = 0; // Only needed if we receive a recursive request.
  4126. Association->Address->Server->OutgoingCallback();
  4127. // NDR_DREP_ASCII | NDR_DREP_LITTLE_ENDIAN | NDR_DREP_IEEE
  4128. Message->DataRepresentation = 0x00 | 0x10 | 0x0000;
  4129. LrpcRequestMessage->LpcHeader.u1.s1.TotalLength = sizeof(PORT_MESSAGE)
  4130. + LrpcRequestMessage->LpcHeader.u1.s1.DataLength;
  4131. LrpcRequestMessage->LpcHeader.u2.s2.Type = LPC_REQUEST;
  4132. INITMSG(LrpcRequestMessage, ClientId, CallbackId, MessageId);
  4133. LrpcRequestMessage->Rpc.RpcHeader.MessageType = LRPC_MSG_CALLBACK;
  4134. LrpcRequestMessage->Rpc.RpcHeader.ProcedureNumber = (unsigned short) Message->ProcNum;
  4135. LrpcRequestMessage->Rpc.RpcHeader.PresentContext =
  4136. SBinding->GetOnTheWirePresentationContext();
  4137. NtStatus = NtRequestWaitReplyPort(Association->LpcServerPort,
  4138. (PORT_MESSAGE *) LrpcRequestMessage,
  4139. (PORT_MESSAGE *) LrpcRequestMessage);
  4140. if (NT_ERROR(NtStatus))
  4141. {
  4142. LrpcReplyMessage = LrpcRequestMessage;
  4143. LrpcRequestMessage = LrpcSavedMessage;
  4144. if (NtStatus == STATUS_NO_MEMORY)
  4145. {
  4146. return(RPC_S_OUT_OF_MEMORY);
  4147. }
  4148. if (NtStatus == STATUS_INSUFFICIENT_RESOURCES)
  4149. {
  4150. return(RPC_S_OUT_OF_RESOURCES);
  4151. }
  4152. #if DBG
  4153. if ((NtStatus != STATUS_INVALID_PORT_HANDLE)
  4154. && (NtStatus != STATUS_INVALID_HANDLE)
  4155. && (NtStatus != STATUS_INVALID_CID)
  4156. && (NtStatus != STATUS_PORT_DISCONNECTED)
  4157. && (NtStatus != STATUS_LPC_REPLY_LOST))
  4158. {
  4159. PrintToDebugger("RPC : NtRequestWaitReplyPort : %lx\n",
  4160. NtStatus);
  4161. ASSERT(0) ;
  4162. }
  4163. #endif // DBG
  4164. return(RPC_S_CALL_FAILED);
  4165. }
  4166. for (;;)
  4167. {
  4168. if (LrpcRequestMessage->Rpc.RpcHeader.MessageType
  4169. == LRPC_MSG_FAULT)
  4170. {
  4171. Status = LrpcRequestMessage->Fault.RpcStatus;
  4172. break;
  4173. }
  4174. if (LrpcRequestMessage->Rpc.RpcHeader.MessageType
  4175. == LRPC_MSG_RESPONSE)
  4176. {
  4177. if (LrpcRequestMessage->Rpc.RpcHeader.Flags & LRPC_BUFFER_REQUEST)
  4178. {
  4179. LrpcRequestMessage->LpcHeader.ClientId = LrpcSavedMessage->Rpc.LpcHeader.ClientId;
  4180. LrpcRequestMessage->LpcHeader.CallbackId = LrpcRequestMessage->Rpc.LpcHeader.CallbackId + 1;
  4181. LrpcSavedMessage->LpcHeader.MessageId = LrpcSavedMessage->Rpc.LpcHeader.MessageId;
  4182. }
  4183. Status = LrpcMessageToRpcMessage(LrpcRequestMessage, Message);
  4184. break;
  4185. }
  4186. if (LrpcRequestMessage->Rpc.RpcHeader.MessageType
  4187. == LRPC_MSG_PUSH)
  4188. {
  4189. ASSERT(PushedResponse == 0);
  4190. PushedResponse = RpcpFarAllocate(
  4191. (unsigned int)
  4192. LrpcRequestMessage->Push.Response.DataEntries[0].Size);
  4193. if (PushedResponse == 0)
  4194. {
  4195. LrpcRequestMessage->Push.RpcStatus = RPC_S_OUT_OF_MEMORY;
  4196. }
  4197. else
  4198. {
  4199. NtStatus = NtReadRequestData(
  4200. Association->LpcServerPort,
  4201. (PORT_MESSAGE *) LrpcRequestMessage,
  4202. 0,
  4203. PushedResponse,
  4204. LrpcRequestMessage->Push.Response.DataEntries[0].Size,
  4205. &NumberOfBytesRead);
  4206. if (NT_ERROR(NtStatus))
  4207. {
  4208. RpcpFarFree(PushedResponse);
  4209. PushedResponse = 0;
  4210. LrpcRequestMessage->Push.RpcStatus = RPC_S_OUT_OF_MEMORY;
  4211. }
  4212. else
  4213. {
  4214. ASSERT(LrpcRequestMessage->Push.Response.DataEntries[0].Size
  4215. == NumberOfBytesRead);
  4216. LrpcRequestMessage->Push.RpcStatus = RPC_S_OK;
  4217. }
  4218. }
  4219. INITMSG(LrpcRequestMessage,
  4220. ClientId,
  4221. CallbackId,
  4222. MessageId) ;
  4223. NtStatus = NtReplyWaitReplyPort(Association->LpcServerPort,
  4224. (PORT_MESSAGE *) LrpcRequestMessage);
  4225. if (PushedResponse)
  4226. {
  4227. RpcpFarFree(PushedResponse);
  4228. PushedResponse = 0;
  4229. }
  4230. }
  4231. else
  4232. {
  4233. VALIDATE(LrpcRequestMessage->Rpc.RpcHeader.MessageType)
  4234. {
  4235. LRPC_MSG_REQUEST
  4236. } END_VALIDATE;
  4237. Status = LrpcMessageToRpcMessage(LrpcRequestMessage,
  4238. Message);
  4239. if (Status != RPC_S_OK)
  4240. {
  4241. LrpcRequestMessage->Fault.RpcHeader.MessageType =
  4242. LRPC_MSG_FAULT;
  4243. LrpcRequestMessage->Fault.RpcStatus = LrpcMapRpcStatus(Status);
  4244. LrpcRequestMessage->LpcHeader.u1.s1.DataLength =
  4245. sizeof(LRPC_FAULT_MESSAGE) - sizeof(PORT_MESSAGE);
  4246. LrpcRequestMessage->LpcHeader.u1.s1.TotalLength =
  4247. sizeof(LRPC_FAULT_MESSAGE);
  4248. INITMSG(LrpcRequestMessage,
  4249. ClientId,
  4250. CallbackId,
  4251. MessageId) ;
  4252. NtStatus = NtReplyWaitReplyPort(Association->LpcServerPort,
  4253. (PORT_MESSAGE *) LrpcRequestMessage);
  4254. }
  4255. else
  4256. {
  4257. LrpcReplyMessage = new LRPC_MESSAGE;
  4258. if (LrpcReplyMessage != 0)
  4259. {
  4260. SBinding->GetSelectedTransferSyntaxAndDispatchTable(&Message->TransferSyntax,
  4261. &DispatchTableToUse);
  4262. Message->ProcNum =
  4263. LrpcRequestMessage->Rpc.RpcHeader.ProcedureNumber;
  4264. RuntimeInfo.Length = sizeof(RPC_RUNTIME_INFO) ;
  4265. RpcMessage = *Message ;
  4266. RpcMessage.ReservedForRuntime = &RuntimeInfo ;
  4267. if (ObjectUuidFlag != 0)
  4268. {
  4269. Status = SBinding->RpcInterface->
  4270. DispatchToStubWithObject(
  4271. &RpcMessage,
  4272. &ObjectUuid,
  4273. 1,
  4274. DispatchTableToUse,
  4275. &ExceptionCode);
  4276. }
  4277. else
  4278. {
  4279. Status = SBinding->RpcInterface->
  4280. DispatchToStub(
  4281. &RpcMessage,
  4282. 1,
  4283. DispatchTableToUse,
  4284. &ExceptionCode);
  4285. }
  4286. *Message = RpcMessage ;
  4287. // Because we must send the reply and recieve the
  4288. // reply into the same message, we just copy the
  4289. // response into the LrpcRequestMessage
  4290. RpcpMemoryCopy(LrpcRequestMessage,
  4291. LrpcReplyMessage,
  4292. sizeof(LRPC_MESSAGE));
  4293. delete LrpcReplyMessage;
  4294. LrpcReplyMessage = 0;
  4295. }
  4296. else
  4297. Status = RPC_S_OUT_OF_MEMORY;
  4298. if (Status != RPC_S_OK)
  4299. {
  4300. VALIDATE(Status)
  4301. {
  4302. RPC_S_OUT_OF_MEMORY,
  4303. RPC_P_EXCEPTION_OCCURED,
  4304. RPC_S_PROCNUM_OUT_OF_RANGE
  4305. } END_VALIDATE;
  4306. if (Status == RPC_P_EXCEPTION_OCCURED)
  4307. {
  4308. Status = LrpcMapRpcStatus(ExceptionCode);
  4309. }
  4310. LrpcRequestMessage->Fault.RpcStatus = Status;
  4311. LrpcRequestMessage->LpcHeader.u1.s1.DataLength =
  4312. sizeof(LRPC_FAULT_MESSAGE) - sizeof(PORT_MESSAGE);
  4313. LrpcRequestMessage->LpcHeader.u1.s1.TotalLength =
  4314. sizeof(LRPC_FAULT_MESSAGE);
  4315. LrpcRequestMessage->Fault.RpcHeader.MessageType =
  4316. LRPC_MSG_FAULT;
  4317. }
  4318. else
  4319. {
  4320. LrpcRequestMessage->LpcHeader.u1.s1.TotalLength =
  4321. sizeof(PORT_MESSAGE)
  4322. + LrpcRequestMessage->LpcHeader.u1.s1.DataLength;
  4323. LrpcRequestMessage->Rpc.RpcHeader.MessageType =
  4324. LRPC_MSG_RESPONSE;
  4325. }
  4326. INITMSG(LrpcRequestMessage,
  4327. ClientId,
  4328. CallbackId,
  4329. MessageId) ;
  4330. NtStatus = NtReplyWaitReplyPort(Association->LpcServerPort,
  4331. (PORT_MESSAGE *) LrpcRequestMessage);
  4332. }
  4333. }
  4334. if (NT_ERROR(NtStatus))
  4335. {
  4336. if (NtStatus == STATUS_NO_MEMORY)
  4337. {
  4338. Status = RPC_S_OUT_OF_MEMORY;
  4339. }
  4340. else if (NtStatus == STATUS_INSUFFICIENT_RESOURCES)
  4341. {
  4342. Status = RPC_S_OUT_OF_RESOURCES;
  4343. }
  4344. else
  4345. {
  4346. VALIDATE(NtStatus)
  4347. {
  4348. STATUS_INVALID_PORT_HANDLE,
  4349. STATUS_INVALID_HANDLE,
  4350. STATUS_INVALID_CID,
  4351. STATUS_PORT_DISCONNECTED,
  4352. STATUS_LPC_REPLY_LOST
  4353. } END_VALIDATE;
  4354. Status = RPC_S_CALL_FAILED;
  4355. }
  4356. break;
  4357. }
  4358. }
  4359. if (Status == RPC_S_OK)
  4360. {
  4361. Message->Handle = (RPC_BINDING_HANDLE) this;
  4362. }
  4363. ASSERT(LrpcReplyMessage == 0);
  4364. LrpcReplyMessage = LrpcRequestMessage;
  4365. LrpcRequestMessage = LrpcSavedMessage;
  4366. return(Status);
  4367. }
  4368. void
  4369. LRPC_SCALL::FreeObject (
  4370. )
  4371. {
  4372. LRPC_SASSOCIATION *MyAssociation;
  4373. ASSERT(pAsync) ;
  4374. ASSERT(DispatchBuffer) ;
  4375. if (DispatchBuffer != LrpcRequestMessage->Rpc.Buffer)
  4376. {
  4377. RpcpFarFree(DispatchBuffer);
  4378. }
  4379. FreeMessage(LrpcRequestMessage) ;
  4380. SBinding->RpcInterface->EndCall(0, 1) ;
  4381. MyAssociation = Association;
  4382. MyAssociation->FreeSCall(this) ;
  4383. MyAssociation->Address->DereferenceAssociation(MyAssociation);
  4384. // Warning: The SCALL could have been nuked at this point.
  4385. // DO NOT touch the SCALL after this
  4386. }
  4387. RPC_STATUS
  4388. LRPC_SCALL::AsyncSend (
  4389. IN OUT PRPC_MESSAGE Message
  4390. )
  4391. /*++
  4392. Routine Description:
  4393. Send an async reply. This request can either be partial or complete.
  4394. If it is a complete request, we cleanup the SCall.
  4395. Arguments:
  4396. Message - contains the request
  4397. Return Value:
  4398. RPC_S_OK - Function succeeded
  4399. RPC_S_SEND_INCOMPLETE - some data still needs to be sent.
  4400. Message->Buffer pointes to the remaining data, and
  4401. Message->BufferLength is the length of the remaining data.
  4402. RPC_S_OUT_OF_MEMORY - we ran out of memory
  4403. --*/
  4404. {
  4405. RPC_STATUS Status = RPC_S_OK;
  4406. NTSTATUS NtStatus ;
  4407. BOOL fRetVal ;
  4408. BOOL Shutup ;
  4409. ASSERT(ReceiveEvent) ;
  4410. if (AsyncStatus != RPC_S_OK)
  4411. {
  4412. if (PARTIAL(Message))
  4413. {
  4414. Status = AsyncStatus;
  4415. }
  4416. goto Cleanup;
  4417. }
  4418. FirstSend = 0;
  4419. if (Flags & LRPC_NON_PIPE)
  4420. {
  4421. LrpcReplyMessage->Rpc.RpcHeader.MessageType = LRPC_MSG_RESPONSE;
  4422. ASSERT(!IsClientAsync()) ;
  4423. NtStatus = Association->ReplyMessage(LrpcReplyMessage);
  4424. if (!NT_SUCCESS(NtStatus))
  4425. {
  4426. Status = RPC_S_OUT_OF_MEMORY ;
  4427. }
  4428. }
  4429. else
  4430. {
  4431. Status = SendRequest(Message, &Shutup) ;
  4432. }
  4433. if (PARTIAL(Message))
  4434. {
  4435. if (Status == RPC_S_OK
  4436. || Status == RPC_S_SEND_INCOMPLETE)
  4437. {
  4438. if ((pAsync->Flags & RPC_C_NOTIFY_ON_SEND_COMPLETE) && !Shutup)
  4439. {
  4440. CallMutex->Request() ;
  4441. if (!IssueNotification(RpcSendComplete))
  4442. {
  4443. Status = RPC_S_OUT_OF_MEMORY ;
  4444. }
  4445. CallMutex->Clear() ;
  4446. }
  4447. return Status;
  4448. }
  4449. }
  4450. else
  4451. {
  4452. //
  4453. // Non partial async sends will always succeed
  4454. // if they fail, we will hide the error
  4455. //
  4456. Status = RPC_S_OK;
  4457. }
  4458. Cleanup:
  4459. //
  4460. // on the server, the stub never calls FreeBuffer
  4461. //
  4462. RemoveReference();
  4463. return Status;
  4464. }
  4465. RPC_STATUS
  4466. LRPC_SCALL::AsyncReceive (
  4467. IN OUT PRPC_MESSAGE Message,
  4468. IN unsigned int Size
  4469. )
  4470. /*++
  4471. Routine Description:
  4472. On the server, this routine is only called when the stub needs
  4473. more data to unmarshall the non pipe parameters, or when it needs
  4474. pipe data.
  4475. Arguments:
  4476. Message - contains information about the request
  4477. Size - needed size
  4478. Return Value:
  4479. RPC_S_OK - Function succeeded
  4480. RPC_S_OUT_OF_MEMORY - we ran out of memory
  4481. --*/
  4482. {
  4483. RPC_STATUS Status ;
  4484. int Extra = IsExtraMessage(Message);
  4485. ASSERT(ReceiveEvent) ;
  4486. if (PARTIAL(Message) == 0)
  4487. {
  4488. return Receive(Message, Size);
  4489. }
  4490. if (Extra)
  4491. {
  4492. Status = Receive(Message, Size);
  4493. //
  4494. // don't need to check the status. If Receive failed, we are
  4495. // never going to access dispatch buffer anyway
  4496. //
  4497. DispatchBuffer = Message->Buffer ;
  4498. return Status;
  4499. }
  4500. CallMutex->Request();
  4501. Message->DataRepresentation = 0x00 | 0x10 | 0x0000;
  4502. if (BufferComplete == 0
  4503. && RcvBufferLength < Size)
  4504. {
  4505. if (NOTIFY(Message))
  4506. {
  4507. NeededLength = Size ;
  4508. }
  4509. CallMutex->Clear() ;
  4510. return RPC_S_ASYNC_CALL_PENDING;
  4511. }
  4512. else
  4513. {
  4514. Status = GetCoalescedBuffer(Message, 0);
  4515. }
  4516. CallMutex->Clear();
  4517. return Status ;
  4518. }
  4519. RPC_STATUS
  4520. LRPC_SCALL::SetAsyncHandle (
  4521. IN PRPC_ASYNC_STATE pAsync
  4522. )
  4523. /*++
  4524. Routine Description:
  4525. Set the async handle corresponding this SCALL. This call is made
  4526. by the stubs.
  4527. Arguments:
  4528. pAsync - The async handle to association with this SCall
  4529. Return Value:
  4530. RPC_S_OK - Function succeeded
  4531. RPC_S_OUT_OF_MEMORY - we ran out of memory
  4532. --*/
  4533. {
  4534. RPC_STATUS Status ;
  4535. THREAD *Thread = RpcpGetThreadPointer();
  4536. ASSERT(Thread);
  4537. ASSERT(pAsync);
  4538. Thread->fAsync = TRUE;
  4539. if (DebugCell)
  4540. {
  4541. ASSERT(IsServerSideDebugInfoEnabled());
  4542. DebugCell->CallFlags |= DBGCELL_ASYNC_CALL;
  4543. }
  4544. if (ReceiveEvent == 0)
  4545. {
  4546. Status = SetupCall();
  4547. if (Status != RPC_S_OK)
  4548. {
  4549. return Status;
  4550. }
  4551. }
  4552. if (LrpcAsyncReplyMessage == 0)
  4553. {
  4554. LrpcAsyncReplyMessage = AllocateMessage() ;
  4555. if (LrpcAsyncReplyMessage == 0)
  4556. {
  4557. return RPC_S_OUT_OF_MEMORY ;
  4558. }
  4559. }
  4560. LrpcReplyMessage = LrpcAsyncReplyMessage;
  4561. LrpcReplyMessage->Rpc.RpcHeader.CallId = CallId ;
  4562. INITMSG(LrpcReplyMessage,
  4563. ClientId,
  4564. CallbackId,
  4565. MessageId) ;
  4566. this->pAsync = pAsync ;
  4567. return RPC_S_OK ;
  4568. }
  4569. RPC_STATUS
  4570. LRPC_SCALL::ProcessResponse (
  4571. IN LRPC_MESSAGE **LrpcMessage
  4572. )
  4573. /*++
  4574. Routine Description:
  4575. A buffer has just arrived, process it. If some other buffer is already
  4576. processing buffers, simply queue it and go away. Otherwise, does
  4577. the processing ourselves.
  4578. Arguments:
  4579. Message - Details on the arrived message
  4580. --*/
  4581. {
  4582. RPC_MESSAGE Message ;
  4583. RPC_STATUS Status ;
  4584. switch ((*LrpcMessage)->Rpc.RpcHeader.MessageType)
  4585. {
  4586. case LRPC_SERVER_SEND_MORE:
  4587. if (pAsync && (pAsync->Flags & RPC_C_NOTIFY_ON_SEND_COMPLETE))
  4588. {
  4589. if (!IssueNotification(RpcSendComplete))
  4590. {
  4591. AsyncStatus = RPC_S_OUT_OF_MEMORY ;
  4592. #if DBG
  4593. PrintToDebugger("RPC: IssueNotification failed\n") ;
  4594. #endif
  4595. //
  4596. // We are pretty much hosed here, but we'll try to
  4597. // queue notification anyway.
  4598. //
  4599. IssueNotification() ;
  4600. return RPC_S_OUT_OF_MEMORY ;
  4601. }
  4602. }
  4603. return RPC_S_OK ;
  4604. case LRPC_MSG_CANCEL:
  4605. InterlockedExchange(&CancelPending, 1);
  4606. return RPC_S_OK;
  4607. default:
  4608. break;
  4609. }
  4610. CallMutex->Request() ;
  4611. ASSERT(BufferComplete == 0);
  4612. Message.RpcFlags = 0;
  4613. Status = LrpcMessageToRpcMessage(
  4614. *LrpcMessage,
  4615. &Message) ;
  4616. if (Status != RPC_S_OK)
  4617. {
  4618. #if DBG
  4619. PrintToDebugger("RPC: LrpcMessageToRpcMessage failed: %x\n", Status) ;
  4620. #endif
  4621. AsyncStatus = Status ;
  4622. IssueNotification() ;
  4623. return Status ;
  4624. }
  4625. if (COMPLETE(&Message))
  4626. {
  4627. ASSERT(BufferComplete == 0);
  4628. BufferComplete = 1;
  4629. }
  4630. if (Message.BufferLength)
  4631. {
  4632. RcvBufferLength += Message.BufferLength ;
  4633. if (BufferQueue.PutOnQueue(Message.Buffer,
  4634. Message.BufferLength))
  4635. {
  4636. AsyncStatus = Status = RPC_S_OUT_OF_MEMORY ;
  4637. #if DBG
  4638. PrintToDebugger("RPC: PutOnQueue failed\n") ;
  4639. #endif
  4640. }
  4641. }
  4642. if (IsSyncCall())
  4643. {
  4644. CallMutex->Clear() ;
  4645. ReceiveEvent->Raise();
  4646. }
  4647. else
  4648. {
  4649. if (Status == RPC_S_OK
  4650. && NeededLength > 0
  4651. && RcvBufferLength >= NeededLength)
  4652. {
  4653. IssueNotification(RpcReceiveComplete);
  4654. }
  4655. CallMutex->Clear() ;
  4656. }
  4657. return Status ;
  4658. }
  4659. RPC_STATUS
  4660. LRPC_SCALL::GetCoalescedBuffer (
  4661. IN PRPC_MESSAGE Message,
  4662. IN BOOL BufferValid
  4663. )
  4664. /*++
  4665. Routine Description:
  4666. Remove buffers from the queue and coalesce them into a single buffer.
  4667. Arguments:
  4668. Message - on return this will contain the coalesced buffer, Message->BufferLength
  4669. gives us the length of the coalesced buffer.
  4670. BufferValid - Tells us if Message->Buffer is valid on entry.
  4671. Return Value:
  4672. RPC_S_OK - Function succeeded
  4673. RPC_S_OUT_OF_MEMORY - we ran out of memory
  4674. --*/
  4675. {
  4676. void *NewBuffer, *Buffer ;
  4677. char *Current ;
  4678. unsigned int bufferlength ;
  4679. unsigned int TotalLength ;
  4680. LRPC_MESSAGE SendMore ;
  4681. NTSTATUS NtStatus ;
  4682. CallMutex->Request() ;
  4683. ASSERT(RcvBufferLength);
  4684. if (BufferValid)
  4685. {
  4686. TotalLength = RcvBufferLength + Message->BufferLength ;
  4687. }
  4688. else
  4689. {
  4690. TotalLength = RcvBufferLength ;
  4691. }
  4692. NewBuffer = RpcpFarAllocate(TotalLength) ;
  4693. if (NewBuffer == 0)
  4694. {
  4695. CallMutex->Clear() ;
  4696. return RPC_S_OUT_OF_MEMORY;
  4697. }
  4698. if (BufferValid)
  4699. {
  4700. RpcpMemoryCopy(NewBuffer, Message->Buffer, Message->BufferLength) ;
  4701. Current = (char *) NewBuffer + Message->BufferLength ;
  4702. }
  4703. else
  4704. {
  4705. Current = (char *) NewBuffer;
  4706. }
  4707. while ((Buffer = BufferQueue.TakeOffQueue(&bufferlength)) != 0)
  4708. {
  4709. RpcpMemoryCopy(Current, Buffer, bufferlength) ;
  4710. Current += bufferlength ;
  4711. RpcpFarFree(Buffer);
  4712. }
  4713. if (BufferValid && Message->Buffer)
  4714. {
  4715. RpcpFarFree(Message->Buffer);
  4716. //
  4717. // Update the dispatch buffer
  4718. //
  4719. ASSERT(Message->ReservedForRuntime) ;
  4720. ((PRPC_RUNTIME_INFO)Message->ReservedForRuntime)->OldBuffer = NewBuffer;
  4721. if (Message->Buffer == DispatchBuffer)
  4722. DispatchBuffer = NewBuffer;
  4723. }
  4724. Message->Buffer = NewBuffer ;
  4725. Message->BufferLength = TotalLength ;
  4726. RcvBufferLength = 0;
  4727. if (BufferComplete)
  4728. {
  4729. Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
  4730. }
  4731. else
  4732. {
  4733. if (Choked)
  4734. {
  4735. CallMutex->Clear() ;
  4736. //
  4737. // send a message to the client
  4738. // to start sending data again
  4739. //
  4740. SendMore.Rpc.RpcHeader.MessageType = LRPC_CLIENT_SEND_MORE;
  4741. SendMore.LpcHeader.u1.s1.DataLength =
  4742. sizeof(LRPC_MESSAGE) - sizeof(PORT_MESSAGE);
  4743. SendMore.LpcHeader.u2.ZeroInit = 0;
  4744. SendMore.Rpc.RpcHeader.CallId = CallId ;
  4745. NtStatus = SendDGReply(&SendMore) ;
  4746. if (!NT_SUCCESS(NtStatus))
  4747. {
  4748. return RPC_S_CALL_FAILED ;
  4749. }
  4750. return RPC_S_OK;
  4751. }
  4752. }
  4753. CallMutex->Clear() ;
  4754. return RPC_S_OK ;
  4755. }
  4756. RPC_STATUS
  4757. LRPC_SCALL::ImpersonateClient (
  4758. )
  4759. /*++
  4760. Routine Description:
  4761. We will impersonate the client which made the remote procedure call.
  4762. --*/
  4763. {
  4764. NTSTATUS NtStatus;
  4765. RPC_STATUS Status;
  4766. HANDLE hToken;
  4767. DWORD LastError;
  4768. Status = SetThreadSecurityContext((SECURITY_CONTEXT *) MAXUINT_PTR);
  4769. if (RPC_S_OK != Status)
  4770. {
  4771. return Status;
  4772. }
  4773. if (SContext)
  4774. {
  4775. if (SContext->GetAnonymousFlag())
  4776. {
  4777. NtStatus = NtImpersonateAnonymousToken(NtCurrentThread());
  4778. if (!NT_SUCCESS(NtStatus))
  4779. {
  4780. RpcpErrorAddRecord(EEInfoGCRuntime,
  4781. RPC_S_ACCESS_DENIED,
  4782. EEInfoDLLRPC_SCALL__ImpersonateClient10,
  4783. (ULONG)NtStatus,
  4784. (ULONG)GetCurrentThreadId());
  4785. ClearThreadSecurityContext();
  4786. return RPC_S_ACCESS_DENIED;
  4787. }
  4788. }
  4789. else if (SetThreadToken(NULL, SContext->hToken) == FALSE)
  4790. {
  4791. LastError = GetLastError();
  4792. ClearThreadSecurityContext();
  4793. if (LastError == ERROR_OUTOFMEMORY)
  4794. {
  4795. return (RPC_S_OUT_OF_MEMORY) ;
  4796. }
  4797. return RPC_S_ACCESS_DENIED;
  4798. }
  4799. }
  4800. else
  4801. {
  4802. NtStatus = NtImpersonateClientOfPort(Association->LpcServerPort,
  4803. (PORT_MESSAGE *) LrpcRequestMessage);
  4804. if ((NtStatus == STATUS_INVALID_CID)
  4805. || (NtStatus == STATUS_PORT_DISCONNECTED)
  4806. || (NtStatus == STATUS_REPLY_MESSAGE_MISMATCH))
  4807. {
  4808. ClearThreadSecurityContext();
  4809. return RPC_S_NO_CONTEXT_AVAILABLE;
  4810. }
  4811. if (!NT_SUCCESS(NtStatus))
  4812. {
  4813. #if DBG
  4814. PrintToDebugger("RPC : NtImpersonateClientOfPort : %lx\n",NtStatus);
  4815. #endif // DBG
  4816. return RPC_S_ACCESS_DENIED;
  4817. }
  4818. }
  4819. return(RPC_S_OK);
  4820. }
  4821. RPC_STATUS
  4822. LRPC_SCALL::RevertToSelf (
  4823. )
  4824. /*++
  4825. Routine Description:
  4826. This reverts a server thread back to itself after impersonating a client.
  4827. We just check to see if the server thread is impersonating; this optimizes
  4828. the common case.
  4829. --*/
  4830. {
  4831. HANDLE ImpersonationToken = 0;
  4832. NTSTATUS NtStatus;
  4833. if (ClearThreadSecurityContext())
  4834. {
  4835. NtStatus = NtSetInformationThread(
  4836. NtCurrentThread(),
  4837. ThreadImpersonationToken,
  4838. &ImpersonationToken,
  4839. sizeof(HANDLE));
  4840. #if DBG
  4841. if (!NT_SUCCESS(NtStatus))
  4842. {
  4843. PrintToDebugger("RPC : NtSetInformationThread : %lx\n", NtStatus);
  4844. }
  4845. #endif // DBG
  4846. if (!NT_SUCCESS(NtStatus))
  4847. {
  4848. if (NtStatus == STATUS_NO_MEMORY)
  4849. {
  4850. return RPC_S_OUT_OF_MEMORY;
  4851. }
  4852. return RPC_S_ACCESS_DENIED;
  4853. }
  4854. }
  4855. return(RPC_S_OK);
  4856. }
  4857. RPC_STATUS
  4858. LRPC_SCALL::GetAuthorizationContext (
  4859. IN BOOL ImpersonateOnReturn,
  4860. IN AUTHZ_RESOURCE_MANAGER_HANDLE AuthzResourceManager,
  4861. IN PLARGE_INTEGER pExpirationTime OPTIONAL,
  4862. IN LUID Identifier,
  4863. IN DWORD Flags,
  4864. IN PVOID DynamicGroupArgs OPTIONAL,
  4865. OUT PAUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContext
  4866. )
  4867. /*++
  4868. Routine Description:
  4869. Gets an authorization context for the client that can be used
  4870. with Authz functions. The resulting context is owned by the caller
  4871. and must be freed by it.
  4872. Arguments:
  4873. ImpersonateOnReturn - if TRUE, when we return, we should be impersonating.
  4874. AuthzResourceManager - the resource manager to use (passed to Authz)
  4875. pExpirationTime - the expiration time to use (passed to Authz)
  4876. Identifier - the LUID (passed to Authz)
  4877. Flags - Flags (passed to Authz)
  4878. DynamicGroupArgs - parameter required by Authz (passed to Authz)
  4879. pAuthzClientContext - the authorization context, returned on success.
  4880. Undefined on failure.
  4881. --*/
  4882. {
  4883. RPC_STATUS Status = RPC_S_OK;
  4884. RPC_STATUS RevertStatus;
  4885. BOOL fNeedToRevert = FALSE;
  4886. HANDLE ImpersonationToken;
  4887. BOOL Result;
  4888. BOOL fImpersonating = FALSE;
  4889. PAUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContextPlaceholder;
  4890. ASSERT (AuthzResourceManager != NULL);
  4891. if (ImpersonateOnReturn
  4892. || (SContext == NULL)
  4893. || (SContext->AuthzClientContext == NULL))
  4894. {
  4895. Status = LRPC_SCALL::ImpersonateClient();
  4896. if (Status != RPC_S_OK)
  4897. {
  4898. RpcpErrorAddRecord(EEInfoGCRuntime,
  4899. Status,
  4900. EEInfoDLLRPC_SCALL__GetAuthorizationContext10,
  4901. (ULONG)ImpersonateOnReturn,
  4902. (ULONGLONG)SContext);
  4903. return Status;
  4904. }
  4905. fImpersonating = TRUE;
  4906. if (!ImpersonateOnReturn)
  4907. {
  4908. fNeedToRevert = TRUE;
  4909. }
  4910. }
  4911. if (SContext && SContext->AuthzClientContext)
  4912. {
  4913. Status = DuplicateAuthzContext(SContext->AuthzClientContext,
  4914. pExpirationTime,
  4915. Identifier,
  4916. Flags,
  4917. DynamicGroupArgs,
  4918. pAuthzClientContext);
  4919. }
  4920. else
  4921. {
  4922. // either we don't have an scontext, or its
  4923. // AuthzClientContext is not set yet.
  4924. // Get the token from the thread
  4925. Result = OpenThreadToken(GetCurrentThread(),
  4926. TOKEN_QUERY,
  4927. TRUE,
  4928. &ImpersonationToken);
  4929. if (Result)
  4930. {
  4931. if (SContext)
  4932. pAuthzClientContextPlaceholder = &SContext->AuthzClientContext;
  4933. else
  4934. pAuthzClientContextPlaceholder = NULL;
  4935. Status = CreateAndSaveAuthzContextFromToken(pAuthzClientContextPlaceholder,
  4936. ImpersonationToken,
  4937. AuthzResourceManager,
  4938. pExpirationTime,
  4939. Identifier,
  4940. Flags,
  4941. DynamicGroupArgs,
  4942. pAuthzClientContext);
  4943. CloseHandle(ImpersonationToken);
  4944. }
  4945. else
  4946. {
  4947. Status = GetLastError();
  4948. if (Status == ERROR_CANT_OPEN_ANONYMOUS)
  4949. {
  4950. Result = AuthzInitializeContextFromSidFn(
  4951. AUTHZ_SKIP_TOKEN_GROUPS,
  4952. (PSID)&AnonymousSid,
  4953. AuthzResourceManager,
  4954. pExpirationTime,
  4955. Identifier,
  4956. DynamicGroupArgs,
  4957. pAuthzClientContext);
  4958. if (Result)
  4959. {
  4960. if (SContext)
  4961. {
  4962. if (InterlockedCompareExchangePointer((PVOID *)&SContext->AuthzClientContext,
  4963. pAuthzClientContext,
  4964. NULL) != NULL)
  4965. {
  4966. // somebody beat us to the punch - free the context we obtained
  4967. AuthzFreeContextFn(*pAuthzClientContext);
  4968. *pAuthzClientContext = SContext->AuthzClientContext;
  4969. }
  4970. }
  4971. // else
  4972. // the authz context is already loaded in pAuthzClientContext
  4973. Status = RPC_S_OK;
  4974. }
  4975. else
  4976. {
  4977. Status = GetLastError();
  4978. RpcpErrorAddRecord(EEInfoGCAuthz,
  4979. Status,
  4980. EEInfoDLLRPC_SCALL__GetAuthorizationContext30,
  4981. GetCurrentThreadId(),
  4982. (ULONGLONG)AuthzResourceManager);
  4983. }
  4984. }
  4985. else
  4986. {
  4987. RpcpErrorAddRecord(EEInfoGCRuntime,
  4988. Status,
  4989. EEInfoDLLRPC_SCALL__GetAuthorizationContext20,
  4990. GetCurrentThreadId());
  4991. }
  4992. }
  4993. }
  4994. // if caller didn't ask us to impersonate and we are,
  4995. // or we if he did ask us, but we failed somewhere,
  4996. // revert to self
  4997. if (fNeedToRevert || (Status && fImpersonating))
  4998. {
  4999. RevertStatus = LRPC_SCALL::RevertToSelf();
  5000. ASSERT(RevertStatus == RPC_S_OK);
  5001. }
  5002. return Status;
  5003. }
  5004. RPC_STATUS
  5005. LRPC_SCALL::IsClientLocal (
  5006. OUT unsigned int * ClientLocalFlag
  5007. )
  5008. /*++
  5009. Routine Description:
  5010. A client using LRPC will always be local.
  5011. Arguments:
  5012. ClientLocalFlag - Returns a flag which will always be set to a non-zero
  5013. value indicating that the client is local.
  5014. --*/
  5015. {
  5016. UNUSED(this);
  5017. *ClientLocalFlag = 1;
  5018. return(RPC_S_OK);
  5019. }
  5020. RPC_STATUS
  5021. LRPC_SCALL::ConvertToServerBinding (
  5022. OUT RPC_BINDING_HANDLE __RPC_FAR * ServerBinding
  5023. )
  5024. /*++
  5025. Routine Description:
  5026. If possible, convert this call into a server binding, meaning a
  5027. binding handle pointing back to the client.
  5028. Arguments:
  5029. ServerBinding - Returns the server binding.
  5030. Return Value:
  5031. RPC_S_OK - The server binding has successfully been created.
  5032. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate
  5033. a new binding handle.
  5034. --*/
  5035. {
  5036. BOOL Boolean;
  5037. RPC_STATUS Status;
  5038. RPC_CHAR UuidString[37];
  5039. RPC_CHAR * StringBinding;
  5040. RPC_CHAR * NetworkAddress;
  5041. DWORD NetworkAddressLength = MAX_COMPUTERNAME_LENGTH + 1;
  5042. if (ObjectUuidFlag != 0)
  5043. {
  5044. ObjectUuid.ConvertToString(UuidString);
  5045. UuidString[36] = '\0';
  5046. }
  5047. NetworkAddress = new RPC_CHAR[NetworkAddressLength];
  5048. if (NetworkAddress == 0)
  5049. {
  5050. return(RPC_S_OUT_OF_MEMORY);
  5051. }
  5052. Boolean = GetComputerNameW(
  5053. NetworkAddress,
  5054. &NetworkAddressLength);
  5055. if (Boolean != TRUE)
  5056. {
  5057. Status = GetLastError();
  5058. #if DBG
  5059. PrintToDebugger("RPC : GetComputerNameW : %d\n", Status);
  5060. #endif // DBG
  5061. if (Status == ERROR_NOT_ENOUGH_MEMORY)
  5062. {
  5063. Status = RPC_S_OUT_OF_MEMORY;
  5064. }
  5065. else if ((Status == ERROR_NOT_ENOUGH_QUOTA)
  5066. || (Status == ERROR_NO_SYSTEM_RESOURCES))
  5067. {
  5068. Status = RPC_S_OUT_OF_RESOURCES;
  5069. }
  5070. else
  5071. {
  5072. ASSERT(0);
  5073. Status = RPC_S_OUT_OF_MEMORY;
  5074. }
  5075. delete NetworkAddress;
  5076. return Status;
  5077. }
  5078. Status = RpcStringBindingComposeW(
  5079. (ObjectUuidFlag != 0 ? UuidString : 0),
  5080. RPC_STRING_LITERAL("ncalrpc"),
  5081. NetworkAddress,
  5082. 0,
  5083. 0,
  5084. &StringBinding);
  5085. delete NetworkAddress;
  5086. if (Status != RPC_S_OK)
  5087. {
  5088. return(Status);
  5089. }
  5090. Status = RpcBindingFromStringBindingW(
  5091. StringBinding,
  5092. ServerBinding);
  5093. RpcStringFreeW(&StringBinding);
  5094. return(Status);
  5095. }
  5096. void
  5097. LRPC_SCALL::InquireObjectUuid (
  5098. OUT RPC_UUID * ObjectUuid
  5099. )
  5100. /*++
  5101. Routine Description:
  5102. This routine copies the object uuid from the call into the supplied
  5103. ObjectUuid argument.
  5104. Arguments:
  5105. ObjectUuid - Returns a copy of the object uuid passed by the client
  5106. in the remote procedure call.
  5107. --*/
  5108. {
  5109. if (ObjectUuidFlag == 0)
  5110. {
  5111. ObjectUuid->SetToNullUuid();
  5112. }
  5113. else
  5114. {
  5115. ObjectUuid->CopyUuid(&(this->ObjectUuid));
  5116. }
  5117. }
  5118. RPC_STATUS
  5119. LRPC_SCALL::ToStringBinding (
  5120. OUT RPC_CHAR ** StringBinding
  5121. )
  5122. /*++
  5123. Routine Description:
  5124. We need to convert this call into a string binding. We will ask the
  5125. address for a binding handle which we can then convert into a string
  5126. binding.
  5127. Arguments:
  5128. StringBinding - Returns the string binding for this call.
  5129. Return Value:
  5130. --*/
  5131. {
  5132. RPC_STATUS Status;
  5133. BINDING_HANDLE * BindingHandle
  5134. = Association->Address->InquireBinding();
  5135. if (BindingHandle == 0)
  5136. {
  5137. return(RPC_S_OUT_OF_MEMORY);
  5138. }
  5139. Status = BindingHandle->ToStringBinding(StringBinding);
  5140. BindingHandle->BindingFree();
  5141. return(Status);
  5142. }
  5143. RPC_STATUS
  5144. LRPC_SCALL::GetAssociationContextCollection (
  5145. OUT ContextCollection **CtxCollection
  5146. )
  5147. {
  5148. return Association->GetAssociationContextCollection(CtxCollection);
  5149. }
  5150. inline RPC_STATUS
  5151. LRPC_SCALL::LrpcMessageToRpcMessage (
  5152. IN LRPC_MESSAGE * LrpcMessage,
  5153. IN OUT PRPC_MESSAGE Message
  5154. )
  5155. /*++
  5156. Routine Description:
  5157. We will convert from an LRPC_MESSAGE representation of a buffer (and
  5158. its length) to an RPC_MESSAGE representation.
  5159. Arguments:
  5160. RpcMessage - Returns the RPC_MESSAGE representation.
  5161. Return Value:
  5162. RPC_S_OK - We have successfully converted the message.
  5163. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to do the
  5164. conversion.
  5165. --*/
  5166. {
  5167. NTSTATUS NtStatus;
  5168. SIZE_T NumberOfBytesRead;
  5169. unsigned char MessageType = LrpcMessage->Rpc.RpcHeader.MessageType;
  5170. RPC_STATUS Status = RPC_S_OK ;
  5171. LRPC_MESSAGE ReplyMessage ;
  5172. if(LrpcMessage->Rpc.RpcHeader.Flags & LRPC_BUFFER_IMMEDIATE)
  5173. {
  5174. Message->Buffer = LrpcMessage->Rpc.Buffer;
  5175. ASSERT(LrpcMessage->LpcHeader.u1.s1.DataLength
  5176. >= sizeof(LRPC_RPC_HEADER));
  5177. Message->BufferLength =
  5178. (unsigned int) LrpcMessage->LpcHeader.u1.s1.DataLength
  5179. - sizeof(LRPC_RPC_HEADER);
  5180. Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
  5181. }
  5182. else if (LrpcMessage->Rpc.RpcHeader.Flags & LRPC_BUFFER_REQUEST)
  5183. {
  5184. Message->BufferLength = LrpcMessage->Rpc.Request.DataEntries[0].Size;
  5185. if (LrpcMessage->Rpc.RpcHeader.Flags & LRPC_BUFFER_PARTIAL)
  5186. {
  5187. CallMutex->Request() ;
  5188. //
  5189. // If the user ever specifies a Size > LRPC_THRESHOLD_SIZE
  5190. // our performance will be bad.
  5191. //
  5192. if (RcvBufferLength >= LRPC_THRESHOLD_SIZE)
  5193. {
  5194. Choked = 1;
  5195. }
  5196. CallMutex->Clear() ;
  5197. }
  5198. else
  5199. {
  5200. Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
  5201. }
  5202. Message->Buffer = RpcpFarAllocate(Message->BufferLength) ;
  5203. if (Message->Buffer == 0)
  5204. {
  5205. Status = RPC_S_OUT_OF_MEMORY ;
  5206. RpcpErrorAddRecord(EEInfoGCRuntime,
  5207. Status,
  5208. EEInfoDLLrpcMessageToRpcMessage10,
  5209. Message->BufferLength);
  5210. }
  5211. else
  5212. {
  5213. NtStatus = NtReadRequestData(Association->LpcServerPort,
  5214. (PORT_MESSAGE *) LrpcMessage,
  5215. 0,
  5216. Message->Buffer,
  5217. Message->BufferLength,
  5218. &NumberOfBytesRead) ;
  5219. if (NT_ERROR(NtStatus))
  5220. {
  5221. RpcpFarFree(Message->Buffer) ;
  5222. Message->Buffer = 0;
  5223. Status = RPC_S_OUT_OF_MEMORY ;
  5224. RpcpErrorAddRecord(EEInfoGCRuntime,
  5225. Status,
  5226. EEInfoDLLrpcMessageToRpcMessage20,
  5227. NtStatus);
  5228. }
  5229. else
  5230. {
  5231. ASSERT(Message->BufferLength == NumberOfBytesRead) ;
  5232. }
  5233. }
  5234. if (IsClientAsync())
  5235. {
  5236. COPYMSG((&ReplyMessage), LrpcMessage) ;
  5237. ReplyMessage.Ack.MessageType = LRPC_MSG_ACK ;
  5238. ReplyMessage.Ack.RpcStatus = Status;
  5239. ReplyMessage.Ack.Shutup = (short) Choked ;
  5240. ReplyMessage.LpcHeader.u1.s1.DataLength =
  5241. sizeof(LRPC_ACK_MESSAGE) - sizeof(PORT_MESSAGE) ;
  5242. NtStatus = Association->ReplyMessage(&ReplyMessage);
  5243. if (NT_ERROR(NtStatus))
  5244. {
  5245. RpcpFarFree(Message->Buffer);
  5246. RpcpErrorAddRecord(EEInfoGCRuntime,
  5247. RPC_S_OUT_OF_MEMORY,
  5248. EEInfoDLLrpcMessageToRpcMessage30,
  5249. NtStatus);
  5250. return(RPC_S_OUT_OF_MEMORY);
  5251. }
  5252. }
  5253. }
  5254. else
  5255. {
  5256. ASSERT((LrpcMessage->Rpc.RpcHeader.Flags & LRPC_BUFFER_IMMEDIATE)
  5257. || (LrpcMessage->Rpc.RpcHeader.Flags & LRPC_BUFFER_REQUEST));
  5258. }
  5259. return(Status);
  5260. }
  5261. RPC_STATUS
  5262. LRPC_SCALL::InquireAuthClient (
  5263. OUT RPC_AUTHZ_HANDLE * Privileges,
  5264. OUT RPC_CHAR * * ServerPrincipalName, OPTIONAL
  5265. OUT unsigned long * AuthenticationLevel,
  5266. OUT unsigned long * AuthenticationService,
  5267. OUT unsigned long * AuthorizationService,
  5268. IN unsigned long Flags
  5269. )
  5270. /*++
  5271. Routine Description:
  5272. Each protocol module must define this routine: it is used to obtain
  5273. the authentication and authorization information about a client making
  5274. the remote procedure call represented by this.
  5275. Arguments:
  5276. Privileges - Returns a the privileges of the client.
  5277. ServerPrincipalName - Returns the server principal name which the client
  5278. specified.
  5279. AuthenticationLevel - Returns the authentication level requested by
  5280. the client.
  5281. AuthenticationService - Returns the authentication service requested by
  5282. the client.
  5283. AuthorizationService - Returns the authorization service requested by
  5284. the client.
  5285. Return Value:
  5286. RPC_S_OK or RPC_S_* / Win32 error
  5287. --*/
  5288. {
  5289. RPC_STATUS Status;
  5290. if(ARGUMENT_PRESENT(Privileges))
  5291. {
  5292. *(RPC_CHAR **)Privileges = NULL;
  5293. Status = Association->GetClientName(this,
  5294. NULL, // ClientPrincipalNameBufferLength
  5295. (RPC_CHAR **) Privileges);
  5296. if (Status != RPC_S_OK)
  5297. {
  5298. return Status;
  5299. }
  5300. }
  5301. if (ARGUMENT_PRESENT(ServerPrincipalName))
  5302. {
  5303. *ServerPrincipalName = NULL;
  5304. }
  5305. if(ARGUMENT_PRESENT(AuthenticationLevel))
  5306. {
  5307. *AuthenticationLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY ;
  5308. }
  5309. if(ARGUMENT_PRESENT(AuthenticationService))
  5310. {
  5311. *AuthenticationService = RPC_C_AUTHN_WINNT ;
  5312. }
  5313. if(ARGUMENT_PRESENT(AuthorizationService))
  5314. {
  5315. *AuthorizationService = RPC_C_AUTHZ_NONE ;
  5316. }
  5317. return(RPC_S_OK);
  5318. }
  5319. RPC_STATUS
  5320. LRPC_SCALL::InquireCallAttributes (
  5321. IN OUT void *RpcCallAttributes
  5322. )
  5323. /*++
  5324. Routine Description:
  5325. Inquire the security context attributes for the LRPC client
  5326. Arguments:
  5327. RpcCallAttributes - a pointer to
  5328. RPC_CALL_ATTRIBUTES_V1_W structure. The Version
  5329. member must be initialized.
  5330. Return Value:
  5331. RPC_S_OK or RPC_S_* / Win32 error. EEInfo will be returned.
  5332. --*/
  5333. {
  5334. RPC_CALL_ATTRIBUTES_V1 *CallAttributes;
  5335. RPC_STATUS Status = RPC_S_OK;
  5336. CallAttributes =
  5337. (RPC_CALL_ATTRIBUTES_V1 *)RpcCallAttributes;
  5338. CallAttributes->AuthenticationLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
  5339. CallAttributes->AuthenticationService = RPC_C_AUTHN_WINNT;
  5340. CallAttributes->NullSession = FALSE;
  5341. if (CallAttributes->Flags & RPC_QUERY_CLIENT_PRINCIPAL_NAME)
  5342. {
  5343. Status = Association->GetClientName(this,
  5344. &CallAttributes->ClientPrincipalNameBufferLength,
  5345. &CallAttributes->ClientPrincipalName);
  5346. if ((Status != RPC_S_OK) && (Status != ERROR_MORE_DATA))
  5347. {
  5348. return Status;
  5349. }
  5350. }
  5351. if (CallAttributes->Flags & RPC_QUERY_SERVER_PRINCIPAL_NAME)
  5352. {
  5353. CallAttributes->ServerPrincipalNameBufferLength = 0;
  5354. }
  5355. return Status;
  5356. }
  5357. LRPC_SBINDING *
  5358. LRPC_SCALL::LookupBinding (
  5359. IN unsigned short PresentContextId
  5360. )
  5361. /*++
  5362. Function Name:LookupBinding
  5363. Parameters:
  5364. Description:
  5365. Returns:
  5366. --*/
  5367. {
  5368. LRPC_SBINDING *CurBinding;
  5369. DictionaryCursor cursor;
  5370. Association->Bindings.Reset(cursor);
  5371. while ((CurBinding = Association->Bindings.Next(cursor)))
  5372. {
  5373. if (CurBinding->GetPresentationContext() == PresentContextId)
  5374. {
  5375. return CurBinding;
  5376. }
  5377. }
  5378. return NULL;
  5379. }
  5380. LRPC_SCONTEXT::LRPC_SCONTEXT (
  5381. IN HANDLE MyToken,
  5382. IN LUID *UserLuid,
  5383. IN LRPC_SASSOCIATION *MyAssociation,
  5384. IN BOOL fDefaultLogonId,
  5385. IN BOOL fAnonymousToken
  5386. )
  5387. {
  5388. hToken = MyToken;
  5389. ClientName = NULL;
  5390. RefCount = 1;
  5391. ClearDeletedFlag();
  5392. Association = MyAssociation;
  5393. AuthzClientContext = NULL;
  5394. if (fAnonymousToken)
  5395. SetAnonymousFlag();
  5396. else
  5397. ClearAnonymousFlag();
  5398. if (fAnonymousToken)
  5399. {
  5400. ASSERT(fDefaultLogonId == FALSE);
  5401. ASSERT(UserLuid == NULL);
  5402. }
  5403. else
  5404. {
  5405. ASSERT(fAnonymousToken == FALSE);
  5406. if (fDefaultLogonId)
  5407. SetDefaultLogonIdFlag();
  5408. else
  5409. ClearDefaultLogonIdFlag();
  5410. FastCopyLUID(&ClientLuid, UserLuid);
  5411. }
  5412. }
  5413. LRPC_SCONTEXT::~LRPC_SCONTEXT (
  5414. void
  5415. )
  5416. {
  5417. if (hToken)
  5418. {
  5419. CloseHandle(hToken);
  5420. }
  5421. RpcpFarFree(ClientName);
  5422. if (AuthzClientContext)
  5423. {
  5424. AuthzFreeContextFn(AuthzClientContext);
  5425. AuthzClientContext = NULL;
  5426. }
  5427. if (GetServerSideOnlyFlag())
  5428. {
  5429. // if this is server side only context, remove us
  5430. // from the garbage collection count
  5431. InterlockedDecrement(&PeriodicGarbageCollectItems);
  5432. }
  5433. }
  5434. RPC_STATUS
  5435. LRPC_SCONTEXT::GetUserName (
  5436. IN OUT ULONG *ClientPrincipalNameBufferLength OPTIONAL,
  5437. OUT RPC_CHAR **UserName,
  5438. IN HANDLE hUserToken OPTIONAL
  5439. )
  5440. /*++
  5441. Routine Description:
  5442. Gets the user name for the given context.
  5443. Arguments:
  5444. ClientPrincipalNameBufferLength - if present, *UserName must
  5445. point to a caller supplied buffer, which if big enough,
  5446. will be filled with the client principal name. If not present,
  5447. *UserName must be NULL.
  5448. UserName - see ClientPrincipalNameBufferLength
  5449. hUserToken - if present, the user name for the given token will
  5450. be retrieved instead of the user name for the token inside
  5451. the LRPC_SCONTEXT
  5452. Return Value:
  5453. RPC_S_OK for success, or RPC_S_* / Win32 error code for error.
  5454. --*/
  5455. {
  5456. TOKEN_USER *pUser;
  5457. RPC_STATUS Status;
  5458. RPC_CHAR *ClientPrincipalName;
  5459. ULONG ClientPrincipalNameLength; // in bytes, including NULL terminator
  5460. if (ClientName == 0)
  5461. {
  5462. if (GetAnonymousFlag() == 0)
  5463. {
  5464. if (hUserToken == NULL)
  5465. {
  5466. ASSERT(hToken != NULL);
  5467. hUserToken = hToken;
  5468. }
  5469. pUser = GetSID(hUserToken);
  5470. if (pUser == 0)
  5471. {
  5472. return RPC_S_OUT_OF_MEMORY;
  5473. }
  5474. Status = LookupUser((SID *)pUser->User.Sid, &ClientPrincipalName);
  5475. delete pUser;
  5476. }
  5477. else
  5478. {
  5479. Status = LookupUser((SID *)&AnonymousSid, &ClientPrincipalName);
  5480. }
  5481. if (Status != RPC_S_OK)
  5482. {
  5483. return Status;
  5484. }
  5485. if (InterlockedCompareExchangePointer((PVOID *)&ClientName, ClientPrincipalName, NULL) != NULL)
  5486. {
  5487. // somebody beat us to the punch. Free the allocated string
  5488. delete ClientPrincipalName;
  5489. }
  5490. }
  5491. // at this stage, ClientName must contain the client principal name
  5492. ASSERT(ClientName);
  5493. // See where our caller wants us to put it
  5494. if (ARGUMENT_PRESENT(ClientPrincipalNameBufferLength))
  5495. {
  5496. // in the future, we may think of caching the length to avoid
  5497. // computing it every time
  5498. ClientPrincipalNameLength = (RpcpStringLength(ClientName) + 1) * sizeof(RPC_CHAR);
  5499. // if there is enough space in the data, copy it to user buffer
  5500. if (ClientPrincipalNameLength <= *ClientPrincipalNameBufferLength)
  5501. {
  5502. RpcpMemoryCopy(*UserName,
  5503. ClientName,
  5504. ClientPrincipalNameLength);
  5505. Status = RPC_S_OK;
  5506. }
  5507. else
  5508. {
  5509. Status = ERROR_MORE_DATA;
  5510. }
  5511. *ClientPrincipalNameBufferLength = ClientPrincipalNameLength;
  5512. return Status;
  5513. }
  5514. else
  5515. {
  5516. ASSERT(*UserName == NULL);
  5517. *UserName = ClientName;
  5518. }
  5519. return RPC_S_OK;
  5520. }
  5521. TOKEN_USER *
  5522. LRPC_SCONTEXT::GetSID (
  5523. IN HANDLE hToken
  5524. )
  5525. {
  5526. char *Buf = NULL;
  5527. ULONG Bufflen = 64 ;
  5528. ULONG Length;
  5529. Buf = new char[Bufflen];
  5530. if (Buf == 0)
  5531. {
  5532. return NULL;
  5533. }
  5534. while (1)
  5535. {
  5536. if (GetTokenInformation(hToken,
  5537. TokenUser, Buf, Bufflen,
  5538. &Length) == FALSE)
  5539. {
  5540. if (Length > Bufflen)
  5541. {
  5542. Bufflen = Length ;
  5543. delete Buf;
  5544. Buf = new char[Bufflen];
  5545. if (Buf == 0)
  5546. {
  5547. return NULL;
  5548. }
  5549. continue;
  5550. }
  5551. else
  5552. {
  5553. #if DBG
  5554. PrintToDebugger("LRPC: GetTokenInformation failed\n") ;
  5555. #endif
  5556. return NULL;
  5557. }
  5558. }
  5559. break;
  5560. }
  5561. return (TOKEN_USER *) Buf;
  5562. }
  5563. RPC_STATUS
  5564. LRPC_SCONTEXT::LookupUser (
  5565. IN SID *pSid,
  5566. OUT RPC_CHAR **UserName
  5567. )
  5568. {
  5569. unsigned long UserLength = USER_NAME_LEN ;
  5570. unsigned long OldDomainLen, OldUserLen;
  5571. unsigned long DomainLen = DOMAIN_NAME_LEN ;
  5572. RPC_CHAR *DomainName = NULL, *MyUserName = NULL;
  5573. SID_NAME_USE Name ;
  5574. RPC_STATUS Status = RPC_S_OK ;
  5575. MyUserName = new RPC_CHAR[UserLength];
  5576. if (MyUserName == 0)
  5577. {
  5578. Status = RPC_S_OUT_OF_MEMORY ;
  5579. goto Cleanup ;
  5580. }
  5581. DomainLen += UserLength ;
  5582. DomainName = new RPC_CHAR [DomainLen];
  5583. if (DomainName == 0)
  5584. {
  5585. Status = RPC_S_OUT_OF_MEMORY ;
  5586. goto Cleanup ;
  5587. }
  5588. OldDomainLen = DomainLen ;
  5589. OldUserLen = UserLength ;
  5590. while (1)
  5591. {
  5592. if (LookupAccountSidW(NULL, pSid,
  5593. MyUserName, &UserLength,
  5594. DomainName, &DomainLen, &Name) == FALSE)
  5595. {
  5596. if ((UserLength > OldUserLen) || (DomainLen > OldDomainLen))
  5597. {
  5598. if (UserLength > OldUserLen)
  5599. {
  5600. OldUserLen = UserLength ;
  5601. delete MyUserName;
  5602. MyUserName = new RPC_CHAR[UserLength];
  5603. if (MyUserName == 0)
  5604. {
  5605. Status = RPC_S_OUT_OF_MEMORY ;
  5606. goto Cleanup ;
  5607. }
  5608. }
  5609. if (DomainLen > OldDomainLen)
  5610. {
  5611. DomainLen += UserLength;
  5612. OldDomainLen = DomainLen;
  5613. delete DomainName;
  5614. DomainName = new RPC_CHAR[DomainLen];
  5615. if (DomainName == 0)
  5616. {
  5617. Status = RPC_S_OUT_OF_MEMORY ;
  5618. goto Cleanup ;
  5619. }
  5620. }
  5621. continue;
  5622. }
  5623. else
  5624. {
  5625. #if DBG
  5626. PrintToDebugger("LRPC: LookupAccountSid failed\n");
  5627. #endif
  5628. Status = RPC_S_UNKNOWN_PRINCIPAL;
  5629. goto Cleanup ;
  5630. }
  5631. }
  5632. break;
  5633. }
  5634. RpcpStringConcatenate(DomainName, RPC_CONST_STRING("\\")) ;
  5635. RpcpStringConcatenate(DomainName, MyUserName) ;
  5636. delete MyUserName;
  5637. *UserName = DomainName ;
  5638. ASSERT(Status == RPC_S_OK);
  5639. Cleanup:
  5640. if (Status)
  5641. {
  5642. if (MyUserName)
  5643. delete MyUserName;
  5644. if (DomainName)
  5645. delete DomainName;
  5646. return Status ;
  5647. }
  5648. return RPC_S_OK;
  5649. }
  5650. LRPC_ADDRESS *LrpcAddressList = NULL;
  5651. RPC_ADDRESS *
  5652. LrpcCreateRpcAddress (
  5653. )
  5654. /*++
  5655. Routine Description:
  5656. We just to create a new LRPC_ADDRESS. This routine is a proxy for the
  5657. new constructor to isolate the other modules.
  5658. --*/
  5659. {
  5660. RPC_STATUS Status = RPC_S_OK;
  5661. RPC_ADDRESS * RpcAddress;
  5662. RpcAddress = new LRPC_ADDRESS(&Status);
  5663. if (Status != RPC_S_OK)
  5664. {
  5665. return(0);
  5666. }
  5667. return(RpcAddress);
  5668. }
  5669. /*
  5670. This private API was requested by KumarP from the LSA group on 04/05/2000.
  5671. Here's his justification:
  5672. I am adding a new auditing feature to LSA that will allow any local process
  5673. to make an rpc call to LSA and generate an arbitrary audit. To be able to
  5674. make this call, the clients will first issue one call to get an audit-context
  5675. handle from LSA. LSA will maintain a list of handles till the client
  5676. explicitly closes the audit-context.
  5677. The reason I would like to have this API is to track which processes have
  5678. opened audit-contexts. This will help in situations where there is a
  5679. rogue/mal-functioning process that opens up a large number of audit-contexts.
  5680. In this case, I should be able to break LSA into debugger and dump the context
  5681. list and know which process has opened which handles. This may optionally
  5682. allow me to prevent certain processes from calling this API (though currently
  5683. there is no such requirement).
  5684. */
  5685. RPC_STATUS
  5686. RPC_ENTRY
  5687. I_RpcBindingInqLocalClientPID (
  5688. IN RPC_BINDING_HANDLE Binding,
  5689. OUT unsigned long *Pid
  5690. )
  5691. {
  5692. LRPC_SCALL * Call;
  5693. HANDLE LocalPid;
  5694. InitializeIfNecessary();
  5695. if (Binding == NULL)
  5696. {
  5697. Call = (LRPC_SCALL *) RpcpGetThreadContext();
  5698. if (Call == NULL)
  5699. return RPC_S_NO_CALL_ACTIVE;
  5700. }
  5701. else
  5702. {
  5703. Call = (LRPC_SCALL *) Binding;
  5704. }
  5705. if (Call->InvalidHandle(LRPC_SCALL_TYPE))
  5706. return(RPC_S_INVALID_BINDING);
  5707. LocalPid = Call->InqLocalClientPID();
  5708. *Pid = HandleToUlong(LocalPid);
  5709. return RPC_S_OK;
  5710. }
  5711. const SID AnonymousSid = { 1, 1, SECURITY_NT_AUTHORITY, SECURITY_ANONYMOUS_LOGON_RID};