Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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