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.

6612 lines
193 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1992 - 1999
  3. Module Name:
  4. lpcclnt.cxx
  5. Abstract:
  6. Implementation of the RPC on LPC protocol engine for the client.
  7. Revision History:
  8. Mazhar Mohammed: Code fork from spcclnt.cxx, 08/02/95
  9. Tony Chan: Added Singled Security Model, 12/15/95
  10. Mazhar Mohammed Merged WMSG and LRPC into a single protocol 05-06-96
  11. Mazhar Mohammed Added Pipes Support
  12. Mazhar Mohammed Added support for Async RPC 08-14-96
  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 <limits.h>
  19. #include <rpcqos.h>
  20. #include <queue.hxx>
  21. #include <lpcpack.hxx>
  22. #include <hndlsvr.hxx>
  23. #include <lpcsvr.hxx>
  24. #include <ProtBind.hxx>
  25. #include <lpcclnt.hxx>
  26. #include <epmap.h>
  27. #include <sidcache.hxx>
  28. #include <CharConv.hxx>
  29. // These need to be the same because client and server will be receiving lpc
  30. // reply messages into LRPC_MESSAGE structures and they must have sufficient space.
  31. C_ASSERT(sizeof(LRPC_MESSAGE) == PORT_MAXIMUM_MESSAGE_LENGTH);
  32. // This is a sanity check to make sure as we modify the format of the
  33. // bind message we leave enough space for the old security contexts.
  34. C_ASSERT(MAX_LRPC_CONTEXTS >= 8);
  35. const SECURITY_IMPERSONATION_LEVEL RpcToNtImp[] =
  36. {
  37. // RPC_C_IMP_LEVEL_DEFAULT
  38. SecurityImpersonation,
  39. // RPC_C_IMP_LEVEL_ANONYMOUS
  40. SecurityAnonymous,
  41. // RPC_C_IMP_LEVEL_IDENTIFY
  42. SecurityIdentification,
  43. //RPC_C_IMP_LEVEL_IMPERSONATE
  44. SecurityImpersonation,
  45. //RPC_C_IMP_LEVEL_DELEGATE
  46. SecurityDelegation
  47. };
  48. const unsigned long NtToRpcImp[] =
  49. {
  50. //SecurityAnonymous,
  51. RPC_C_IMP_LEVEL_ANONYMOUS,
  52. //SecurityIdentification,
  53. RPC_C_IMP_LEVEL_IDENTIFY,
  54. // SecurityImpersonation,
  55. RPC_C_IMP_LEVEL_IMPERSONATE,
  56. //SecurityDelegation
  57. RPC_C_IMP_LEVEL_DELEGATE
  58. };
  59. SECURITY_IMPERSONATION_LEVEL
  60. MapRpcToNtImp (
  61. IN unsigned long ImpersonationType
  62. )
  63. {
  64. if (ImpersonationType <= RPC_C_IMP_LEVEL_DELEGATE)
  65. {
  66. return RpcToNtImp[ImpersonationType];
  67. }
  68. ASSERT(0) ;
  69. return SecurityImpersonation ;
  70. }
  71. unsigned long
  72. MapNtToRpcImp (
  73. IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
  74. )
  75. {
  76. if (ImpersonationLevel <= SecurityDelegation)
  77. {
  78. return NtToRpcImp[ImpersonationLevel];
  79. }
  80. ASSERT(0);
  81. return RPC_C_IMP_LEVEL_IMPERSONATE;
  82. }
  83. RPC_STATUS
  84. InitializeLrpcIfNecessary(
  85. ) ;
  86. RPC_STATUS
  87. InitializeAsyncLrpcIfNecessary (
  88. )
  89. /*++
  90. Routine Description:
  91. We need to perform the required initialization for Async RPC to
  92. work. If we currently don't have a listening thread. We need to
  93. add a note in the docs that if the app ever plans to start a
  94. listening thread on the client (ie: become a server),
  95. it should do it before it makes the first Async RPC call. This is
  96. not a requirement, it is just an effeciency consideration.
  97. Return Value:
  98. RPC_S_OK - Function succeeded
  99. RPC_S_OUT_OF_MEMORY - we ran out of memory
  100. --*/
  101. {
  102. RPC_STATUS Status;
  103. Status = InitializeLrpcIfNecessary();
  104. if (Status != RPC_S_OK)
  105. {
  106. #if DBG
  107. PrintToDebugger("LRPC: InitializeLrpcIfNecessary failed: %x\n", Status) ;
  108. #endif
  109. return RPC_S_OUT_OF_MEMORY ;
  110. }
  111. return GlobalLrpcServer->InitializeAsync();
  112. }
  113. LRPC_BINDING_HANDLE::LRPC_BINDING_HANDLE (
  114. OUT RPC_STATUS * Status
  115. ) : BINDING_HANDLE (Status),
  116. BindingReferenceCount(1)
  117. /*++
  118. Routine Description:
  119. We just allocate an LRPC_BINDING_HANDLE and initialize things so that
  120. we can use it later.
  121. Arguments:
  122. Status - Returns the result of initializing the binding mutex.
  123. --*/
  124. {
  125. BindingMutex.SetSpinCount(4000);
  126. ObjectType = LRPC_BINDING_HANDLE_TYPE;
  127. CurrentAssociation = 0;
  128. DceBinding = 0;
  129. AuthInfoInitialized = 0;
  130. StaticTokenHandle = 0;
  131. EffectiveOnly = TRUE;
  132. }
  133. LRPC_BINDING_HANDLE::~LRPC_BINDING_HANDLE (
  134. )
  135. /*++
  136. --*/
  137. {
  138. LRPC_CASSOCIATION *Association;
  139. DictionaryCursor cursor;
  140. if (SecAssociation.Size() != 0)
  141. {
  142. SecAssociation.Reset(cursor);
  143. while ((Association = SecAssociation.Next(cursor)) != 0)
  144. {
  145. if (Association != 0)
  146. {
  147. // take away from the bindinghandle dictionary
  148. RemoveAssociation(Association);
  149. // take away from the global dict
  150. Association->RemoveBindingHandleReference();
  151. }
  152. }
  153. }
  154. delete DceBinding;
  155. if (StaticTokenHandle)
  156. {
  157. CloseHandle(StaticTokenHandle);
  158. }
  159. }
  160. RPC_STATUS
  161. LRPC_BINDING_HANDLE::NegotiateTransferSyntax (
  162. IN OUT PRPC_MESSAGE Message
  163. )
  164. /*++
  165. Routine Description:
  166. Arguments:
  167. Message - Supplies the length of the buffer required, and returns the
  168. new buffer.
  169. Return Value:
  170. --*/
  171. {
  172. LRPC_CCALL * CCall;
  173. RPC_STATUS Status;
  174. int RetryCount = 0;
  175. static long nInitialized = -1 ;
  176. LRPC_CASSOCIATION *Association ;
  177. DictionaryCursor cursor;
  178. for (;;)
  179. {
  180. for (;;)
  181. {
  182. Status = AllocateCCall(&CCall, (RPC_CLIENT_INTERFACE *)
  183. Message->RpcInterfaceInformation,
  184. Message);
  185. if (Status != RPC_S_SERVER_UNAVAILABLE)
  186. {
  187. break;
  188. }
  189. if (!fDynamicEndpoint)
  190. {
  191. break;
  192. }
  193. // If we reach here, it means that we are iterating through the
  194. // list of endpoints obtained from the endpoint mapper.
  195. BindingMutex.Request() ;
  196. if (BindingReferenceCount.GetInteger() == 1)
  197. {
  198. if (SecAssociation.Size() != 0)
  199. {
  200. DceBinding = CurrentAssociation->DuplicateDceBinding();
  201. if(DceBinding == 0)
  202. {
  203. BindingMutex.Clear() ;
  204. return(RPC_S_OUT_OF_MEMORY);
  205. }
  206. CurrentAssociation = 0;
  207. DceBinding->MaybeMakePartiallyBound(
  208. (PRPC_CLIENT_INTERFACE)Message->RpcInterfaceInformation,
  209. InqPointerAtObjectUuid());
  210. if ( *InquireEpLookupHandle() != 0 )
  211. {
  212. EpFreeLookupHandle(*InquireEpLookupHandle());
  213. *InquireEpLookupHandle() = 0;
  214. }
  215. // remove references
  216. SecAssociation.Reset(cursor);
  217. while((Association = SecAssociation.Next(cursor)) != 0)
  218. {
  219. if (Association != 0)
  220. {
  221. // in the AssociationDict all DceBinding should be the same
  222. // may be we can take out this line. or remove ref
  223. // on the first Association
  224. RemoveAssociation(Association);
  225. Association->RemoveReference();
  226. }
  227. }
  228. }
  229. }
  230. BindingMutex.Clear() ;
  231. RetryCount ++;
  232. if (RetryCount > 2)
  233. {
  234. break;
  235. }
  236. RpcpPurgeEEInfo();
  237. }
  238. if (Status == RPC_S_OK)
  239. {
  240. break;
  241. }
  242. if (InqComTimeout() != RPC_C_BINDING_INFINITE_TIMEOUT)
  243. {
  244. return(Status);
  245. }
  246. if ((Status != RPC_S_SERVER_UNAVAILABLE)
  247. && (Status != RPC_S_SERVER_TOO_BUSY))
  248. {
  249. return(Status);
  250. }
  251. }
  252. Message->TransferSyntax = CCall->Binding->GetTransferSyntaxId();
  253. Message->Handle = CCall;
  254. return RPC_S_OK;
  255. }
  256. RPC_STATUS
  257. LRPC_BINDING_HANDLE::GetBuffer (
  258. IN OUT PRPC_MESSAGE Message,
  259. IN UUID *ObjectUuid
  260. )
  261. /*++
  262. Routine Description:
  263. Arguments:
  264. Message - Supplies the length of the buffer required, and returns the
  265. new buffer.
  266. Return Value:
  267. --*/
  268. {
  269. ASSERT(!"We should never be here - the binding handle cannot allocate a buffer");
  270. return RPC_S_INTERNAL_ERROR;
  271. }
  272. RPC_STATUS
  273. LRPC_BINDING_HANDLE::BindingCopy (
  274. OUT BINDING_HANDLE * * DestinationBinding,
  275. IN unsigned int MaintainContext
  276. )
  277. /*++
  278. Routine Description:
  279. We will make a copy of this binding handle in one of two ways, depending
  280. on whether on not this binding handle has an association.
  281. Arguments:
  282. DestinationBinding - Returns a copy of this binding handle.
  283. MaintainContext - Supplies a flag that indicates whether or not context
  284. is being maintained over this binding handle. A non-zero value
  285. indicates that context is being maintained.
  286. Return Value:
  287. RPC_S_OK - This binding handle has been successfully copied.
  288. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to make a copy
  289. of this binding handle.
  290. --*/
  291. {
  292. RPC_STATUS Status = RPC_S_OK;
  293. LRPC_BINDING_HANDLE * NewBindingHandle;
  294. CLIENT_AUTH_INFO * AuthInfo;
  295. LRPC_CASSOCIATION *SecAssoc;
  296. DictionaryCursor cursor;
  297. int Key;
  298. UNUSED(MaintainContext);
  299. NewBindingHandle = new LRPC_BINDING_HANDLE(&Status);
  300. if (NewBindingHandle == 0)
  301. {
  302. return(RPC_S_OUT_OF_MEMORY);
  303. }
  304. if (Status != RPC_S_OK)
  305. {
  306. delete NewBindingHandle;
  307. return(Status);
  308. }
  309. BindingMutex.Request();
  310. Status = NewBindingHandle->BINDING_HANDLE::BaseClone(this);
  311. if (Status != RPC_S_OK)
  312. {
  313. delete NewBindingHandle;
  314. BindingMutex.Clear();
  315. return(Status);
  316. }
  317. NewBindingHandle->fDynamicEndpoint = fDynamicEndpoint;
  318. if ((AuthInfo = InquireAuthInformation()) != 0)
  319. {
  320. Status = NewBindingHandle->SetAuthInformation(
  321. AuthInfo->ServerPrincipalName,
  322. AuthInfo->AuthenticationLevel,
  323. AuthInfo->AuthenticationService,
  324. NULL,
  325. AuthInfo->AuthorizationService,
  326. 0,
  327. AuthInfo->ImpersonationType,
  328. AuthInfo->IdentityTracking,
  329. AuthInfo->Capabilities,
  330. FALSE, // bAcquireNewCredentials
  331. AuthInfo->AdditionalTransportCredentialsType,
  332. AuthInfo->AdditionalCredentials,
  333. AuthInfo->ServerSid
  334. );
  335. if (Status != RPC_S_OK)
  336. {
  337. ASSERT (Status == RPC_S_OUT_OF_MEMORY);
  338. delete NewBindingHandle;
  339. BindingMutex.Clear();
  340. return(RPC_S_OUT_OF_MEMORY);
  341. }
  342. }
  343. if (SecAssociation.Size() == 0)
  344. {
  345. NewBindingHandle->DceBinding = DceBinding->DuplicateDceBinding();
  346. if (NewBindingHandle->DceBinding == 0)
  347. {
  348. BindingMutex.Clear() ;
  349. delete NewBindingHandle;
  350. return(RPC_S_OUT_OF_MEMORY);
  351. }
  352. }
  353. else
  354. {
  355. // copy all sec associations
  356. SecAssociation.Reset(cursor);
  357. while((SecAssoc = SecAssociation.Next(cursor)) != 0)
  358. {
  359. Key = NewBindingHandle->AddAssociation(SecAssoc);
  360. if (Key == -1)
  361. {
  362. BindingMutex.Clear() ;
  363. delete NewBindingHandle;
  364. return (RPC_S_OUT_OF_MEMORY);
  365. }
  366. SecAssoc->DuplicateAssociation();
  367. }
  368. // since the CurrentAssociation is in the SecAssociation dictionary,
  369. // it should have already been copied. Just assign it
  370. NewBindingHandle->CurrentAssociation = CurrentAssociation;
  371. }
  372. BindingMutex.Clear();
  373. *DestinationBinding = (BINDING_HANDLE *) NewBindingHandle;
  374. return(RPC_S_OK);
  375. }
  376. RPC_STATUS
  377. LRPC_BINDING_HANDLE::BindingFree (
  378. )
  379. /*++
  380. Routine Description:
  381. When the application is done with a binding handle, this routine will
  382. get called.
  383. Return Value:
  384. RPC_S_OK - This operation always succeeds.
  385. --*/
  386. {
  387. int LocalRefCount;
  388. LocalRefCount = BindingReferenceCount.Decrement();
  389. if (LocalRefCount == 0)
  390. {
  391. delete this;
  392. }
  393. return(RPC_S_OK);
  394. }
  395. RPC_STATUS
  396. LRPC_BINDING_HANDLE::PrepareBindingHandle (
  397. IN TRANS_INFO * TransportInformation,
  398. IN DCE_BINDING * DceBinding
  399. )
  400. /*++
  401. Routine Description:
  402. This method will be called just before a new binding handle is returned
  403. to the user. We just stack the binding information so that we can use
  404. it later when the first remote procedure call is made. At that time,
  405. we will actually bind to the interface.
  406. Arguments:
  407. TransportInformation - Unused.
  408. DceBinding - Supplies the binding information for this binding handle.
  409. --*/
  410. {
  411. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  412. RPC_STATUS Status;
  413. UNUSED(TransportInformation);
  414. if (DceBinding->InqNetworkOptions() != 0 &&
  415. DceBinding->InqNetworkOptions()[0] != 0)
  416. {
  417. Status = I_RpcParseSecurity(DceBinding->InqNetworkOptions(),
  418. &SecurityQualityOfService);
  419. if (Status != RPC_S_OK)
  420. {
  421. ASSERT(Status == RPC_S_INVALID_NETWORK_OPTIONS);
  422. return(Status);
  423. }
  424. Status = SetAuthInformation(NULL,
  425. RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
  426. RPC_C_AUTHN_WINNT,
  427. NULL,
  428. NULL,
  429. 0,
  430. MapNtToRpcImp(SecurityQualityOfService.ImpersonationLevel),
  431. SecurityQualityOfService.ContextTrackingMode,
  432. RPC_C_QOS_CAPABILITIES_DEFAULT,
  433. TRUE);
  434. if (Status != RPC_S_OK)
  435. {
  436. return Status;
  437. }
  438. EffectiveOnly = SecurityQualityOfService.EffectiveOnly;
  439. }
  440. this->DceBinding = DceBinding;
  441. fDynamicEndpoint = DceBinding->IsNullEndpoint();
  442. return RPC_S_OK;
  443. }
  444. RPC_STATUS
  445. LRPC_BINDING_HANDLE::ToStringBinding (
  446. OUT RPC_CHAR * * StringBinding
  447. )
  448. /*++
  449. Routine Description:
  450. We need to convert the binding handle into a string binding. If the
  451. handle is unbound, use the DceBinding directly, otherwise, get it from
  452. the association.
  453. Arguments:
  454. StringBinding - Returns the string representation of the binding
  455. handle.
  456. Return Value:
  457. RPC_S_OK - The binding handle has successfully been converted into a
  458. string binding.
  459. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate the
  460. string.
  461. --*/
  462. {
  463. if (CurrentAssociation == 0)
  464. {
  465. *StringBinding = DceBinding->StringBindingCompose(
  466. InqPointerAtObjectUuid());
  467. }
  468. else
  469. {
  470. *StringBinding = CurrentAssociation->StringBindingCompose(
  471. InqPointerAtObjectUuid());
  472. }
  473. if (*StringBinding == 0)
  474. {
  475. return(RPC_S_OUT_OF_MEMORY);
  476. }
  477. return(RPC_S_OK);
  478. }
  479. RPC_STATUS
  480. LRPC_BINDING_HANDLE::ResolveBinding (
  481. IN RPC_CLIENT_INTERFACE * RpcClientInterface
  482. )
  483. /*++
  484. Routine Description:
  485. We need to try and resolve the endpoint for this binding handle
  486. if necessary (the binding handle is partially-bound). If there is
  487. isn't a association allocated, call the binding management routines
  488. to do it.
  489. Arguments:
  490. RpcClientInterface - Supplies interface information to be used
  491. in resolving the endpoint.
  492. Return Value:
  493. RPC_S_OK - This binding handle is a full resolved binding handle.
  494. RPC_S_NO_ENDPOINT_FOUND - The endpoint can not be resolved.
  495. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to resolve
  496. the endpoint.
  497. EPT_S_NOT_REGISTERED - There are no more endpoints to be found
  498. for the specified combination of interface, network address,
  499. and lookup handle.
  500. EPT_S_CANT_PERFORM_OP - The operation failed due to misc. error e.g.
  501. unable to bind to the EpMapper.
  502. --*/
  503. {
  504. RPC_STATUS Status;
  505. if (CurrentAssociation == 0)
  506. {
  507. BindingMutex.Request();
  508. Status = DceBinding->ResolveEndpointIfNecessary(
  509. RpcClientInterface,
  510. InqPointerAtObjectUuid(),
  511. InquireEpLookupHandle(),
  512. FALSE,
  513. InqComTimeout(),
  514. INFINITE, // CallTimeout
  515. NULL // AuthInfo
  516. );
  517. BindingMutex.Clear();
  518. return(Status);
  519. }
  520. return(RPC_S_OK);
  521. }
  522. RPC_STATUS
  523. LRPC_BINDING_HANDLE::BindingReset (
  524. )
  525. /*++
  526. Routine Description:
  527. This routine will set the endpoint of this binding handle to zero,
  528. if possible. The binding handle will become partially bound as a
  529. result. If a remote procedure call has been made on this binding
  530. handle, it will fail as well.
  531. Return Value:
  532. RPC_S_OK - The binding handle has successfully been made partially
  533. bound.
  534. RPC_S_WRONG_KIND_OF_BINDING - The binding handle currently has remote
  535. procedure calls active.
  536. --*/
  537. {
  538. LRPC_CASSOCIATION *Association ;
  539. DictionaryCursor cursor;
  540. BindingMutex.Request() ;
  541. if (CurrentAssociation != 0)
  542. {
  543. if (BindingReferenceCount.GetInteger() != 1)
  544. {
  545. BindingMutex.Clear() ;
  546. return(RPC_S_WRONG_KIND_OF_BINDING);
  547. }
  548. DceBinding = CurrentAssociation->DuplicateDceBinding();
  549. if(DceBinding == 0)
  550. {
  551. BindingMutex.Clear() ;
  552. return(RPC_S_OUT_OF_MEMORY);
  553. }
  554. CurrentAssociation = 0;
  555. SecAssociation.Reset(cursor);
  556. while((Association = SecAssociation.Next(cursor)) != 0)
  557. {
  558. RemoveAssociation(Association);
  559. Association->RemoveBindingHandleReference();
  560. }
  561. }
  562. fDynamicEndpoint = TRUE;
  563. DceBinding->MakePartiallyBound();
  564. if (*InquireEpLookupHandle() != 0)
  565. {
  566. EpFreeLookupHandle(*InquireEpLookupHandle());
  567. *InquireEpLookupHandle() = 0;
  568. }
  569. BindingMutex.Clear() ;
  570. return(RPC_S_OK);
  571. }
  572. void
  573. LRPC_BINDING_HANDLE::FreeCCall (
  574. IN LRPC_CCALL * CCall
  575. )
  576. /*++
  577. Routine Description:
  578. This routine will get called to notify this binding handle that a remote
  579. procedure call on this binding handle has completed.
  580. Arguments:
  581. CCall - Supplies the remote procedure call which has completed.
  582. --*/
  583. {
  584. int LocalRefCount;
  585. CCall->InqAssociation()->FreeCCall(CCall);
  586. // do not touch the association beyond this. It could be freed.
  587. LocalRefCount = BindingReferenceCount.Decrement();
  588. if (LocalRefCount == 0)
  589. {
  590. delete this;
  591. }
  592. }
  593. RPC_STATUS
  594. LRPC_BINDING_HANDLE::AllocateCCall (
  595. OUT LRPC_CCALL ** CCall,
  596. IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation,
  597. IN OUT PRPC_MESSAGE Message
  598. )
  599. /*++
  600. Routine Description:
  601. This method will allocate an LRPC_CCALL which has been bound to the
  602. interface specified by the interface information. First, we have got
  603. to see if we have an association for this binding. If not, we need
  604. to find or create one. Before we can find or create an association,
  605. we need to resolve the endpoint if necessary. Next we need to see
  606. if there is already an LRPC_CCALL allocated for this interface and
  607. thread. Otherwise, we need to ask the association to allocate a
  608. LRPC_CCALL for us.
  609. Arguments:
  610. CCall - Returns the allocated LRPC_CCALL which has been bound to
  611. the interface specified by the rpc interface information.
  612. RpcInterfaceInformation - Supplies information describing the
  613. interface to which we wish to bind.
  614. Return Value:
  615. --*/
  616. {
  617. RPC_STATUS Status;
  618. BOOL Boolean;
  619. BOOL FoundSameAuthInfo = FALSE;
  620. LRPC_CASSOCIATION * Association;
  621. LRPC_CASSOCIATION *MyAssociation = NULL;
  622. DictionaryCursor cursor;
  623. int LocalRefCount;
  624. BOOL Supported;
  625. BindingMutex.Request();
  626. if (AuthInfoInitialized == 0)
  627. {
  628. Status = SetAuthInformation(NULL,
  629. RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
  630. RPC_C_AUTHN_WINNT,
  631. NULL,
  632. NULL,
  633. 0,
  634. RPC_C_IMP_LEVEL_IMPERSONATE,
  635. RPC_C_QOS_IDENTITY_DYNAMIC,
  636. RPC_C_QOS_CAPABILITIES_DEFAULT,
  637. TRUE);
  638. if (Status != RPC_S_OK)
  639. {
  640. BindingMutex.Clear();
  641. return Status;
  642. }
  643. }
  644. // First we need to check if there is already a call active for this
  645. // thread and interface. To make the common case quicker, we will check
  646. // to see if there are any calls in the dictionary first.
  647. if (RecursiveCalls.Size() != 0)
  648. {
  649. RecursiveCalls.Reset(cursor);
  650. while ((*CCall = RecursiveCalls.Next(cursor)) != 0)
  651. {
  652. if ((*CCall)->IsThisMyActiveCall(
  653. GetThreadIdentifier(),
  654. RpcInterfaceInformation) != 0)
  655. {
  656. BindingMutex.Clear();
  657. return(RPC_S_OK);
  658. }
  659. }
  660. }
  661. // To start off, see if the binding handle points to an association
  662. // yet. If not, we have got to get one.
  663. if (CurrentAssociation == 0)
  664. {
  665. // Before we even bother to find or create an association, lets
  666. // check to make sure that we are on the same machine as the server.
  667. ASSERT(DceBinding->InqNetworkAddress() != 0);
  668. if (DceBinding->InqNetworkAddress()[0] != 0)
  669. {
  670. if (RpcpStringCompareInt(DceBinding->InqNetworkAddress(),
  671. gLocalComputerName) != 0)
  672. {
  673. BindingMutex.Clear();
  674. RpcpErrorAddRecord(EEInfoGCRuntime,
  675. RPC_S_SERVER_UNAVAILABLE,
  676. EEInfoDLLRPC_BINDING_HANDLE__AllocateCCall10,
  677. DceBinding->InqNetworkAddress(),
  678. gLocalComputerName);
  679. return(RPC_S_SERVER_UNAVAILABLE);
  680. }
  681. }
  682. if (DceBinding->IsNullEndpoint())
  683. {
  684. LrpcMutexRequest();
  685. MyAssociation = FindOrCreateLrpcAssociation(
  686. DceBinding,
  687. InquireAuthInformation(),
  688. RpcInterfaceInformation);
  689. LrpcMutexClear();
  690. // don't do anything in the both success and failure
  691. // case. In failure case we'll try full endpoint resolution
  692. // In success case, we leave FoundSameAuthInfo to be FALSE,
  693. // and the code below will figure out we have something
  694. // in MyAssociation and will do the housekeeping tasks
  695. // associated with finding an association
  696. ASSERT(DceBinding);
  697. }
  698. if (!MyAssociation)
  699. {
  700. Status = DceBinding->ResolveEndpointIfNecessary(
  701. RpcInterfaceInformation,
  702. InqPointerAtObjectUuid(),
  703. InquireEpLookupHandle(),
  704. FALSE,
  705. InqComTimeout(),
  706. INFINITE, // CallTimeout
  707. &ClientAuthInfo // AuthInfo
  708. );
  709. if (Status != RPC_S_OK)
  710. {
  711. BindingMutex.Clear();
  712. RpcpErrorAddRecord(EEInfoGCRuntime,
  713. Status,
  714. EEInfoDLLRPC_BINDING_HANDLE__AllocateCCall20,
  715. RpcInterfaceInformation->InterfaceId.SyntaxGUID.Data1);
  716. return(Status);
  717. }
  718. }
  719. }
  720. else
  721. {
  722. Status = CurrentAssociation->IsSupportedAuthInfo(InquireAuthInformation(),
  723. &Supported);
  724. if (Status != RPC_S_OK)
  725. {
  726. BindingMutex.Clear();
  727. return(Status);
  728. }
  729. if (Supported)
  730. {
  731. MyAssociation = CurrentAssociation ;
  732. FoundSameAuthInfo = TRUE;
  733. }
  734. else
  735. {
  736. SecAssociation.Reset(cursor);
  737. while ((Association = SecAssociation.Next(cursor)) != 0)
  738. {
  739. Status = Association->IsSupportedAuthInfo(InquireAuthInformation(),
  740. &Supported);
  741. if (Status != RPC_S_OK)
  742. {
  743. BindingMutex.Clear();
  744. return(Status);
  745. }
  746. if(Supported)
  747. {
  748. MyAssociation = Association ;
  749. FoundSameAuthInfo = TRUE;
  750. break;
  751. }
  752. }
  753. }
  754. }
  755. if (FoundSameAuthInfo == FALSE)
  756. {
  757. // we have some association in the dictionary, check for security level
  758. if (DceBinding == 0)
  759. {
  760. SecAssociation.Reset(cursor);
  761. Association = SecAssociation.Next(cursor);
  762. // it will get deleted when Assoc goes
  763. DceBinding = Association->DuplicateDceBinding();
  764. if(DceBinding == 0)
  765. {
  766. BindingMutex.Clear() ;
  767. return(RPC_S_OUT_OF_MEMORY);
  768. }
  769. }
  770. // if we still haven't found the association
  771. // (may do so during the interface based search for
  772. // an endpoint).
  773. if (!MyAssociation)
  774. {
  775. LrpcMutexRequest();
  776. MyAssociation = FindOrCreateLrpcAssociation(
  777. DceBinding,
  778. InquireAuthInformation(),
  779. NULL);
  780. LrpcMutexClear();
  781. }
  782. if (CurrentAssociation == 0)
  783. {
  784. CurrentAssociation = MyAssociation ;
  785. }
  786. if (MyAssociation == 0)
  787. {
  788. BindingMutex.Clear();
  789. return(RPC_S_OUT_OF_MEMORY);
  790. }
  791. // The association now owns the DceBinding.
  792. DceBinding = 0;
  793. if((AddAssociation(MyAssociation)) == -1)
  794. {
  795. delete MyAssociation;
  796. if (CurrentAssociation == MyAssociation)
  797. {
  798. CurrentAssociation = 0;
  799. }
  800. BindingMutex.Clear();
  801. return (RPC_S_OUT_OF_MEMORY);
  802. }
  803. }
  804. BindingReferenceCount.Increment();
  805. BindingMutex.Clear();
  806. ASSERT(MyAssociation) ;
  807. Status = MyAssociation->AllocateCCall(
  808. this,
  809. CCall,
  810. Message,
  811. RpcInterfaceInformation);
  812. if (Status != RPC_S_OK)
  813. {
  814. LocalRefCount = BindingReferenceCount.Decrement();
  815. ASSERT(LocalRefCount != 0);
  816. }
  817. return(Status);
  818. }
  819. RPC_STATUS
  820. LRPC_BINDING_HANDLE::SetAuthInformation (
  821. IN RPC_CHAR * ServerPrincipalName, OPTIONAL
  822. IN unsigned long AuthenticationLevel,
  823. IN unsigned long AuthenticationService,
  824. IN RPC_AUTH_IDENTITY_HANDLE AuthIdentity, OPTIONAL
  825. IN unsigned long AuthorizationService,
  826. IN SECURITY_CREDENTIALS * Credentials,
  827. IN unsigned long ImpersonationType,
  828. IN unsigned long IdentityTracking,
  829. IN unsigned long Capabilities,
  830. IN BOOL bAcquireNewCredentials,
  831. IN ULONG AdditionalTransportCredentialsType, OPTIONAL
  832. IN void *AdditionalCredentials, OPTIONAL
  833. IN PSID Sid OPTIONAL
  834. )
  835. /*++
  836. Routine Description:
  837. We set the authentication and authorization information in this binding
  838. handle.
  839. Arguments:
  840. ServerPrincipalName - Optionally supplies the server principal name.
  841. AuthenticationLevel - Supplies the authentication level to use.
  842. AuthenticationService - Supplies the authentication service to use.
  843. AuthIdentity - Optionally supplies the security context to use.
  844. AuthorizationService - Supplies the authorization service to use.
  845. AdditionalTransportCredentialsType - the type of additional credentials
  846. supplied in AdditionalCredentials. Not supported for LRPC.
  847. AdditionalCredentials - pointer to additional credentials if any. Not supported
  848. for LRPC.
  849. Sid - the SID to mutually authenticate to
  850. Return Value:
  851. RPC_S_OK - The supplied authentication and authorization information has
  852. been set in the binding handle.
  853. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete the
  854. operation.
  855. RPC_S_UNKNOWN_AUTHN_SERVICE - The specified authentication service is
  856. not supported.
  857. RPC_S_UNKNOWN_AUTHN_LEVEL - The specified authentication level is
  858. not supported.
  859. RPC_S_INVALID_AUTH_IDENTITY - The specified security context (supplied
  860. by the auth identity argument) is invalid.
  861. RPC_S_UNKNOWN_AUTHZ_SERVICE - The specified authorization service is
  862. not supported.
  863. --*/
  864. {
  865. RPC_CHAR * NewString ;
  866. RPC_STATUS Status;
  867. HANDLE hToken;
  868. unsigned long MappedAuthenticationLevel;
  869. PSID ServerSid = NULL;
  870. ULONG SidLength;
  871. BOOL Result;
  872. BOOL fCachedSid = TRUE;
  873. if ((AdditionalTransportCredentialsType != 0) || (AdditionalCredentials != NULL))
  874. return RPC_S_CANNOT_SUPPORT;
  875. if (AuthenticationLevel == RPC_C_AUTHN_LEVEL_DEFAULT)
  876. {
  877. AuthenticationLevel = RPC_C_AUTHN_LEVEL_CONNECT;
  878. }
  879. MappedAuthenticationLevel = MapAuthenticationLevel(AuthenticationLevel);
  880. if (AuthenticationLevel > RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
  881. {
  882. return(RPC_S_UNKNOWN_AUTHN_LEVEL);
  883. }
  884. ClientAuthInfo.AuthenticationLevel = MappedAuthenticationLevel;
  885. ClientAuthInfo.AuthenticationService = AuthenticationService;
  886. ClientAuthInfo.AuthIdentity = AuthIdentity;
  887. ClientAuthInfo.AuthorizationService = AuthorizationService;
  888. ClientAuthInfo.IdentityTracking = IdentityTracking;
  889. if (MappedAuthenticationLevel == RPC_C_AUTHN_LEVEL_NONE)
  890. {
  891. ClientAuthInfo.ImpersonationType = RPC_C_IMP_LEVEL_ANONYMOUS;
  892. }
  893. else
  894. {
  895. ClientAuthInfo.ImpersonationType = ImpersonationType;
  896. }
  897. if (AuthenticationService == RPC_C_AUTHN_NONE)
  898. {
  899. AuthInfoInitialized = 0;
  900. return (RPC_S_OK);
  901. }
  902. if(AuthenticationService != RPC_C_AUTHN_WINNT)
  903. {
  904. return(RPC_S_UNKNOWN_AUTHN_SERVICE) ;
  905. }
  906. // For LRPC, MA implies local MA hint.
  907. if (Capabilities & RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH)
  908. {
  909. Capabilities |= RPC_C_QOS_CAPABILITIES_LOCAL_MA_HINT;
  910. // if the SPN is not translated to a SID, we must do that now
  911. if (!ARGUMENT_PRESENT(Sid))
  912. {
  913. Status = RpcpLookupAccountName (ServerPrincipalName,
  914. &fCachedSid,
  915. &ServerSid);
  916. if (Status != RPC_S_OK)
  917. return Status;
  918. Sid = ServerSid;
  919. // fall through to SID processing code below
  920. }
  921. }
  922. ClientAuthInfo.Capabilities = Capabilities;
  923. if (ARGUMENT_PRESENT(Sid))
  924. {
  925. // duplicate if not already allocated
  926. if (ServerSid == NULL)
  927. {
  928. ServerSid = DuplicateSID (Sid);
  929. if (ServerSid == NULL)
  930. return(RPC_S_OUT_OF_MEMORY);
  931. }
  932. BindingMutex.Request();
  933. if ( ClientAuthInfo.ServerSid != 0 )
  934. {
  935. delete ClientAuthInfo.ServerSid;
  936. }
  937. ClientAuthInfo.ServerSid = ServerSid;
  938. BindingMutex.Clear();
  939. }
  940. if (ARGUMENT_PRESENT(ServerPrincipalName) && (*ServerPrincipalName))
  941. {
  942. NewString = DuplicateString(ServerPrincipalName);
  943. if ( NewString == 0 )
  944. {
  945. return(RPC_S_OUT_OF_MEMORY);
  946. }
  947. BindingMutex.Request();
  948. if ( ClientAuthInfo.ServerPrincipalName != 0 )
  949. {
  950. delete ClientAuthInfo.ServerPrincipalName;
  951. }
  952. ClientAuthInfo.ServerPrincipalName = NewString;
  953. BindingMutex.Clear();
  954. }
  955. else
  956. {
  957. BindingMutex.Request();
  958. if ( ClientAuthInfo.ServerPrincipalName != 0 )
  959. {
  960. delete ClientAuthInfo.ServerPrincipalName;
  961. }
  962. ClientAuthInfo.ServerPrincipalName = NULL;
  963. BindingMutex.Clear();
  964. }
  965. if (IdentityTracking == RPC_C_QOS_IDENTITY_STATIC)
  966. {
  967. if (StaticTokenHandle)
  968. {
  969. CloseHandle(StaticTokenHandle);
  970. }
  971. if (OpenThreadToken (GetCurrentThread(),
  972. TOKEN_IMPERSONATE | TOKEN_QUERY,
  973. TRUE,
  974. &StaticTokenHandle) == FALSE)
  975. {
  976. StaticTokenHandle = 0;
  977. }
  978. Status = ReAcquireCredentialsIfNecessary();
  979. if (Status != RPC_S_OK)
  980. {
  981. return Status;
  982. }
  983. }
  984. AuthInfoInitialized = 1;
  985. return(RPC_S_OK);
  986. }
  987. unsigned long
  988. LRPC_BINDING_HANDLE::MapAuthenticationLevel (
  989. IN unsigned long AuthenticationLevel
  990. )
  991. /*++
  992. Routine Description:
  993. The connection oriented protocol module supports all authentication
  994. levels except for RPC_C_AUTHN_LEVEL_CALL. We just need to map it
  995. to RPC_C_AUTHN_LEVEL_PKT.
  996. --*/
  997. {
  998. UNUSED(this);
  999. if (AuthenticationLevel >= RPC_C_AUTHN_LEVEL_CONNECT)
  1000. {
  1001. return(RPC_C_AUTHN_LEVEL_PKT_PRIVACY);
  1002. }
  1003. return(AuthenticationLevel);
  1004. }
  1005. inline int
  1006. LRPC_BINDING_HANDLE::AddAssociation (
  1007. IN LRPC_CASSOCIATION * Association
  1008. )
  1009. /*++
  1010. Routine Description:
  1011. This supplied remote procedure call needs to be put into the dictionary
  1012. of association
  1013. --*/
  1014. {
  1015. int err;
  1016. BindingMutex.Request() ;
  1017. err = SecAssociation.Insert(Association) ;
  1018. BindingMutex.Clear() ;
  1019. return(err);
  1020. }
  1021. inline void
  1022. LRPC_BINDING_HANDLE::RemoveAssociation (
  1023. IN LRPC_CASSOCIATION * Association
  1024. )
  1025. /*++
  1026. Routine Description:
  1027. Remove Association from BindingHandle, can keep a Key for Association because
  1028. 1 association may be added to many BINDINGHANDLE::SecAssociationDict, 1 key per
  1029. Association won't do the job. Therefore, we delete Association this way.
  1030. Remember, there will be 5 Association in the SecAssoc the most, 1 per SecurityLevel
  1031. --*/
  1032. {
  1033. BindingMutex.Request() ;
  1034. SecAssociation.DeleteItemByBruteForce(Association);
  1035. BindingMutex.Clear() ;
  1036. }
  1037. RPC_STATUS
  1038. LRPC_BINDING_HANDLE::SetTransportOption( IN unsigned long option,
  1039. IN ULONG_PTR optionValue )
  1040. {
  1041. if (option == RPC_C_OPT_DONT_LINGER)
  1042. {
  1043. if (CurrentAssociation == NULL)
  1044. return RPC_S_WRONG_KIND_OF_BINDING;
  1045. if (CurrentAssociation->GetDontLingerState())
  1046. return RPC_S_OK;
  1047. CurrentAssociation->SetDontLingerState((BOOL)optionValue);
  1048. return RPC_S_OK;
  1049. }
  1050. else
  1051. {
  1052. return BINDING_HANDLE::SetTransportOption(option, optionValue);
  1053. }
  1054. }
  1055. RPC_STATUS
  1056. LRPC_BINDING_HANDLE::InqTransportOption( IN unsigned long option,
  1057. OUT ULONG_PTR * pOptionValue )
  1058. {
  1059. if (option == RPC_C_OPT_DONT_LINGER)
  1060. {
  1061. if (CurrentAssociation == NULL)
  1062. return RPC_S_WRONG_KIND_OF_BINDING;
  1063. *pOptionValue = CurrentAssociation->GetDontLingerState();
  1064. return RPC_S_OK;
  1065. }
  1066. else
  1067. {
  1068. return BINDING_HANDLE::InqTransportOption(option, pOptionValue);
  1069. }
  1070. }
  1071. MTSyntaxBinding *CreateLrpcBinding(
  1072. IN RPC_SYNTAX_IDENTIFIER *InterfaceId,
  1073. IN TRANSFER_SYNTAX_STUB_INFO *TransferSyntaxInfo,
  1074. IN int CapabilitiesBitmap
  1075. )
  1076. {
  1077. return new LRPC_BINDING(InterfaceId,
  1078. TransferSyntaxInfo,
  1079. CapabilitiesBitmap);
  1080. }
  1081. // protected by the LrpcMutex
  1082. LRPC_CASSOCIATION_DICT * LrpcAssociationDict = 0;
  1083. long LrpcLingeredAssociations = 0;
  1084. unsigned long LrpcDestroyedAssociations = 0;
  1085. ULARGE_INTEGER LastDestroyedAssociationsBatchTimestamp;
  1086. LRPC_CASSOCIATION::LRPC_CASSOCIATION (
  1087. IN DCE_BINDING * DceBinding,
  1088. IN CLIENT_AUTH_INFO *pClientAuthInfo,
  1089. IN USHORT MySequenceNumber,
  1090. OUT RPC_STATUS * Status
  1091. ) : AssociationMutex(Status, 4000),
  1092. AssocAuthInfo(pClientAuthInfo, Status)
  1093. /*++
  1094. Routine Description:
  1095. This association will be initialized, so that it is ready to be
  1096. placed into the dictionary of associations.
  1097. Arguments:
  1098. DceBinding - Supplies the DCE_BINDING which will name this association.
  1099. Status - Returns the result of creating the association mutex.
  1100. --*/
  1101. {
  1102. ObjectType = LRPC_CASSOCIATION_TYPE;
  1103. this->DceBinding = DceBinding;
  1104. LpcClientPort = 0;
  1105. LpcReceivePort = 0;
  1106. BackConnectionCreated = 0;
  1107. CallIdCounter = 1;
  1108. SequenceNumber = MySequenceNumber;
  1109. Linger.fAssociationLingered = FALSE;
  1110. DeletedContextCount = 0;
  1111. BindingHandleReferenceCount = 1;
  1112. RefCount.SetInteger(2);
  1113. CachedCCall = NULL;
  1114. DontLinger = FALSE;
  1115. LastSecContextTrimmingTimestamp = 0;
  1116. // Generate the bind back cookie.
  1117. // The cookie will be used to verify that bind back
  1118. // originates from a legitimate server.
  1119. GenerateRandomNumber((unsigned char *)BindBackCookie, BIND_BACK_COOKIE_SIZE);
  1120. if (*Status == RPC_S_OK)
  1121. {
  1122. CachedCCall = new LRPC_CCALL(Status);
  1123. if (*Status == RPC_S_OK)
  1124. {
  1125. if (CachedCCall == 0)
  1126. {
  1127. *Status = RPC_S_OUT_OF_MEMORY ;
  1128. return;
  1129. }
  1130. CachedCCall->SetAssociation(this);
  1131. CachedCCallFlag = 1;
  1132. }
  1133. }
  1134. }
  1135. LRPC_CASSOCIATION::~LRPC_CASSOCIATION (
  1136. )
  1137. {
  1138. LRPC_BINDING * Binding;
  1139. LRPC_CCALL * CCall ;
  1140. LRPC_CCONTEXT *SecurityContext;
  1141. DictionaryCursor cursor;
  1142. if (DceBinding != 0)
  1143. {
  1144. delete DceBinding;
  1145. }
  1146. Bindings.Reset(cursor);
  1147. while ((Binding = Bindings.RemoveNext(cursor)) != 0)
  1148. {
  1149. Binding->RemoveReference();
  1150. }
  1151. SecurityContextDict.Reset(cursor);
  1152. while (SecurityContext = SecurityContextDict.RemoveNext(cursor))
  1153. {
  1154. delete SecurityContext;
  1155. }
  1156. // delete all CCalls
  1157. ActiveCCalls.Reset(cursor) ;
  1158. while ((CCall = ActiveCCalls.Next(cursor, TRUE)) != 0)
  1159. {
  1160. delete CCall ;
  1161. }
  1162. if (CachedCCallFlag != 0)
  1163. {
  1164. delete CachedCCall;
  1165. }
  1166. FreeCCalls.Reset(cursor);
  1167. while ((CCall = FreeCCalls.Next(cursor)) != 0)
  1168. {
  1169. delete CCall;
  1170. }
  1171. CloseLpcClientPort();
  1172. }
  1173. RPC_STATUS
  1174. LRPC_CASSOCIATION::CreateBackConnection (
  1175. IN LRPC_BINDING_HANDLE *BindingHandle
  1176. )
  1177. /*++
  1178. Routine Description:
  1179. Ask the server to create a back connection to us. Used in
  1180. conjuction with Async RPC.
  1181. Return Value:
  1182. RPC_S_OK - Function succeeded
  1183. RPC_S_OUT_OF_MEMORY - we ran out of memory
  1184. --*/
  1185. {
  1186. #if defined(BUILD_WOW6432)
  1187. char LrpcMessageBuffer[sizeof(LRPC_BIND_BACK_MESSAGE) + 8];
  1188. char LrpcReplyBuffer[sizeof(LRPC_MESSAGE) + 8];
  1189. LRPC_BIND_BACK_MESSAGE *LrpcMessagePtr = (LRPC_BIND_BACK_MESSAGE *) AlignPtr8(LrpcMessageBuffer);
  1190. LRPC_MESSAGE *LrpcReplyPtr = (LRPC_MESSAGE *)AlignPtr8(LrpcReplyBuffer);
  1191. #else
  1192. LRPC_BIND_BACK_MESSAGE LrpcMessageBuffer;
  1193. LRPC_MESSAGE LrpcReplyBuffer;
  1194. LRPC_BIND_BACK_MESSAGE *LrpcMessagePtr = &LrpcMessageBuffer;
  1195. LRPC_MESSAGE *LrpcReplyPtr = &LrpcReplyBuffer;
  1196. #endif
  1197. NTSTATUS NtStatus ;
  1198. RPC_STATUS Status = RPC_S_OK;
  1199. if (BackConnectionCreated == 0)
  1200. {
  1201. Status = AssociationMutex.RequestSafe() ;
  1202. if (Status)
  1203. return Status;
  1204. if (BackConnectionCreated)
  1205. {
  1206. AssociationMutex.Clear() ;
  1207. return RPC_S_OK ;
  1208. }
  1209. if (LpcClientPort == 0)
  1210. {
  1211. Status = OpenLpcPort(BindingHandle, TRUE) ;
  1212. if (Status != RPC_S_OK)
  1213. {
  1214. AssociationMutex.Clear() ;
  1215. RpcpErrorAddRecord(EEInfoGCRuntime,
  1216. Status,
  1217. EEInfoDLLRPC_CASSOCIATION__CreateBackConnection10,
  1218. InqEndpoint());
  1219. return Status ;
  1220. }
  1221. }
  1222. else
  1223. {
  1224. // zero out the message to prevent data leak
  1225. RpcpMemorySet(LrpcMessagePtr, 0, sizeof(*LrpcMessagePtr));
  1226. LrpcGetEndpoint((RPC_CHAR *) LrpcMessagePtr->szPortName) ;
  1227. LrpcMessagePtr->LpcHeader.u1.s1.DataLength =
  1228. sizeof(LRPC_BIND_BACK_MESSAGE) - sizeof(PORT_MESSAGE);
  1229. LrpcMessagePtr->LpcHeader.u1.s1.TotalLength =
  1230. sizeof(LRPC_BIND_BACK_MESSAGE);
  1231. LrpcMessagePtr->LpcHeader.u2.ZeroInit = 0;
  1232. LrpcMessagePtr->MessageType = LRPC_MSG_BIND_BACK;
  1233. // Make sure we can't be impersonated on the transport level.
  1234. // A legitimate Lrpc server will never do this on a bind back.
  1235. LrpcMessagePtr->LpcHeader.u2.s2.Type |= LPC_NO_IMPERSONATE;
  1236. DWORD Key;
  1237. LPC_KEY *LpcKey = (LPC_KEY *) &Key;
  1238. LpcKey->SeqNumber = SequenceNumber;
  1239. LpcKey->AssocKey = (unsigned short) AssociationDictKey;
  1240. LrpcMessagePtr->AssocKey = Key;
  1241. // Initialize a cookie to be sent in the message.
  1242. RpcpMemoryCopy(LrpcMessagePtr->Cookie, BindBackCookie, BIND_BACK_COOKIE_SIZE);
  1243. NtStatus = NtRequestWaitReplyPort(LpcClientPort,
  1244. (PORT_MESSAGE *) LrpcMessagePtr,
  1245. (PORT_MESSAGE *) LrpcReplyPtr) ;
  1246. if (NT_ERROR(NtStatus))
  1247. {
  1248. AssociationMutex.Clear() ;
  1249. if (NtStatus == STATUS_NO_MEMORY)
  1250. {
  1251. Status = RPC_S_OUT_OF_MEMORY;
  1252. }
  1253. else if (NtStatus == STATUS_INSUFFICIENT_RESOURCES)
  1254. {
  1255. Status = RPC_S_OUT_OF_RESOURCES;
  1256. }
  1257. else
  1258. {
  1259. VALIDATE(NtStatus)
  1260. {
  1261. STATUS_INVALID_PORT_HANDLE,
  1262. STATUS_INVALID_HANDLE,
  1263. STATUS_PORT_DISCONNECTED,
  1264. STATUS_LPC_REPLY_LOST
  1265. } END_VALIDATE;
  1266. Status = RPC_S_SERVER_UNAVAILABLE;
  1267. }
  1268. RpcpErrorAddRecord(EEInfoGCLPC,
  1269. Status,
  1270. EEInfoDLLRPC_CASSOCIATION__CreateBackConnection20,
  1271. NtStatus);
  1272. return (Status);
  1273. }
  1274. ASSERT(LrpcReplyPtr->Ack.MessageType == LRPC_MSG_ACK) ;
  1275. if (LrpcReplyPtr->Ack.RpcStatus != RPC_S_OK)
  1276. {
  1277. AssociationMutex.Clear() ;
  1278. RpcpErrorAddRecord(EEInfoGCRuntime,
  1279. LrpcReplyPtr->Ack.RpcStatus,
  1280. EEInfoDLLRPC_CASSOCIATION__CreateBackConnection30);
  1281. return LrpcReplyPtr->Ack.RpcStatus;
  1282. }
  1283. }
  1284. BackConnectionCreated = 1 ;
  1285. AssociationMutex.Clear() ;
  1286. }
  1287. return Status ;
  1288. }
  1289. void
  1290. LRPC_CASSOCIATION::RemoveBindingHandleReference (
  1291. void
  1292. )
  1293. {
  1294. BOOL fWillLinger = FALSE;
  1295. LRPC_CASSOCIATION *CurrentAssociation;
  1296. LRPC_CASSOCIATION *OldestAssociation = NULL;
  1297. DWORD OldestAssociationTimestamp;
  1298. DictionaryCursor cursor;
  1299. BOOL fEnableGarbageCollection = FALSE;
  1300. LrpcMutexRequest();
  1301. LogEvent(SU_CASSOC, EV_DEC, this, 0, BindingHandleReferenceCount, 1, 1);
  1302. BindingHandleReferenceCount --;
  1303. if (BindingHandleReferenceCount == 0)
  1304. {
  1305. if (LpcClientPort && IsGarbageCollectionAvailable() && (!DontLinger))
  1306. {
  1307. fWillLinger = PrepareForLoopbackTicklingIfNecessary();
  1308. if (fWillLinger)
  1309. {
  1310. if (LrpcLingeredAssociations >= MaxLrpcLingeredAssociations)
  1311. {
  1312. OldestAssociationTimestamp = ~(DWORD)0;
  1313. // need to walk the dictionary and clean up the oldest item
  1314. LrpcAssociationDict->Reset(cursor);
  1315. while ((CurrentAssociation = LrpcAssociationDict->Next(cursor)) != 0)
  1316. {
  1317. if (CurrentAssociation->Linger.fAssociationLingered)
  1318. {
  1319. // yes, if the tick count wraps around, we may make a
  1320. // suboptimal decision and destroy a newer lingering
  1321. // association. That's ok - it will be a slight perf hit once
  1322. // every ~47 days - it won't be a bug
  1323. if (OldestAssociationTimestamp > CurrentAssociation->Linger.Timestamp)
  1324. {
  1325. OldestAssociation = CurrentAssociation;
  1326. }
  1327. }
  1328. }
  1329. // there must be an oldest association here
  1330. ASSERT(OldestAssociation);
  1331. LrpcAssociationDict->Delete(OldestAssociation->AssociationDictKey);
  1332. OldestAssociation->AssociationDictKey = -1;
  1333. // no need to update LrpcLingeredAssociations - we removed one,
  1334. // but we add one, so the balance is the same
  1335. }
  1336. else
  1337. {
  1338. LrpcLingeredAssociations ++;
  1339. ASSERT(LrpcLingeredAssociations <= MaxLrpcLingeredAssociations);
  1340. }
  1341. Linger.Timestamp = GetTickCount() + gThreadTimeout;
  1342. Linger.fAssociationLingered = TRUE;
  1343. }
  1344. }
  1345. if (!fWillLinger)
  1346. {
  1347. LrpcDestroyedAssociations ++;
  1348. fEnableGarbageCollection = CheckIfGCShouldBeTurnedOn(
  1349. LrpcDestroyedAssociations,
  1350. NumberOfLrpcDestroyedAssociationsToSample,
  1351. DestroyedLrpcAssociationBatchThreshold,
  1352. &LastDestroyedAssociationsBatchTimestamp
  1353. );
  1354. Delete();
  1355. }
  1356. }
  1357. LrpcMutexClear();
  1358. if (fEnableGarbageCollection)
  1359. {
  1360. // ignore the return value - we'll make a best effort to
  1361. // create the thread, but if there's no memory, that's
  1362. // still ok as the garbage collection thread only
  1363. // provides better perf in this case
  1364. (void) CreateGarbageCollectionThread();
  1365. }
  1366. if (OldestAssociation)
  1367. {
  1368. #if defined (RPC_GC_AUDIT)
  1369. int Diff;
  1370. Diff = (int)(GetTickCount() - OldestAssociation->Linger.Timestamp);
  1371. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) LRPC association sync gc'ed %d ms after expire\n",
  1372. GetCurrentProcessId(), GetCurrentProcessId(), Diff);
  1373. #endif
  1374. OldestAssociation->Delete();
  1375. }
  1376. if (fWillLinger)
  1377. {
  1378. fWillLinger = GarbageCollectionNeeded(TRUE, gThreadTimeout);
  1379. if (fWillLinger == FALSE)
  1380. {
  1381. // uh-oh - we couldn't register for garbage collection - probably
  1382. // extremely low on memory. If nobody has picked us up in the meantime,
  1383. // delete this association. Otherwise, let it go - somebody is using
  1384. // it and we don't need to worry about gc'ing it. We also need to guard
  1385. // against the gc thread trying to do Delete on this also. If it does
  1386. // so, it will set the AssociationDictKey to -1 before it releases
  1387. // the mutex - therefore we can check for this. A gc thread cannot
  1388. // completely kill the object as we will hold one reference on it
  1389. LrpcMutexRequest();
  1390. if (AssociationDictKey != -1)
  1391. {
  1392. LrpcLingeredAssociations --;
  1393. ASSERT(LrpcLingeredAssociations >= 0);
  1394. if (Linger.fAssociationLingered)
  1395. Delete();
  1396. }
  1397. LrpcMutexClear();
  1398. }
  1399. #if defined (RPC_GC_AUDIT)
  1400. else
  1401. {
  1402. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) LRPC association lingered %X\n",
  1403. GetCurrentProcessId(), GetCurrentProcessId(), this);
  1404. }
  1405. #endif
  1406. }
  1407. // removing the reference should be the last thing to do. Otherwise we're racing
  1408. // with a gc thread which may kill the this pointer underneath us
  1409. REFERENCED_OBJECT::RemoveReference();
  1410. }
  1411. void LRPC_CASSOCIATION::Delete(void)
  1412. {
  1413. int MyCount;
  1414. if (SetDeletedFlag())
  1415. {
  1416. if (AssociationDictKey != -1)
  1417. {
  1418. LrpcMutexRequest();
  1419. LrpcAssociationDict->Delete(AssociationDictKey);
  1420. LrpcMutexClear();
  1421. }
  1422. REFERENCED_OBJECT::RemoveReference();
  1423. }
  1424. }
  1425. BOOL
  1426. LRPC_CASSOCIATION::DoesBindingForInterfaceExist (
  1427. IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation
  1428. )
  1429. /*++
  1430. Routine Description:
  1431. Checks if an association supports a binding for this interface.
  1432. Arguments:
  1433. RpcInterfaceInformation - Supplies the interface information for
  1434. which we are looking for an osf binding object.
  1435. Return Value:
  1436. FALSE if it doesn't. Non-zero if it does.
  1437. --*/
  1438. {
  1439. LRPC_BINDING *Binding;
  1440. DictionaryCursor cursor;
  1441. BOOL fRetVal = FALSE;
  1442. BOOL fMutexTaken;
  1443. fMutexTaken = AssociationMutex.TryRequest();
  1444. if (!fMutexTaken)
  1445. return FALSE;
  1446. Bindings.Reset(cursor);
  1447. while ((Binding = Bindings.Next(cursor)) != 0)
  1448. {
  1449. // if we have a binding on the same interface,
  1450. // return TRUE
  1451. if (RpcpMemoryCompare(Binding->GetInterfaceId(),
  1452. &RpcInterfaceInformation->InterfaceId,
  1453. sizeof(RPC_SYNTAX_IDENTIFIER)) == 0)
  1454. {
  1455. fRetVal = TRUE;
  1456. break;
  1457. }
  1458. }
  1459. AssociationMutex.Clear();
  1460. return fRetVal;
  1461. }
  1462. RPC_STATUS
  1463. LRPC_CASSOCIATION::AllocateCCall (
  1464. IN LRPC_BINDING_HANDLE *BindingHandle,
  1465. OUT LRPC_CCALL ** CCall,
  1466. IN OUT PRPC_MESSAGE Message,
  1467. IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation
  1468. )
  1469. /*++
  1470. Routine Description:
  1471. This method will allocate an LRPC_CCALL which has been bound to the
  1472. interface specified by the interface information. This means that
  1473. first we need to find the presentation context corresponding to the
  1474. requested interface.
  1475. Arguments:
  1476. CCall - Returns the allocated LRPC_CCALL which has been bound to
  1477. the interface specified by the rpc interface information.
  1478. RpcInterfaceInformation - Supplies information describing the
  1479. interface to which we wish to bind.
  1480. Return Value:
  1481. --*/
  1482. {
  1483. LRPC_BINDING *SelectedBinding;
  1484. int RetryCount;
  1485. RPC_STATUS Status;
  1486. LRPC_CCONTEXT *SecurityContext;
  1487. BOOL fAlterSecurityContextNeeded = FALSE;
  1488. BOOL fAlterContextNeeded = FALSE;
  1489. LRPC_CCONTEXT *CurrentSecurityContext = NULL;
  1490. BOOL fUpdateCredentials = FALSE;
  1491. LUID CurrentModifiedId;
  1492. DictionaryCursor cursor;
  1493. LRPC_BINDING *BindingsForThisInterface[MaximumNumberOfTransferSyntaxes];
  1494. int NumberOfBindingsAvailable;
  1495. BOOL BindingCreated[MaximumNumberOfTransferSyntaxes];
  1496. int i;
  1497. int PreferredTransferSyntax;
  1498. int MatchingTransferSyntax;
  1499. BOOL IsBackConnectionNeeded = IsNonsyncMessage(Message);
  1500. RPC_STATUS CaptureStatus;
  1501. LRPC_BINDING *CurrentBinding;
  1502. BOOL fAssociationAborted = FALSE;
  1503. ULONG EffectiveIdentityTracking;
  1504. if (IsBackConnectionNeeded)
  1505. {
  1506. CLIENT_AUTH_INFO * AuthInfo;
  1507. AuthInfo = BindingHandle->InquireAuthInformation();
  1508. ASSERT(AuthInfo);
  1509. if (AuthInfo->IdentityTracking == RPC_C_QOS_IDENTITY_DYNAMIC)
  1510. {
  1511. CaptureStatus = CaptureModifiedId(&CurrentModifiedId);
  1512. fUpdateCredentials = TRUE;
  1513. }
  1514. }
  1515. Status = AssociationMutex.RequestSafe();
  1516. if (Status)
  1517. return Status;
  1518. if (fUpdateCredentials)
  1519. {
  1520. BindingHandle->UpdateCredentials((CaptureStatus != RPC_S_OK), &CurrentModifiedId);
  1521. }
  1522. RetryCount = 0;
  1523. EffectiveIdentityTracking = BindingHandle->GetIdentityTracking();
  1524. do
  1525. {
  1526. //
  1527. // We need to look at two things here. Presentation context
  1528. // and security context (in the async dynamic case only). If both match
  1529. // then we can allocate the call. Otherwise, we need to first bind
  1530. // in order to negotiate the interface/presentation context.
  1531. //
  1532. if (IsBackConnectionNeeded
  1533. || EffectiveIdentityTracking == RPC_C_QOS_IDENTITY_STATIC)
  1534. {
  1535. SecurityContextDict.Reset(cursor);
  1536. while (SecurityContext = SecurityContextDict.Next(cursor))
  1537. {
  1538. if (BindingHandle->CompareCredentials(SecurityContext))
  1539. {
  1540. CurrentSecurityContext = SecurityContext;
  1541. CurrentSecurityContext->AddReference();
  1542. CurrentSecurityContext->UpdateTimestamp();
  1543. break;
  1544. }
  1545. }
  1546. if (SecurityContext == 0)
  1547. {
  1548. fAlterSecurityContextNeeded = TRUE;
  1549. }
  1550. }
  1551. Status = MTSyntaxBinding::FindOrCreateBinding(RpcInterfaceInformation,
  1552. Message,
  1553. &Bindings,
  1554. CreateLrpcBinding,
  1555. NULL, // CheckBinding
  1556. NULL, // CallbackContext
  1557. &NumberOfBindingsAvailable,
  1558. (MTSyntaxBinding **)BindingsForThisInterface,
  1559. BindingCreated
  1560. );
  1561. if (Status != RPC_S_OK)
  1562. {
  1563. goto Cleanup;
  1564. }
  1565. PreferredTransferSyntax = -1;
  1566. MatchingTransferSyntax = -1;
  1567. for (i = 0; i < NumberOfBindingsAvailable; i ++)
  1568. {
  1569. // do we support the preferred server
  1570. if (BindingsForThisInterface[i]->IsTransferSyntaxServerPreferred())
  1571. {
  1572. PreferredTransferSyntax = i;
  1573. break;
  1574. }
  1575. else if ((BindingCreated[i] == FALSE) && (MatchingTransferSyntax < 0))
  1576. {
  1577. MatchingTransferSyntax = i;
  1578. }
  1579. }
  1580. // is there a syntax preferred by the server
  1581. if (PreferredTransferSyntax >= 0)
  1582. {
  1583. // do we already support it (i.e. the binding was not created)
  1584. if (BindingCreated[PreferredTransferSyntax] == FALSE)
  1585. {
  1586. // then we're all set - just use it
  1587. fAlterContextNeeded = FALSE;
  1588. SelectedBinding = BindingsForThisInterface[PreferredTransferSyntax];
  1589. }
  1590. else
  1591. {
  1592. // we don't support it - negotiate it. We know this
  1593. // will succeed, because the server preferences
  1594. // are set. This should be hit in the auto-retry case only
  1595. fAlterContextNeeded = TRUE;
  1596. ASSERT(_NOT_COVERED_);
  1597. }
  1598. }
  1599. else
  1600. {
  1601. // no preferred syntax - any will do. Check if we found anything supported
  1602. if (MatchingTransferSyntax >= 0)
  1603. {
  1604. SelectedBinding = BindingsForThisInterface[MatchingTransferSyntax];
  1605. fAlterContextNeeded = FALSE;
  1606. }
  1607. else
  1608. {
  1609. fAlterContextNeeded = TRUE;
  1610. }
  1611. }
  1612. if (fAlterContextNeeded == FALSE)
  1613. {
  1614. if (IsBackConnectionNeeded)
  1615. {
  1616. Status = InitializeAsyncLrpcIfNecessary() ;
  1617. if (Status == RPC_S_OK)
  1618. {
  1619. Status = CreateBackConnection(BindingHandle);
  1620. }
  1621. if (Status != RPC_S_OK)
  1622. {
  1623. goto Cleanup;
  1624. }
  1625. }
  1626. }
  1627. if (fAlterContextNeeded || fAlterSecurityContextNeeded)
  1628. {
  1629. Status = ActuallyDoBinding(
  1630. BindingHandle,
  1631. IsBackConnectionNeeded,
  1632. fAlterContextNeeded,
  1633. fAlterSecurityContextNeeded,
  1634. BindingHandle->ClientAuthInfo.DefaultLogonId,
  1635. NumberOfBindingsAvailable,
  1636. BindingsForThisInterface,
  1637. &SelectedBinding,
  1638. &CurrentSecurityContext);
  1639. if (Status != RPC_S_SERVER_UNAVAILABLE)
  1640. {
  1641. fAssociationAborted = FALSE;
  1642. break;
  1643. }
  1644. // The server appears to have gone away, close the port and retry.
  1645. RetryCount++;
  1646. SelectedBinding = 0;
  1647. // both the creation in ActuallyDoBinding and the
  1648. // retrieval from the cache will add a refcount -
  1649. // remove it
  1650. if (CurrentSecurityContext)
  1651. {
  1652. CurrentSecurityContext->RemoveReference();
  1653. CurrentSecurityContext = NULL;
  1654. }
  1655. fAlterContextNeeded = TRUE;
  1656. if (IsBackConnectionNeeded
  1657. || EffectiveIdentityTracking == RPC_C_QOS_IDENTITY_STATIC)
  1658. {
  1659. fAlterSecurityContextNeeded = TRUE;
  1660. }
  1661. AbortAssociation();
  1662. if (RetryCount < 3)
  1663. {
  1664. RpcpPurgeEEInfo();
  1665. }
  1666. fAssociationAborted = TRUE;
  1667. }
  1668. else
  1669. {
  1670. Status = RPC_S_OK;
  1671. break;
  1672. }
  1673. } while(RetryCount < 3);
  1674. if (Status == RPC_S_OK)
  1675. {
  1676. ASSERT(SelectedBinding != 0);
  1677. Status = ActuallyAllocateCCall(
  1678. CCall,
  1679. SelectedBinding,
  1680. IsBackConnectionNeeded,
  1681. BindingHandle,
  1682. CurrentSecurityContext);
  1683. }
  1684. else
  1685. {
  1686. // if the association was aborted, the bindings were already removed from the
  1687. // dictionary - don't do it again
  1688. if (fAssociationAborted == FALSE)
  1689. {
  1690. // the binding failed - remove the created bindings from the dictionary
  1691. for (i = 0; i < NumberOfBindingsAvailable; i ++)
  1692. {
  1693. if (BindingCreated[i])
  1694. {
  1695. CurrentBinding = Bindings.Delete(BindingsForThisInterface[i]->GetPresentationContext());
  1696. ASSERT(CurrentBinding == BindingsForThisInterface[i]);
  1697. delete CurrentBinding;
  1698. }
  1699. }
  1700. }
  1701. }
  1702. Cleanup:
  1703. if (CurrentSecurityContext)
  1704. {
  1705. if (Status == RPC_S_OK)
  1706. {
  1707. (*CCall)->SetCurrentSecurityContext(CurrentSecurityContext);
  1708. }
  1709. else
  1710. {
  1711. // remove the added reference
  1712. CurrentSecurityContext->RemoveReference();
  1713. }
  1714. }
  1715. AssociationMutex.Clear();
  1716. return(Status);
  1717. }
  1718. RPC_STATUS
  1719. LRPC_CASSOCIATION::ActuallyAllocateCCall (
  1720. OUT LRPC_CCALL ** CCall,
  1721. IN LRPC_BINDING * Binding,
  1722. IN BOOL IsBackConnectionNeeded,
  1723. IN LRPC_BINDING_HANDLE * BindingHandle,
  1724. IN LRPC_CCONTEXT *SecurityContext
  1725. )
  1726. /*++
  1727. Routine Description:
  1728. We need to allocate a LRPC_CCALL object for the call. We also need
  1729. to initialize it so that it specified the correct bound interface.
  1730. Arguments:
  1731. CCall - Returns the allocated LRPC_CCALL which has been bound to
  1732. the interface specified by the rpc interface information.
  1733. Binding - Supplies a representation of the interface to which the
  1734. remote procedure call is supposed to be directed.
  1735. Return Value:
  1736. RPC_S_OK - An LRPC_CCALL has been allocated and is ready to be used
  1737. to make a remote procedure call.
  1738. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate
  1739. the LRPC_CALL object.
  1740. Notes:
  1741. The global mutex will be held when this routine is called.
  1742. --*/
  1743. {
  1744. RPC_STATUS Status = RPC_S_OK ;
  1745. DictionaryCursor cursor;
  1746. LRPC_CCALL *LocalCall;
  1747. THREAD *ThisThread;
  1748. if (CachedCCallFlag != 0)
  1749. {
  1750. LocalCall = CachedCCall ;
  1751. CachedCCallFlag = 0;
  1752. }
  1753. else
  1754. {
  1755. ThisThread = RpcpGetThreadPointer();
  1756. ASSERT(ThisThread);
  1757. if (ThisThread->GetCachedLrpcCall())
  1758. {
  1759. LocalCall = ThisThread->GetCachedLrpcCall();
  1760. ThisThread->SetCachedLrpcCall(NULL);
  1761. LocalCall->SetAssociation(this);
  1762. }
  1763. else
  1764. {
  1765. FreeCCalls.Reset(cursor) ;
  1766. while ((LocalCall = FreeCCalls.Next(cursor)) != 0)
  1767. {
  1768. FreeCCalls.Delete(LocalCall->FreeCallKey) ;
  1769. break;
  1770. }
  1771. }
  1772. if (LocalCall == 0)
  1773. {
  1774. LocalCall = new LRPC_CCALL(&Status);
  1775. if (LocalCall == 0)
  1776. {
  1777. return(RPC_S_OUT_OF_MEMORY);
  1778. }
  1779. if (Status != RPC_S_OK)
  1780. {
  1781. delete LocalCall ;
  1782. return Status ;
  1783. }
  1784. LocalCall->SetAssociation(this);
  1785. }
  1786. }
  1787. Status = LocalCall->ActivateCall(BindingHandle,
  1788. Binding,
  1789. IsBackConnectionNeeded,
  1790. SecurityContext);
  1791. if (Status != RPC_S_OK)
  1792. {
  1793. goto Cleanup;
  1794. }
  1795. if (IsBackConnectionNeeded)
  1796. {
  1797. if (ActiveCCalls.Insert(ULongToPtr(CallIdCounter), LocalCall) == -1)
  1798. {
  1799. Status = RPC_S_OUT_OF_MEMORY;
  1800. // remove the reference we added to this
  1801. // binding
  1802. Binding->RemoveReference();
  1803. goto Cleanup;
  1804. }
  1805. LocalCall->CallId = CallIdCounter++;
  1806. LogEvent(SU_CCALL, EV_START, LocalCall, this, LocalCall->CallId, 1, 0);
  1807. }
  1808. AddReference();
  1809. *CCall = LocalCall;
  1810. return(RPC_S_OK);
  1811. Cleanup:
  1812. if (LocalCall == CachedCCall)
  1813. {
  1814. CachedCCallFlag = 1;
  1815. }
  1816. else
  1817. {
  1818. delete LocalCall ;
  1819. }
  1820. return (Status) ;
  1821. }
  1822. void
  1823. LRPC_CASSOCIATION::PrepareBindPacket(LRPC_MESSAGE *LrpcMessage)
  1824. {
  1825. int MessageSize;
  1826. int NumContexts = 0;
  1827. LRPC_CCONTEXT *CContext;
  1828. LRPC_CCONTEXT *DeletedContext;
  1829. DictionaryCursor cursor;
  1830. DWORD OldestUnusedAge = 0;
  1831. LRPC_CCONTEXT *OldestUnusedCContext = NULL;
  1832. DWORD CurrentTime = GetTickCount();
  1833. // Expire old and unused contexts.
  1834. // If we have some space left for expiring additional contexts and
  1835. // the cache is at the max size, we will trim the oldest remaining context.
  1836. // This is done to make sure that when the cache is at the max, even if
  1837. // none of the contexts are old, we will still expire at least one context for
  1838. // each new one we establish.
  1839. SecurityContextDict.Reset(cursor);
  1840. // Proceed while the packet has space left for expiring more contexts.
  1841. while (NumContexts < MAX_LRPC_CONTEXTS)
  1842. {
  1843. // Pick the next unused context.
  1844. CContext = SecurityContextDict.Next(cursor);
  1845. if (CContext
  1846. && CContext->IsUnused())
  1847. {
  1848. // If the security context is old, we expire it.
  1849. if (CContext->IsSecurityContextOld())
  1850. {
  1851. LrpcMessage->Bind.OldSecurityContexts.SecurityContextId[NumContexts]
  1852. = CContext->SecurityContextId;
  1853. DeletedContext = SecurityContextDict.Delete(CContext->ContextKey);
  1854. ASSERT(DeletedContext == CContext);
  1855. NumContexts++;
  1856. delete CContext;
  1857. }
  1858. // Otherwise, we check if we should force expiration of the oldest context.
  1859. else if (SecurityContextDict.Size() > LRPC_CCONTEXT_CACHE_SIZE_THRESHOLD)
  1860. {
  1861. // Compute the age of the current context taking into account tick count wrapping.
  1862. // Note that since both values are unsigned, we will get a large positive Age if CurrentTime < CContext->GetTimestamp().
  1863. DWORD Age = CurrentTime - CContext->GetTimestamp();
  1864. // If we have the oldest context, remember it.
  1865. if (Age > OldestUnusedAge)
  1866. {
  1867. OldestUnusedAge = Age;
  1868. OldestUnusedCContext = CContext;
  1869. }
  1870. }
  1871. }
  1872. else
  1873. {
  1874. break;
  1875. }
  1876. }
  1877. // If there is space left to expire more contexts and we were able to find the oldest unused context, delete it.
  1878. if (NumContexts < MAX_LRPC_CONTEXTS
  1879. && OldestUnusedCContext != NULL)
  1880. {
  1881. LrpcMessage->Bind.OldSecurityContexts.SecurityContextId[NumContexts] = OldestUnusedCContext->SecurityContextId;
  1882. DeletedContext = SecurityContextDict.Delete(OldestUnusedCContext->ContextKey);
  1883. ASSERT(DeletedContext == OldestUnusedCContext);
  1884. NumContexts++;
  1885. delete OldestUnusedCContext;
  1886. }
  1887. UpdateLastSecContextTrimmingTimestamp();
  1888. MessageSize = FIELD_OFFSET(LRPC_BIND_MESSAGE, OldSecurityContexts) +
  1889. FIELD_OFFSET(OLD_SECURITY_CONTEXTS, SecurityContextId) +
  1890. NumContexts*sizeof(DWORD);
  1891. LrpcMessage->Bind.OldSecurityContexts.NumContexts = NumContexts;
  1892. LrpcMessage->LpcHeader.u1.s1.DataLength = (CSHORT) (MessageSize - sizeof(PORT_MESSAGE));
  1893. LrpcMessage->LpcHeader.u1.s1.TotalLength = (CSHORT) MessageSize;
  1894. }
  1895. RPC_STATUS
  1896. LRPC_CASSOCIATION::ActuallyDoBinding (
  1897. IN LRPC_BINDING_HANDLE *BindingHandle,
  1898. IN BOOL IsBackConnectionNeeded,
  1899. IN BOOL fAlterContextNeeded,
  1900. IN BOOL fAlterSecurityContextNeeded,
  1901. IN BOOL fDefaultLogonId,
  1902. IN int NumberOfBindings,
  1903. LRPC_BINDING *BindingsForThisInterface[],
  1904. OUT LRPC_BINDING ** Binding,
  1905. OUT LRPC_CCONTEXT **pSecurityContext
  1906. )
  1907. /*++
  1908. Routine Description:
  1909. Arguments:
  1910. RpcInterfaceInformation - Supplies information describing the interface
  1911. to which we wish to bind.
  1912. Binding - Returns an object representing the binding to the interface
  1913. described by the first argument.
  1914. Return Value:
  1915. --*/
  1916. {
  1917. NTSTATUS NtStatus;
  1918. NTSTATUS MyNtStatus;
  1919. RPC_STATUS Status = RPC_S_OK;
  1920. int DictKey ;
  1921. HANDLE ImpersonationToken = 0;
  1922. BOOL fTokenAltered = 0;
  1923. int i;
  1924. LRPC_BIND_EXCHANGE *BindExchange;
  1925. int BindingForNDR20PresentationContext;
  1926. int BindingForNDR64PresentationContext;
  1927. int BindingForNDRTestPresentationContext;
  1928. int ChosenBindingIndex;
  1929. LRPC_BINDING *SelectedBinding;
  1930. LRPC_MESSAGE *LrpcMessage;
  1931. ULONG EffectiveIdentityTracking;
  1932. //
  1933. // To start with, see if we have an LPC port; if we dont, open one
  1934. // up.
  1935. //
  1936. //
  1937. // The AssociationMutex is held when this function is called
  1938. //
  1939. AssociationMutex.VerifyOwned();
  1940. if (IsBackConnectionNeeded)
  1941. {
  1942. Status = InitializeAsyncLrpcIfNecessary() ;
  1943. if (Status == RPC_S_OK)
  1944. {
  1945. Status = CreateBackConnection(BindingHandle) ;
  1946. }
  1947. if (Status != RPC_S_OK)
  1948. {
  1949. RpcpErrorAddRecord(EEInfoGCRuntime,
  1950. Status,
  1951. EEInfoDLLRPC_CASSOCIATION__ActuallyDoBinding10,
  1952. InqEndpoint());
  1953. return Status ;
  1954. }
  1955. }
  1956. else
  1957. {
  1958. if (LpcClientPort == 0)
  1959. {
  1960. //
  1961. // we now need to bind explicitly
  1962. //
  1963. Status = OpenLpcPort(BindingHandle, FALSE);
  1964. ASSERT(fAlterContextNeeded == TRUE);
  1965. if (Status != RPC_S_OK)
  1966. {
  1967. RpcpErrorAddRecord(EEInfoGCRuntime,
  1968. Status,
  1969. EEInfoDLLRPC_CASSOCIATION__ActuallyDoBinding20,
  1970. InqEndpoint());
  1971. return Status ;
  1972. }
  1973. }
  1974. }
  1975. LrpcMessage = (LRPC_MESSAGE *)AlignOnNaturalBoundary(
  1976. _alloca(sizeof(LRPC_MESSAGE) + RPCRT_NATURAL_BOUNDARY_ALIGNMENT_MAX_SHIFT));
  1977. SanitizeLpcHeader (&LrpcMessage->LpcHeader);
  1978. if (CacheNeedsTrimming())
  1979. {
  1980. PrepareBindPacket(LrpcMessage);
  1981. }
  1982. else
  1983. {
  1984. LrpcMessage->LpcHeader.u1.s1.DataLength = FIELD_OFFSET(LRPC_BIND_MESSAGE, OldSecurityContexts)
  1985. + sizeof(LrpcMessage->Bind.OldSecurityContexts.NumContexts)
  1986. - sizeof(PORT_MESSAGE);
  1987. LrpcMessage->LpcHeader.u1.s1.TotalLength = FIELD_OFFSET(LRPC_BIND_MESSAGE, OldSecurityContexts)
  1988. + sizeof(LrpcMessage->Bind.OldSecurityContexts.NumContexts);
  1989. LrpcMessage->Bind.OldSecurityContexts.NumContexts = 0;
  1990. }
  1991. BindExchange = &LrpcMessage->Bind.BindExchange;
  1992. // Zero out uninitialized data.
  1993. BindExchange->ConnectType = 0;
  1994. BindExchange->AssocKey = 0;
  1995. BindExchange->RpcStatus = 0;
  1996. BindExchange->SecurityContextId = 0;
  1997. RpcpMemorySet(BindExchange->Cookie, 0, BIND_BACK_COOKIE_SIZE);
  1998. RpcpMemorySet(&BindExchange->szPortName, 0, sizeof(BindExchange->szPortName));
  1999. // Otherwise, just go ahead and send the bind request message to the
  2000. // server, and then wait for the bind response.
  2001. LrpcMessage->LpcHeader.u2.ZeroInit = 0;
  2002. LrpcMessage->Bind.MessageType = LRPC_MSG_BIND;
  2003. LrpcMessage->Bind.Pad[0] = 0;
  2004. LrpcMessage->Bind.Pad[1] = 0;
  2005. LrpcMessage->Bind.Pad[2] = 0;
  2006. if (fAlterContextNeeded)
  2007. {
  2008. SelectedBinding = *Binding = NULL;
  2009. ASSERT(NumberOfBindings > 0);
  2010. // all bindings have the same interface ID. Therefore, it is
  2011. // safe to use the first
  2012. RpcpMemoryCopy(&BindExchange->InterfaceId,
  2013. BindingsForThisInterface[0]->GetInterfaceId(),
  2014. sizeof(RPC_SYNTAX_IDENTIFIER));
  2015. BindExchange->Flags = NEW_PRESENTATION_CONTEXT_FLAG;
  2016. BindExchange->TransferSyntaxSet = 0;
  2017. BindingForNDR20PresentationContext = BindingForNDR64PresentationContext = -1;
  2018. ASSERT (NumberOfBindings <= MaximumNumberOfTransferSyntaxes);
  2019. for (i = 0; i < NumberOfBindings; i ++)
  2020. {
  2021. if (RpcpMemoryCompare(BindingsForThisInterface[i]->GetTransferSyntaxId(),
  2022. NDR20TransferSyntax, sizeof(RPC_SYNTAX_IDENTIFIER)) == 0)
  2023. {
  2024. BindExchange->TransferSyntaxSet |= TS_NDR20_FLAG;
  2025. BindExchange->PresentationContext[0]
  2026. = BindingsForThisInterface[i]->GetOnTheWirePresentationContext();
  2027. BindingForNDR20PresentationContext = i;
  2028. }
  2029. else if (RpcpMemoryCompare(BindingsForThisInterface[i]->GetTransferSyntaxId(),
  2030. NDR64TransferSyntax, sizeof(RPC_SYNTAX_IDENTIFIER)) == 0)
  2031. {
  2032. BindExchange->TransferSyntaxSet |= TS_NDR64_FLAG;
  2033. BindExchange->PresentationContext[1]
  2034. = BindingsForThisInterface[i]->GetOnTheWirePresentationContext();
  2035. BindingForNDR64PresentationContext = i;
  2036. }
  2037. else if (RpcpMemoryCompare(BindingsForThisInterface[i]->GetTransferSyntaxId(),
  2038. NDRTestTransferSyntax, sizeof(RPC_SYNTAX_IDENTIFIER)) == 0)
  2039. {
  2040. BindExchange->TransferSyntaxSet |= TS_NDRTEST_FLAG;
  2041. BindExchange->PresentationContext[2]
  2042. = BindingsForThisInterface[i]->GetOnTheWirePresentationContext();
  2043. BindingForNDRTestPresentationContext = i;
  2044. }
  2045. else
  2046. {
  2047. ASSERT(!"Unknown transfer syntax\n");
  2048. Status = RPC_S_UNSUPPORTED_TRANS_SYN;
  2049. goto Cleanup;
  2050. }
  2051. }
  2052. }
  2053. else
  2054. {
  2055. RpcpMemorySet(&BindExchange->InterfaceId,
  2056. 0,
  2057. sizeof(RPC_SYNTAX_IDENTIFIER));
  2058. BindExchange->Flags = 0;
  2059. BindExchange->TransferSyntaxSet = 0;
  2060. BindExchange->PresentationContext[0] = 0;
  2061. BindExchange->PresentationContext[1] = 0;
  2062. BindExchange->PresentationContext[2] = 0;
  2063. ASSERT(*Binding != NULL);
  2064. SelectedBinding = *Binding;
  2065. }
  2066. if (fAlterSecurityContextNeeded)
  2067. {
  2068. BindExchange->Flags |= NEW_SECURITY_CONTEXT_FLAG;
  2069. if (fDefaultLogonId)
  2070. BindExchange->Flags |= DEFAULT_LOGONID_FLAG;
  2071. EffectiveIdentityTracking = BindingHandle->GetIdentityTracking();
  2072. if (EffectiveIdentityTracking == RPC_C_QOS_IDENTITY_STATIC)
  2073. {
  2074. if (OpenThreadToken (GetCurrentThread(),
  2075. TOKEN_IMPERSONATE | TOKEN_QUERY,
  2076. TRUE,
  2077. &ImpersonationToken) == FALSE)
  2078. {
  2079. ImpersonationToken = 0;
  2080. }
  2081. MyNtStatus = NtSetInformationThread(NtCurrentThread(),
  2082. ThreadImpersonationToken,
  2083. &(BindingHandle->StaticTokenHandle),
  2084. sizeof(HANDLE));
  2085. #if DBG
  2086. if (!NT_SUCCESS(MyNtStatus))
  2087. {
  2088. PrintToDebugger("RPC : NtSetInformationThread : %lx\n", MyNtStatus);
  2089. }
  2090. #endif // DBG
  2091. fTokenAltered = 1;
  2092. }
  2093. }
  2094. // We will allow the server to impersonate us on this call.
  2095. // This is fine since for static identity tracking this is when the server
  2096. // obtains the client's token.
  2097. NtStatus = NtRequestWaitReplyPort(LpcClientPort,
  2098. (PORT_MESSAGE *) LrpcMessage,
  2099. (PORT_MESSAGE *) LrpcMessage) ;
  2100. if (fTokenAltered)
  2101. {
  2102. MyNtStatus = NtSetInformationThread(NtCurrentThread(),
  2103. ThreadImpersonationToken,
  2104. &ImpersonationToken,
  2105. sizeof(HANDLE));
  2106. #if DBG
  2107. if (!NT_SUCCESS(MyNtStatus))
  2108. {
  2109. PrintToDebugger("RPC : NtSetInformationThread : %lx\n", MyNtStatus);
  2110. }
  2111. #endif // DBG
  2112. if (ImpersonationToken)
  2113. {
  2114. CloseHandle(ImpersonationToken);
  2115. }
  2116. }
  2117. if (NT_SUCCESS(NtStatus))
  2118. {
  2119. ASSERT(LrpcMessage->Bind.MessageType == LRPC_BIND_ACK);
  2120. if (BindExchange->RpcStatus == RPC_S_OK)
  2121. {
  2122. if (fAlterSecurityContextNeeded &&
  2123. (IsBackConnectionNeeded
  2124. || EffectiveIdentityTracking == RPC_C_QOS_IDENTITY_STATIC))
  2125. {
  2126. //
  2127. // The security context ID should never be -1 for success bind_ack.
  2128. // Note that this is the case only if we are setting up a new security context.
  2129. // If BindExchange->Flags is not set with NEW_SECURITY_CONTEXT_FLAG, then we
  2130. // may get back a -1 SecurityContextId, but we will not create a security context.
  2131. //
  2132. if (BindExchange->SecurityContextId == -1)
  2133. {
  2134. CORRUPTION_ASSERT(BindExchange->SecurityContextId != -1);
  2135. Status = RPC_S_PROTOCOL_ERROR;
  2136. goto Cleanup;
  2137. }
  2138. *pSecurityContext = new LRPC_CCONTEXT(
  2139. BindingHandle->InquireAuthInformation(),
  2140. BindExchange->SecurityContextId,
  2141. this);
  2142. if (*pSecurityContext == 0)
  2143. {
  2144. Status = RPC_S_OUT_OF_MEMORY;
  2145. goto Cleanup;
  2146. }
  2147. if ((DictKey = SecurityContextDict.Insert(*pSecurityContext)) == -1)
  2148. {
  2149. delete *pSecurityContext;
  2150. *pSecurityContext = NULL;
  2151. Status = RPC_S_OUT_OF_MEMORY;
  2152. goto Cleanup;
  2153. }
  2154. (*pSecurityContext)->AddReference();
  2155. (*pSecurityContext)->ContextKey = DictKey;
  2156. }
  2157. if (fAlterContextNeeded)
  2158. {
  2159. ChosenBindingIndex = -1;
  2160. // which presentation context did the server pick?
  2161. if (BindExchange->TransferSyntaxSet & TS_NDR20_FLAG)
  2162. {
  2163. ASSERT(BindingForNDR20PresentationContext != -1);
  2164. // the server should choose only one transfer syntax
  2165. ASSERT((BindExchange->TransferSyntaxSet & ~TS_NDR20_FLAG) == 0);
  2166. ChosenBindingIndex = BindingForNDR20PresentationContext;
  2167. }
  2168. else if (BindExchange->TransferSyntaxSet & TS_NDR64_FLAG)
  2169. {
  2170. ASSERT(BindingForNDR64PresentationContext != -1);
  2171. // the server should choose only one transfer syntax
  2172. ASSERT((BindExchange->TransferSyntaxSet & ~TS_NDR64_FLAG) == 0);
  2173. ChosenBindingIndex = BindingForNDR64PresentationContext;
  2174. }
  2175. else if (BindExchange->TransferSyntaxSet & TS_NDRTEST_FLAG)
  2176. {
  2177. ASSERT(BindingForNDRTestPresentationContext != -1);
  2178. // the server should choose only one transfer syntax
  2179. ASSERT((BindExchange->TransferSyntaxSet & ~TS_NDRTEST_FLAG) == 0);
  2180. ChosenBindingIndex = BindingForNDRTestPresentationContext;
  2181. }
  2182. else
  2183. {
  2184. ASSERT(!"Server supplied invalid response");
  2185. }
  2186. if (ChosenBindingIndex < 0)
  2187. {
  2188. ASSERT(_NOT_COVERED_);
  2189. BindExchange->RpcStatus = RPC_S_UNSUPPORTED_TRANS_SYN;
  2190. }
  2191. else
  2192. {
  2193. // if we offered the server a choice of bindings and it
  2194. // exercised this choice, record its preferences
  2195. if (NumberOfBindings > 1)
  2196. {
  2197. BindingsForThisInterface[ChosenBindingIndex]->
  2198. TransferSyntaxIsServerPreferred();
  2199. for (i = 0; i < NumberOfBindings; i ++)
  2200. {
  2201. if (ChosenBindingIndex != i)
  2202. {
  2203. BindingsForThisInterface[i]->TransferSyntaxIsNotServerPreferred();
  2204. }
  2205. }
  2206. }
  2207. SelectedBinding = BindingsForThisInterface[ChosenBindingIndex];
  2208. }
  2209. }
  2210. }
  2211. else
  2212. {
  2213. if (BindExchange->Flags & EXTENDED_ERROR_INFO_PRESENT)
  2214. {
  2215. ExtendedErrorInfo *EEInfo;
  2216. // In the [out] bind direction the eeinfo is contained in the
  2217. // Bind.BindExchangeReturn structure.
  2218. // Bind.BindExchange is used for passing the port name in the
  2219. // [in] direction and does not have enough space.
  2220. ASSERT(IsBufferAligned(LrpcMessage->Bind.BindExchangeReturn.Buffer));
  2221. Status = UnpickleEEInfo(LrpcMessage->Bind.BindExchangeReturn.Buffer,
  2222. LrpcMessage->LpcHeader.u1.s1.DataLength
  2223. - BIND_NAK_PICKLE_BUFFER_OFFSET
  2224. + sizeof(PORT_MESSAGE),
  2225. &EEInfo);
  2226. if (Status == RPC_S_OK)
  2227. {
  2228. RpcpSetEEInfo(EEInfo);
  2229. }
  2230. RpcpErrorAddRecord(EEInfoGCRuntime,
  2231. BindExchange->RpcStatus,
  2232. EEInfoDLLRPC_CASSOCIATION__ActuallyDoBinding30);
  2233. }
  2234. }
  2235. Status = BindExchange->RpcStatus;
  2236. ASSERT (Status != RPC_S_SERVER_UNAVAILABLE
  2237. && Status != RPC_S_ACCESS_DENIED) ;
  2238. }
  2239. else
  2240. {
  2241. Status = RPC_S_SERVER_UNAVAILABLE;
  2242. RpcpErrorAddRecord(EEInfoGCLPC,
  2243. Status,
  2244. EEInfoDLLRPC_CASSOCIATION__ActuallyDoBinding40,
  2245. NtStatus);
  2246. }
  2247. Cleanup:
  2248. *Binding = SelectedBinding;
  2249. return (Status);
  2250. }
  2251. void
  2252. LRPC_CASSOCIATION::ProcessResponse (
  2253. IN LRPC_MESSAGE *LrpcResponse,
  2254. IN BOOL AssocMutexHeld,
  2255. IN OUT LRPC_MESSAGE **LrpcReplyMessage
  2256. )
  2257. /*++
  2258. Routine Description:
  2259. Process a response on the back connection.
  2260. Two types of responses can show up on the back connection:
  2261. 1. Responses from async calls.
  2262. Arguments:
  2263. LrpcResponse - Reply message.
  2264. AssocMutexHeld - used to indicate that we are calling this function
  2265. while holding the AssociationMutex.
  2266. Return Value:
  2267. RPC_S_OK - Function succeeded
  2268. RPC_S_OUT_OF_MEMORY - we ran out of memory
  2269. --*/
  2270. {
  2271. LRPC_CCALL *CCall ;
  2272. RPC_MESSAGE RpcMessage ;
  2273. THREAD *ThisThread;
  2274. LRPC_CCALL *ExistingCCall;
  2275. ULONG OriginalCallId;
  2276. ThisThread = RpcpGetThreadPointer();
  2277. ASSERT(ThisThread);
  2278. ASSERT(ThisThread->GetDestroyedWithOutstandingLocksFlag() == 0);
  2279. OriginalCallId = LrpcResponse->Rpc.RpcHeader.CallId;
  2280. if (!AssocMutexHeld){
  2281. AssociationMutex.Request();
  2282. }
  2283. CCall = ActiveCCalls.Find(ULongToPtr(OriginalCallId)) ;
  2284. if (CCall == 0)
  2285. {
  2286. AssociationMutex.Clear() ;
  2287. if (LrpcResponse->Rpc.RpcHeader.Flags & LRPC_BUFFER_SERVER)
  2288. {
  2289. // There may be a server thread stuck waiting for the reply
  2290. // in which case we should treat this as a synchronous call
  2291. // and make sure the message is not dropped.
  2292. // We do this only if the buffer is server. If it is not,
  2293. // we don't do that, because the LPC response we received
  2294. // was datagram, and we can't send a response to a datagram.
  2295. // Note that this is not necessary either, since the response
  2296. // is from a server, and we don't have any use on the server
  2297. // for a fault to a response (it just gets dropped). If the
  2298. // buffer is server, we still need to do it to free
  2299. // the thread, because it is doing NtRequestWaitReplyPort,
  2300. // and this is blocking.
  2301. SetFaultPacket(LrpcResponse,
  2302. RPC_S_CALL_FAILED_DNE,
  2303. LrpcResponse->Rpc.RpcHeader.Flags | LRPC_SYNC_CLIENT,
  2304. NULL);
  2305. *LrpcReplyMessage = LrpcResponse;
  2306. }
  2307. return ;
  2308. }
  2309. CCall->LockCallFromResponse();
  2310. AssociationMutex.Clear() ;
  2311. CCall->ProcessResponse(LrpcResponse);
  2312. // if this call was destroyed with outstanding locks, don't
  2313. // touch it - just clear the flag
  2314. if (ThisThread->GetDestroyedWithOutstandingLocksFlag())
  2315. {
  2316. ThisThread->ClearDestroyedWithOutstandingLocksFlag();
  2317. }
  2318. else
  2319. {
  2320. AssociationMutex.Request() ;
  2321. // check if somebody has freed the call. If yes, don't do anything - the counter
  2322. // would have been reset
  2323. ExistingCCall = ActiveCCalls.Find(ULongToPtr(OriginalCallId));
  2324. if (ExistingCCall
  2325. && (ExistingCCall == CCall))
  2326. {
  2327. CCall->UnlockCallFromResponse();
  2328. }
  2329. AssociationMutex.Clear() ;
  2330. }
  2331. }
  2332. RPC_STATUS
  2333. LRPC_CASSOCIATION::OpenLpcPort (
  2334. IN LRPC_BINDING_HANDLE *BindingHandle,
  2335. IN BOOL fBindBack
  2336. )
  2337. /*++
  2338. Routine Description:
  2339. Arguments:
  2340. RpcInterfaceInformation - Supplies information describing the interface
  2341. to which we wish to bind.
  2342. Binding - Returns an object representing the binding to the interface
  2343. described by the first argument.
  2344. Return Value:
  2345. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete the
  2346. operation.
  2347. Notes:
  2348. The global mutex will be held when this routine is called.
  2349. --*/
  2350. {
  2351. NTSTATUS NtStatus;
  2352. UNICODE_STRING UnicodeString;
  2353. RPC_CHAR * LpcPortName;
  2354. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  2355. RPC_STATUS Status;
  2356. LRPC_BIND_EXCHANGE BindExchange;
  2357. unsigned long BindExchangeLength = sizeof(LRPC_BIND_EXCHANGE);
  2358. PSID SidToUse;
  2359. int RetryCount;
  2360. BOOL fCachedSid = TRUE;
  2361. //
  2362. // Look at the network options and initialize the security quality
  2363. // of service appropriately.
  2364. //
  2365. SecurityQualityOfService.EffectiveOnly = (unsigned char) BindingHandle->EffectiveOnly;
  2366. SecurityQualityOfService.ContextTrackingMode =
  2367. SECURITY_DYNAMIC_TRACKING;
  2368. SecurityQualityOfService.ImpersonationLevel =
  2369. MapRpcToNtImp(AssocAuthInfo.ImpersonationType) ;
  2370. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  2371. //
  2372. // Allocate and initialize the port name. We need to stick the
  2373. // LRPC_DIRECTORY_NAME on the front of the endpoint. This is for
  2374. // security reasons (so that anyone can create LRPC endpoints).
  2375. //
  2376. LpcPortName = new RPC_CHAR[
  2377. RpcpStringLength(DceBinding->InqEndpoint())
  2378. + RpcpStringLength(LRPC_DIRECTORY_NAME) + 1];
  2379. if (LpcPortName == 0)
  2380. {
  2381. return(RPC_S_OUT_OF_MEMORY);
  2382. }
  2383. RpcpMemoryCopy(LpcPortName, LRPC_DIRECTORY_NAME,
  2384. RpcpStringLength(LRPC_DIRECTORY_NAME) * sizeof(RPC_CHAR));
  2385. RpcpMemoryCopy(LpcPortName + RpcpStringLength(LRPC_DIRECTORY_NAME),
  2386. DceBinding->InqEndpoint(),
  2387. (RpcpStringLength(DceBinding->InqEndpoint()) + 1)
  2388. * sizeof(RPC_CHAR));
  2389. RtlInitUnicodeString(&UnicodeString, LpcPortName);
  2390. // zero out buffer to prevent data leak
  2391. RpcpMemorySet (&BindExchange, 0, sizeof(BindExchange));
  2392. DWORD Key;
  2393. LPC_KEY *LpcKey = (LPC_KEY *) &Key;
  2394. LpcKey->SeqNumber = SequenceNumber;
  2395. LpcKey->AssocKey = (unsigned short) AssociationDictKey;
  2396. BindExchange.ConnectType = LRPC_CONNECT_REQUEST ;
  2397. BindExchange.AssocKey = Key;
  2398. if (fBindBack)
  2399. {
  2400. BindExchange.Flags = BIND_BACK_FLAG;
  2401. // Initialize a cookie to be sent in the message.
  2402. RpcpMemoryCopy(BindExchange.Cookie, BindBackCookie, BIND_BACK_COOKIE_SIZE);
  2403. // LRPC_BIND_EXCHANGE::szPortName can be at most PORT_NAME_LEN chars.
  2404. // The global lrpc server's port name can be initialized either in
  2405. // LRPC_SERVER::InitializeAsync or in LRPC_ADDRESS::ActuallySetupAddress.
  2406. // In the former case, it is just "MSAsyncRPC_DECIMALPID" and in the latter,
  2407. // we check to make sure the name does not overflow.
  2408. LrpcGetEndpoint((RPC_CHAR *) BindExchange.szPortName) ;
  2409. }
  2410. else
  2411. {
  2412. BindExchange.Flags = 0;
  2413. }
  2414. if ((AssocAuthInfo.Capabilities & RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH)
  2415. && AssocAuthInfo.ServerPrincipalName)
  2416. {
  2417. PSID pSID;
  2418. // if we don't have a SID, we'll have to convert the name to a SID.
  2419. if (AssocAuthInfo.ServerSid == NULL)
  2420. {
  2421. Status = RpcpLookupAccountName (AssocAuthInfo.ServerPrincipalName,
  2422. &fCachedSid,
  2423. &pSID
  2424. );
  2425. if (Status != RPC_S_OK)
  2426. {
  2427. delete [] LpcPortName;
  2428. return Status;
  2429. }
  2430. }
  2431. else
  2432. {
  2433. ASSERT(IsValidSid(AssocAuthInfo.ServerSid));
  2434. pSID = AssocAuthInfo.ServerSid;
  2435. }
  2436. RetryCount = 0;
  2437. do
  2438. {
  2439. Status = NormalizeAccountSid(pSID, &SidToUse, &RetryCount);
  2440. if (Status != RPC_S_OK)
  2441. {
  2442. if (AssocAuthInfo.ServerSid == NULL)
  2443. {
  2444. delete [] pSID;
  2445. }
  2446. delete [] LpcPortName;
  2447. return Status;
  2448. }
  2449. NtStatus = NtSecureConnectPort (
  2450. &LpcClientPort,
  2451. &UnicodeString,
  2452. &SecurityQualityOfService,
  2453. NULL,
  2454. SidToUse,
  2455. NULL,
  2456. NULL,
  2457. &BindExchange,
  2458. &BindExchangeLength);
  2459. // we may attempt retry only if we got the server sid
  2460. // wrong.
  2461. if (NtStatus != STATUS_SERVER_SID_MISMATCH)
  2462. break;
  2463. }
  2464. while (RetryCount != 0);
  2465. if (AssocAuthInfo.ServerSid == NULL)
  2466. {
  2467. delete [] pSID;
  2468. }
  2469. }
  2470. else
  2471. {
  2472. NtStatus = NtConnectPort(
  2473. &LpcClientPort,
  2474. &UnicodeString,
  2475. &SecurityQualityOfService,
  2476. NULL,
  2477. NULL,
  2478. NULL,
  2479. &BindExchange,
  2480. &BindExchangeLength);
  2481. }
  2482. delete [] LpcPortName;
  2483. if (NT_SUCCESS(NtStatus))
  2484. {
  2485. ASSERT(BindExchangeLength == sizeof(LRPC_BIND_EXCHANGE));
  2486. return(BindExchange.RpcStatus);
  2487. }
  2488. if (NtStatus == STATUS_PORT_CONNECTION_REFUSED)
  2489. {
  2490. if (BindExchange.Flags & SERVER_BIND_EXCH_RESP)
  2491. {
  2492. RpcpErrorAddRecord(EEInfoGCRuntime,
  2493. BindExchange.RpcStatus,
  2494. EEInfoDLLRPC_CASSOCIATION__OpenLpcPort20,
  2495. NtStatus);
  2496. return(BindExchange.RpcStatus);
  2497. }
  2498. // if the SERVER_BIND_EXCH_RESP flag is not set, the rejection
  2499. // comes from LPC. The only case where this can happen is if
  2500. // the server is not available.
  2501. RpcpErrorAddRecord(EEInfoGCRuntime,
  2502. RPC_S_SERVER_UNAVAILABLE,
  2503. EEInfoDLLRPC_CASSOCIATION__OpenLpcPort30,
  2504. NtStatus);
  2505. return(RPC_S_SERVER_UNAVAILABLE);
  2506. }
  2507. if (NtStatus == STATUS_NO_MEMORY)
  2508. {
  2509. Status = RPC_S_OUT_OF_MEMORY;
  2510. }
  2511. else if ((NtStatus == STATUS_INSUFFICIENT_RESOURCES)
  2512. || (NtStatus == STATUS_QUOTA_EXCEEDED))
  2513. {
  2514. Status = RPC_S_OUT_OF_RESOURCES;
  2515. }
  2516. else if (NtStatus == STATUS_OBJECT_PATH_INVALID)
  2517. {
  2518. Status = RPC_S_INVALID_ENDPOINT_FORMAT;
  2519. }
  2520. else if (NtStatus == STATUS_ACCESS_DENIED
  2521. || NtStatus == STATUS_SERVER_SID_MISMATCH
  2522. || NtStatus == STATUS_BAD_IMPERSONATION_LEVEL)
  2523. {
  2524. // Invalidate our cache entry for this SPN
  2525. (void) RemoveFromSIDCache(AssocAuthInfo.ServerPrincipalName);
  2526. Status = RPC_S_ACCESS_DENIED;
  2527. }
  2528. else
  2529. {
  2530. #if DBG
  2531. if (NtStatus != STATUS_OBJECT_NAME_NOT_FOUND)
  2532. {
  2533. PrintToDebugger("LRPC: NtConnectPort : %lx\n", NtStatus);
  2534. }
  2535. #endif // DBG
  2536. ASSERT(NtStatus == STATUS_OBJECT_NAME_NOT_FOUND);
  2537. Status = RPC_S_SERVER_UNAVAILABLE;
  2538. }
  2539. RpcpErrorAddRecord(EEInfoGCRuntime,
  2540. Status,
  2541. EEInfoDLLRPC_CASSOCIATION__OpenLpcPort40,
  2542. NtStatus);
  2543. return Status;
  2544. }
  2545. void
  2546. LRPC_CASSOCIATION::FreeCCall (
  2547. IN LRPC_CCALL * CCall
  2548. )
  2549. /*++
  2550. Routine Description:
  2551. This routine will get called to notify this association that a remote
  2552. procedure call on this association has completed.
  2553. Arguments:
  2554. CCall - Supplies the remote procedure call which has completed.
  2555. --*/
  2556. {
  2557. LRPC_CCALL *DeletedCall;
  2558. BOOL fMutexTaken = FALSE;
  2559. ExtendedErrorInfo *LocalEEInfo;
  2560. LRPC_MESSAGE *LocalLrpcMessage;
  2561. THREAD *ThisThread;
  2562. BOOL fCacheToThread;
  2563. BOOL fOutstandingLocks = FALSE;
  2564. BOOL fUnlocked;
  2565. void *Buffer;
  2566. unsigned int BufferLength ;
  2567. if (CCall->CallId != (ULONG) -1)
  2568. {
  2569. // Try to take both resources, but if fail on the second, release
  2570. // the first and retry. There is a potential deadlock here, since
  2571. // another thread may have the call locked while holding the AssociationMutex,
  2572. // release the mutex, and try to take it again. This may happen in
  2573. // ProcessResponse()
  2574. while (TRUE)
  2575. {
  2576. AssociationMutex.Request();
  2577. fMutexTaken = TRUE;
  2578. LogEvent(SU_CCALL, EV_STOP, CCall, this, CCall->CallId, 1, 0);
  2579. if (CCall->AsyncStatus == RPC_S_CALL_CANCELLED)
  2580. {
  2581. // if the call was cancelled, there is a race condition
  2582. // where the server may still be sending us a response
  2583. // make sure we wait for any response already in the pipeline
  2584. // to go through
  2585. fOutstandingLocks = CCall->TryWaitForCallToBecomeUnlocked(&fUnlocked);
  2586. if (fUnlocked)
  2587. break;
  2588. else
  2589. {
  2590. AssociationMutex.Clear();
  2591. fMutexTaken = FALSE;
  2592. Sleep(10);
  2593. }
  2594. }
  2595. else
  2596. {
  2597. // this is not a cancel. It is possible that a response
  2598. // is still being processed. We zero out the counter now,
  2599. // and we will remove the element from the dictionary and
  2600. // reset its CallId (we're still inside the mutex). When
  2601. // the thread that processes the response is about to
  2602. // decrease the refcount, it will check whether the call is
  2603. // in the dictionary and whether it has the same call id.
  2604. // If yes, it won't touch the call.
  2605. CCall->ResponseLockCount.SetInteger(0);
  2606. break;
  2607. }
  2608. }
  2609. DeletedCall = ActiveCCalls.Delete(ULongToPtr(CCall->CallId));
  2610. ASSERT((DeletedCall == 0) || (CCall == DeletedCall));
  2611. CCall->CallId = (ULONG) -1;
  2612. }
  2613. LogEvent(SU_CCALL, EV_REMOVED, CCall, this, 0, 1, 2);
  2614. LogEvent(SU_CCALL, EV_REMOVED, CCall, this, 0, 1, 6);
  2615. if (CCall->BufferQueue.Size() != 0)
  2616. {
  2617. if (!fMutexTaken)
  2618. {
  2619. AssociationMutex.Request();
  2620. fMutexTaken = TRUE;
  2621. }
  2622. while ((Buffer = CCall->BufferQueue.TakeOffQueue(&BufferLength)) != 0)
  2623. {
  2624. CCall->ActuallyFreeBuffer(Buffer);
  2625. }
  2626. }
  2627. if (fMutexTaken)
  2628. {
  2629. LocalEEInfo = CCall->EEInfo;
  2630. CCall->EEInfo = NULL;
  2631. }
  2632. else
  2633. {
  2634. LocalEEInfo =
  2635. (ExtendedErrorInfo *)InterlockedExchangePointer((PVOID *)(&CCall->EEInfo), NULL);
  2636. }
  2637. if (LocalEEInfo != NULL)
  2638. {
  2639. FreeEEInfoChain(LocalEEInfo);
  2640. }
  2641. CCall->Binding->RemoveReference();
  2642. CCall->Binding = NULL;
  2643. if (CCall == CachedCCall)
  2644. {
  2645. CachedCCallFlag = 1 ;
  2646. }
  2647. else
  2648. {
  2649. if (fMutexTaken)
  2650. {
  2651. LocalLrpcMessage = CCall->LrpcMessage;
  2652. CCall->LrpcMessage = 0;
  2653. }
  2654. else
  2655. {
  2656. LocalLrpcMessage =
  2657. (LRPC_MESSAGE *)InterlockedExchangePointer((PVOID *)(&CCall->LrpcMessage), 0);
  2658. }
  2659. FreeMessage(LocalLrpcMessage);
  2660. ThisThread = RpcpGetThreadPointer();
  2661. ASSERT(ThisThread);
  2662. if (gfServerPlatform && (ThisThread->GetCachedLrpcCall() == NULL))
  2663. {
  2664. CCall->FreeCallKey = -1;
  2665. // set the association to NULL to toast anybody who tries to touch it
  2666. CCall->Association = NULL;
  2667. ThisThread->SetCachedLrpcCall(CCall);
  2668. }
  2669. else if (FreeCCalls.Size() < 64)
  2670. {
  2671. if (!fMutexTaken)
  2672. {
  2673. AssociationMutex.Request();
  2674. fMutexTaken = TRUE;
  2675. }
  2676. if ((CCall->FreeCallKey = FreeCCalls.Insert(CCall)) == -1)
  2677. {
  2678. delete CCall;
  2679. }
  2680. }
  2681. else
  2682. {
  2683. CCall->FreeCallKey = -1;
  2684. delete CCall;
  2685. }
  2686. }
  2687. if (fMutexTaken)
  2688. {
  2689. AssociationMutex.Clear();
  2690. }
  2691. if (fOutstandingLocks)
  2692. {
  2693. ThisThread = RpcpGetThreadPointer();
  2694. ASSERT(ThisThread);
  2695. ThisThread->SetDestroyedWithOutstandingLocksFlag();
  2696. }
  2697. RemoveReference();
  2698. }
  2699. LRPC_CASSOCIATION *
  2700. FindOrCreateLrpcAssociation (
  2701. IN DCE_BINDING * DceBinding,
  2702. IN CLIENT_AUTH_INFO *pClientAuthInfo,
  2703. IN RPC_CLIENT_INTERFACE *InterfaceInfo
  2704. )
  2705. /*++
  2706. Routine Description:
  2707. This routine finds an existing association supporting the requested
  2708. DCE binding, or creates a new association which supports the
  2709. requested DCE binding. Ownership of the passed DceBinding passes
  2710. to this routine.
  2711. Arguments:
  2712. DceBinding - Supplies binding information; if an association is
  2713. returned the ownership of the DceBinding is passed
  2714. to the association.
  2715. pClientAuthInfo - pointer to the client auth info from the binding handle.
  2716. We compare the client auth info of each association against the client
  2717. auth info of the binding handle to determine if there is a match.
  2718. InterfaceInfo - pointer to the interface we are about to make a call on
  2719. while we try to find the association. If present, it also indicates
  2720. we are trying to do shortcut endpoint resolution. If not present,
  2721. we have already resolved the endpoint.
  2722. Return Value:
  2723. An association which supports the requested binding will be returned.
  2724. Otherwise, zero will be returned, indicating insufficient memory.
  2725. --*/
  2726. {
  2727. LRPC_CASSOCIATION * Association;
  2728. RPC_STATUS Status = RPC_S_OK;
  2729. static USHORT SequenceNumber = 1;
  2730. DictionaryCursor cursor;
  2731. BOOL fOnlyEndpointDiffers;
  2732. int Result;
  2733. BOOL Supported;
  2734. // First, we check for an existing association.
  2735. LrpcAssociationDict->Reset(cursor);
  2736. while ((Association = LrpcAssociationDict->Next(cursor)) != 0)
  2737. {
  2738. #if defined (RPC_GC_AUDIT)
  2739. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) Comparing association to: %S, %S, %S\n",
  2740. GetCurrentProcessId(), GetCurrentProcessId(), Association->DceBinding->InqRpcProtocolSequence(),
  2741. Association->DceBinding->InqNetworkAddress(), Association->DceBinding->InqEndpoint());
  2742. #endif
  2743. Status = Association->IsSupportedAuthInfo(pClientAuthInfo, &Supported);
  2744. if (Status != RPC_S_OK)
  2745. {
  2746. return NULL;
  2747. }
  2748. // if we are doing shortcut endpoint resolution, but the association
  2749. // did not mutually authenticate the server with the endpoint mapper
  2750. // (endpoint mapper name space partitioning), and the binding
  2751. // handle wants to mutually authenticate the server with the endpoint
  2752. // mapper, we cannot do shortcut endpoint resolution - we must allow
  2753. // the endpoint resolution.
  2754. if (Supported
  2755. && InterfaceInfo
  2756. && (pClientAuthInfo->Capabilities & RPC_C_QOS_CAPABILITIES_LOCAL_MA_HINT)
  2757. && !(Association->GetAuthInfoCapabilities() & RPC_C_QOS_CAPABILITIES_LOCAL_MA_HINT)
  2758. )
  2759. {
  2760. return NULL;
  2761. }
  2762. Result = Association->CompareWithDceBinding(DceBinding, &fOnlyEndpointDiffers);
  2763. if ((Supported)
  2764. &&
  2765. (!Result
  2766. ||
  2767. (
  2768. fOnlyEndpointDiffers
  2769. && InterfaceInfo
  2770. && DceBinding->IsNullEndpoint()
  2771. && Association->DoesBindingForInterfaceExist(InterfaceInfo)
  2772. )
  2773. )
  2774. )
  2775. {
  2776. Association->AddBindingHandleReference();
  2777. if (Association->Linger.fAssociationLingered == TRUE)
  2778. {
  2779. #if defined (RPC_GC_AUDIT)
  2780. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) LRPC lingering association resurrected %X %S %S %S\n",
  2781. GetCurrentProcessId(), GetCurrentProcessId(), Association,
  2782. Association->DceBinding->InqRpcProtocolSequence(),
  2783. Association->DceBinding->InqNetworkAddress(),
  2784. Association->DceBinding->InqEndpoint());
  2785. #endif
  2786. LrpcLingeredAssociations --;
  2787. ASSERT(LrpcLingeredAssociations >= 0);
  2788. Association->Linger.fAssociationLingered = FALSE;
  2789. }
  2790. if ((pClientAuthInfo->Capabilities & RPC_C_QOS_CAPABILITIES_LOCAL_MA_HINT)
  2791. && !(Association->GetAuthInfoCapabilities() & RPC_C_QOS_CAPABILITIES_LOCAL_MA_HINT))
  2792. {
  2793. Association->AddLocalMAToCapabilities();
  2794. }
  2795. delete DceBinding;
  2796. return(Association);
  2797. }
  2798. }
  2799. // if asked to do short endpoint resolution, don't create new association
  2800. if (InterfaceInfo)
  2801. return NULL;
  2802. #if defined (RPC_GC_AUDIT)
  2803. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) Creating association to: %S, %S, %S\n",
  2804. GetCurrentProcessId(), GetCurrentProcessId(), DceBinding->InqRpcProtocolSequence(),
  2805. DceBinding->InqNetworkAddress(), DceBinding->InqEndpoint());
  2806. #endif
  2807. SequenceNumber = (SequenceNumber+1) % (0x7FFF);
  2808. Association = new LRPC_CASSOCIATION(DceBinding,
  2809. pClientAuthInfo,
  2810. SequenceNumber,
  2811. &Status);
  2812. if ((Association != 0) && (Status == RPC_S_OK))
  2813. {
  2814. Association->AssociationDictKey = LrpcAssociationDict->Insert(Association);
  2815. if (Association->AssociationDictKey == -1)
  2816. {
  2817. Association->DceBinding = 0;
  2818. delete Association;
  2819. return(0);
  2820. }
  2821. return(Association);
  2822. }
  2823. else
  2824. {
  2825. if (Association != 0)
  2826. {
  2827. Association->DceBinding = 0;
  2828. delete Association;
  2829. }
  2830. return(0);
  2831. }
  2832. ASSERT(0);
  2833. return(0);
  2834. }
  2835. void
  2836. ShutdownLrpcClient (
  2837. )
  2838. /*++
  2839. Routine Description:
  2840. This routine will get called when the process which is using this dll
  2841. exits. We will go through and notify any servers that we are going
  2842. away.
  2843. --*/
  2844. {
  2845. LRPC_CASSOCIATION * Association;
  2846. DictionaryCursor cursor;
  2847. if (LrpcAssociationDict != 0)
  2848. {
  2849. LrpcAssociationDict->Reset(cursor);
  2850. while ((Association = LrpcAssociationDict->Next(cursor)) != 0)
  2851. {
  2852. Association->RemoveReference() ;
  2853. }
  2854. }
  2855. }
  2856. void
  2857. LRPC_CASSOCIATION::AbortAssociation (
  2858. IN BOOL ServerAborted
  2859. )
  2860. /*++
  2861. Routine Description:
  2862. This association needs to be aborted because a the server side of the
  2863. lpc port has been closed.
  2864. --*/
  2865. {
  2866. LRPC_BINDING * Binding;
  2867. LRPC_CCALL *CCall ;
  2868. LRPC_CCONTEXT *SecurityContext;
  2869. DictionaryCursor cursor;
  2870. AssociationMutex.Request();
  2871. LogEvent(SU_CASSOC, EV_ABORT, this, 0, ServerAborted, 1, 0);
  2872. CloseLpcClientPort();
  2873. Bindings.Reset(cursor);
  2874. while ((Binding = Bindings.RemoveNext(cursor)) != 0)
  2875. {
  2876. // RemoveReference will destroy the binding if its
  2877. // ref count reaches 0
  2878. Binding->RemoveReference();
  2879. }
  2880. SecurityContextDict.Reset(cursor);
  2881. while (SecurityContext = SecurityContextDict.RemoveNext(cursor))
  2882. {
  2883. SecurityContext->Destroy();
  2884. }
  2885. int waitIterations = 8;
  2886. if (ServerAborted)
  2887. {
  2888. ActiveCCalls.Reset(cursor);
  2889. while ((CCall = ActiveCCalls.Next(cursor, TRUE)) != 0)
  2890. {
  2891. CCall->ServerAborted(&waitIterations);
  2892. }
  2893. }
  2894. // nuke the free calls as well, because when we abort the association
  2895. // some information in them will be stale
  2896. FreeCCalls.Reset(cursor);
  2897. while ((CCall = FreeCCalls.Next(cursor)) != 0)
  2898. {
  2899. delete CCall;
  2900. }
  2901. AssociationMutex.Clear();
  2902. }
  2903. void
  2904. LRPC_CASSOCIATION::CloseLpcClientPort (
  2905. )
  2906. /*++
  2907. Routine Description:
  2908. The LpcClientPort will be closed (and a close message sent to the server).
  2909. --*/
  2910. {
  2911. NTSTATUS NtStatus;
  2912. HANDLE LpcPortLocal;
  2913. if (LpcClientPort != 0)
  2914. {
  2915. // Another thread might be trying to do a send or a send/receive on this port
  2916. // while the association is being aborted. We need to make sure the send on
  2917. // the port can't come after the port has been closed.
  2918. // To accomplish this, we set the port to NULL and close a local copy. The clients
  2919. // may still send on a NULL port, via a small race, but the probability
  2920. // can be reduced by checking for a NULL handle and we will just get an error from LPC.
  2921. // Also, the port sits on the stack for a little bit while we call the
  2922. // LPC routines, so the race is still there, but its minimal.
  2923. LpcPortLocal = LpcClientPort;
  2924. LpcClientPort = 0;
  2925. NtStatus = NtClose(LpcPortLocal);
  2926. #if DBG
  2927. if (!NT_SUCCESS(NtStatus))
  2928. {
  2929. PrintToDebugger("RPC : NtClose : %lx\n", NtStatus);
  2930. }
  2931. #endif // DBG
  2932. if (LpcReceivePort)
  2933. {
  2934. // Similarly to the above case, set the port to NULL and close a local copy.
  2935. LpcPortLocal = LpcReceivePort;
  2936. LpcReceivePort = 0;
  2937. NtStatus = NtClose(LpcPortLocal) ;
  2938. #if DBG
  2939. if (!NT_SUCCESS(NtStatus))
  2940. {
  2941. PrintToDebugger("RPC : NtClose : %lx\n", NtStatus);
  2942. }
  2943. #endif
  2944. ASSERT(NT_SUCCESS(NtStatus));
  2945. }
  2946. BackConnectionCreated = 0;
  2947. }
  2948. }
  2949. RPC_STATUS
  2950. LRPC_CASSOCIATION::IsSupportedAuthInfo(
  2951. IN CLIENT_AUTH_INFO * ClientAuthInfo,
  2952. OUT BOOL *Supported
  2953. )
  2954. /*++
  2955. Routine Description:
  2956. Check if this association supports the needed auth info.
  2957. Arguments:
  2958. ClientAuthInfo - description
  2959. Supported - on output, contains non-zero if the association supports
  2960. this auth info, and 0 otherwise. Undefined on failure
  2961. Return Value:
  2962. RPC_S_OK or RPC_S_* error
  2963. --*/
  2964. {
  2965. PSID Sid;
  2966. RPC_STATUS RpcStatus;
  2967. *Supported = FALSE;
  2968. if (!ClientAuthInfo)
  2969. {
  2970. if (AssocAuthInfo.ImpersonationType == RPC_C_IMP_LEVEL_IMPERSONATE)
  2971. {
  2972. *Supported = TRUE;
  2973. return RPC_S_OK;
  2974. }
  2975. return RPC_S_OK;
  2976. }
  2977. if ((ClientAuthInfo->AuthenticationLevel == RPC_C_AUTHN_LEVEL_NONE
  2978. && AssocAuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE)
  2979. || (AssocAuthInfo.AuthenticationLevel == RPC_C_AUTHN_LEVEL_NONE
  2980. && ClientAuthInfo->AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE))
  2981. {
  2982. return RPC_S_OK;
  2983. }
  2984. ASSERT(ClientAuthInfo->AuthenticationService == RPC_C_AUTHN_WINNT);
  2985. if (ClientAuthInfo->AuthorizationService
  2986. != AssocAuthInfo.AuthorizationService)
  2987. {
  2988. return RPC_S_OK;
  2989. }
  2990. #if 0
  2991. if (ClientAuthInfo->IdentityTracking != AssocAuthInfo.IdentityTracking)
  2992. {
  2993. return RPC_S_OK;
  2994. }
  2995. #endif
  2996. if (ClientAuthInfo->ImpersonationType != AssocAuthInfo.ImpersonationType)
  2997. {
  2998. return RPC_S_OK;
  2999. }
  3000. if (ClientAuthInfo->Capabilities & RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH)
  3001. {
  3002. // if the SPN and SID are equal, this is supported
  3003. return AssocAuthInfo.CompareSPNAndSID (ClientAuthInfo, Supported);
  3004. }
  3005. *Supported = TRUE;
  3006. return RPC_S_OK;
  3007. }
  3008. LRPC_CCALL::LRPC_CCALL (
  3009. IN OUT RPC_STATUS *Status
  3010. ) : CallMutex(Status),
  3011. SyncEvent(Status, 0),
  3012. ResponseLockCount(0)
  3013. /*++
  3014. --*/
  3015. {
  3016. ObjectType = LRPC_CCALL_TYPE;
  3017. CurrentBindingHandle = 0;
  3018. Association = 0;
  3019. CallAbortedFlag = 0;
  3020. LrpcMessage = 0;
  3021. CachedLrpcMessage = 0;
  3022. FreeCallKey = -1;
  3023. CallId = (ULONG) -1;
  3024. EEInfo = NULL;
  3025. }
  3026. LRPC_CCALL::~LRPC_CCALL (
  3027. )
  3028. /*++
  3029. --*/
  3030. {
  3031. if (LrpcMessage)
  3032. {
  3033. FreeMessage(LrpcMessage) ;
  3034. }
  3035. if (CachedLrpcMessage)
  3036. {
  3037. FreeMessage(CachedLrpcMessage) ;
  3038. }
  3039. if (CallId != (ULONG) -1)
  3040. {
  3041. // the association mutex is currently held
  3042. Association->ActiveCCalls.Delete(ULongToPtr(CallId));
  3043. }
  3044. if (FreeCallKey != -1)
  3045. {
  3046. Association->FreeCCalls.Delete(FreeCallKey) ;
  3047. }
  3048. }
  3049. RPC_STATUS
  3050. LRPC_CCALL::NegotiateTransferSyntax (
  3051. IN OUT PRPC_MESSAGE Message
  3052. )
  3053. {
  3054. // just return the transfer syntax already negotiated in the binding
  3055. Message->TransferSyntax = Binding->GetTransferSyntaxId();
  3056. return RPC_S_OK;
  3057. }
  3058. RPC_STATUS
  3059. LRPC_CCALL::GetBuffer (
  3060. IN OUT PRPC_MESSAGE Message,
  3061. IN UUID *ObjectUuid
  3062. )
  3063. /*++
  3064. Routine Description:
  3065. We will allocate a buffer which will be used to either send a request
  3066. or receive a response.
  3067. ObjectUuid - Ignored
  3068. Arguments:
  3069. Message - Supplies the length of the buffer that is needed. The buffer
  3070. will be returned.
  3071. Return Value:
  3072. RPC_S_OK - A buffer has been successfully allocated. It will be of at
  3073. least the required length.
  3074. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate that
  3075. large a buffer.
  3076. --*/
  3077. {
  3078. RPC_STATUS Status;
  3079. SetObjectUuid(ObjectUuid);
  3080. if (LrpcMessage == 0)
  3081. {
  3082. LrpcMessage = AllocateMessage();
  3083. if (LrpcMessage == 0)
  3084. {
  3085. Status = RPC_S_OUT_OF_MEMORY;
  3086. goto Cleanup;
  3087. }
  3088. }
  3089. if (PARTIAL(Message))
  3090. {
  3091. CurrentBufferLength = (Message->BufferLength < MINIMUM_PARTIAL_BUFFLEN)
  3092. ? MINIMUM_PARTIAL_BUFFLEN:Message->BufferLength ;
  3093. Message->Buffer = RpcpFarAllocate(CurrentBufferLength);
  3094. if (Message->Buffer == 0)
  3095. {
  3096. CurrentBufferLength = 0 ;
  3097. Status = RPC_S_OUT_OF_MEMORY;
  3098. goto Cleanup;
  3099. }
  3100. }
  3101. else if (Message->BufferLength <= MAXIMUM_MESSAGE_BUFFER)
  3102. {
  3103. CurrentBufferLength = MAXIMUM_MESSAGE_BUFFER ;
  3104. // Uncomment to check for 16 byte alignment on 64 bit
  3105. // ASSERT(IsBufferAligned(LrpcMessage->Rpc.Buffer));
  3106. Message->Buffer = LrpcMessage->Rpc.Buffer;
  3107. LrpcMessage->Rpc.RpcHeader.Flags = LRPC_BUFFER_IMMEDIATE;
  3108. LrpcMessage->LpcHeader.u2.ZeroInit = 0;
  3109. LrpcMessage->LpcHeader.u1.s1.DataLength = (USHORT)
  3110. (Align4(Message->BufferLength) + sizeof(LRPC_RPC_HEADER));
  3111. return(RPC_S_OK);
  3112. }
  3113. else
  3114. {
  3115. CurrentBufferLength = Message->BufferLength ;
  3116. Message->Buffer = RpcpFarAllocate(Message->BufferLength);
  3117. if (Message->Buffer == 0)
  3118. {
  3119. Status = RPC_S_OUT_OF_MEMORY;
  3120. goto Cleanup;
  3121. }
  3122. }
  3123. LrpcMessage->Rpc.RpcHeader.Flags = LRPC_BUFFER_REQUEST;
  3124. LrpcMessage->Rpc.Request.CountDataEntries = 1;
  3125. LrpcMessage->Rpc.Request.DataEntries[0].Base = PtrToMsgPtr(Message->Buffer);
  3126. LrpcMessage->Rpc.Request.DataEntries[0].Size = Message->BufferLength;
  3127. LrpcMessage->LpcHeader.CallbackId = 0;
  3128. LrpcMessage->LpcHeader.u2.ZeroInit = 0;
  3129. LrpcMessage->LpcHeader.u2.s2.DataInfoOffset = sizeof(PORT_MESSAGE)
  3130. + sizeof(LRPC_RPC_HEADER);
  3131. LrpcMessage->LpcHeader.u1.s1.DataLength = sizeof(LRPC_RPC_HEADER)
  3132. + sizeof(PORT_DATA_INFORMATION);
  3133. Status = RPC_S_OK;
  3134. Cleanup:
  3135. if (Status != RPC_S_OK)
  3136. {
  3137. AbortCCall();
  3138. ASSERT(Status == RPC_S_OUT_OF_MEMORY);
  3139. }
  3140. return(Status);
  3141. }
  3142. RPC_STATUS
  3143. LpcError (
  3144. IN NTSTATUS NtStatus,
  3145. IN BOOL fDNE
  3146. )
  3147. {
  3148. if (NtStatus == STATUS_NO_MEMORY)
  3149. {
  3150. return(RPC_S_OUT_OF_MEMORY);
  3151. }
  3152. if (NtStatus == STATUS_INSUFFICIENT_RESOURCES)
  3153. {
  3154. return(RPC_S_OUT_OF_RESOURCES);
  3155. }
  3156. VALIDATE(NtStatus)
  3157. {
  3158. STATUS_INVALID_PORT_HANDLE,
  3159. STATUS_INVALID_HANDLE,
  3160. STATUS_PORT_DISCONNECTED,
  3161. STATUS_LPC_REPLY_LOST
  3162. } END_VALIDATE;
  3163. if ((NtStatus != STATUS_LPC_REPLY_LOST) && fDNE)
  3164. {
  3165. return (RPC_S_CALL_FAILED_DNE) ;
  3166. }
  3167. return (RPC_S_CALL_FAILED);
  3168. }
  3169. RPC_STATUS
  3170. LRPC_CCALL::AsyncSend (
  3171. IN OUT PRPC_MESSAGE Message
  3172. )
  3173. /*++
  3174. Routine Description:
  3175. Send an async request. This request can be either partial or complete.
  3176. Arguments:
  3177. Message - contains the request.
  3178. Return Value:
  3179. RPC_S_OK - Function succeeded
  3180. RPC_S_OUT_OF_MEMORY - we ran out of memory
  3181. --*/
  3182. {
  3183. RPC_STATUS Status ;
  3184. NTSTATUS NtStatus ;
  3185. BOOL fRetVal ;
  3186. BOOL Shutup ;
  3187. ULONG_PTR fNonCausal;
  3188. ULONG AsyncStateFlags;
  3189. // If it is a small request, we send it here, otherwise, we
  3190. // use the helper function.
  3191. ASSERT(pAsync) ;
  3192. Status = CurrentBindingHandle->InqTransportOption(
  3193. RPC_C_OPT_BINDING_NONCAUSAL,
  3194. &fNonCausal);
  3195. ASSERT(Status == RPC_S_OK);
  3196. if (fNonCausal == 0)
  3197. {
  3198. LrpcMessage->Rpc.RpcHeader.Flags |= LRPC_CAUSAL;
  3199. }
  3200. if (LrpcMessage->Rpc.RpcHeader.Flags & LRPC_BUFFER_IMMEDIATE)
  3201. {
  3202. LrpcMessage->LpcHeader.u1.s1.TotalLength = sizeof(PORT_MESSAGE)
  3203. + LrpcMessage->LpcHeader.u1.s1.DataLength;
  3204. LrpcMessage->Rpc.RpcHeader.MessageType = LRPC_MSG_REQUEST;
  3205. LrpcMessage->Rpc.RpcHeader.Pad = 0;
  3206. LrpcMessage->Rpc.RpcHeader.ProcedureNumber = (unsigned short) Message->ProcNum;
  3207. LrpcMessage->Rpc.RpcHeader.PresentContext = GetOnTheWirePresentationContext();
  3208. if (CurrentSecurityContext)
  3209. {
  3210. LrpcMessage->Rpc.RpcHeader.SecurityContextId = CurrentSecurityContext->SecurityContextId;
  3211. }
  3212. else
  3213. {
  3214. LrpcMessage->Rpc.RpcHeader.SecurityContextId = -1;
  3215. }
  3216. ASSERT(CallId != (ULONG) -1);
  3217. LrpcMessage->Rpc.RpcHeader.CallId = CallId ;
  3218. if (UuidSpecified)
  3219. {
  3220. RpcpMemoryCopy(&(LrpcMessage->Rpc.RpcHeader.ObjectUuid),
  3221. &ObjectUuid, sizeof(UUID));
  3222. LrpcMessage->Rpc.RpcHeader.Flags |= LRPC_OBJECT_UUID;
  3223. }
  3224. else
  3225. {
  3226. // zero out the guid to prevent data leak
  3227. RpcpMemorySet(&(LrpcMessage->Rpc.RpcHeader.ObjectUuid),
  3228. 0, sizeof(UUID));
  3229. }
  3230. // Make sure the port has not been closed due to an association abort.
  3231. if (Association->LpcClientPort)
  3232. {
  3233. NtStatus = NtRequestPort(Association->LpcClientPort,
  3234. (PORT_MESSAGE *) LrpcMessage) ;
  3235. }
  3236. else
  3237. {
  3238. NtStatus = STATUS_INVALID_PORT_HANDLE;
  3239. }
  3240. if (NT_ERROR(NtStatus))
  3241. {
  3242. FreeCCall() ;
  3243. return LpcError(NtStatus, TRUE) ;
  3244. }
  3245. Status = RPC_S_OK;
  3246. }
  3247. else
  3248. {
  3249. AsyncStateFlags = pAsync->Flags;
  3250. // Take the call mutex if this is an async pipe call, we can assume that
  3251. // it is async since we are in AsyncSend, we must check if its pipe.
  3252. // We need to take the mutex to avoid a race between setting fSendMoreExpected in AsyncSend and
  3253. // checking it in the thread pool when servicing a LRPC_SERVER_SEND_MORE (ProcessResponse). Without this
  3254. // we could end up not getting a notification for this send
  3255. if (PARTIAL(Message))
  3256. CallMutex.Request();
  3257. Status = SendRequest(Message, &Shutup) ;
  3258. if ((AsyncStateFlags & RPC_C_NOTIFY_ON_SEND_COMPLETE)
  3259. && (Status == RPC_S_OK || Status == RPC_S_SEND_INCOMPLETE))
  3260. {
  3261. if (Shutup)
  3262. {
  3263. fSendMoreExpected = TRUE;
  3264. }
  3265. else
  3266. {
  3267. fSendMoreExpected = FALSE;
  3268. if (!IssueNotification(RpcSendComplete))
  3269. {
  3270. Status = RPC_S_OUT_OF_MEMORY ;
  3271. }
  3272. }
  3273. }
  3274. if (PARTIAL(Message))
  3275. CallMutex.Clear();
  3276. }
  3277. if (Status == RPC_S_OK)
  3278. {
  3279. CallMutex.Request();
  3280. if (AsyncStatus == RPC_S_CALL_FAILED)
  3281. {
  3282. LogEvent(SU_CCALL, EV_ABORT, this, (PVOID) 44, 44, 1, 0);
  3283. Status = RPC_S_CALL_FAILED;
  3284. CallMutex.Clear();
  3285. FreeCCall();
  3286. }
  3287. else
  3288. {
  3289. fSendComplete = 1;
  3290. CallMutex.Clear();
  3291. }
  3292. }
  3293. return(Status);
  3294. }
  3295. RPC_STATUS
  3296. LRPC_CCALL::AsyncReceive (
  3297. IN OUT PRPC_MESSAGE Message,
  3298. IN unsigned int Size
  3299. )
  3300. /*++
  3301. Routine Description:
  3302. Arguments:
  3303. Message - Contains the request. On return, it will contain the received buffer
  3304. and its length.
  3305. Size - Requested size.
  3306. Return Value:
  3307. RPC_S_OK - Function succeeded
  3308. RPC_S_OUT_OF_MEMORY - we ran out of memory
  3309. --*/
  3310. {
  3311. RPC_STATUS Status;
  3312. int Extra = IsExtraMessage(Message);
  3313. Message->DataRepresentation = 0x00 | 0x10 | 0x0000;
  3314. if (!Extra && Message->Buffer)
  3315. {
  3316. ActuallyFreeBuffer((char *)Message->Buffer);
  3317. Message->Buffer = 0;
  3318. Message->BufferLength = 0;
  3319. }
  3320. CallMutex.Request();
  3321. if (BufferComplete)
  3322. {
  3323. Status = GetCoalescedBuffer(Message, Extra);
  3324. }
  3325. else
  3326. {
  3327. if (PARTIAL(Message))
  3328. {
  3329. if (RcvBufferLength < Size)
  3330. {
  3331. if (NOTIFY(Message))
  3332. {
  3333. NeededLength = Size ;
  3334. }
  3335. Status = RPC_S_ASYNC_CALL_PENDING;
  3336. }
  3337. else
  3338. {
  3339. Status = GetCoalescedBuffer(Message, Extra);
  3340. }
  3341. }
  3342. else
  3343. {
  3344. Status = AsyncStatus;
  3345. ASSERT(Status != RPC_S_OK);
  3346. }
  3347. }
  3348. CallMutex.Clear();
  3349. if (Status == RPC_S_OK
  3350. || Status == RPC_S_ASYNC_CALL_PENDING)
  3351. {
  3352. return Status;
  3353. }
  3354. FreeCCall();
  3355. return Status;
  3356. }
  3357. RPC_STATUS
  3358. LRPC_CCALL::CancelAsyncCall (
  3359. IN BOOL fAbort
  3360. )
  3361. /*++
  3362. Function Name:CancelAsyncCall
  3363. Parameters:
  3364. fAbort - TRUE: the cancel is abortive, ie, the call completes immediately
  3365. FALSE: a cancel PDU is sent to the server, the call doesn't complete
  3366. until the server returns
  3367. Description:
  3368. Returns:
  3369. RPC_S_OK: The call was successfully cancelled
  3370. others - an error occured during the cancellation process
  3371. --*/
  3372. {
  3373. #if defined(BUILD_WOW6432)
  3374. char LrpcCancelMessageBuffer[sizeof(LRPC_CANCEL_MESSAGE) + 8];
  3375. LRPC_CANCEL_MESSAGE *LrpcCancelMessagePtr = (LRPC_CANCEL_MESSAGE *)AlignPtr8(LrpcCancelMessageBuffer);
  3376. #else
  3377. LRPC_CANCEL_MESSAGE LrpcCancelMessageBuffer;
  3378. LRPC_CANCEL_MESSAGE *LrpcCancelMessagePtr = &LrpcCancelMessageBuffer;
  3379. #endif
  3380. NTSTATUS NtStatus;
  3381. LogEvent(SU_CCALL, EV_ABORT, this, 0, fAbort, 1, 1);
  3382. //
  3383. // Notify the server that the call has been cancelled
  3384. //
  3385. LrpcCancelMessagePtr->LpcHeader.u1.s1.DataLength = sizeof(LRPC_CANCEL_MESSAGE)
  3386. - sizeof(PORT_MESSAGE);
  3387. LrpcCancelMessagePtr->LpcHeader.u1.s1.TotalLength = sizeof(LRPC_CANCEL_MESSAGE);
  3388. LrpcCancelMessagePtr->LpcHeader.u2.ZeroInit = 0;
  3389. SanitizeLpcHeader (&LrpcCancelMessagePtr->LpcHeader);
  3390. ASSERT(CallId != (ULONG) -1);
  3391. // zero out everything b/n MessageType and CallId
  3392. RPCP_ZERO_OUT_STRUCT_RANGE(LRPC_RPC_HEADER,
  3393. &LrpcCancelMessagePtr->RpcHeader,
  3394. Pad,
  3395. CallId
  3396. );
  3397. LrpcCancelMessagePtr->RpcHeader.CallId = CallId;
  3398. LrpcCancelMessagePtr->RpcHeader.MessageType = LRPC_MSG_CANCEL;
  3399. // Make sure the port has not been closed due to an association abort.
  3400. if (Association->LpcClientPort)
  3401. {
  3402. NtStatus = NtRequestPort(Association->LpcClientPort,
  3403. (PORT_MESSAGE *) LrpcCancelMessagePtr) ;
  3404. }
  3405. else
  3406. {
  3407. NtStatus = STATUS_INVALID_PORT_HANDLE;
  3408. }
  3409. // sending the notification to the server is a best effort. We ignore the
  3410. // result
  3411. if (fAbort)
  3412. {
  3413. //
  3414. // If the cancel was abortive, complete the call right away.
  3415. //
  3416. //
  3417. // We indicate completion. When the app calls RpcAsyncCompleteCall
  3418. // we will destroy the call. That is fine, even if the server
  3419. // hasn't replied yet, because if the server sends a reply to
  3420. // a call or an association that is not there, the client code
  3421. // is protected, and will simply free the packet.
  3422. //
  3423. CallFailed(RPC_S_CALL_CANCELLED);
  3424. }
  3425. return RPC_S_OK;
  3426. }
  3427. void
  3428. LRPC_CCALL::ProcessResponse(
  3429. IN LRPC_MESSAGE *LrpcResponse
  3430. )
  3431. /*++
  3432. Routine Description:
  3433. A buffer has just arrived, process it. If some other buffer is already
  3434. processing buffers, simply queue it and go away. Otherwise, does
  3435. the processing ourselves.
  3436. Arguments:
  3437. Message - Details on the arrived message
  3438. --*/
  3439. {
  3440. RPC_MESSAGE Message ;
  3441. RPC_STATUS Status ;
  3442. BOOL fRetVal = 0;
  3443. BOOL fFault2;
  3444. RPC_STATUS FaultStatus;
  3445. THREAD *ThisThread;
  3446. ExtendedErrorInfo *EEInfo;
  3447. DelayedPipeAckData AckData;
  3448. //
  3449. // So that abort will not issue a notification
  3450. //
  3451. fSendComplete = 0;
  3452. switch (LrpcResponse->Rpc.RpcHeader.MessageType)
  3453. {
  3454. case LRPC_MSG_FAULT:
  3455. if (LrpcResponse->Fault.RpcHeader.Flags & LRPC_EEINFO_PRESENT)
  3456. {
  3457. ThisThread = RpcpGetThreadPointer();
  3458. ASSERT(ThisThread);
  3459. ASSERT(ThisThread->GetEEInfo() == NULL);
  3460. if (LrpcResponse->Fault.LpcHeader.u1.s1.TotalLength >
  3461. (sizeof(LRPC_FAULT_MESSAGE) - sizeof(LrpcResponse->Fault.Buffer)))
  3462. {
  3463. Status = UnpickleEEInfo(LrpcResponse->Fault.Buffer,
  3464. LrpcResponse->Fault.LpcHeader.u1.s1.TotalLength
  3465. - sizeof(LRPC_FAULT_MESSAGE)
  3466. + sizeof(LrpcResponse->Fault.Buffer),
  3467. &EEInfo);
  3468. if (Status == RPC_S_OK)
  3469. {
  3470. this->EEInfo = EEInfo;
  3471. }
  3472. }
  3473. }
  3474. if (pAsync == 0)
  3475. {
  3476. AsyncStatus = LrpcResponse->Fault.RpcStatus ;
  3477. SyncEvent.Raise();
  3478. }
  3479. else
  3480. {
  3481. CallFailed(LrpcResponse->Fault.RpcStatus);
  3482. }
  3483. FreeMessage(LrpcResponse);
  3484. return ;
  3485. case LRPC_CLIENT_SEND_MORE:
  3486. if (pAsync
  3487. && (pAsync->Flags & RPC_C_NOTIFY_ON_SEND_COMPLETE))
  3488. {
  3489. // Take the call mutex if this is an async pipe call, we can assume that
  3490. // it is async since we are in AsyncSend, we must check if its pipe.
  3491. // We need to take the mutex to avoid a race between setting fSendMoreExpected in AsyncSend and
  3492. // checking it in the thread pool when servicing a LRPC_SERVER_SEND_MORE (ProcessResponse). Without this
  3493. // we could end up not getting a notification for this send
  3494. CallMutex.Request();
  3495. if (fSendMoreExpected)
  3496. {
  3497. CallMutex.Clear();
  3498. if (!IssueNotification(RpcSendComplete))
  3499. {
  3500. CallFailed(RPC_S_OUT_OF_MEMORY);
  3501. }
  3502. }
  3503. else
  3504. {
  3505. CallMutex.Clear();
  3506. CORRUPTION_ASSERT(0);
  3507. CallFailed(RPC_S_PROTOCOL_ERROR);
  3508. }
  3509. }
  3510. FreeMessage(LrpcResponse);
  3511. return;
  3512. }
  3513. ASSERT((LrpcResponse->Rpc.RpcHeader.MessageType == LRPC_MSG_FAULT2)
  3514. || (LrpcResponse->Rpc.RpcHeader.MessageType == LRPC_MSG_RESPONSE));
  3515. if (LrpcResponse->Rpc.RpcHeader.MessageType == LRPC_MSG_FAULT2)
  3516. {
  3517. fFault2 = TRUE;
  3518. FaultStatus = LrpcResponse->Fault2.RpcStatus;
  3519. }
  3520. else
  3521. fFault2 = FALSE;
  3522. Message.RpcFlags = 0;
  3523. AckData.DelayedAckPipeNeeded = FALSE;
  3524. Status = LrpcMessageToRpcMessage(LrpcResponse,
  3525. &Message,
  3526. Association->LpcReceivePort,
  3527. TRUE, // IsReplyFromBackConnection
  3528. &AckData
  3529. ) ;
  3530. if (fFault2 && (Status == RPC_S_OK))
  3531. {
  3532. ThisThread = RpcpGetThreadPointer();
  3533. ASSERT(ThisThread);
  3534. ASSERT(ThisThread->GetEEInfo() == NULL);
  3535. Status = UnpickleEEInfo((unsigned char *)Message.Buffer,
  3536. Message.BufferLength,
  3537. &EEInfo);
  3538. if (Status == RPC_S_OK)
  3539. {
  3540. this->EEInfo = EEInfo;
  3541. }
  3542. // else
  3543. // fall through the error case below, which will
  3544. // handle the failure properly
  3545. }
  3546. if ((Status != RPC_S_OK) || fFault2)
  3547. {
  3548. // remember to send delayed ack if any
  3549. if (AckData.DelayedAckPipeNeeded)
  3550. {
  3551. (void) SendPipeAck(Association->LpcReceivePort,
  3552. LrpcResponse,
  3553. AckData.CurrentStatus);
  3554. if ((Status != RPC_S_OK) && (Message.Buffer))
  3555. {
  3556. RpcpFarFree(Message.Buffer);
  3557. }
  3558. FreeMessage(LrpcResponse) ;
  3559. }
  3560. if (fFault2)
  3561. {
  3562. AsyncStatus = FaultStatus;
  3563. Status = FaultStatus;
  3564. }
  3565. else
  3566. AsyncStatus = Status ;
  3567. if (pAsync == 0)
  3568. {
  3569. SyncEvent.Raise();
  3570. }
  3571. else
  3572. {
  3573. CallFailed(Status);
  3574. }
  3575. return;
  3576. }
  3577. CallMutex.Request() ;
  3578. // we have taken the mutex - now we can send the ack
  3579. // The reason we need to wait for the mutex to be
  3580. // taken before we send the delayed ack for pipes is
  3581. // that once we send an ack, the server will send more
  3582. // data and these can race with this thread. To be
  3583. // safe, we need to take the mutex.
  3584. if (AckData.DelayedAckPipeNeeded)
  3585. {
  3586. Status = SendPipeAck(Association->LpcReceivePort,
  3587. LrpcResponse,
  3588. AckData.CurrentStatus);
  3589. FreeMessage(LrpcResponse) ;
  3590. if (Status != RPC_S_OK)
  3591. {
  3592. CallMutex.Clear();
  3593. if (Message.Buffer)
  3594. {
  3595. RpcpFarFree(Message.Buffer);
  3596. }
  3597. AsyncStatus = Status ;
  3598. if (pAsync == 0)
  3599. {
  3600. SyncEvent.Raise();
  3601. }
  3602. else
  3603. {
  3604. CallFailed(Status);
  3605. }
  3606. return;
  3607. }
  3608. }
  3609. if (COMPLETE(&Message))
  3610. {
  3611. BufferComplete = 1;
  3612. }
  3613. RcvBufferLength += Message.BufferLength ;
  3614. if (Message.BufferLength)
  3615. {
  3616. if (BufferQueue.PutOnQueue(Message.Buffer,
  3617. Message.BufferLength))
  3618. {
  3619. Status = RPC_S_OUT_OF_MEMORY ;
  3620. #if DBG
  3621. PrintToDebugger("RPC: PutOnQueue failed\n") ;
  3622. #endif
  3623. if (pAsync)
  3624. {
  3625. CallMutex.Clear();
  3626. CallFailed(Status);
  3627. return;
  3628. }
  3629. else
  3630. {
  3631. AsyncStatus = Status;
  3632. }
  3633. }
  3634. }
  3635. if (pAsync == 0)
  3636. {
  3637. CallMutex.Clear() ;
  3638. SyncEvent.Raise();
  3639. return;
  3640. }
  3641. if (BufferComplete)
  3642. {
  3643. AsyncStatus = RPC_S_OK;
  3644. CallMutex.Clear() ;
  3645. IssueNotification();
  3646. }
  3647. else
  3648. {
  3649. if (NeededLength > 0 && RcvBufferLength >= NeededLength)
  3650. {
  3651. CallMutex.Clear() ;
  3652. IssueNotification(RpcReceiveComplete);
  3653. }
  3654. else
  3655. {
  3656. CallMutex.Clear() ;
  3657. }
  3658. }
  3659. }
  3660. RPC_STATUS
  3661. LRPC_CCALL::GetCoalescedBuffer (
  3662. IN PRPC_MESSAGE Message,
  3663. IN BOOL BufferValid
  3664. )
  3665. /*++
  3666. Routine Description:
  3667. Remove buffers from the queue and coalesce them into a single buffer.
  3668. Arguments:
  3669. Message - on return this will contain the coalesced buffer, Message->BufferLength
  3670. gives us the length of the coalesced buffer.
  3671. BufferValid - Tells us if Message->Buffer is valid on entry.
  3672. Return Value:
  3673. RPC_S_OK - Function succeeded
  3674. RPC_S_OUT_OF_MEMORY - we ran out of memory
  3675. --*/
  3676. {
  3677. void *NewBuffer, *Buffer ;
  3678. char *Current ;
  3679. unsigned int bufferlength ;
  3680. unsigned int TotalLength ;
  3681. LRPC_SENDMORE_MESSAGE SendMore ;
  3682. NTSTATUS NtStatus ;
  3683. CallMutex.Request() ;
  3684. if (RcvBufferLength == 0)
  3685. {
  3686. if (BufferComplete)
  3687. {
  3688. Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
  3689. }
  3690. if (BufferValid == 0)
  3691. {
  3692. Message->Buffer = 0;
  3693. Message->BufferLength = 0;
  3694. }
  3695. CallMutex.Clear();
  3696. return RPC_S_OK;
  3697. }
  3698. BOOL fFillNewBuffer;
  3699. if (BufferValid)
  3700. {
  3701. TotalLength = RcvBufferLength + Message->BufferLength ;
  3702. NewBuffer = RpcpFarAllocate(TotalLength) ;
  3703. if (NewBuffer == 0)
  3704. {
  3705. CallMutex.Clear() ;
  3706. return RPC_S_OUT_OF_MEMORY;
  3707. }
  3708. RpcpMemoryCopy(NewBuffer, Message->Buffer, Message->BufferLength) ;
  3709. Current = (char *) NewBuffer + Message->BufferLength ;
  3710. fFillNewBuffer = 1;
  3711. }
  3712. else
  3713. {
  3714. TotalLength = RcvBufferLength ;
  3715. if (BufferQueue.Size() == 1)
  3716. {
  3717. Buffer = BufferQueue.TakeOffQueue(&bufferlength);
  3718. ASSERT(Buffer);
  3719. NewBuffer = Buffer;
  3720. ASSERT(TotalLength == bufferlength);
  3721. fFillNewBuffer = 0;
  3722. }
  3723. else
  3724. {
  3725. NewBuffer = RpcpFarAllocate(TotalLength) ;
  3726. if (NewBuffer == 0)
  3727. {
  3728. CallMutex.Clear() ;
  3729. return RPC_S_OUT_OF_MEMORY;
  3730. }
  3731. Current = (char *) NewBuffer;
  3732. fFillNewBuffer = 1;
  3733. }
  3734. }
  3735. if (fFillNewBuffer)
  3736. {
  3737. while ((Buffer = BufferQueue.TakeOffQueue(&bufferlength)) != 0)
  3738. {
  3739. RpcpMemoryCopy(Current, Buffer, bufferlength) ;
  3740. Current += bufferlength ;
  3741. ActuallyFreeBuffer(Buffer);
  3742. }
  3743. }
  3744. if (Message->Buffer)
  3745. {
  3746. ActuallyFreeBuffer(Message->Buffer);
  3747. }
  3748. Message->Buffer = NewBuffer ;
  3749. Message->BufferLength = TotalLength ;
  3750. RcvBufferLength = 0;
  3751. if (BufferComplete)
  3752. {
  3753. Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
  3754. }
  3755. else
  3756. {
  3757. if (Choked)
  3758. {
  3759. CallMutex.Clear() ;
  3760. //
  3761. // send a message to the server
  3762. // to start sending data again
  3763. //
  3764. SendMore.LpcHeader.u1.s1.DataLength =
  3765. sizeof(SendMore) - sizeof(PORT_MESSAGE);
  3766. SendMore.LpcHeader.u1.s1.TotalLength = sizeof(SendMore);
  3767. SendMore.LpcHeader.u2.ZeroInit = 0;
  3768. SendMore.LpcHeader.CallbackId = 0;
  3769. SendMore.LpcHeader.MessageId = 0;
  3770. SanitizeLpcHeader (&SendMore.LpcHeader);
  3771. // zero out everything b/n MessageType and CallId
  3772. RPCP_ZERO_OUT_STRUCT_RANGE(LRPC_RPC_HEADER,
  3773. &SendMore.RpcHeader,
  3774. Pad,
  3775. CallId
  3776. );
  3777. SendMore.RpcHeader.MessageType = LRPC_SERVER_SEND_MORE;
  3778. SendMore.RpcHeader.CallId = CallId ;
  3779. ASSERT(CallId != (ULONG) -1);
  3780. // Make sure the port has not been closed due to an association abort.
  3781. if (Association->LpcClientPort)
  3782. {
  3783. NtStatus = NtRequestPort(Association->LpcClientPort,
  3784. (PORT_MESSAGE *) &SendMore) ;
  3785. }
  3786. else
  3787. {
  3788. NtStatus = STATUS_INVALID_PORT_HANDLE;
  3789. }
  3790. if (!NT_SUCCESS(NtStatus))
  3791. {
  3792. return RPC_S_CALL_FAILED ;
  3793. }
  3794. return RPC_S_OK;
  3795. }
  3796. }
  3797. CallMutex.Clear() ;
  3798. return RPC_S_OK ;
  3799. }
  3800. void
  3801. LRPC_CCALL::ServerAborted (
  3802. IN OUT int *waitIterations
  3803. )
  3804. /*++
  3805. Routine Description:
  3806. The server has died, we need the call needs to reflect that, and
  3807. cleanup if possible.
  3808. --*/
  3809. {
  3810. if (pAsync)
  3811. {
  3812. int i;
  3813. for (;*waitIterations && AsyncStatus == RPC_S_ASYNC_CALL_PENDING; (*waitIterations)--)
  3814. {
  3815. Sleep(500);
  3816. }
  3817. LogEvent(SU_CCALL, EV_ABORT, this, (PVOID) 22, 22, 1, 0);
  3818. CallMutex.Request();
  3819. if (AsyncStatus == RPC_S_ASYNC_CALL_PENDING)
  3820. {
  3821. if (fSendComplete == 0)
  3822. {
  3823. AsyncStatus = RPC_S_CALL_FAILED;
  3824. CallMutex.Clear();
  3825. }
  3826. else
  3827. {
  3828. CallMutex.Clear();
  3829. CallFailed(RPC_S_CALL_FAILED);
  3830. }
  3831. }
  3832. else
  3833. {
  3834. CallMutex.Clear();
  3835. }
  3836. }
  3837. }
  3838. RPC_STATUS
  3839. LRPC_CCALL::SendReceive (
  3840. IN OUT PRPC_MESSAGE Message
  3841. )
  3842. /*++
  3843. Routine Description:
  3844. Arguments:
  3845. Message - Supplies the request and returns the response of a remote
  3846. procedure call.
  3847. Return Value:
  3848. RPC_S_OK - The remote procedure call completed successful.
  3849. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to perform the
  3850. remote procedure call.
  3851. RPC_S_OUT_OF_RESOURCES - Insufficient resources are available to complete
  3852. the remote procedure call.
  3853. --*/
  3854. {
  3855. NTSTATUS NtStatus;
  3856. RPC_STATUS ExceptionCode, Status;
  3857. void * OriginalMessageBuffer;
  3858. LRPC_MESSAGE *SavedLrpcMessage = 0;
  3859. LRPC_MESSAGE *TmpLrpcMessage = 0;
  3860. int ActiveCallSetupFlag = 0;
  3861. void * TempBuffer;
  3862. ExtendedErrorInfo *EEInfo;
  3863. DebugClientCallInfo *ClientCallInfo;
  3864. DebugCallTargetInfo *CallTargetInfo;
  3865. CellTag ClientCallInfoCellTag;
  3866. CellTag CallTargetInfoCellTag;
  3867. THREAD *ThisThread = RpcpGetThreadPointer();
  3868. BOOL fDebugInfoSet = FALSE;
  3869. if (CallAbortedFlag != 0)
  3870. {
  3871. //
  3872. // Don't know if it is safe to free the buffer here
  3873. //
  3874. return(RPC_S_CALL_FAILED_DNE);
  3875. }
  3876. ASSERT(ThisThread);
  3877. // if either client side debugging is enabled or we are
  3878. // calling on a thread that has a scall dispatched
  3879. if ((IsClientSideDebugInfoEnabled() || ((ThisThread->Context) && IsServerSideDebugInfoEnabled())) && (RecursionCount == 0))
  3880. {
  3881. CStackAnsi AnsiString;
  3882. RPC_CHAR *Endpoint;
  3883. int EndpointLength;
  3884. if (!IsClientSideDebugInfoEnabled())
  3885. {
  3886. Status = SetDebugClientCallInformation(&ClientCallInfo, &ClientCallInfoCellTag,
  3887. &CallTargetInfo, &CallTargetInfoCellTag, Message, ThisThread->DebugCell,
  3888. ThisThread->DebugCellTag);
  3889. }
  3890. else
  3891. {
  3892. Status = SetDebugClientCallInformation(&ClientCallInfo, &ClientCallInfoCellTag,
  3893. &CallTargetInfo, &CallTargetInfoCellTag, Message, NULL, NULL);
  3894. }
  3895. if (Status != RPC_S_OK)
  3896. {
  3897. TempBuffer = NULL;
  3898. goto Cleanup;
  3899. }
  3900. ClientCallInfo->CallID = CallId;
  3901. Endpoint = Association->InqEndpoint();
  3902. EndpointLength = RpcpStringLength(Endpoint) + 1;
  3903. *(AnsiString.GetPAnsiString()) = (char *)_alloca(EndpointLength);
  3904. Status = AnsiString.Attach(Endpoint, EndpointLength, EndpointLength * 2);
  3905. // effectively ignore failure in the conversion
  3906. if (Status == RPC_S_OK)
  3907. {
  3908. strncpy(ClientCallInfo->Endpoint, AnsiString, sizeof(ClientCallInfo->Endpoint));
  3909. }
  3910. CallTargetInfo->ProtocolSequence = LRPC_TOWER_ID;
  3911. CallTargetInfo->TargetServer[0] = 0;
  3912. fDebugInfoSet = TRUE;
  3913. }
  3914. // NDR_DREP_ASCII | NDR_DREP_LITTLE_ENDIAN | NDR_DREP_IEEE
  3915. Message->DataRepresentation = 0x00 | 0x10 | 0x0000;
  3916. if (CallStack == 0)
  3917. {
  3918. if (UuidSpecified)
  3919. {
  3920. RpcpMemoryCopy(&(LrpcMessage->Rpc.RpcHeader.ObjectUuid),
  3921. &ObjectUuid, sizeof(UUID));
  3922. LrpcMessage->Rpc.RpcHeader.Flags |= LRPC_OBJECT_UUID;
  3923. }
  3924. }
  3925. else
  3926. {
  3927. LrpcMessage->LpcHeader.u2.s2.Type = LPC_REQUEST;
  3928. LrpcMessage->LpcHeader.ClientId = ClientIdToMsgClientId(ClientId);
  3929. LrpcMessage->LpcHeader.MessageId = MessageId;
  3930. LrpcMessage->LpcHeader.CallbackId = CallbackId;
  3931. }
  3932. LrpcMessage->LpcHeader.u1.s1.TotalLength = sizeof(PORT_MESSAGE)
  3933. + LrpcMessage->LpcHeader.u1.s1.DataLength;
  3934. LrpcMessage->Rpc.RpcHeader.MessageType = LRPC_MSG_REQUEST;
  3935. LrpcMessage->Rpc.RpcHeader.ProcedureNumber = (unsigned short) Message->ProcNum;
  3936. LrpcMessage->Rpc.RpcHeader.PresentContext = GetOnTheWirePresentationContext();
  3937. if (CurrentSecurityContext)
  3938. {
  3939. LrpcMessage->Rpc.RpcHeader.SecurityContextId = CurrentSecurityContext->SecurityContextId;
  3940. // Make sure we can't be impersonated on the transport level if
  3941. // static identity tracking is being used. We may be under different
  3942. // identity now then we were during the bind. The server is supposed
  3943. // to capture the token during bind and use it later under
  3944. // static idenitity tracking.
  3945. ASSERT(CurrentBindingHandle != NULL);
  3946. if (CurrentBindingHandle->GetIdentityTracking() == RPC_C_QOS_IDENTITY_STATIC)
  3947. {
  3948. LrpcMessage->LpcHeader.u2.s2.Type |= LPC_NO_IMPERSONATE;
  3949. }
  3950. }
  3951. else
  3952. {
  3953. LrpcMessage->Rpc.RpcHeader.SecurityContextId = -1;
  3954. }
  3955. TempBuffer = Message->Buffer;
  3956. LrpcMessage->Rpc.RpcHeader.Flags |= LRPC_SYNC_CLIENT | LRPC_NON_PIPE;
  3957. LrpcMessage->Rpc.RpcHeader.Pad = 0;
  3958. // Make sure the port has not been closed due to an association abort.
  3959. if (Association->LpcClientPort)
  3960. {
  3961. NtStatus = NtRequestWaitReplyPort(Association->LpcClientPort,
  3962. (PORT_MESSAGE *) LrpcMessage,
  3963. (PORT_MESSAGE *) LrpcMessage);
  3964. }
  3965. else
  3966. {
  3967. NtStatus = STATUS_INVALID_PORT_HANDLE;
  3968. }
  3969. if (NT_ERROR(NtStatus))
  3970. {
  3971. if (NtStatus == STATUS_NO_MEMORY)
  3972. {
  3973. Status = RPC_S_OUT_OF_MEMORY;
  3974. goto Cleanup;
  3975. }
  3976. if (NtStatus == STATUS_INSUFFICIENT_RESOURCES)
  3977. {
  3978. Status = RPC_S_OUT_OF_RESOURCES;
  3979. goto Cleanup;
  3980. }
  3981. VALIDATE(NtStatus)
  3982. {
  3983. STATUS_INVALID_PORT_HANDLE,
  3984. STATUS_INVALID_HANDLE,
  3985. STATUS_PORT_DISCONNECTED,
  3986. STATUS_LPC_REPLY_LOST
  3987. } END_VALIDATE;
  3988. Association->AbortAssociation();
  3989. if ((CallStack == 0)
  3990. && (NtStatus != STATUS_LPC_REPLY_LOST))
  3991. {
  3992. //
  3993. // It's possible that the server stopped and has now restarted.
  3994. // We'll try re-binding and only fail if the new call fails.
  3995. //
  3996. // We can only retry if we are SURE that the server did not
  3997. // execute the request.
  3998. if (RecursionCount > 3)
  3999. {
  4000. // Prevent an infinite loop when GetBuffer returns ok but
  4001. // the SendReceive always fails.
  4002. Status = RPC_S_CALL_FAILED_DNE;
  4003. }
  4004. else
  4005. {
  4006. Status = AutoRetryCall(Message,
  4007. TRUE // fFromSendReceive
  4008. );
  4009. }
  4010. }
  4011. else
  4012. {
  4013. // In a callback and/or couldn't retry.
  4014. Status = RPC_S_CALL_FAILED;
  4015. }
  4016. Cleanup:
  4017. if (fDebugInfoSet)
  4018. {
  4019. FreeCell(CallTargetInfo, &CallTargetInfoCellTag);
  4020. FreeCell(ClientCallInfo, &ClientCallInfoCellTag);
  4021. }
  4022. ActuallyFreeBuffer(TempBuffer);
  4023. AbortCCall();
  4024. return Status;
  4025. }
  4026. // The message was sent and we got a reply okay.
  4027. ActuallyFreeBuffer(Message->Buffer);
  4028. for (;;)
  4029. {
  4030. if (LrpcMessage->Rpc.RpcHeader.MessageType == LRPC_MSG_FAULT)
  4031. {
  4032. if (LrpcMessage->Fault.RpcHeader.Flags & LRPC_EEINFO_PRESENT)
  4033. {
  4034. Status = UnpickleEEInfo(LrpcMessage->Fault.Buffer,
  4035. LrpcMessage->Fault.LpcHeader.u1.s1.TotalLength
  4036. - sizeof(LRPC_FAULT_MESSAGE)
  4037. + sizeof(LrpcMessage->Fault.Buffer),
  4038. &EEInfo);
  4039. if (Status == RPC_S_OK)
  4040. {
  4041. RpcpSetEEInfoForThread(ThisThread, EEInfo);
  4042. }
  4043. // else we just fall through and return an error code -
  4044. // this is best effort, so it's Ok
  4045. }
  4046. Status = LrpcMessage->Fault.RpcStatus;
  4047. break;
  4048. }
  4049. if ((LrpcMessage->Rpc.RpcHeader.MessageType == LRPC_MSG_RESPONSE)
  4050. || (LrpcMessage->Rpc.RpcHeader.MessageType == LRPC_MSG_FAULT2))
  4051. {
  4052. BOOL fFault2;
  4053. RPC_STATUS FaultStatus;
  4054. // remember if the message was fault2
  4055. if (LrpcMessage->Rpc.RpcHeader.MessageType == LRPC_MSG_FAULT2)
  4056. {
  4057. fFault2 = TRUE;
  4058. FaultStatus = LrpcMessage->Fault2.RpcStatus;
  4059. }
  4060. else
  4061. fFault2 = FALSE;
  4062. Status = LrpcMessageToRpcMessage(LrpcMessage,
  4063. Message,
  4064. Association->LpcClientPort,
  4065. FALSE, // IsReplyFromBackConnection
  4066. NULL // StatusIfDelayedAck
  4067. );
  4068. if (fFault2)
  4069. {
  4070. if (Status == RPC_S_OK)
  4071. {
  4072. Status = UnpickleEEInfo((unsigned char *)Message->Buffer,
  4073. Message->BufferLength,
  4074. &EEInfo);
  4075. if (Status == RPC_S_OK)
  4076. {
  4077. RpcpSetEEInfoForThread(ThisThread, EEInfo);
  4078. }
  4079. // else
  4080. // fall through to restoring the original status
  4081. }
  4082. // the status of the retrieval of
  4083. // the extended error info is irrelevant - we
  4084. // need to restore the original fault code
  4085. Status = FaultStatus;
  4086. }
  4087. break;
  4088. }
  4089. ASSERT(LrpcMessage->Rpc.RpcHeader.MessageType
  4090. == LRPC_MSG_CALLBACK);
  4091. CallStack += 1;
  4092. Status = RPC_S_OK;
  4093. if ((CallStack == 1)
  4094. && (ActiveCallSetupFlag == 0))
  4095. {
  4096. ClientId = MsgClientIdToClientId(LrpcMessage->LpcHeader.ClientId);
  4097. MessageId = LrpcMessage->LpcHeader.MessageId;
  4098. CallbackId = LrpcMessage->LpcHeader.CallbackId;
  4099. RecursiveCallsKey = CurrentBindingHandle->AddRecursiveCall(this);
  4100. if (RecursiveCallsKey == -1)
  4101. {
  4102. Status = RPC_S_OUT_OF_MEMORY;
  4103. }
  4104. else
  4105. {
  4106. ActiveCallSetupFlag = 1;
  4107. }
  4108. }
  4109. if (SavedLrpcMessage == 0)
  4110. {
  4111. // First callback, we may need to allocated a new LRPC_MESSAGE.
  4112. if (CachedLrpcMessage == 0)
  4113. {
  4114. CachedLrpcMessage = AllocateMessage() ;
  4115. }
  4116. if (CachedLrpcMessage == 0)
  4117. Status = RPC_S_OUT_OF_MEMORY;
  4118. }
  4119. if (Status == RPC_S_OK)
  4120. {
  4121. Status = LrpcMessageToRpcMessage(LrpcMessage,
  4122. Message,
  4123. Association->LpcClientPort,
  4124. FALSE, // IsReplyFromBackConnection
  4125. NULL // StatusIfDelayedAck
  4126. );
  4127. }
  4128. if (Status != RPC_S_OK)
  4129. {
  4130. ActuallyFreeBuffer(Message->Buffer);
  4131. LrpcMessage->Fault.RpcHeader.MessageType = LRPC_MSG_FAULT;
  4132. LrpcMessage->Fault.RpcStatus = LrpcMapRpcStatus(Status);
  4133. LrpcMessage->LpcHeader.u1.s1.DataLength =
  4134. sizeof(LRPC_FAULT_MESSAGE) - sizeof(PORT_MESSAGE);
  4135. LrpcMessage->LpcHeader.u1.s1.TotalLength =
  4136. sizeof(LRPC_FAULT_MESSAGE);
  4137. LrpcMessage->LpcHeader.ClientId = ClientIdToMsgClientId(ClientId);
  4138. LrpcMessage->LpcHeader.MessageId = MessageId;
  4139. LrpcMessage->LpcHeader.CallbackId = CallbackId;
  4140. // Make sure the port has not been closed due to an association abort.
  4141. if (Association->LpcClientPort)
  4142. {
  4143. NtStatus = NtReplyWaitReplyPort(Association->LpcClientPort,
  4144. (PORT_MESSAGE *) LrpcMessage);
  4145. }
  4146. else
  4147. {
  4148. NtStatus = STATUS_INVALID_PORT_HANDLE;
  4149. }
  4150. }
  4151. else
  4152. {
  4153. PRPC_DISPATCH_TABLE DispatchTableToUse;
  4154. OriginalMessageBuffer = Message->Buffer;
  4155. Message->TransferSyntax = Binding->GetTransferSyntaxId();
  4156. Message->ProcNum = LrpcMessage->Rpc.RpcHeader.ProcedureNumber;
  4157. if (SavedLrpcMessage == 0)
  4158. {
  4159. // First callback
  4160. ASSERT(CachedLrpcMessage != 0);
  4161. SavedLrpcMessage = LrpcMessage;
  4162. LrpcMessage = CachedLrpcMessage;
  4163. CachedLrpcMessage = 0;
  4164. }
  4165. else
  4166. {
  4167. // >First callback, LrpcMessage and SavedLrpcMessages swap roles
  4168. TmpLrpcMessage = SavedLrpcMessage;
  4169. SavedLrpcMessage = LrpcMessage;
  4170. LrpcMessage = TmpLrpcMessage;
  4171. }
  4172. // Check to make sure this procnum can actually receive callbacks and
  4173. // a valid callback is specified.
  4174. // On error - ignore the PDU.
  4175. PRPC_DISPATCH_TABLE DispatchTableCallback = Binding->GetDispatchTable();
  4176. if (DispatchTableCallback &&
  4177. Message->ProcNum < DispatchTableCallback->DispatchTableCount &&
  4178. DispatchTableCallback->DispatchTable[Message->ProcNum] != NULL)
  4179. {
  4180. Status = DispatchCallback(DispatchTableCallback,
  4181. Message,
  4182. &ExceptionCode);
  4183. }
  4184. else
  4185. {
  4186. CORRUPTION_ASSERT(0);
  4187. Status = RPC_S_PROTOCOL_ERROR;
  4188. }
  4189. if (OriginalMessageBuffer != SavedLrpcMessage->Rpc.Buffer)
  4190. {
  4191. ActuallyFreeBuffer(OriginalMessageBuffer);
  4192. }
  4193. if (Status != RPC_S_OK)
  4194. {
  4195. VALIDATE(Status)
  4196. {
  4197. RPC_P_EXCEPTION_OCCURED,
  4198. RPC_S_PROCNUM_OUT_OF_RANGE
  4199. } END_VALIDATE;
  4200. if (Status == RPC_P_EXCEPTION_OCCURED)
  4201. {
  4202. Status = LrpcMapRpcStatus(ExceptionCode);
  4203. }
  4204. LrpcMessage->Fault.RpcStatus = Status;
  4205. LrpcMessage->LpcHeader.u1.s1.DataLength =
  4206. sizeof(LRPC_FAULT_MESSAGE) - sizeof(PORT_MESSAGE);
  4207. LrpcMessage->LpcHeader.u1.s1.TotalLength =
  4208. sizeof(LRPC_FAULT_MESSAGE);
  4209. LrpcMessage->Fault.RpcHeader.MessageType = LRPC_MSG_FAULT;
  4210. }
  4211. else
  4212. {
  4213. LrpcMessage->Rpc.RpcHeader.MessageType =
  4214. LRPC_MSG_RESPONSE;
  4215. if (LrpcMessage->Rpc.RpcHeader.Flags & LRPC_BUFFER_REQUEST)
  4216. {
  4217. Status = MakeServerCopyResponse();
  4218. if (Status != RPC_S_OK)
  4219. {
  4220. break;
  4221. }
  4222. }
  4223. }
  4224. LrpcMessage->LpcHeader.ClientId = ClientIdToMsgClientId(ClientId);
  4225. LrpcMessage->LpcHeader.MessageId = MessageId;
  4226. LrpcMessage->LpcHeader.CallbackId = CallbackId;
  4227. LrpcMessage->LpcHeader.u1.s1.TotalLength =
  4228. LrpcMessage->LpcHeader.u1.s1.DataLength + sizeof(PORT_MESSAGE);
  4229. // Make sure the port has not been closed due to an association abort.
  4230. if (Association->LpcClientPort)
  4231. {
  4232. NtStatus = NtReplyWaitReplyPort(Association->LpcClientPort,
  4233. (PORT_MESSAGE *) LrpcMessage);
  4234. }
  4235. else
  4236. {
  4237. NtStatus = STATUS_INVALID_PORT_HANDLE;
  4238. }
  4239. RpcpPurgeEEInfo();
  4240. }
  4241. CallStack -= 1;
  4242. if (NT_ERROR(NtStatus))
  4243. {
  4244. if (NtStatus == STATUS_NO_MEMORY)
  4245. {
  4246. Status = RPC_S_OUT_OF_MEMORY;
  4247. }
  4248. else if (NtStatus == STATUS_INSUFFICIENT_RESOURCES)
  4249. {
  4250. Status = RPC_S_OUT_OF_RESOURCES;
  4251. }
  4252. else
  4253. {
  4254. Association->AbortAssociation();
  4255. VALIDATE(NtStatus)
  4256. {
  4257. STATUS_INVALID_PORT_HANDLE,
  4258. STATUS_INVALID_HANDLE,
  4259. STATUS_PORT_DISCONNECTED,
  4260. STATUS_LPC_REPLY_LOST
  4261. } END_VALIDATE;
  4262. Status = RPC_S_CALL_FAILED;
  4263. }
  4264. break;
  4265. }
  4266. }
  4267. if (SavedLrpcMessage != 0)
  4268. {
  4269. if (CachedLrpcMessage != 0)
  4270. {
  4271. FreeMessage(CachedLrpcMessage) ;
  4272. }
  4273. CachedLrpcMessage = SavedLrpcMessage;
  4274. }
  4275. if (ActiveCallSetupFlag != 0)
  4276. {
  4277. CurrentBindingHandle->RemoveRecursiveCall(RecursiveCallsKey);
  4278. }
  4279. if (Status != RPC_S_OK)
  4280. {
  4281. if (CallStack == 0)
  4282. {
  4283. FreeCCall();
  4284. }
  4285. }
  4286. if (fDebugInfoSet)
  4287. {
  4288. FreeCell(CallTargetInfo, &CallTargetInfoCellTag);
  4289. FreeCell(ClientCallInfo, &ClientCallInfoCellTag);
  4290. }
  4291. return(Status);
  4292. }
  4293. RPC_STATUS
  4294. LRPC_CCALL::SendRequest (
  4295. IN OUT PRPC_MESSAGE Message,
  4296. OUT BOOL *Shutup
  4297. )
  4298. /*++
  4299. Routine Description:
  4300. Helper function used for sending async requests or pipe requests
  4301. Arguments:
  4302. Message - request message
  4303. Return Value:
  4304. RPC_S_OK - Function succeeded
  4305. RPC_S_OUT_OF_MEMORY - we ran out of memory
  4306. RPC_S_SEND_INCOMPLETE - we were unable to send the complete request.
  4307. --*/
  4308. {
  4309. NTSTATUS NtStatus;
  4310. RPC_STATUS ExceptionCode, Status;
  4311. void * OriginalMessageBuffer;
  4312. LRPC_MESSAGE *TmpLrpcMessage = 0;
  4313. void * TempBuffer;
  4314. LRPC_MESSAGE *LrpcReplyMessage ;
  4315. int RemainingLength = 0;
  4316. ASSERT((LrpcMessage->Rpc.RpcHeader.Flags
  4317. & LRPC_BUFFER_IMMEDIATE) == 0) ;
  4318. *Shutup = 0;
  4319. if (CallAbortedFlag != 0)
  4320. {
  4321. return(RPC_S_CALL_FAILED_DNE);
  4322. }
  4323. if (CallStack > 0)
  4324. {
  4325. return (RPC_S_CALL_FAILED);
  4326. }
  4327. if (PARTIAL(Message))
  4328. {
  4329. if (Message->BufferLength < MINIMUM_PARTIAL_BUFFLEN)
  4330. {
  4331. return (RPC_S_SEND_INCOMPLETE);
  4332. }
  4333. LrpcMessage->Rpc.RpcHeader.Flags |= LRPC_BUFFER_PARTIAL ;
  4334. if (NOT_MULTIPLE_OF_EIGHT(Message->BufferLength))
  4335. {
  4336. RemainingLength = Message->BufferLength & LOW_BITS ;
  4337. Message->BufferLength &= ~LOW_BITS ;
  4338. }
  4339. }
  4340. // NDR_DREP_ASCII | NDR_DREP_LITTLE_ENDIAN | NDR_DREP_IEEE
  4341. Message->DataRepresentation = 0x00 | 0x10 | 0x0000;
  4342. ASSERT(CallId != (ULONG) -1);
  4343. LrpcMessage->Rpc.RpcHeader.CallId = CallId ;
  4344. if (FirstFrag)
  4345. {
  4346. LrpcMessage->Rpc.RpcHeader.MessageType = LRPC_MSG_REQUEST;
  4347. }
  4348. else
  4349. {
  4350. LrpcMessage->Rpc.RpcHeader.MessageType = LRPC_PARTIAL_REQUEST;
  4351. }
  4352. LrpcMessage->LpcHeader.u1.s1.TotalLength =
  4353. sizeof(PORT_MESSAGE) + LrpcMessage->LpcHeader.u1.s1.DataLength;
  4354. LrpcMessage->Rpc.Request.DataEntries[0].Size = Message->BufferLength;
  4355. LrpcMessage->Rpc.RpcHeader.ProcedureNumber = (unsigned short) Message->ProcNum;
  4356. LrpcMessage->Rpc.RpcHeader.PresentContext = GetOnTheWirePresentationContext();
  4357. LrpcMessage->Rpc.RpcHeader.Pad = 0;
  4358. if (CurrentSecurityContext)
  4359. {
  4360. LrpcMessage->Rpc.RpcHeader.SecurityContextId = CurrentSecurityContext->SecurityContextId;
  4361. }
  4362. else
  4363. {
  4364. LrpcMessage->Rpc.RpcHeader.SecurityContextId = -1;
  4365. }
  4366. if (UuidSpecified)
  4367. {
  4368. ASSERT(CallStack == 0) ;
  4369. RpcpMemoryCopy(&(LrpcMessage->Rpc.RpcHeader.ObjectUuid),
  4370. &ObjectUuid, sizeof(UUID));
  4371. LrpcMessage->Rpc.RpcHeader.Flags |= LRPC_OBJECT_UUID;
  4372. }
  4373. else
  4374. {
  4375. // zero out uninitialized data
  4376. RpcpMemorySet(&(LrpcMessage->Rpc.RpcHeader.ObjectUuid),
  4377. 0, sizeof(UUID));
  4378. }
  4379. // Make sure we can't be impersonated on the transport level if
  4380. // static identity tracking is being used.
  4381. ASSERT(CurrentBindingHandle != NULL);
  4382. if (CurrentBindingHandle->GetIdentityTracking() == RPC_C_QOS_IDENTITY_STATIC)
  4383. {
  4384. LrpcMessage->LpcHeader.u2.s2.Type |= LPC_NO_IMPERSONATE;
  4385. }
  4386. if (Association->LpcClientPort)
  4387. {
  4388. NtStatus = NtRequestWaitReplyPort(Association->LpcClientPort,
  4389. (PORT_MESSAGE *) LrpcMessage,
  4390. (PORT_MESSAGE *) LrpcMessage);
  4391. }
  4392. else
  4393. {
  4394. NtStatus = STATUS_INVALID_PORT_HANDLE;
  4395. }
  4396. if (NT_ERROR(NtStatus))
  4397. {
  4398. TempBuffer = Message->Buffer;
  4399. if (NtStatus == STATUS_NO_MEMORY)
  4400. {
  4401. Status = RPC_S_OUT_OF_MEMORY;
  4402. goto Cleanup;
  4403. }
  4404. if (NtStatus == STATUS_INSUFFICIENT_RESOURCES)
  4405. {
  4406. Status = RPC_S_OUT_OF_RESOURCES;
  4407. goto Cleanup;
  4408. }
  4409. VALIDATE(NtStatus)
  4410. {
  4411. STATUS_INVALID_PORT_HANDLE,
  4412. STATUS_INVALID_HANDLE,
  4413. STATUS_PORT_DISCONNECTED,
  4414. STATUS_LPC_REPLY_LOST
  4415. } END_VALIDATE;
  4416. if (pAsync)
  4417. {
  4418. ASSERT(RecursionCount == 0);
  4419. if (NtStatus != STATUS_LPC_REPLY_LOST)
  4420. {
  4421. Status = RPC_S_CALL_FAILED_DNE;
  4422. }
  4423. else
  4424. {
  4425. Status = RPC_S_CALL_FAILED;
  4426. }
  4427. goto Cleanup;
  4428. }
  4429. Association->AbortAssociation();
  4430. if ((NtStatus != STATUS_LPC_REPLY_LOST) && FirstFrag)
  4431. {
  4432. ASSERT(CallStack == 0) ;
  4433. //
  4434. // It's possible that the server stopped and has now restarted.
  4435. // We'll try re-binding and only fail if the new call fails.
  4436. //
  4437. // We can only retry if we are SURE that the server did not
  4438. // execute the request.
  4439. if (RecursionCount > 3)
  4440. {
  4441. // Prevent an infinite loop when GetBuffer returns ok but
  4442. // the SendReceive always fails.
  4443. Status = RPC_S_CALL_FAILED_DNE;
  4444. }
  4445. else
  4446. {
  4447. Status = AutoRetryCall(Message,
  4448. FALSE // fFromSendReceive
  4449. );
  4450. }
  4451. }
  4452. else
  4453. {
  4454. // In a callback and/or couldn't retry.
  4455. Status = RPC_S_CALL_FAILED;
  4456. }
  4457. Cleanup:
  4458. ActuallyFreeBuffer(TempBuffer);
  4459. AbortCCall();
  4460. return Status;
  4461. }
  4462. else
  4463. {
  4464. FirstFrag = 0;
  4465. }
  4466. if (LrpcMessage->Rpc.RpcHeader.MessageType == LRPC_MSG_ACK)
  4467. {
  4468. *Shutup = LrpcMessage->Ack.Shutup ;
  4469. if (PARTIAL(Message))
  4470. {
  4471. if (LrpcMessage->Ack.RpcStatus == RPC_S_OK)
  4472. {
  4473. if (RemainingLength)
  4474. {
  4475. RpcpMemoryMove(Message->Buffer,
  4476. (char *) Message->Buffer + Message->BufferLength,
  4477. RemainingLength) ;
  4478. Message->BufferLength = RemainingLength ;
  4479. return (RPC_S_SEND_INCOMPLETE) ;
  4480. }
  4481. return RPC_S_OK;
  4482. }
  4483. }
  4484. ActuallyFreeBuffer(Message->Buffer);
  4485. Message->Buffer = 0;
  4486. return LrpcMessage->Ack.RpcStatus ;
  4487. }
  4488. ActuallyFreeBuffer(Message->Buffer);
  4489. Message->Buffer = 0;
  4490. if (LrpcMessage->Rpc.RpcHeader.MessageType == LRPC_MSG_RESPONSE)
  4491. {
  4492. ASSERT(!PARTIAL(Message)) ;
  4493. CurrentBufferLength = 0;
  4494. Status = LrpcMessageToRpcMessage(LrpcMessage,
  4495. Message,
  4496. Association->LpcClientPort,
  4497. FALSE, // IsReplyFromBackConnection
  4498. NULL // StatusIfDelayedAck
  4499. );
  4500. if (Status == RPC_S_OK
  4501. && COMPLETE(Message))
  4502. {
  4503. BufferComplete = 1;
  4504. }
  4505. Message->RpcFlags = 0;
  4506. // we have no out pipes
  4507. ASSERT(Status != RPC_S_OK || BufferComplete) ;
  4508. }
  4509. else if (LrpcMessage->Rpc.RpcHeader.MessageType == LRPC_MSG_FAULT)
  4510. {
  4511. CurrentBufferLength = 0;
  4512. Status = LrpcMessage->Fault.RpcStatus;
  4513. }
  4514. else
  4515. {
  4516. // The server should only return messages of types: LRPC_MSG_ACK,
  4517. // LRPC_MSG_RESPONSE, and LRPC_MSG_FAULT. All of these have been handled in
  4518. // the above clauses.
  4519. ASSERT(0 && "Invalid message type");
  4520. Status = RPC_S_CALL_FAILED;
  4521. }
  4522. if (Status != RPC_S_OK)
  4523. {
  4524. ASSERT(CallStack == 0) ;
  4525. FreeCCall();
  4526. }
  4527. return Status ;
  4528. }
  4529. RPC_STATUS
  4530. LRPC_CCALL::AutoRetryCall (
  4531. IN OUT PRPC_MESSAGE Message,
  4532. BOOL fFromSendReceive
  4533. )
  4534. {
  4535. RPC_STATUS Status;
  4536. void *OldBuffer;
  4537. UUID *UuidToUse;
  4538. LRPC_CCALL *NewCall;
  4539. // any failure after this is unrelated
  4540. RpcpPurgeEEInfo();
  4541. OldBuffer = Message->Buffer;
  4542. Message->Handle = (RPC_BINDING_HANDLE) CurrentBindingHandle;
  4543. if (UuidSpecified)
  4544. {
  4545. UuidToUse = &ObjectUuid;
  4546. }
  4547. else
  4548. {
  4549. UuidToUse = 0;
  4550. }
  4551. Status = CurrentBindingHandle->NegotiateTransferSyntax(Message);
  4552. if (Status != RPC_S_OK)
  4553. goto CleanupAndReturn;
  4554. NewCall = ((LRPC_CCALL *)(Message->Handle));
  4555. Status = NewCall->GetBuffer(Message, UuidToUse);
  4556. if (Status != RPC_S_OK)
  4557. goto CleanupAndReturn;
  4558. ASSERT(Message->Buffer != OldBuffer);
  4559. RpcpMemoryCopy(Message->Buffer, OldBuffer,
  4560. Message->BufferLength);
  4561. // This CCALL should be freed,
  4562. // a new one was allocated in NegotiateTransferSyntax and is now being used.
  4563. ASSERT(NewCall != this);
  4564. NewCall->SetRecursionCount(RecursionCount + 1);
  4565. if (fFromSendReceive)
  4566. Status = NewCall->SendReceive(Message);
  4567. else
  4568. Status = NewCall->Send(Message);
  4569. // the caller has remembered the old buffer and call object,
  4570. // and will clean them up regardless of what we return - our
  4571. // job is simply to allocate a new call and buffer, and stick
  4572. // them in the Message
  4573. CleanupAndReturn:
  4574. if (Status == RPC_S_SERVER_UNAVAILABLE)
  4575. {
  4576. // Since we're retrying, if the server has gone missing,
  4577. // it just means that the call failed.
  4578. Status = RPC_S_CALL_FAILED_DNE;
  4579. }
  4580. return(Status);
  4581. }
  4582. RPC_STATUS
  4583. LRPC_CCALL::Send (
  4584. IN OUT PRPC_MESSAGE Message
  4585. )
  4586. /*++
  4587. Routine Description:
  4588. This rountine is used by pipes to send partila data...
  4589. Arguments:
  4590. Message - Supplies the request and returns the response of a remote
  4591. procedure call.
  4592. Return Value:
  4593. RPC_S_OK - The remote procedure call completed successful.
  4594. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to perform the
  4595. remote procedure call.
  4596. RPC_S_OUT_OF_RESOURCES - Insufficient resources are available to complete
  4597. the remote procedure call.
  4598. --*/
  4599. {
  4600. RPC_STATUS Status ;
  4601. BOOL Shutup ;
  4602. Status = SendRequest(Message, &Shutup) ;
  4603. return(Status);
  4604. }
  4605. RPC_STATUS
  4606. LRPC_CCALL::Receive (
  4607. IN PRPC_MESSAGE Message,
  4608. IN unsigned int Size
  4609. )
  4610. /*++
  4611. Routine Description:
  4612. description
  4613. Arguments:
  4614. arg1 - description
  4615. Return Value:
  4616. RPC_S_OK - Function succeeded
  4617. RPC_S_OUT_OF_MEMORY - we ran out of memory
  4618. --*/
  4619. {
  4620. int size = 0 ;
  4621. int BufferLength ;
  4622. int RequestedLength ;
  4623. RPC_STATUS Status ;
  4624. int ActualBufferLength = 0;
  4625. int Extra = IsExtraMessage(Message) ;
  4626. if (BufferComplete
  4627. && RcvBufferLength == 0)
  4628. {
  4629. Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
  4630. return (RPC_S_OK) ;
  4631. }
  4632. // If you get here, it means that you have out pipe data.
  4633. //
  4634. // allocate a buffer big enough to hold the out data:
  4635. // if you have a partial receive, you can allocate the buffer up
  4636. // front and start receive data.
  4637. //
  4638. if (PARTIAL(Message))
  4639. {
  4640. if (Extra)
  4641. {
  4642. ActualBufferLength = Message->BufferLength ;
  4643. BufferLength = Message->BufferLength+Size ;
  4644. }
  4645. else
  4646. {
  4647. BufferLength = Size ;
  4648. }
  4649. }
  4650. else
  4651. {
  4652. if (Extra)
  4653. {
  4654. ActualBufferLength = Message->BufferLength ;
  4655. BufferLength = Message->BufferLength + MINIMUM_PARTIAL_BUFFLEN ;
  4656. }
  4657. else
  4658. {
  4659. BufferLength = MINIMUM_PARTIAL_BUFFLEN ;
  4660. }
  4661. }
  4662. Status = GetBufferDo(Message, BufferLength, Extra) ;
  4663. if (Status != RPC_S_OK)
  4664. {
  4665. FreeCCall();
  4666. return Status ;
  4667. }
  4668. RequestedLength = Message->BufferLength - ActualBufferLength;
  4669. while (!BufferComplete
  4670. && (!PARTIAL(Message) || (RcvBufferLength < Size)))
  4671. {
  4672. if (SyncEvent.Wait() == WAIT_FAILED)
  4673. {
  4674. return RPC_S_CALL_FAILED;
  4675. }
  4676. }
  4677. return GetCoalescedBuffer(Message, Extra);
  4678. }
  4679. void
  4680. LRPC_CCALL::FreeBuffer (
  4681. IN PRPC_MESSAGE Message
  4682. )
  4683. /*++
  4684. Routine Description:
  4685. We will free the supplied buffer.
  4686. Arguments:
  4687. Message - Supplies the buffer to be freed.
  4688. --*/
  4689. {
  4690. ActuallyFreeBuffer(Message->Buffer);
  4691. if (CallStack == 0)
  4692. {
  4693. FreeCCall();
  4694. }
  4695. }
  4696. void
  4697. LRPC_CCALL::FreePipeBuffer (
  4698. IN PRPC_MESSAGE Message
  4699. )
  4700. /*++
  4701. Routine Description:
  4702. description
  4703. Arguments:
  4704. arg1 - description
  4705. Return Value:
  4706. RPC_S_OK - Function succeeded
  4707. RPC_S_OUT_OF_MEMORY - we ran out of memory
  4708. --*/
  4709. {
  4710. RpcpFarFree(Message->Buffer) ;
  4711. }
  4712. RPC_STATUS
  4713. LRPC_CCALL::GetBufferDo (
  4714. IN OUT PRPC_MESSAGE Message,
  4715. IN unsigned long NewSize,
  4716. IN int fDataValid
  4717. )
  4718. /*++
  4719. Routine Description:
  4720. description
  4721. Arguments:
  4722. arg1 - description
  4723. Return Value:
  4724. RPC_S_OK - Function succeeded
  4725. RPC_S_OUT_OF_MEMORY - we ran out of memory
  4726. --*/
  4727. {
  4728. void *NewBuffer ;
  4729. int SizeToAlloc ;
  4730. if (NewSize < CurrentBufferLength)
  4731. {
  4732. Message->BufferLength = NewSize ;
  4733. }
  4734. else
  4735. {
  4736. SizeToAlloc = (NewSize < MINIMUM_PARTIAL_BUFFLEN) ?
  4737. MINIMUM_PARTIAL_BUFFLEN:NewSize ;
  4738. NewBuffer = RpcpFarAllocate(SizeToAlloc) ;
  4739. if (NewBuffer == 0)
  4740. {
  4741. RpcpFarFree(Message->Buffer) ;
  4742. CurrentBufferLength = 0;
  4743. Message->BufferLength = 0;
  4744. return RPC_S_OUT_OF_MEMORY ;
  4745. }
  4746. if (fDataValid && Message->BufferLength > 0)
  4747. {
  4748. RpcpMemoryCopy(NewBuffer,
  4749. Message->Buffer,
  4750. Message->BufferLength) ;
  4751. }
  4752. RpcpFarFree(Message->Buffer) ;
  4753. Message->Buffer = NewBuffer ;
  4754. Message->BufferLength = NewSize ;
  4755. CurrentBufferLength = SizeToAlloc ;
  4756. }
  4757. return RPC_S_OK ;
  4758. }
  4759. RPC_STATUS
  4760. LRPC_CCALL::ReallocPipeBuffer (
  4761. IN PRPC_MESSAGE Message,
  4762. IN unsigned int NewSize
  4763. )
  4764. /*++
  4765. Routine Description:
  4766. description
  4767. Arguments:
  4768. arg1 - description
  4769. Return Value:
  4770. RPC_S_OK - Function succeeded
  4771. RPC_S_OUT_OF_MEMORY - we ran out of memory
  4772. --*/
  4773. {
  4774. unsigned int SizeToAlloc ;
  4775. void *TempBuffer ;
  4776. if (LrpcMessage == 0)
  4777. {
  4778. LrpcMessage = AllocateMessage();
  4779. if (LrpcMessage == 0)
  4780. {
  4781. return(RPC_S_OUT_OF_MEMORY);
  4782. }
  4783. }
  4784. if (GetBufferDo(Message, NewSize, 1) != RPC_S_OK)
  4785. return RPC_S_OUT_OF_MEMORY ;
  4786. Message->BufferLength = NewSize ;
  4787. LrpcMessage->Rpc.RpcHeader.Flags = LRPC_BUFFER_REQUEST;
  4788. LrpcMessage->Rpc.Request.CountDataEntries = 1;
  4789. LrpcMessage->Rpc.Request.DataEntries[0].Base = PtrToMsgPtr(Message->Buffer);
  4790. LrpcMessage->Rpc.Request.DataEntries[0].Size = Message->BufferLength;
  4791. LrpcMessage->LpcHeader.CallbackId = 0;
  4792. LrpcMessage->LpcHeader.u2.ZeroInit = 0;
  4793. LrpcMessage->LpcHeader.u2.s2.DataInfoOffset = sizeof(PORT_MESSAGE)
  4794. + sizeof(LRPC_RPC_HEADER);
  4795. LrpcMessage->LpcHeader.u1.s1.DataLength = sizeof(LRPC_RPC_HEADER)
  4796. + sizeof(PORT_DATA_INFORMATION);
  4797. return (RPC_S_OK) ;
  4798. }
  4799. void
  4800. LRPC_CCALL::AbortCCall (
  4801. )
  4802. /*++
  4803. Routine Description:
  4804. This client call has failed, so we need to abort it. We may called
  4805. while nested in one or more callbacks.
  4806. --*/
  4807. {
  4808. LRPC_BINDING_HANDLE * BindingHandle;
  4809. CallAbortedFlag = 1;
  4810. if (CallStack == 0)
  4811. {
  4812. ASSERT(CurrentBindingHandle != 0);
  4813. BindingHandle = CurrentBindingHandle;
  4814. CurrentBindingHandle = 0;
  4815. BindingHandle->FreeCCall(this);
  4816. }
  4817. }
  4818. inline RPC_STATUS
  4819. LRPC_CCALL::LrpcMessageToRpcMessage (
  4820. IN LRPC_MESSAGE *LrpcResponse,
  4821. OUT RPC_MESSAGE *Message,
  4822. IN HANDLE LpcPort,
  4823. IN BOOL IsReplyFromBackConnection OPTIONAL,
  4824. OUT DelayedPipeAckData *AckData OPTIONAL
  4825. )
  4826. /*++
  4827. Routine Description:
  4828. We will convert from an LRPC_MESSAGE representation of a buffer (and
  4829. its length) to an RPC_MESSAGE representation.
  4830. Arguments:
  4831. LrpcResponse - the response we received from the server
  4832. RpcMessage - Returns the RPC_MESSAGE representation.
  4833. LpcPort - the association port on which we send data to the server
  4834. IsReplyFromBackConnection - non-zero if the reply is from back connection
  4835. AckData - if non-NULL, and the received data are pipe data, an
  4836. acknowledgement to a pipe response will be delayed, the current
  4837. status will be placed here, and it will be indicated the ack was
  4838. delayed. Also, if non-NULL, the caller must set
  4839. AckData->DelayedAckPipeNeeded to FALSE.
  4840. If NULL, any acknowledgement will be sent immediately.
  4841. --*/
  4842. {
  4843. NTSTATUS NtStatus;
  4844. SIZE_T NumberOfBytesRead;
  4845. #if defined(BUILD_WOW6432)
  4846. char CopyMessageBuffer[sizeof(LRPC_COPY_MESSAGE) + 8];
  4847. LRPC_COPY_MESSAGE *CopyMessagePtr = (LRPC_COPY_MESSAGE *) AlignPtr8(CopyMessageBuffer);
  4848. #else
  4849. LRPC_COPY_MESSAGE CopyMessageBuffer;
  4850. LRPC_COPY_MESSAGE *CopyMessagePtr = &CopyMessageBuffer;
  4851. #endif
  4852. RPC_STATUS Status = RPC_S_OK;
  4853. RPC_STATUS Status2;
  4854. BOOL fPartialResponse;
  4855. if (ARGUMENT_PRESENT(AckData))
  4856. {
  4857. ASSERT(AckData->DelayedAckPipeNeeded == FALSE);
  4858. }
  4859. if(LrpcResponse->Rpc.RpcHeader.Flags & LRPC_BUFFER_IMMEDIATE)
  4860. {
  4861. if (LrpcResponse->LpcHeader.u1.s1.DataLength < sizeof(LRPC_RPC_HEADER))
  4862. {
  4863. ASSERT(LrpcResponse->LpcHeader.u1.s1.DataLength >= sizeof(LRPC_RPC_HEADER));
  4864. return RPC_S_PROTOCOL_ERROR;
  4865. }
  4866. Message->Buffer = LrpcResponse->Rpc.Buffer;
  4867. Message->BufferLength =
  4868. (unsigned int) LrpcResponse->LpcHeader.u1.s1.DataLength
  4869. - sizeof(LRPC_RPC_HEADER);
  4870. if ((LrpcResponse->Rpc.RpcHeader.Flags & LRPC_BUFFER_PARTIAL) == 0)
  4871. {
  4872. Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
  4873. }
  4874. if (IsReplyFromBackConnection)
  4875. {
  4876. LpcReplyMessage = LrpcResponse ;
  4877. }
  4878. }
  4879. else if (LrpcResponse->Rpc.RpcHeader.Flags & LRPC_BUFFER_SERVER)
  4880. {
  4881. if (IsReplyFromBackConnection == 0)
  4882. {
  4883. UINT BufferLength;
  4884. LPC_PVOID ServerBuffer;
  4885. ASSERT(LrpcMessage == LrpcResponse);
  4886. BufferLength = LrpcResponse->Rpc.Server.Length;
  4887. ServerBuffer = LrpcResponse->Rpc.Server.Buffer;
  4888. Message->BufferLength = BufferLength;
  4889. Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
  4890. CopyMessagePtr->LpcHeader.u2.ZeroInit = 0;
  4891. SanitizeLpcHeader (&CopyMessagePtr->LpcHeader);
  4892. CopyMessagePtr->Server.Buffer = ServerBuffer;
  4893. CopyMessagePtr->Server.Length = BufferLength;
  4894. if (BufferLength >= 0x80000000)
  4895. {
  4896. ASSERT(BufferLength < 0x80000000);
  4897. Message->Buffer = 0;
  4898. CopyMessagePtr->RpcStatus = RPC_S_PROTOCOL_ERROR;
  4899. }
  4900. else {
  4901. Message->Buffer = RpcpFarAllocate(BufferLength) ;
  4902. if (Message->Buffer == 0)
  4903. {
  4904. CopyMessagePtr->RpcStatus = RPC_S_OUT_OF_MEMORY;
  4905. }
  4906. else
  4907. {
  4908. CopyMessagePtr->RpcStatus = RPC_S_OK;
  4909. CopyMessagePtr->Request.CountDataEntries = 1;
  4910. CopyMessagePtr->Request.DataEntries[0].Base = PtrToMsgPtr(Message->Buffer);
  4911. CopyMessagePtr->Request.DataEntries[0].Size = Message->BufferLength ;
  4912. CopyMessagePtr->LpcHeader.u2.s2.DataInfoOffset =
  4913. sizeof(PORT_MESSAGE) + sizeof(LRPC_RPC_HEADER);
  4914. }
  4915. }
  4916. CopyMessagePtr->LpcHeader.CallbackId = 0;
  4917. CopyMessagePtr->RpcHeader.Flags = LRPC_SYNC_CLIENT ;
  4918. CopyMessagePtr->LpcHeader.u1.s1.DataLength =
  4919. sizeof(LRPC_COPY_MESSAGE) - sizeof(PORT_MESSAGE);
  4920. CopyMessagePtr->LpcHeader.u1.s1.TotalLength =
  4921. sizeof(LRPC_COPY_MESSAGE);
  4922. CopyMessagePtr->RpcHeader.MessageType = LRPC_MSG_COPY;
  4923. CopyMessagePtr->RpcHeader.Pad = 0;
  4924. // zero out unused fields
  4925. RPCP_ZERO_OUT_STRUCT_TAIL (LRPC_RPC_HEADER, &CopyMessagePtr->RpcHeader, ProcedureNumber);
  4926. CopyMessagePtr->RpcHeader.PresentContext = 0;
  4927. CopyMessagePtr->IsPartial = 0 ;
  4928. // Make sure we can't be impersonated on the transport level if
  4929. // static identity tracking is being used.
  4930. ASSERT(CurrentBindingHandle != NULL);
  4931. if (CurrentBindingHandle->GetIdentityTracking() == RPC_C_QOS_IDENTITY_STATIC)
  4932. {
  4933. CopyMessagePtr->LpcHeader.u2.s2.Type |= LPC_NO_IMPERSONATE;
  4934. }
  4935. if (Association->LpcClientPort)
  4936. {
  4937. NtStatus = NtRequestWaitReplyPort(Association->LpcClientPort,
  4938. (PORT_MESSAGE *) CopyMessagePtr,
  4939. (PORT_MESSAGE *) CopyMessagePtr);
  4940. }
  4941. else
  4942. {
  4943. NtStatus = STATUS_INVALID_PORT_HANDLE;
  4944. }
  4945. if ((NT_ERROR(NtStatus))
  4946. || (CopyMessagePtr->RpcStatus != RPC_S_OK))
  4947. {
  4948. RpcpFarFree(Message->Buffer);
  4949. return(RPC_S_OUT_OF_MEMORY);
  4950. }
  4951. }
  4952. else
  4953. {
  4954. fPartialResponse = FALSE;
  4955. if (LrpcResponse->Rpc.RpcHeader.Flags & LRPC_BUFFER_PARTIAL)
  4956. {
  4957. fPartialResponse = TRUE;
  4958. CallMutex.Request() ;
  4959. if ((RcvBufferLength >= LRPC_THRESHOLD_SIZE))
  4960. {
  4961. Choked = 1;
  4962. }
  4963. CallMutex.Clear() ;
  4964. }
  4965. else
  4966. {
  4967. Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
  4968. }
  4969. Message->BufferLength = (unsigned int)
  4970. LrpcResponse->Rpc.Request.DataEntries[0].Size ;
  4971. Message->Buffer = RpcpFarAllocate(
  4972. Message->BufferLength);
  4973. if (Message->Buffer != NULL)
  4974. {
  4975. NtStatus = NtReadRequestData(LpcPort,
  4976. (PORT_MESSAGE*) LrpcResponse,
  4977. 0,
  4978. Message->Buffer,
  4979. Message->BufferLength,
  4980. &NumberOfBytesRead) ;
  4981. if (NT_ERROR(NtStatus))
  4982. {
  4983. #if DBG
  4984. PrintToDebugger("LRPC: NtReadRequestData failed: %x\n", NtStatus) ;
  4985. #endif
  4986. Status = RPC_S_OUT_OF_MEMORY;
  4987. }
  4988. else
  4989. {
  4990. ASSERT(Message->BufferLength == NumberOfBytesRead);
  4991. }
  4992. }
  4993. else
  4994. {
  4995. Status = RPC_S_OUT_OF_MEMORY;
  4996. }
  4997. if (ARGUMENT_PRESENT(AckData) && fPartialResponse && (Status == RPC_S_OK))
  4998. {
  4999. // if pipe and delayed ack was asked for, and
  5000. // moreover the operation didn't fail
  5001. // just store the relevant data in the caller
  5002. // supplied data structure
  5003. AckData->DelayedAckPipeNeeded = TRUE;
  5004. AckData->CurrentStatus = Status;
  5005. }
  5006. else
  5007. {
  5008. Status2 = SendPipeAck(LpcPort,
  5009. LrpcResponse,
  5010. Status);
  5011. FreeMessage(LrpcResponse) ;
  5012. // if either operation failed, fail the whole function
  5013. // if both operations failed, the first one is considered
  5014. // the original failure and the error code from it is
  5015. // preserved
  5016. if ((Status == RPC_S_OK) && (Status2 != RPC_S_OK))
  5017. Status = Status2;
  5018. }
  5019. if ((Status != RPC_S_OK) && (Message->Buffer))
  5020. {
  5021. RpcpFarFree(Message->Buffer);
  5022. }
  5023. }
  5024. }
  5025. else
  5026. {
  5027. CORRUPTION_ASSERT((LrpcResponse->Rpc.RpcHeader.Flags & LRPC_BUFFER_IMMEDIATE)
  5028. || (LrpcResponse->Rpc.RpcHeader.Flags & LRPC_BUFFER_SERVER));
  5029. return (RPC_S_PROTOCOL_ERROR);
  5030. }
  5031. return(Status);
  5032. }
  5033. RPC_STATUS
  5034. LRPC_CCALL::SendPipeAck (
  5035. IN HANDLE LpcPort,
  5036. IN LRPC_MESSAGE *LrpcResponse,
  5037. IN RPC_STATUS CurrentStatus
  5038. )
  5039. /*++
  5040. Routine Description:
  5041. Sends an acknowledgement to the server.
  5042. Arguments:
  5043. LpcPort - the port to send the ack to.
  5044. LrpcResponse - the response that we received from the server
  5045. CurrentStatus - the status up to the moment. It will
  5046. be sent to the server.
  5047. Return Value:
  5048. The result of the operation. RPC_S_OK for success
  5049. or RPC_S_* for error.
  5050. --*/
  5051. {
  5052. unsigned char MessageType;
  5053. RPC_STATUS RpcStatus = RPC_S_OK;
  5054. NTSTATUS NtStatus;
  5055. MessageType = LrpcResponse->Rpc.RpcHeader.MessageType ;
  5056. LrpcResponse->Ack.MessageType = LRPC_MSG_ACK ;
  5057. LrpcResponse->Ack.Shutup = (short) Choked ;
  5058. LrpcResponse->Ack.RpcStatus = CurrentStatus;
  5059. LrpcResponse->LpcHeader.u1.s1.DataLength = sizeof(LRPC_ACK_MESSAGE)
  5060. - sizeof(PORT_MESSAGE) ;
  5061. LrpcResponse->LpcHeader.u1.s1.TotalLength =
  5062. sizeof(LRPC_ACK_MESSAGE) ;
  5063. // setup the reply message
  5064. NtStatus = NtReplyPort(LpcPort,
  5065. (PORT_MESSAGE *) LrpcResponse) ;
  5066. LrpcResponse->Rpc.RpcHeader.MessageType = MessageType ;
  5067. if (NT_ERROR(NtStatus))
  5068. {
  5069. #if DBG
  5070. PrintToDebugger("LRPC: NtReplyPort failed: %x\n", NtStatus) ;
  5071. #endif
  5072. RpcStatus = RPC_S_OUT_OF_MEMORY;
  5073. }
  5074. return RpcStatus;
  5075. }
  5076. BOOL
  5077. LRPC_CCALL::TryWaitForCallToBecomeUnlocked (
  5078. BOOL *fUnlocked
  5079. )
  5080. /*++
  5081. Routine Description:
  5082. Checks if a call is unlocked. If the lock count
  5083. becomes 0, or if the lock count becomes 1 and this thread
  5084. is the last one with a lock, the call is considered unlocked.
  5085. In this case *fUnlocked is set to TRUE. Otherwise it is set to FALSE.
  5086. Return Value:
  5087. If fUnlocked == TRUE:
  5088. TRUE - the call has 1 outstanding lock count and the
  5089. LastProcessResponseTID is our TID. This means that we're
  5090. called from ProcessResponse (indirectly - through COM as
  5091. they complete the call on the thread that issues the
  5092. notification). If we return TRUE, we have already taken
  5093. the lock down and the caller should not remove any locks
  5094. FALSE - the call has no outstanding locks
  5095. If fUnlocked == FALSE
  5096. Undefined
  5097. --*/
  5098. {
  5099. ULONG CurrentThreadId = GetCurrentThreadId();
  5100. if (ResponseLockCount.GetInteger() == 0)
  5101. {
  5102. *fUnlocked = TRUE;
  5103. return FALSE;
  5104. }
  5105. else if ((ResponseLockCount.GetInteger() == 1)
  5106. && (LastProcessResponseTID == CurrentThreadId))
  5107. {
  5108. // If our caller has an outstanding lock and we free the call
  5109. // with the lock held, zero out the count on their behalf.
  5110. // In our caller we will notify the ultimate caller so that it
  5111. // doesn't double take away the lock.
  5112. ResponseLockCount.SetInteger(0);
  5113. // the only outstanding lock is by us in our caller - process
  5114. // response. Indicate to the caller that only our lock is
  5115. // active and it has been taken down.
  5116. *fUnlocked = TRUE;
  5117. return TRUE;
  5118. }
  5119. *fUnlocked = FALSE;
  5120. // The return value is meaningless. Arbitrarily, return FALSE.
  5121. return FALSE;
  5122. }
  5123. void
  5124. LRPC_CCALL::FreeCCall (
  5125. )
  5126. /*++
  5127. Routine Description:
  5128. We are done with this client call. We need to notify the binding
  5129. handle we are done.
  5130. --*/
  5131. {
  5132. LRPC_BINDING_HANDLE * BindingHandle;
  5133. THREAD *Thread;
  5134. ASSERT(CurrentBindingHandle != 0);
  5135. BindingHandle = CurrentBindingHandle;
  5136. CurrentBindingHandle = 0;
  5137. if (CurrentSecurityContext)
  5138. {
  5139. CurrentSecurityContext->RemoveReference();
  5140. CurrentSecurityContext = 0;
  5141. }
  5142. // if async, and there is EEInfo,
  5143. // transfer the EEInfo from the call to
  5144. // the thread
  5145. if (EEInfo)
  5146. {
  5147. Thread = RpcpGetThreadPointer();
  5148. RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
  5149. Thread->SetEEInfo(EEInfo);
  5150. EEInfo = NULL;
  5151. }
  5152. BindingHandle->FreeCCall(this);
  5153. }
  5154. void
  5155. LRPC_CCALL::ActuallyFreeBuffer (
  5156. IN void * Buffer
  5157. )
  5158. /*++
  5159. Routine Description:
  5160. Actually free a message buffer.
  5161. Arguments:
  5162. Buffer - Supplies the message buffer to be freed.
  5163. --*/
  5164. {
  5165. if (LpcReplyMessage && (Buffer == LpcReplyMessage->Rpc.Buffer))
  5166. {
  5167. FreeMessage(LpcReplyMessage) ;
  5168. LpcReplyMessage = 0;
  5169. }
  5170. else
  5171. {
  5172. if ((Buffer != LrpcMessage->Rpc.Buffer)
  5173. && ((CachedLrpcMessage == 0)
  5174. || (Buffer != CachedLrpcMessage->Rpc.Buffer)))
  5175. {
  5176. RpcpFarFree(Buffer);
  5177. }
  5178. }
  5179. }
  5180. RPC_STATUS
  5181. LRPC_CCALL::MakeServerCopyResponse (
  5182. )
  5183. /*++
  5184. Routine Description:
  5185. NtReadRequestData only works if the client has made a request. The client
  5186. wants to send a large buffer back as a response. We need to make a request
  5187. to the server so that it will copy the data.
  5188. Return Value:
  5189. RPC_S_OK - The server successfully copied the data.
  5190. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete the
  5191. operation.
  5192. --*/
  5193. {
  5194. #if defined(BUILD_WOW6432)
  5195. char PushMessageBuffer[sizeof(LRPC_PUSH_MESSAGE) + 8];
  5196. LRPC_PUSH_MESSAGE *PushMessagePtr = (LRPC_PUSH_MESSAGE *) AlignPtr8(PushMessageBuffer);
  5197. #else
  5198. LRPC_PUSH_MESSAGE PushMessageBuffer;
  5199. LRPC_PUSH_MESSAGE *PushMessagePtr = &PushMessageBuffer;
  5200. #endif
  5201. NTSTATUS NtStatus;
  5202. SanitizeLpcHeader (&PushMessagePtr->LpcHeader);
  5203. PushMessagePtr->LpcHeader.u1.s1.TotalLength =
  5204. sizeof(LRPC_PUSH_MESSAGE);
  5205. PushMessagePtr->LpcHeader.u1.s1.DataLength =
  5206. sizeof(LRPC_PUSH_MESSAGE) - sizeof(PORT_MESSAGE);
  5207. PushMessagePtr->LpcHeader.ClientId = ClientIdToMsgClientId(ClientId);
  5208. PushMessagePtr->LpcHeader.MessageId = MessageId;
  5209. PushMessagePtr->LpcHeader.CallbackId = CallbackId ;
  5210. PushMessagePtr->LpcHeader.u2.s2.Type = LPC_REQUEST;
  5211. PushMessagePtr->RpcHeader.MessageType = LRPC_MSG_PUSH;
  5212. // initialize unused fields. Zero out from the pad in RpcHeader to
  5213. // the end of the containing LRPC_PUSH_MESSAGE
  5214. RPCP_ZERO_OUT_STRUCT_TAIL (LRPC_PUSH_MESSAGE, PushMessagePtr, RpcHeader.Pad);
  5215. PushMessagePtr->Response.CountDataEntries = 1;
  5216. PushMessagePtr->Response.DataEntries[0] =
  5217. LrpcMessage->Rpc.Request.DataEntries[0];
  5218. PushMessagePtr->LpcHeader.u2.s2.DataInfoOffset = sizeof(PORT_MESSAGE)
  5219. + sizeof(LRPC_RPC_HEADER);
  5220. // Make sure we can't be impersonated on the transport level.
  5221. // A legitimate Lrpc server will never do this.
  5222. PushMessagePtr->LpcHeader.u2.s2.Type |= LPC_NO_IMPERSONATE;
  5223. if (Association->LpcClientPort)
  5224. {
  5225. NtStatus = NtRequestWaitReplyPort(Association->LpcClientPort,
  5226. (PORT_MESSAGE *) PushMessagePtr,
  5227. (PORT_MESSAGE *) PushMessagePtr);
  5228. }
  5229. else
  5230. {
  5231. NtStatus = STATUS_INVALID_PORT_HANDLE;
  5232. }
  5233. if (NT_ERROR(NtStatus))
  5234. {
  5235. // Assume that when the client tries to send the response it will
  5236. // fail as well, so just claim that everything worked.
  5237. #if DBG
  5238. if ((NtStatus != STATUS_NO_MEMORY)
  5239. && (NtStatus != STATUS_INSUFFICIENT_RESOURCES))
  5240. {
  5241. PrintToDebugger("RPC : NtRequestWaitReplyPort : %lx\n", NtStatus);
  5242. ASSERT(0);
  5243. }
  5244. #endif // DBG
  5245. return(RPC_S_OK);
  5246. }
  5247. VALIDATE(PushMessagePtr->RpcStatus)
  5248. {
  5249. RPC_S_OK,
  5250. RPC_S_OUT_OF_MEMORY
  5251. } END_VALIDATE;
  5252. return(PushMessagePtr->RpcStatus);
  5253. }
  5254. BINDING_HANDLE *
  5255. LrpcCreateBindingHandle (
  5256. )
  5257. /*++
  5258. Routine Description:
  5259. We just need to create a new LRPC_BINDING_HANDLE. This routine is a
  5260. proxy for the new constructor to isolate the other modules.
  5261. --*/
  5262. {
  5263. LRPC_BINDING_HANDLE * BindingHandle;
  5264. RPC_STATUS Status = RPC_S_OK;
  5265. Status = InitializeLrpcIfNecessary() ;
  5266. if (Status != RPC_S_OK)
  5267. {
  5268. return 0 ;
  5269. }
  5270. BindingHandle = new LRPC_BINDING_HANDLE(&Status);
  5271. if (Status != RPC_S_OK)
  5272. {
  5273. delete BindingHandle;
  5274. return(0);
  5275. }
  5276. return(BindingHandle);
  5277. }
  5278. void
  5279. LRPC_CASSOCIATION::LrpcDeleteLingeringAssociations (
  5280. void
  5281. )
  5282. /*++
  5283. Routine Description:
  5284. Will attempt to clean up lingering LRPC associations.
  5285. Return Value:
  5286. --*/
  5287. {
  5288. BOOL fMutexTaken;
  5289. LRPC_CASSOCIATION *CurrentAssociation;
  5290. LRPC_CASSOCIATION *NextAssociation;
  5291. LRPC_CASSOCIATION *FirstAssociation;
  5292. DictionaryCursor cursor;
  5293. DWORD CurrentTickCount;
  5294. int Diff;
  5295. // if there are no lrpc associations, return
  5296. if (!GlobalLrpcServer)
  5297. return;
  5298. fMutexTaken = LrpcMutexTryRequest();
  5299. if (!fMutexTaken)
  5300. {
  5301. // we couldn't cleanup anything - restore the flag
  5302. if (!GarbageCollectionRequested)
  5303. GarbageCollectionRequested = TRUE;
  5304. return;
  5305. }
  5306. FirstAssociation = NULL;
  5307. CurrentTickCount = GetTickCount();
  5308. // need to walk the dictionary and clean up all associations with
  5309. // expired timeouts
  5310. LrpcAssociationDict->Reset(cursor);
  5311. while ((CurrentAssociation = LrpcAssociationDict->Next(cursor)) != 0)
  5312. {
  5313. if (CurrentAssociation->Linger.fAssociationLingered)
  5314. {
  5315. // this will work even for wrapped tick count
  5316. Diff = (int)(CurrentTickCount - CurrentAssociation->Linger.Timestamp);
  5317. if (Diff > 0)
  5318. {
  5319. #if defined (RPC_GC_AUDIT)
  5320. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) LRPC association gc'ed %d ms after expire\n",
  5321. GetCurrentProcessId(), GetCurrentProcessId(), Diff);
  5322. #endif
  5323. // enlink the expired associations to a list - we'll clean it up
  5324. // later
  5325. CurrentAssociation->NextAssociation = FirstAssociation;
  5326. FirstAssociation = CurrentAssociation;
  5327. LrpcAssociationDict->Delete(CurrentAssociation->AssociationDictKey);
  5328. // indicate to the other threads (needed once we release the mutex)
  5329. // that this association is being cleaned up and they cannot call
  5330. // Delete on it
  5331. CurrentAssociation->AssociationDictKey = -1;
  5332. LrpcLingeredAssociations --;
  5333. }
  5334. else
  5335. {
  5336. // this item hasn't expired yet - update the first gc time, and
  5337. // raise the GarbageCollectionRequested flag if necessary
  5338. if ((int)(CurrentAssociation->Linger.Timestamp - NextOneTimeCleanup) < 0)
  5339. {
  5340. // there is a race between this thread and threads calling
  5341. // GarbageCollectionNeeded. Those threads may overwrite the
  5342. // value we're about to write, which can result in delayed
  5343. // garbage collection for this value - that's ok.
  5344. NextOneTimeCleanup = CurrentAssociation->Linger.Timestamp;
  5345. }
  5346. if (!GarbageCollectionRequested)
  5347. GarbageCollectionRequested = TRUE;
  5348. }
  5349. }
  5350. }
  5351. LrpcMutexClear();
  5352. // destroy the associations at our leasure
  5353. CurrentAssociation = FirstAssociation;
  5354. while (CurrentAssociation != NULL)
  5355. {
  5356. NextAssociation = CurrentAssociation->NextAssociation;
  5357. CurrentAssociation->Delete();
  5358. CurrentAssociation = NextAssociation;
  5359. }
  5360. }
  5361. int
  5362. InitializeRpcProtocolLrpc (
  5363. )
  5364. /*++
  5365. Routine Description:
  5366. For each process, this routine will be called once. All initialization
  5367. will be done here.
  5368. Return Value:
  5369. Zero will be returned if initialization completes successfully,
  5370. otherwise, non-zero will be returned.
  5371. --*/
  5372. {
  5373. if (LrpcAssociationDict == 0)
  5374. {
  5375. LrpcAssociationDict = new LRPC_CASSOCIATION_DICT;
  5376. if (LrpcAssociationDict == 0)
  5377. {
  5378. return(1);
  5379. }
  5380. }
  5381. return(0);
  5382. }
  5383. RPC_STATUS
  5384. LrpcMapRpcStatus (
  5385. IN RPC_STATUS Status
  5386. )
  5387. /*++
  5388. Routine Description:
  5389. Some NTSTATUS codes need to be mapped into RPC_STATUS codes before being
  5390. returned as a fault code. We take care of doing that mapping in this
  5391. routine.
  5392. --*/
  5393. {
  5394. switch (Status)
  5395. {
  5396. case STATUS_INTEGER_DIVIDE_BY_ZERO :
  5397. return(RPC_S_ZERO_DIVIDE);
  5398. case STATUS_ACCESS_VIOLATION :
  5399. case STATUS_ILLEGAL_INSTRUCTION :
  5400. return(RPC_S_ADDRESS_ERROR);
  5401. case STATUS_FLOAT_DIVIDE_BY_ZERO :
  5402. return(RPC_S_FP_DIV_ZERO);
  5403. case STATUS_FLOAT_UNDERFLOW :
  5404. return(RPC_S_FP_UNDERFLOW);
  5405. case STATUS_FLOAT_OVERFLOW :
  5406. return(RPC_S_FP_OVERFLOW);
  5407. }
  5408. return(Status);
  5409. }