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.

6366 lines
187 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1990 - 1999
  6. //
  7. // File: hndlsvr.cxx
  8. //
  9. //--------------------------------------------------------------------------
  10. /* --------------------------------------------------------------------
  11. Microsoft OS/2 LAN Manager
  12. Copyright(c) Microsoft Corp., 1990
  13. -------------------------------------------------------------------- */
  14. /* --------------------------------------------------------------------
  15. File : hndlsvr.cxx
  16. Description :
  17. This file contains the implementations of the classes defined in hndlsvr.hxx.
  18. These routines are independent of the actual RPC protocol / transport layer.
  19. In addition, these routines are also independent of the specific operating
  20. system in use.
  21. History :
  22. mikemon ??-??-?? Beginning of recorded history.
  23. mikemon 10-15-90 Changed the shutdown functionality to PauseExecution
  24. rather than suspending and resuming a thread.
  25. mikemon 12-28-90 Updated the comments to match reality.
  26. connieh 17-Feb-94 Created RPC_SERVER::RegisterRpcForwardFunction
  27. Kamen Moutafov (KamenM) Dec 99 - Feb 2000 - Support for cell debugging stuff
  28. -------------------------------------------------------------------- */
  29. #include <precomp.hxx>
  30. #include <queue.hxx>
  31. #include <Context.hxx>
  32. #include <SContext.hxx>
  33. #include <hndlsvr.hxx>
  34. #include <svrbind.hxx>
  35. #include <thrdctx.hxx>
  36. #include <rpcobj.hxx>
  37. #include <rpccfg.h>
  38. #include <sdict2.hxx>
  39. #include <dispatch.h>
  40. #include <queue.hxx>
  41. #include <lpcpack.hxx>
  42. #include <lpcsvr.hxx>
  43. extern LRPC_SERVER *GlobalLrpcServer ;
  44. #include <ProtBind.hxx>
  45. #include <osfpcket.hxx>
  46. #include <bitset.hxx>
  47. #include <osfclnt.hxx>
  48. #include <osfsvr.hxx>
  49. #include <dgpkt.hxx>
  50. #include <dgsvr.hxx>
  51. #include <sddl.h>
  52. //
  53. // The flags below are used with the RPC verifier.
  54. // They allow us to keep track of whether any remotely accessible interfaces
  55. // use weak security. If they do, we will print warnings.
  56. //
  57. // Set if an interface has been registered that is not secure.
  58. // An interface is considered secure iff it has been registred with a
  59. // RPC_IF_ALLOW_SECURE_ONLY flag or with a security callback.
  60. // All other interfaces are considered unsecure.
  61. BOOL gfUnsecureInterfaceRegistered;
  62. // Set if a protseq has been registred that makes
  63. // the server accessible remotely.
  64. BOOL gfRemoteProtseqRegistered;
  65. RPC_STATUS RPC_ENTRY
  66. DefaultCallbackFn (
  67. IN RPC_IF_HANDLE InterfaceUuid,
  68. IN void *Context
  69. )
  70. /*++
  71. Function Name:DefaultCallbackFn
  72. Parameters:
  73. Description:
  74. Returns:
  75. RPC_S_OK: Access is allowed
  76. other failures: Access is denied
  77. --*/
  78. {
  79. RPC_CALL_ATTRIBUTES CallAttributes;
  80. RPC_STATUS Status;
  81. CallAttributes.Version = RPC_CALL_ATTRIBUTES_VERSION;
  82. CallAttributes.Flags = 0;
  83. Status = RpcServerInqCallAttributesW(Context,
  84. &CallAttributes);
  85. if (Status != RPC_S_OK)
  86. return Status;
  87. if ((CallAttributes.AuthenticationService == RPC_C_AUTHN_NONE)
  88. || (CallAttributes.AuthenticationLevel == RPC_C_AUTHN_LEVEL_NONE)
  89. || (CallAttributes.NullSession)
  90. )
  91. {
  92. return RPC_S_ACCESS_DENIED;
  93. }
  94. return RPC_S_OK;
  95. }
  96. RPC_INTERFACE::RPC_INTERFACE (
  97. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
  98. IN RPC_SERVER * Server,
  99. IN unsigned int Flags,
  100. IN unsigned int MaxCalls,
  101. IN unsigned int MaxRpcSize,
  102. IN RPC_IF_CALLBACK_FN PAPI *IfCallbackFn,
  103. OUT RPC_STATUS *Status
  104. ) : NullManagerActiveCallCount(0), AutoListenCallCount(0), AutoListenCallNumber(0)
  105. /*++
  106. Routine Description:
  107. This method will get called to construct an instance of the
  108. RPC_INTERFACE class. We have got to make a copy of the rpc interface
  109. information supplied. The copy is necessary because we do not delete
  110. interfaces when they are unregistered. We just mark them as being
  111. inactive. In addition, we need to set the NullManagerFlag
  112. to zero, since this is used as the flag indicating whether we have
  113. got a manager for the NULL type UUID.
  114. Arguments:
  115. RpcInterfaceInformation - Supplies the rpc interface information
  116. which describes this interface.
  117. Server - Supplies the rpc server which owns this rpc interface.
  118. --*/
  119. {
  120. ALLOCATE_THIS(RPC_INTERFACE);
  121. unsigned int Length;
  122. PipeInterfaceFlag = 0;
  123. SequenceNumber = 1;
  124. #if DBG
  125. Strict = iuschDontKnow;
  126. #endif
  127. if (RpcInterfaceInformation->Length > sizeof(RPC_SERVER_INTERFACE) )
  128. {
  129. Length = sizeof(RPC_SERVER_INTERFACE);
  130. }
  131. else
  132. {
  133. Length = RpcInterfaceInformation->Length;
  134. }
  135. if ((RpcInterfaceInformation->Length > NT351_INTERFACE_SIZE)
  136. && (RpcInterfaceInformation->Flags & RPC_INTERFACE_HAS_PIPES))
  137. {
  138. PipeInterfaceFlag = 1;
  139. }
  140. RpcpMemoryCopy(&(this->RpcInterfaceInformation), RpcInterfaceInformation, Length);
  141. NullManagerFlag = 0;
  142. ManagerCount = 0;
  143. this->Server = Server;
  144. this->Flags = Flags;
  145. this->MaxCalls = MaxCalls;
  146. // By specifying a custom RPC size the user can override the gMaxRpcSize
  147. // call size limit. This is the only API that overrides the gMaxRpcSize default.
  148. this->MaxRpcSize = MaxRpcSize;
  149. fBindingsExported = 0;
  150. UuidVector = NULL;
  151. if (Flags & RPC_IF_ALLOW_SECURE_ONLY
  152. && IfCallbackFn == NULL)
  153. {
  154. this->CallbackFn = DefaultCallbackFn;
  155. }
  156. else
  157. {
  158. this->CallbackFn = IfCallbackFn ;
  159. }
  160. if (DoesInterfaceSupportMultipleTransferSyntaxes(RpcInterfaceInformation))
  161. {
  162. *Status = NdrServerGetSupportedSyntaxes(RpcInterfaceInformation,
  163. &NumberOfSupportedTransferSyntaxes,
  164. &TransferSyntaxesArray, &PreferredTransferSyntax);
  165. if (*Status != RPC_S_OK)
  166. return;
  167. }
  168. else
  169. {
  170. NumberOfSupportedTransferSyntaxes = 0;
  171. }
  172. *Status = RPC_S_OK;
  173. }
  174. RPC_STATUS
  175. RPC_INTERFACE::RegisterTypeManager (
  176. IN RPC_UUID PAPI * ManagerTypeUuid OPTIONAL,
  177. IN RPC_MGR_EPV PAPI * ManagerEpv OPTIONAL
  178. )
  179. /*++
  180. Routine Description:
  181. This method is used to register a type manager with this interface.
  182. If no type UUID is specified, or it is the NULL type UUID, we
  183. stick the manager entry point vector right in this instance (assuming
  184. that there is not already one), otherwise, we put it into the
  185. dictionary of interface manager objects.
  186. Arguments:
  187. ManagerTypeUuid - Optionally supplies the type UUID for the manager
  188. we want to register with this rpc interface. If no type UUID
  189. is supplied then the NULL type UUID is assumed.
  190. ManagerEpv - Supplies then entry point vector for this manager. This
  191. vector is used to dispatch from the stub to the application
  192. code.
  193. Return Values:
  194. RPC_S_OK - The type manager has been successfully added to this
  195. rpc interface.
  196. RPC_S_OUT_OF_MEMORY - Insufficient memory is availabe to add the
  197. type manager to the rpc interface.
  198. RPC_S_TYPE_ALREADY_REGISTERED - A manager entry point vector has
  199. already been registered for the this interface under the
  200. specified manager type UUID.
  201. --*/
  202. {
  203. RPC_INTERFACE_MANAGER * InterfaceManager;
  204. // First we need to check if the null UUID is being specified as
  205. // the type UUID; either, explicit or implicit by not specifying
  206. // a type UUID argument.
  207. RequestGlobalMutex();
  208. if ( (ARGUMENT_PRESENT(ManagerTypeUuid) == 0)
  209. || ( (ARGUMENT_PRESENT(ManagerTypeUuid) != 0)
  210. && (ManagerTypeUuid->IsNullUuid() != 0)))
  211. {
  212. if (NullManagerFlag != 0)
  213. {
  214. ClearGlobalMutex();
  215. return(RPC_S_TYPE_ALREADY_REGISTERED);
  216. }
  217. NullManagerEpv = ManagerEpv;
  218. NullManagerFlag = 1;
  219. ManagerCount += 1;
  220. ClearGlobalMutex();
  221. return(RPC_S_OK);
  222. }
  223. // If we reach here, a non-NULL type UUID is specified.
  224. InterfaceManager = FindInterfaceManager(ManagerTypeUuid);
  225. if (InterfaceManager == 0)
  226. {
  227. InterfaceManager = new RPC_INTERFACE_MANAGER(ManagerTypeUuid,
  228. ManagerEpv);
  229. if (InterfaceManager == 0)
  230. {
  231. ClearGlobalMutex();
  232. return(RPC_S_OUT_OF_MEMORY);
  233. }
  234. if (InterfaceManagerDictionary.Insert(InterfaceManager) == -1)
  235. {
  236. ClearGlobalMutex();
  237. delete InterfaceManager;
  238. return(RPC_S_OUT_OF_MEMORY);
  239. }
  240. ManagerCount += 1;
  241. ClearGlobalMutex();
  242. return(RPC_S_OK);
  243. }
  244. if (InterfaceManager->ValidManager() == 0)
  245. {
  246. InterfaceManager->SetManagerEpv(ManagerEpv);
  247. ManagerCount += 1;
  248. ClearGlobalMutex();
  249. return(RPC_S_OK);
  250. }
  251. ClearGlobalMutex();
  252. return(RPC_S_TYPE_ALREADY_REGISTERED);
  253. }
  254. RPC_INTERFACE_MANAGER *
  255. RPC_INTERFACE::FindInterfaceManager (
  256. IN RPC_UUID PAPI * ManagerTypeUuid
  257. )
  258. /*++
  259. Routine Description:
  260. This method is used to obtain the interface manager corresponding to
  261. the specified type UUID. The type UUID must not be the null UUID.
  262. Arguments:
  263. ManagerTypeUuid - Supplies the type UUID for which we are trying to
  264. find the interface manager.
  265. Return Value:
  266. If a interface manager for this type UUID is found, a pointer to it
  267. will be returned; otherwise, zero will be returned.
  268. --*/
  269. {
  270. RPC_INTERFACE_MANAGER * InterfaceManager;
  271. DictionaryCursor cursor;
  272. InterfaceManagerDictionary.Reset(cursor);
  273. while ((InterfaceManager = InterfaceManagerDictionary.Next(cursor)) != 0)
  274. {
  275. if (InterfaceManager->MatchTypeUuid(ManagerTypeUuid) == 0)
  276. return(InterfaceManager);
  277. }
  278. return(0);
  279. }
  280. RPC_STATUS
  281. RPC_INTERFACE::DispatchToStub (
  282. IN OUT PRPC_MESSAGE Message,
  283. IN unsigned int CallbackFlag,
  284. IN PRPC_DISPATCH_TABLE DispatchTableToUse,
  285. OUT RPC_STATUS PAPI * ExceptionCode
  286. )
  287. /*++
  288. Routine Description:
  289. This method is used to dispatch remote procedure calls to the
  290. appropriate stub and hence to the appropriate manager entry point.
  291. This routine is used for calls having a null UUID (implicit or
  292. explicit). We go to great pains to insure that we do not grab
  293. a mutex.
  294. Arguments:
  295. Message - Supplies the response message and returns the reply
  296. message.
  297. CallbackFlag - Supplies a flag indicating whether this is a callback
  298. or not. The argument will be zero if this is an original call,
  299. and non-zero if it is a callback.
  300. ExceptionCode - Returns the exact exception code if an exception
  301. occurs.
  302. Return Value:
  303. RPC_S_OK - This value will be returned if the operation completed
  304. successfully.
  305. RPC_S_PROCNUM_OUT_OF_RANGE - If the procedure number for this call is
  306. too large, this value will be returned.
  307. RPC_S_UNKNOWN_IF - If this interface does not exist, you will get this
  308. value back.
  309. RPC_S_NOT_LISTENING - The rpc server which owns this rpc interface
  310. is not listening for remote procedure calls right now.
  311. RPC_S_SERVER_TOO_BUSY - This call will cause there to be too many
  312. concurrent remote procedure calls for the rpc server which owns
  313. this interface.
  314. RPC_P_EXCEPTION_OCCURED - A fault occured, and we need to remote it. The
  315. ExceptionCode argument will contain the exception code for the
  316. fault.
  317. RPC_S_UNSUPPORTED_TYPE - This interface exists, but does not have a manager
  318. for the null type.
  319. --*/
  320. {
  321. RPC_STATUS RpcStatus = RPC_S_OK;
  322. if ( CallbackFlag == 0 )
  323. {
  324. //
  325. // AutoListen and NullManager call counts.
  326. //
  327. // Async calls require 2 counts. Sync calls require only 1 count.
  328. // The first count is the same in both sync and async.
  329. //
  330. // For async calls:
  331. //
  332. // - The first count is added in: RPC_INTERFACE::DispatchToStub iff CallbackFlag == 0
  333. // - The second count is added in: SetAsyncHandle iff the execution of the procedure
  334. // has been successful and pAsync hads been initialized.
  335. // - The first count is removed in: RPC_INTERFACE::DispatchToStub after returning
  336. // from DispatchToStubWorker. At this point the second ref count may or may not have been set
  337. // depending on whether an exception was raised by NDR and how SetAsyncHandle has executed.
  338. // - The second count will be removed only if the async handle was set. We will check
  339. // this and decrement when freeing the call in FreeSCall/CleanupCall. For lrpc, the call
  340. // is always cached and freed via FreeSCall. For OSF, the call may pass through FreeSCall
  341. // if it is "really" being freed or through OSF_SCALL::CleanupCall if it will be cached.
  342. // We need to decrement the counts in all of these cases.
  343. //
  344. // The counts are independent of the number of calls since a call can hold 1 or 2 counts.
  345. //
  346. if (IsAutoListenInterface())
  347. {
  348. // Since this is the dispatch path we need to increment the CallNumber.
  349. BeginAutoListenCall(TRUE);
  350. }
  351. BeginNullManagerCall();
  352. if ( NullManagerFlag == 0 )
  353. {
  354. RpcStatus = RPC_S_UNSUPPORTED_TYPE;
  355. RpcpErrorAddRecord(EEInfoGCRuntime,
  356. RpcStatus,
  357. EEInfoDLDispatchToStub10);
  358. if ( ManagerCount == 0 )
  359. {
  360. RpcStatus = RPC_S_UNKNOWN_IF;
  361. RpcpErrorAddRecord(EEInfoGCRuntime,
  362. RpcStatus,
  363. EEInfoDLDispatchToStub20);
  364. }
  365. }
  366. }
  367. if (RpcStatus != RPC_S_OK)
  368. {
  369. // We can only fail here if NullManagerFlag != 0 above.
  370. ASSERT(RpcStatus == RPC_S_UNSUPPORTED_TYPE || RpcStatus == RPC_S_UNKNOWN_IF);
  371. ((MESSAGE_OBJECT *) Message->Handle)->FreeBuffer(Message);
  372. EndNullManagerCall();
  373. if (IsAutoListenInterface())
  374. {
  375. // Decrement the CallNumber since from the user's perspective the call has completed
  376. // after the exception is raised.
  377. EndAutoListenCall(TRUE);
  378. }
  379. return RpcStatus;
  380. }
  381. Message->ManagerEpv = NullManagerEpv;
  382. RpcStatus = DispatchToStubWorker(Message, CallbackFlag, DispatchTableToUse, ExceptionCode);
  383. // If either we failed, or this is a sync call and not a callback,
  384. // decrement the refcount on the interface.
  385. if (CallbackFlag == 0)
  386. {
  387. EndNullManagerCall(); // We always increment this count if the call gets this far.
  388. if (IsAutoListenInterface())
  389. {
  390. // This is the path on which sync calls complete, from the user's perspective.
  391. // We need to decrement the CallNumber for sync calls.
  392. // We determine whether the call is sync by looking at fAsync thread flag which is
  393. // set in SetAsyncHandle. If the flag is set then pAsync is set also,
  394. // we will notice this in call cleanup and decrement the call number there.
  395. EndAutoListenCall(RpcpGetThreadPointer()->IsSyncCall());
  396. }
  397. }
  398. //
  399. // DispatchToStubWorker freed Message.Buffer if an error occurred.
  400. //
  401. return(RpcStatus);
  402. }
  403. RPC_STATUS
  404. RPC_INTERFACE::DispatchToStubWorker (
  405. IN OUT PRPC_MESSAGE Message,
  406. IN unsigned int CallbackFlag,
  407. IN PRPC_DISPATCH_TABLE DispatchTableToUse,
  408. OUT RPC_STATUS PAPI * ExceptionCode
  409. )
  410. /*++
  411. Routine Description:
  412. This method is used to dispatch remote procedure calls to the
  413. appropriate stub and hence to the appropriate manager entry point.
  414. It will be used for calls with and without objects specified.
  415. We go to great pains to insure that we do not grab a mutex.
  416. Arguments:
  417. Message - Supplies the response message and returns the reply
  418. message. If this routine returns anything other than RPC_S_OK
  419. Message->Buffer has already been freed.
  420. CallbackFlag - Supplies a flag indicating whether this is a callback
  421. or not. The argument will be zero if this is an original call,
  422. and non-zero if it is a callback.
  423. DispatchTableToUse - a pointer to the dispatch table to use. This is
  424. used to select b/n stubs for NDR20 and NDR64 transfer syntaxes
  425. ExceptionCode - Returns the exact exception code if an exception
  426. occurs.
  427. Return Value:
  428. RPC_S_OK - This value will be returned if the operation completed
  429. successfully.
  430. RPC_S_PROCNUM_OUT_OF_RANGE - If the procedure number for this call is
  431. too large, this value will be returned.
  432. RPC_S_NOT_LISTENING - The rpc server which owns this rpc interface
  433. is not listening for remote procedure calls right now.
  434. RPC_S_SERVER_TOO_BUSY - This call will cause there to be too many
  435. concurrent remote procedure calls for the rpc server which owns
  436. this interface.
  437. RPC_P_EXCEPTION_OCCURED - A fault occured, and we need to remote it. The
  438. ExceptionCode argument will contain the exception code for the
  439. fault.
  440. --*/
  441. {
  442. RPC_STATUS RpcStatus = RPC_S_OK;
  443. void * OldServerContextList;
  444. unsigned int procnum ;
  445. THREAD *Self = RpcpGetThreadPointer() ;
  446. ASSERT(Self);
  447. if (Flags & RPC_IF_OLE)
  448. {
  449. procnum = 0 ;
  450. }
  451. else
  452. {
  453. procnum = Message->ProcNum ;
  454. }
  455. if (CallbackFlag == 0)
  456. {
  457. if (IsAutoListenInterface())
  458. {
  459. if (AutoListenCallNumber.GetInteger() > (long) MaxCalls)
  460. {
  461. RpcStatus = RPC_S_SERVER_TOO_BUSY ;
  462. RpcpErrorAddRecord(EEInfoGCRuntime,
  463. RpcStatus,
  464. EEInfoDLDispatchToStubWorker10,
  465. (ULONG)AutoListenCallNumber.GetInteger(),
  466. (ULONG)MaxCalls);
  467. }
  468. }
  469. else
  470. {
  471. if (Server->IsServerListening() == 0)
  472. {
  473. RpcStatus = RPC_S_NOT_LISTENING;
  474. RpcpErrorAddRecord(EEInfoGCRuntime,
  475. RpcStatus,
  476. EEInfoDLDispatchToStubWorker20);
  477. }
  478. else if (Server->fAccountForMaxCalls && Server->CallBeginning() == 0)
  479. {
  480. RpcStatus = RPC_S_SERVER_TOO_BUSY;
  481. RpcpErrorAddRecord(EEInfoGCRuntime,
  482. RpcStatus,
  483. EEInfoDLDispatchToStubWorker30);
  484. }
  485. }
  486. }
  487. if (procnum >=
  488. DispatchTableToUse->DispatchTableCount)
  489. {
  490. if (RpcStatus != RPC_S_SERVER_TOO_BUSY)
  491. {
  492. EndCall(CallbackFlag) ;
  493. }
  494. RpcStatus = RPC_S_PROCNUM_OUT_OF_RANGE;
  495. RpcpErrorAddRecord(EEInfoGCRuntime,
  496. RpcStatus,
  497. EEInfoDLDispatchToStubWorker40);
  498. }
  499. if (RpcStatus != RPC_S_OK)
  500. {
  501. MO(Message)->FreeBuffer(Message);
  502. return RpcStatus;
  503. }
  504. Server->IncomingCall();
  505. ((PRPC_RUNTIME_INFO) Message->ReservedForRuntime)->OldBuffer =
  506. Message->Buffer ;
  507. Message->RpcInterfaceInformation = &RpcInterfaceInformation;
  508. SCALL(Message)->DoPreDispatchProcessing(Message, CallbackFlag);
  509. if ( DispatchToStubInC(DispatchTableToUse->DispatchTable[procnum], Message, ExceptionCode) != 0 )
  510. {
  511. LogEvent(SU_EXCEPT, EV_STATUS, LongToPtr(*ExceptionCode),
  512. DispatchTableToUse->DispatchTable[procnum], (ULONG_PTR)Message, 1, 1);
  513. RpcStatus = RPC_P_EXCEPTION_OCCURED;
  514. RpcpErrorAddRecord(EEInfoGCApplication,
  515. *ExceptionCode,
  516. EEInfoDLRaiseExc,
  517. GetInterfaceFirstDWORD(),
  518. (short)procnum,
  519. Message->RpcFlags,
  520. GetCurrentThreadId());
  521. }
  522. RPC_MESSAGE OriginalMessage ;
  523. OriginalMessage.ReservedForRuntime = 0;
  524. OriginalMessage.Buffer =
  525. ((PRPC_RUNTIME_INFO) Message->ReservedForRuntime)->OldBuffer;
  526. Self->ResetYield();
  527. if (Self->IsSyncCall())
  528. {
  529. //
  530. // Since this is a sync call, we know that it has
  531. // not been freed yet. So we can safely touch it.
  532. //
  533. SCALL(Message)->DoPostDispatchProcessing();
  534. //
  535. // The dispatched call was a sync call
  536. //
  537. if (RPC_S_OK == RpcStatus)
  538. {
  539. //
  540. // If the stub didn't allocate an output buffer, do so now.
  541. //
  542. if (OriginalMessage.Buffer == Message->Buffer)
  543. {
  544. Message->RpcFlags = 0;
  545. Message->BufferLength = 0;
  546. MO(Message)->GetBuffer(Message, 0);
  547. }
  548. //
  549. // Free the [in] buffer that we saved.
  550. //
  551. MO(Message)->FreeBuffer(&OriginalMessage);
  552. EndCall(CallbackFlag) ;
  553. }
  554. else
  555. {
  556. ASSERT(RpcStatus == RPC_P_EXCEPTION_OCCURED) ;
  557. //
  558. // Free the buffer in the caller's message; this can be either
  559. // the [in] buffer or the [out] buffer, depending upon which
  560. // line of the stub caused the error.
  561. //
  562. // If the exception occurred after allocating the [out] buffer,
  563. // also free the [in] buffer.
  564. //
  565. if (OriginalMessage.Buffer != Message->Buffer)
  566. {
  567. MO(Message)->FreeBuffer(&OriginalMessage);
  568. }
  569. if (Message->Buffer)
  570. {
  571. MO(Message)->FreeBuffer(Message);
  572. }
  573. EndCall(CallbackFlag) ;
  574. }
  575. }
  576. else
  577. {
  578. //
  579. // The dispatched call was an async call
  580. //
  581. if (RpcStatus != RPC_S_OK
  582. && OriginalMessage.Buffer != Message->Buffer)
  583. {
  584. //
  585. // The dispatch buffer will be freed during cleanup
  586. // of the async call
  587. //
  588. MO(Message)->FreeBuffer(Message);
  589. }
  590. }
  591. return(RpcStatus);
  592. }
  593. void
  594. RPC_INTERFACE::EndCall(
  595. IN unsigned int CallbackFlag,
  596. BOOL fAsync
  597. )
  598. {
  599. if (fAsync)
  600. {
  601. EndNullManagerCall();
  602. }
  603. if (CallbackFlag == 0)
  604. {
  605. if (!(Flags & RPC_IF_AUTOLISTEN) && Server->fAccountForMaxCalls)
  606. {
  607. Server->CallEnding();
  608. }
  609. }
  610. }
  611. RPC_STATUS
  612. RPC_INTERFACE::DispatchToStubWithObject (
  613. IN OUT PRPC_MESSAGE Message,
  614. IN RPC_UUID * ObjectUuid,
  615. IN unsigned int CallbackFlag,
  616. IN PRPC_DISPATCH_TABLE DispatchTableToUse,
  617. OUT RPC_STATUS PAPI * ExceptionCode
  618. )
  619. /*++
  620. Routine Description:
  621. This method is used to dispatch remote procedure calls to the
  622. appropriate stub and hence to the appropriate manager entry point.
  623. This routine is used for calls which have an associated object.
  624. Arguments:
  625. Message - Supplies the response message and returns the reply
  626. message.
  627. ObjectUuid - Supplies the object uuid to map into the manager entry
  628. point for this call.
  629. CallbackFlag - Supplies a flag indicating whether this is a callback
  630. or not. The argument will be zero if this is an original call,
  631. and non-zero if it is a callback.
  632. ExceptionCode - Returns the exact exception code if an exception
  633. occurs.
  634. Return Value:
  635. RPC_S_OK - The operation completed successfully.
  636. RPC_S_PROCNUM_OUT_OF_RANGE - If the procedure number for this call is
  637. too large, this value will be returned.
  638. RPC_S_UNKNOWN_IF - If the specified manager is no longer
  639. valid, you will get this value back.
  640. RPC_S_NOT_LISTENING - The rpc server which owns this rpc interface
  641. is not listening for remote procedure calls right now.
  642. RPC_S_SERVER_TOO_BUSY - This call will cause there to be too many
  643. concurrent remote procedure calls for the rpc server which owns
  644. this interface.
  645. RPC_P_EXCEPTION_OCCURED - A fault occured, and we need to remote it. The
  646. ExceptionCode argument will contain the exception code for the
  647. fault.
  648. RPC_S_UNSUPPORTED_TYPE - There is no type manager for the object's type
  649. for this interface.
  650. --*/
  651. {
  652. RPC_UUID TypeUuid;
  653. RPC_STATUS RpcStatus;
  654. RPC_INTERFACE_MANAGER * RpcInterfaceManager;
  655. RpcStatus = ObjectInqType(ObjectUuid, &TypeUuid);
  656. VALIDATE(RpcStatus)
  657. {
  658. RPC_S_OK,
  659. RPC_S_OBJECT_NOT_FOUND
  660. } END_VALIDATE;
  661. if ( RpcStatus == RPC_S_OK )
  662. {
  663. RpcInterfaceManager = FindInterfaceManager(&TypeUuid);
  664. if ( ( RpcInterfaceManager != 0 )
  665. && ( ( CallbackFlag != 0 )
  666. || ( RpcInterfaceManager->ValidManager() != 0 ) ) )
  667. {
  668. Message->ManagerEpv = RpcInterfaceManager->QueryManagerEpv();
  669. if ( CallbackFlag == 0 )
  670. {
  671. RpcInterfaceManager->CallBeginning();
  672. }
  673. RpcStatus = DispatchToStubWorker(Message, CallbackFlag, DispatchTableToUse,
  674. ExceptionCode);
  675. if ( CallbackFlag == 0 )
  676. {
  677. RpcInterfaceManager->CallEnding();
  678. }
  679. return(RpcStatus);
  680. }
  681. if (this != GlobalManagementInterface)
  682. {
  683. // There is a type for this object, but no type manager for
  684. // this interface.
  685. RpcStatus = RPC_S_UNSUPPORTED_TYPE;
  686. if ( ManagerCount == 0 )
  687. {
  688. RpcStatus = RPC_S_UNKNOWN_IF;
  689. }
  690. ((MESSAGE_OBJECT *) Message->Handle)->FreeBuffer(Message);
  691. return RpcStatus;
  692. }
  693. }
  694. // There has not been a type registered for this object, so we will
  695. // just go ahead and try and use the NULL type manager.
  696. return(DispatchToStub(Message, CallbackFlag, DispatchTableToUse, ExceptionCode));
  697. }
  698. BOOL
  699. RPC_INTERFACE::IsObjectSupported (
  700. IN RPC_UUID * ObjectUuid
  701. )
  702. /*++
  703. Routine Description:
  704. Determines whether the manager for the given object UUID is registered.
  705. Arguments:
  706. ObjectUuid - the client's object UUID
  707. Return Value:
  708. RPC_S_OK if it is OK to dispatch
  709. RPC_S_UNKNOWN_IF if the interface is not registered
  710. RPC_S_UNSUPPORTED_TYPE if this particular object's type is not registered
  711. --*/
  712. {
  713. RPC_STATUS Status = RPC_S_OK;
  714. if (ObjectUuid->IsNullUuid() )
  715. {
  716. if ( NullManagerFlag == 0 )
  717. {
  718. Status = RPC_S_UNSUPPORTED_TYPE;
  719. if ( ManagerCount == 0 )
  720. {
  721. Status = RPC_S_UNKNOWN_IF;
  722. }
  723. }
  724. }
  725. else
  726. {
  727. RPC_UUID TypeUuid;
  728. Status = ObjectInqType(ObjectUuid, &TypeUuid);
  729. if ( Status == RPC_S_OK )
  730. {
  731. RPC_INTERFACE_MANAGER * RpcInterfaceManager = 0;
  732. RpcInterfaceManager = FindInterfaceManager(&TypeUuid);
  733. if (!RpcInterfaceManager ||
  734. !RpcInterfaceManager->ValidManager())
  735. {
  736. Status = RPC_S_UNSUPPORTED_TYPE;
  737. if ( ManagerCount == 0 )
  738. {
  739. Status = RPC_S_UNKNOWN_IF;
  740. }
  741. }
  742. }
  743. else
  744. {
  745. Status = RPC_S_OK;
  746. if ( NullManagerFlag == 0 )
  747. {
  748. Status = RPC_S_UNSUPPORTED_TYPE;
  749. if ( ManagerCount == 0 )
  750. {
  751. Status = RPC_S_UNKNOWN_IF;
  752. }
  753. }
  754. }
  755. }
  756. return Status;
  757. }
  758. RPC_STATUS
  759. RPC_INTERFACE::UpdateBindings (
  760. IN RPC_BINDING_VECTOR *BindingVector
  761. )
  762. /*++
  763. Function Name:UpdateEpMapperBindings
  764. Parameters:
  765. Description:
  766. Returns:
  767. --*/
  768. {
  769. RPC_STATUS Status;
  770. unsigned int Length;
  771. #if !defined(NO_LOCATOR_CODE)
  772. NS_ENTRY *NsEntry;
  773. #endif
  774. DictionaryCursor cursor;
  775. if (fBindingsExported)
  776. {
  777. Status = RegisterEntries(&RpcInterfaceInformation,
  778. BindingVector,
  779. UuidVector,
  780. (unsigned char *) Annotation,
  781. fReplace);
  782. if (Status != RPC_S_OK)
  783. {
  784. return Status;
  785. }
  786. }
  787. #if !defined(NO_LOCATOR_CODE)
  788. // shortcut the common path and avoid taking and holding
  789. // unnecessarily the high contention global mutex
  790. if (NsEntries.Size() == 0)
  791. return RPC_S_OK;
  792. RequestGlobalMutex();
  793. NsEntries.Reset(cursor);
  794. while ((NsEntry = NsEntries.Next(cursor)) != 0)
  795. {
  796. //
  797. // Actually update the locator bindings
  798. //
  799. Status = GlobalRpcServer->NsBindingUnexport(
  800. NsEntry->EntryNameSyntax,
  801. NsEntry->EntryName,
  802. &RpcInterfaceInformation);
  803. if (Status == RPC_S_OK)
  804. {
  805. Status = GlobalRpcServer->NsBindingExport(
  806. NsEntry->EntryNameSyntax,
  807. NsEntry->EntryName,
  808. &RpcInterfaceInformation,
  809. BindingVector);
  810. #if DBG
  811. if (Status != RPC_S_OK)
  812. {
  813. PrintToDebugger("RPC: Bindings were unexported, but could not re-export\n");
  814. }
  815. #endif
  816. }
  817. }
  818. ClearGlobalMutex();
  819. #endif
  820. return RPC_S_OK;
  821. }
  822. RPC_STATUS
  823. RPC_INTERFACE::InterfaceExported (
  824. IN UUID_VECTOR *MyObjectUuidVector,
  825. IN unsigned char *MyAnnotation,
  826. IN BOOL MyfReplace
  827. )
  828. /*++
  829. Function Name:InterfaceExported
  830. Parameters:
  831. Description:
  832. RpcEpRegister was called on this interface. We need to keep track
  833. of the parameters, so that if we get a PNP notification, we can update
  834. the bindings using there params
  835. Returns:
  836. RPC_S_OK: things went fine
  837. RPC_S_OUT_OF_MEMORY: ran out of memory
  838. --*/
  839. {
  840. RequestGlobalMutex();
  841. if (UuidVector
  842. && UuidVector != MyObjectUuidVector)
  843. {
  844. RpcpFarFree(UuidVector);
  845. UuidVector = 0;
  846. }
  847. if (MyObjectUuidVector)
  848. {
  849. if (UuidVector != MyObjectUuidVector)
  850. {
  851. int Size = MyObjectUuidVector->Count*(sizeof(UUID)+sizeof(UUID *))
  852. +sizeof(unsigned long);
  853. UUID *Uuids;
  854. unsigned i;
  855. UuidVector = (UUID_VECTOR *) RpcpFarAllocate(Size);
  856. if (UuidVector == 0)
  857. {
  858. ClearGlobalMutex();
  859. return RPC_S_OUT_OF_MEMORY;
  860. }
  861. Uuids = (UUID *) ((char *) UuidVector + sizeof(unsigned long)
  862. +(sizeof(UUID *) * MyObjectUuidVector->Count));
  863. UuidVector->Count = MyObjectUuidVector->Count;
  864. for (i = 0; i < UuidVector->Count; i++)
  865. {
  866. Uuids[i] = *(MyObjectUuidVector->Uuid[i]);
  867. UuidVector->Uuid[i] = &Uuids[i];
  868. }
  869. }
  870. }
  871. else
  872. {
  873. UuidVector = 0;
  874. }
  875. if (MyAnnotation)
  876. {
  877. strncpy((char *) Annotation, (char *) MyAnnotation, 63);
  878. Annotation[63]=0;
  879. }
  880. else
  881. {
  882. Annotation[0] = 0;
  883. }
  884. fReplace = MyfReplace;
  885. fBindingsExported = 1;
  886. ClearGlobalMutex();
  887. return RPC_S_OK;
  888. }
  889. #if !defined(NO_LOCATOR_CODE)
  890. NS_ENTRY *
  891. RPC_INTERFACE::FindEntry (
  892. IN unsigned long EntryNameSyntax,
  893. IN RPC_CHAR *EntryName
  894. )
  895. {
  896. NS_ENTRY *NsEntry;
  897. DictionaryCursor cursor;
  898. //
  899. // This function will always be called with the mutex held
  900. //
  901. NsEntries.Reset(cursor);
  902. while ((NsEntry = NsEntries.Next(cursor)) != 0)
  903. {
  904. if (NsEntry->Match(EntryNameSyntax, EntryName))
  905. {
  906. return NsEntry;
  907. }
  908. }
  909. return 0;
  910. }
  911. RPC_STATUS
  912. RPC_INTERFACE::NsInterfaceUnexported (
  913. IN unsigned long EntryNameSyntax,
  914. IN RPC_CHAR *EntryName
  915. )
  916. {
  917. NS_ENTRY *NsEntry;
  918. RequestGlobalMutex();
  919. NsEntry = FindEntry(EntryNameSyntax, EntryName);
  920. if (NsEntry == 0)
  921. {
  922. ClearGlobalMutex();
  923. #if DBG
  924. PrintToDebugger("RPC: No corresponding exported entry\n");
  925. #endif
  926. return RPC_S_ENTRY_NOT_FOUND;
  927. }
  928. NsEntries.Delete(NsEntry->Key);
  929. ClearGlobalMutex();
  930. return RPC_S_OK;
  931. }
  932. RPC_STATUS
  933. RPC_INTERFACE::NsInterfaceExported (
  934. IN unsigned long EntryNameSyntax,
  935. IN RPC_CHAR *EntryName
  936. )
  937. {
  938. RPC_STATUS Status = RPC_S_OK;
  939. NS_ENTRY *NsEntry;
  940. int retval;
  941. RequestGlobalMutex();
  942. NsEntry = FindEntry(EntryNameSyntax, EntryName);
  943. ClearGlobalMutex();
  944. if (NsEntry)
  945. {
  946. return RPC_S_OK;
  947. }
  948. NsEntry = new NS_ENTRY(
  949. EntryNameSyntax,
  950. EntryName,
  951. &Status);
  952. if (NsEntry == 0)
  953. {
  954. return RPC_S_OUT_OF_MEMORY;
  955. }
  956. if (Status != RPC_S_OK)
  957. {
  958. delete NsEntry;
  959. return Status;
  960. }
  961. RequestGlobalMutex();
  962. NsEntry->Key = NsEntries.Insert(NsEntry);
  963. ClearGlobalMutex();
  964. if (NsEntry->Key == -1)
  965. {
  966. delete NsEntry;
  967. return RPC_S_OUT_OF_MEMORY;
  968. }
  969. return RPC_S_OK;
  970. }
  971. #endif
  972. static unsigned int
  973. MatchSyntaxIdentifiers (
  974. IN PRPC_SYNTAX_IDENTIFIER ServerSyntax,
  975. IN PRPC_SYNTAX_IDENTIFIER ClientSyntax
  976. )
  977. /*++
  978. Routine Description:
  979. This method compares two syntax identifiers (which consist of a
  980. uuid, a major version number, and a minor version number). In
  981. order for the syntax identifiers to match, the uuids must be the
  982. same, the major version numbers must be the same, and the client
  983. minor version number must be less than or equal to the server
  984. minor version number.
  985. Arguments:
  986. ServerSyntax - Supplies the server syntax identifier.
  987. ClientSyntax - Supplies the client syntax identifer.
  988. Return Value:
  989. Zero will be returned if the client syntax identifier matches the
  990. server syntax identifier; otherwise, non-zero will be returned.
  991. --*/
  992. {
  993. if (RpcpMemoryCompare(&(ServerSyntax->SyntaxGUID),
  994. &(ClientSyntax->SyntaxGUID), sizeof(UUID)) != 0)
  995. return(1);
  996. if (ServerSyntax->SyntaxVersion.MajorVersion
  997. != ClientSyntax->SyntaxVersion.MajorVersion)
  998. return(1);
  999. if (ServerSyntax->SyntaxVersion.MinorVersion
  1000. < ClientSyntax->SyntaxVersion.MinorVersion)
  1001. return(1);
  1002. return(0);
  1003. }
  1004. unsigned int
  1005. RPC_INTERFACE::MatchInterfaceIdentifier (
  1006. IN PRPC_SYNTAX_IDENTIFIER InterfaceIdentifier
  1007. )
  1008. /*++
  1009. Routine Description:
  1010. This method compares the supplied interface identifier (which consists
  1011. of the interface uuid and interface version) against that contained
  1012. in this rpc interface. In order for this rpc interface to match,
  1013. the interface uuids must be the same, the interface major versions
  1014. must be the same, and the supplied interface minor version must be
  1015. less than or equal to the interface minor version contained in this
  1016. rpc interface.
  1017. Arguments:
  1018. InterfaceIdentifier - Supplies the interface identifier to compare
  1019. against that contained in this rpc interface.
  1020. Return Value:
  1021. Zero will be returned if the supplied interface identifer matches
  1022. (according to the rules described above) the interface identifier
  1023. contained in this rpc interface; otherwise, non-zero will be returned.
  1024. --*/
  1025. {
  1026. if (ManagerCount == 0)
  1027. return(1);
  1028. return(MatchSyntaxIdentifiers(&(RpcInterfaceInformation.InterfaceId),
  1029. InterfaceIdentifier));
  1030. }
  1031. unsigned int
  1032. RPC_INTERFACE::SelectTransferSyntax (
  1033. IN PRPC_SYNTAX_IDENTIFIER ProposedTransferSyntaxes,
  1034. IN unsigned int NumberOfTransferSyntaxes,
  1035. OUT PRPC_SYNTAX_IDENTIFIER AcceptedTransferSyntax,
  1036. OUT BOOL *fIsInterfaceTransferPreferred,
  1037. OUT int *ProposedTransferSyntaxIndex,
  1038. OUT int *AvailableTransferSyntaxIndex
  1039. )
  1040. /*++
  1041. Routine Description:
  1042. This method is used to select a transfer syntax from a list of one
  1043. or more transfer syntaxes. If a transfer syntax is selected, then
  1044. it will be returned in one of the arguments.
  1045. Arguments:
  1046. ProposedTransferSyntaxes - Supplies a list of one or more transfer
  1047. syntaxes from which this interface should select one which it
  1048. supports if possible.
  1049. NumberOfTransferSyntaxes - Supplies the number of transfer syntaxes
  1050. in the proposed transfer syntaxes argument.
  1051. AcceptedTransferSyntax - Returns the selected transfer syntax, if
  1052. one is selected.
  1053. fIsInterfaceTransferPreferred - true if the selected transfer syntax
  1054. is preferred by the server
  1055. ProposedTransferSyntaxIndex - the index of the transfer syntax that is
  1056. chosen from the proposed transfer syntaxes array. Zero based.
  1057. AvailableTransferSyntaxIndex - the index of the transfer syntax that is
  1058. chosen from the available transfer syntaxes in the interface. This
  1059. value must be stored in the binding and retrieved when asking for the
  1060. transfer syntax and dispatch table. Zero based.
  1061. Return Value:
  1062. Zero will be returned if a transfer syntax is selected; otherwise,
  1063. non-zero will be returned.
  1064. --*/
  1065. {
  1066. unsigned int ProposedIndex;
  1067. unsigned int AvailableIndex;
  1068. unsigned int NumberOfAvailableSyntaxes;
  1069. BOOL fMultipleTranfserSyntaxesSelected;
  1070. RPC_SYNTAX_IDENTIFIER *CurrentTransferSyntax;
  1071. RPC_SYNTAX_IDENTIFIER *BackupTransferSyntax = NULL;
  1072. int BackupProposedTransferSyntaxIndex;
  1073. int BackupAvailableTransferSyntaxIndex;
  1074. fMultipleTranfserSyntaxesSelected = AreMultipleTransferSyntaxesSupported();
  1075. if (fMultipleTranfserSyntaxesSelected)
  1076. NumberOfAvailableSyntaxes = NumberOfSupportedTransferSyntaxes;
  1077. else
  1078. NumberOfAvailableSyntaxes = 1;
  1079. for (AvailableIndex = 0; AvailableIndex < NumberOfAvailableSyntaxes; AvailableIndex ++)
  1080. {
  1081. if (fMultipleTranfserSyntaxesSelected)
  1082. CurrentTransferSyntax = &(TransferSyntaxesArray[AvailableIndex].TransferSyntax);
  1083. else
  1084. CurrentTransferSyntax = &RpcInterfaceInformation.TransferSyntax;
  1085. for (ProposedIndex = 0; ProposedIndex < NumberOfTransferSyntaxes;
  1086. ProposedIndex++)
  1087. {
  1088. if (MatchSyntaxIdentifiers(CurrentTransferSyntax,
  1089. &(ProposedTransferSyntaxes[ProposedIndex])) == 0)
  1090. {
  1091. // is this the preferred transfer syntax for the server?
  1092. if (AvailableIndex == PreferredTransferSyntax)
  1093. {
  1094. // this is the preferred transfer syntax - just
  1095. // copy it and return
  1096. RpcpMemoryCopy(AcceptedTransferSyntax,
  1097. &(ProposedTransferSyntaxes[ProposedIndex]),
  1098. sizeof(RPC_SYNTAX_IDENTIFIER));
  1099. *fIsInterfaceTransferPreferred = TRUE;
  1100. *ProposedTransferSyntaxIndex = ProposedIndex;
  1101. *AvailableTransferSyntaxIndex = AvailableIndex;
  1102. return(0);
  1103. }
  1104. else
  1105. {
  1106. // this is not the preferred syntax - just remeber this
  1107. // one (if no previous match was found) and continue
  1108. if (BackupTransferSyntax == NULL)
  1109. {
  1110. BackupTransferSyntax = &(ProposedTransferSyntaxes[ProposedIndex]);
  1111. BackupProposedTransferSyntaxIndex = ProposedIndex;
  1112. BackupAvailableTransferSyntaxIndex = AvailableIndex;
  1113. }
  1114. }
  1115. }
  1116. }
  1117. }
  1118. // if we're here, this means we didn't find the preferred transfer syntax
  1119. // check whether there is a backup syntax
  1120. if (BackupTransferSyntax)
  1121. {
  1122. RpcpMemoryCopy(AcceptedTransferSyntax, BackupTransferSyntax,
  1123. sizeof(RPC_SYNTAX_IDENTIFIER));
  1124. *fIsInterfaceTransferPreferred = FALSE;
  1125. *ProposedTransferSyntaxIndex = BackupProposedTransferSyntaxIndex;
  1126. *AvailableTransferSyntaxIndex = BackupAvailableTransferSyntaxIndex;
  1127. return(0);
  1128. }
  1129. // nada - no transfer syntax matches
  1130. return(1);
  1131. }
  1132. void RPC_INTERFACE::GetSelectedTransferSyntaxAndDispatchTable(IN int SelectedTransferSyntaxIndex,
  1133. OUT RPC_SYNTAX_IDENTIFIER **SelectedTransferSyntax,
  1134. OUT PRPC_DISPATCH_TABLE *SelectedDispatchTable)
  1135. {
  1136. MIDL_SYNTAX_INFO *SelectedSyntaxInfo;
  1137. if (DoesInterfaceSupportMultipleTransferSyntaxes(&RpcInterfaceInformation))
  1138. {
  1139. ASSERT((unsigned int)SelectedTransferSyntaxIndex <= NumberOfSupportedTransferSyntaxes);
  1140. SelectedSyntaxInfo = &TransferSyntaxesArray[SelectedTransferSyntaxIndex];
  1141. *SelectedTransferSyntax = &SelectedSyntaxInfo->TransferSyntax;
  1142. // DCOM has only one dispatch table - they change the dispatch target
  1143. // internally. They will define only the dispatch table in the
  1144. // interface
  1145. if (SelectedSyntaxInfo->DispatchTable)
  1146. *SelectedDispatchTable = SelectedSyntaxInfo->DispatchTable;
  1147. else
  1148. *SelectedDispatchTable = GetDefaultDispatchTable();
  1149. }
  1150. else
  1151. {
  1152. *SelectedTransferSyntax = &RpcInterfaceInformation.TransferSyntax;
  1153. *SelectedDispatchTable = GetDefaultDispatchTable();
  1154. }
  1155. }
  1156. RPC_STATUS
  1157. RPC_INTERFACE::UnregisterManagerEpv (
  1158. IN RPC_UUID PAPI * ManagerTypeUuid, OPTIONAL
  1159. IN unsigned int WaitForCallsToComplete
  1160. )
  1161. /*++
  1162. Routine Description:
  1163. In this method, we unregister one or all of the manager entry point
  1164. vectors for this interface, depending on what, if anything, is
  1165. specified for the manager type uuid argument.
  1166. Arguments:
  1167. ManagerTypeUuid - Optionally supplies the type uuid of the manager
  1168. entry point vector to be removed. If this argument is not supplied,
  1169. then all manager entry point vectors for this interface will
  1170. be removed.
  1171. WaitForCallsToComplete - Supplies a flag indicating whether or not
  1172. this routine should wait for all calls to complete using the
  1173. interface and manager being unregistered. A non-zero value
  1174. indicates to wait.
  1175. Return Value:
  1176. RPC_S_OK - The manager entry point vector(s) are(were) successfully
  1177. removed from the this interface.
  1178. RPC_S_UNKNOWN_MGR_TYPE - The specified type uuid is not registered
  1179. with this interface.
  1180. RPC_S_UNKNOWN_IF - The specified interface is not registered with
  1181. the rpc server.
  1182. --*/
  1183. {
  1184. RPC_INTERFACE_MANAGER * InterfaceManager;
  1185. DictionaryCursor cursor;
  1186. RequestGlobalMutex();
  1187. if (ManagerCount == 0)
  1188. {
  1189. ClearGlobalMutex();
  1190. return(RPC_S_UNKNOWN_MGR_TYPE);
  1191. }
  1192. if (ARGUMENT_PRESENT(ManagerTypeUuid) == 0)
  1193. {
  1194. InterfaceManagerDictionary.Reset(cursor);
  1195. while ((InterfaceManager = InterfaceManagerDictionary.Next(cursor)) != 0)
  1196. {
  1197. InterfaceManager->InvalidateManager();
  1198. }
  1199. ManagerCount = 0;
  1200. NullManagerFlag = 0;
  1201. ClearGlobalMutex();
  1202. if ( WaitForCallsToComplete != 0 )
  1203. {
  1204. while ( NullManagerActiveCallCount.GetInteger() > 0 )
  1205. {
  1206. PauseExecution(500L);
  1207. }
  1208. InterfaceManagerDictionary.Reset(cursor);
  1209. while ((InterfaceManager = InterfaceManagerDictionary.Next(cursor)) != 0)
  1210. {
  1211. while ( InterfaceManager->InquireActiveCallCount() > 0 )
  1212. {
  1213. PauseExecution(500L);
  1214. }
  1215. }
  1216. }
  1217. return(RPC_S_OK);
  1218. }
  1219. if (ManagerTypeUuid->IsNullUuid() != 0)
  1220. {
  1221. if (NullManagerFlag == 0)
  1222. {
  1223. ClearGlobalMutex();
  1224. return(RPC_S_UNKNOWN_MGR_TYPE);
  1225. }
  1226. ManagerCount -= 1;
  1227. NullManagerFlag = 0;
  1228. ClearGlobalMutex();
  1229. if ( WaitForCallsToComplete != 0 )
  1230. {
  1231. while ( NullManagerActiveCallCount.GetInteger() > 0 )
  1232. {
  1233. PauseExecution(500L);
  1234. }
  1235. }
  1236. return(RPC_S_OK);
  1237. }
  1238. InterfaceManager = FindInterfaceManager(ManagerTypeUuid);
  1239. if ( (InterfaceManager == 0)
  1240. || (InterfaceManager->ValidManager() == 0))
  1241. {
  1242. ClearGlobalMutex();
  1243. return(RPC_S_UNKNOWN_MGR_TYPE);
  1244. }
  1245. InterfaceManager->InvalidateManager();
  1246. ManagerCount -= 1;
  1247. ClearGlobalMutex();
  1248. if ( WaitForCallsToComplete != 0 )
  1249. {
  1250. while ( InterfaceManager->InquireActiveCallCount() > 0 )
  1251. {
  1252. PauseExecution(500L);
  1253. }
  1254. }
  1255. return(RPC_S_OK);
  1256. }
  1257. RPC_STATUS
  1258. RPC_INTERFACE::InquireManagerEpv (
  1259. IN RPC_UUID PAPI * ManagerTypeUuid, OPTIONAL
  1260. OUT RPC_MGR_EPV PAPI * PAPI * ManagerEpv
  1261. )
  1262. /*++
  1263. Routine Description:
  1264. This method is used to obtain the manager entry point vector
  1265. with the specified type uuid supported by this interface.
  1266. Arguments:
  1267. ManagerTypeUuid - Optionally supplies the type uuid of the manager
  1268. entry point vector we want returned. If no manager type uuid
  1269. is specified, then the null uuid is assumed.
  1270. ManagerEpv - Returns the manager entry point vector.
  1271. Return Value:
  1272. RPC_S_OK - The manager entry point vector has successfully been
  1273. returned.
  1274. RPC_S_UNKNOWN_MGR_TYPE - The specified type uuid is not registered
  1275. with the interface.
  1276. RPC_S_UNKNOWN_IF - The specified interface is not registered with
  1277. the rpc server.
  1278. --*/
  1279. {
  1280. RPC_INTERFACE_MANAGER * InterfaceManager;
  1281. RequestGlobalMutex();
  1282. if (ManagerCount == 0)
  1283. {
  1284. ClearGlobalMutex();
  1285. return(RPC_S_UNKNOWN_IF);
  1286. }
  1287. if ( (ARGUMENT_PRESENT(ManagerTypeUuid) == 0)
  1288. || (ManagerTypeUuid->IsNullUuid() != 0))
  1289. {
  1290. if (NullManagerFlag == 0)
  1291. {
  1292. ClearGlobalMutex();
  1293. return(RPC_S_UNKNOWN_MGR_TYPE);
  1294. }
  1295. *ManagerEpv = NullManagerEpv;
  1296. ClearGlobalMutex();
  1297. return(RPC_S_OK);
  1298. }
  1299. InterfaceManager = FindInterfaceManager(ManagerTypeUuid);
  1300. if ( (InterfaceManager == 0)
  1301. || (InterfaceManager->ValidManager() == 0))
  1302. {
  1303. ClearGlobalMutex();
  1304. return(RPC_S_UNKNOWN_MGR_TYPE);
  1305. }
  1306. *ManagerEpv = InterfaceManager->QueryManagerEpv();
  1307. ClearGlobalMutex();
  1308. return(RPC_S_OK);
  1309. }
  1310. RPC_STATUS
  1311. RPC_INTERFACE::UpdateRpcInterfaceInformation (
  1312. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
  1313. IN unsigned int Flags,
  1314. IN unsigned int MaxCalls,
  1315. IN unsigned int MaxRpcSize,
  1316. IN RPC_IF_CALLBACK_FN PAPI *IfCallbackFn
  1317. )
  1318. /*++
  1319. Routine Description:
  1320. We never delete the interface objects from a server; we just invalidate
  1321. them. This means that if an interface has been complete unregistered
  1322. (ie. it has no managers), we need to update the interface information
  1323. again.
  1324. Arguments:
  1325. RpcInterfaceInformation - Supplies the interface information which this
  1326. interface should be using.
  1327. --*/
  1328. {
  1329. unsigned int Length;
  1330. RPC_STATUS Status;
  1331. Length = RpcInterfaceInformation->Length;
  1332. ASSERT((Length == sizeof(RPC_SERVER_INTERFACE)) ||
  1333. (Length == NT351_INTERFACE_SIZE));
  1334. // make it stick on free builds as well
  1335. if ((Length != sizeof(RPC_SERVER_INTERFACE)) &&
  1336. (Length != NT351_INTERFACE_SIZE))
  1337. return RPC_S_UNKNOWN_IF;
  1338. if ( ManagerCount == 0 )
  1339. {
  1340. if (DoesInterfaceSupportMultipleTransferSyntaxes(RpcInterfaceInformation))
  1341. {
  1342. Status = NdrServerGetSupportedSyntaxes(RpcInterfaceInformation,
  1343. &NumberOfSupportedTransferSyntaxes,
  1344. &TransferSyntaxesArray, &PreferredTransferSyntax);
  1345. if (Status != RPC_S_OK)
  1346. return Status;
  1347. }
  1348. else
  1349. {
  1350. NumberOfSupportedTransferSyntaxes = 0;
  1351. }
  1352. RpcpMemoryCopy(&(this->RpcInterfaceInformation),
  1353. RpcInterfaceInformation, Length);
  1354. }
  1355. if (Flags & RPC_IF_AUTOLISTEN
  1356. && (this->Flags & RPC_IF_AUTOLISTEN) == 0)
  1357. {
  1358. GlobalRpcServer->IncrementAutoListenInterfaceCount() ;
  1359. }
  1360. this->Flags = Flags ;
  1361. this->MaxCalls = MaxCalls ;
  1362. this->MaxRpcSize = MaxRpcSize;
  1363. SequenceNumber++ ;
  1364. if (Flags & RPC_IF_ALLOW_SECURE_ONLY
  1365. && IfCallbackFn == NULL)
  1366. {
  1367. this->CallbackFn = DefaultCallbackFn;
  1368. }
  1369. else
  1370. {
  1371. this->CallbackFn = IfCallbackFn ;
  1372. }
  1373. return RPC_S_OK;
  1374. }
  1375. RPC_IF_ID __RPC_FAR *
  1376. RPC_INTERFACE::InquireInterfaceId (
  1377. )
  1378. /*++
  1379. Return Value:
  1380. If this interface is active, its interface id will be returned in a
  1381. newly allocated chunk of memory; otherwise, zero will be returned.
  1382. --*/
  1383. {
  1384. RPC_IF_ID __RPC_FAR * RpcIfId;
  1385. if ( ManagerCount == 0 )
  1386. {
  1387. return(0);
  1388. }
  1389. RpcIfId = (RPC_IF_ID __RPC_FAR *) RpcpFarAllocate(sizeof(RPC_IF_ID));
  1390. if ( RpcIfId == 0 )
  1391. {
  1392. return(0);
  1393. }
  1394. RpcIfId->Uuid = RpcInterfaceInformation.InterfaceId.SyntaxGUID;
  1395. RpcIfId->VersMajor =
  1396. RpcInterfaceInformation.InterfaceId.SyntaxVersion.MajorVersion;
  1397. RpcIfId->VersMinor =
  1398. RpcInterfaceInformation.InterfaceId.SyntaxVersion.MinorVersion;
  1399. return(RpcIfId);
  1400. }
  1401. RPC_STATUS
  1402. RPC_INTERFACE::CheckSecurityIfNecessary(
  1403. IN void * Context
  1404. )
  1405. {
  1406. //
  1407. // If manager count in non-zero, this interface is still registered
  1408. // If it has been registered with a call back function, invoke the callback
  1409. // function, else return success....
  1410. RPC_IF_ID RpcIfId;
  1411. RPC_STATUS RpcStatus = RPC_S_OK;
  1412. if (CallbackFn != 0)
  1413. {
  1414. RpcIfId.Uuid = RpcInterfaceInformation.InterfaceId.SyntaxGUID;
  1415. RpcIfId.VersMajor =
  1416. RpcInterfaceInformation.InterfaceId.SyntaxVersion.MajorVersion;
  1417. RpcIfId.VersMinor =
  1418. RpcInterfaceInformation.InterfaceId.SyntaxVersion.MinorVersion;
  1419. BeginAutoListenCall();
  1420. if (ManagerCount == 0)
  1421. {
  1422. EndAutoListenCall();
  1423. return (RPC_S_UNKNOWN_IF);
  1424. }
  1425. RpcTryExcept
  1426. {
  1427. RpcStatus = CallbackFn(&RpcIfId, Context);
  1428. }
  1429. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  1430. {
  1431. RpcStatus = RPC_S_ACCESS_DENIED;
  1432. }
  1433. RpcEndExcept
  1434. EndAutoListenCall();
  1435. }
  1436. return(RpcStatus);
  1437. }
  1438. void
  1439. RPC_INTERFACE::WaitForCalls(
  1440. )
  1441. /*++
  1442. Routine Description:
  1443. Waits for the completion of all the calls on a given interface.
  1444. --*/
  1445. {
  1446. DictionaryCursor cursor;
  1447. RPC_INTERFACE_MANAGER * InterfaceManager;
  1448. while ( NullManagerActiveCallCount.GetInteger() > 0 )
  1449. {
  1450. PauseExecution(500L);
  1451. }
  1452. InterfaceManagerDictionary.Reset(cursor);
  1453. while ((InterfaceManager = InterfaceManagerDictionary.Next(cursor)) != 0)
  1454. {
  1455. while ( InterfaceManager->InquireActiveCallCount() > 0 )
  1456. {
  1457. PauseExecution(500L);
  1458. }
  1459. }
  1460. }
  1461. RPC_SERVER::RPC_SERVER (
  1462. IN OUT RPC_STATUS PAPI * RpcStatus
  1463. ) : AvailableCallCount(0),
  1464. ServerMutex(RpcStatus,
  1465. TRUE // pre-allocate semaphore
  1466. ),
  1467. StopListeningEvent(RpcStatus),
  1468. ThreadCacheMutex(RpcStatus,
  1469. TRUE, // pre-allocate semaphore
  1470. 100
  1471. ),
  1472. NumAutoListenInterfaces(0)
  1473. /*++
  1474. Routine Description:
  1475. This routine will get called to construct an instance of the
  1476. RPC_SERVER class.
  1477. --*/
  1478. {
  1479. ALLOCATE_THIS(RPC_SERVER);
  1480. ServerListeningFlag = 0;
  1481. ListeningThreadFlag = 0;
  1482. WaitingThreadFlag = 0;
  1483. MinimumCallThreads = 1;
  1484. MaximumConcurrentCalls = 1;
  1485. IncomingRpcCount = 0;
  1486. OutgoingRpcCount = 0;
  1487. ReceivedPacketCount = 0;
  1488. SentPacketCount = 0;
  1489. ThreadCache = 0;
  1490. ListenStatusCode = RPC_S_OK;
  1491. fAccountForMaxCalls = TRUE;
  1492. pRpcForwardFunction = (RPC_FORWARD_FUNCTION *)0;
  1493. #if !defined(NO_LOCATOR_CODE)
  1494. pNsBindingExport = 0;
  1495. pNsBindingUnexport = 0;
  1496. #endif
  1497. }
  1498. RPC_INTERFACE *
  1499. RPC_SERVER::FindInterface (
  1500. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation
  1501. )
  1502. /*++
  1503. Routine Description:
  1504. This method is used to find the rpc interface registered with this
  1505. server which matches the supplied rpc interface information.
  1506. Arguments:
  1507. RpcInterfaceInformation - Supplies the rpc interface information
  1508. identifying the rpc interface we are looking for.
  1509. Return Value:
  1510. The rpc interface matching the supplied rpc interface information
  1511. will be returned if it is found; otherwise, zero will be returned.
  1512. --*/
  1513. {
  1514. RPC_INTERFACE * RpcInterface;
  1515. DictionaryCursor cursor;
  1516. ServerMutex.VerifyOwned();
  1517. RpcInterfaceDictionary.Reset(cursor);
  1518. while ((RpcInterface = RpcInterfaceDictionary.Next(cursor)) != 0)
  1519. {
  1520. if (RpcInterface->MatchRpcInterfaceInformation(
  1521. RpcInterfaceInformation) == 0)
  1522. {
  1523. return(RpcInterface);
  1524. }
  1525. }
  1526. // The management interface is implicitly registered in all servers.
  1527. if ( (GlobalManagementInterface)
  1528. && (GlobalManagementInterface->MatchRpcInterfaceInformation(
  1529. RpcInterfaceInformation) == 0) )
  1530. {
  1531. return(GlobalManagementInterface);
  1532. }
  1533. return(0);
  1534. }
  1535. int
  1536. RPC_SERVER::AddInterface (
  1537. IN RPC_INTERFACE * RpcInterface
  1538. )
  1539. /*++
  1540. Routine Description:
  1541. This method will be used to add an rpc interface to the set of
  1542. interfaces known about by this server.
  1543. Arguments:
  1544. RpcInterface - Supplies the rpc interface to add to the set of
  1545. interfaces.
  1546. Return Value:
  1547. Zero will be returned if the interface is successfully added to
  1548. the set; otherwise, non-zero will be returned indicating that
  1549. insufficient memory is available to complete the operation.
  1550. --*/
  1551. {
  1552. if (RpcInterfaceDictionary.Insert(RpcInterface) == -1)
  1553. {
  1554. return(-1);
  1555. }
  1556. return(0);
  1557. }
  1558. RPC_STATUS
  1559. RPC_SERVER::FindInterfaceTransfer (
  1560. IN PRPC_SYNTAX_IDENTIFIER InterfaceIdentifier,
  1561. IN PRPC_SYNTAX_IDENTIFIER ProposedTransferSyntaxes,
  1562. IN unsigned int NumberOfTransferSyntaxes,
  1563. OUT PRPC_SYNTAX_IDENTIFIER AcceptedTransferSyntax,
  1564. OUT RPC_INTERFACE ** AcceptingRpcInterface,
  1565. OUT BOOL *fInterfaceTransferIsPreferred,
  1566. OUT int *ProposedTransferSyntaxIndex,
  1567. OUT int *AvailableTransferSyntaxIndex
  1568. )
  1569. /*++
  1570. Routine Description:
  1571. This method is used to determine if a client bind request can be
  1572. accepted or not. All we have got to do here is hand off to the
  1573. server which owns this address.
  1574. Arguments:
  1575. InterfaceIdentifier - Supplies the syntax identifier for the
  1576. interface; this is the interface uuid and version.
  1577. ProposedTransferSyntaxes - Supplies a list of one or more transfer
  1578. syntaxes which the client initiating the binding supports. The
  1579. server should pick one of these which is supported by the
  1580. interface.
  1581. NumberOfTransferSyntaxes - Supplies the number of transfer syntaxes
  1582. specified in the proposed transfer syntaxes argument.
  1583. AcceptedTransferSyntax - Returns the transfer syntax which the
  1584. server accepted.
  1585. AcceptingRpcInterface - Returns a pointer to the rpc interface found
  1586. which supports the requested interface and one of the requested
  1587. transfer syntaxes.
  1588. fInterfaceTransferIsPreferred - non zero if the interface transfer
  1589. returned is preferred.
  1590. TransferSyntaxIndex - the index of the chosen transfer syntax in the
  1591. ProposedTransferSyntaxesArray
  1592. Return Value:
  1593. RPC_S_OK - The requested interface exists and it supports at least
  1594. one of the proposed transfer syntaxes. We are all set, now we
  1595. can make remote procedure calls.
  1596. RPC_S_UNSUPPORTED_TRANSFER_SYNTAX - The requested interface exists,
  1597. but it does not support any of the proposed transfer syntaxes.
  1598. RPC_S_UNKNOWN_IF - The requested interface is not supported
  1599. by this rpc server.
  1600. --*/
  1601. {
  1602. RPC_INTERFACE * RpcInterface;
  1603. unsigned int InterfaceFound = 0;
  1604. DictionaryCursor cursor;
  1605. ServerMutex.Request();
  1606. RpcInterfaceDictionary.Reset(cursor);
  1607. while ((RpcInterface = RpcInterfaceDictionary.Next(cursor)) != 0)
  1608. {
  1609. if (RpcInterface->MatchInterfaceIdentifier(InterfaceIdentifier) == 0)
  1610. {
  1611. InterfaceFound = 1;
  1612. if (RpcInterface->SelectTransferSyntax(ProposedTransferSyntaxes,
  1613. NumberOfTransferSyntaxes, AcceptedTransferSyntax,
  1614. fInterfaceTransferIsPreferred, ProposedTransferSyntaxIndex,
  1615. AvailableTransferSyntaxIndex) == 0)
  1616. {
  1617. ServerMutex.Clear();
  1618. *AcceptingRpcInterface = RpcInterface;
  1619. return(RPC_S_OK);
  1620. }
  1621. }
  1622. }
  1623. ServerMutex.Clear();
  1624. // The management interface is implicitly registered in all servers.
  1625. if ( (GlobalManagementInterface)
  1626. && (GlobalManagementInterface->MatchInterfaceIdentifier(
  1627. InterfaceIdentifier) == 0 ) )
  1628. {
  1629. InterfaceFound = 1;
  1630. if (GlobalManagementInterface->SelectTransferSyntax(
  1631. ProposedTransferSyntaxes, NumberOfTransferSyntaxes,
  1632. AcceptedTransferSyntax, fInterfaceTransferIsPreferred,
  1633. ProposedTransferSyntaxIndex, AvailableTransferSyntaxIndex) == 0)
  1634. {
  1635. *AcceptingRpcInterface = GlobalManagementInterface;
  1636. return(RPC_S_OK);
  1637. }
  1638. }
  1639. if (InterfaceFound == 0)
  1640. return(RPC_S_UNKNOWN_IF);
  1641. return(RPC_S_UNSUPPORTED_TRANS_SYN);
  1642. }
  1643. RPC_INTERFACE *
  1644. RPC_SERVER::FindInterface (
  1645. IN PRPC_SYNTAX_IDENTIFIER InterfaceIdentifier
  1646. )
  1647. /*++
  1648. Routine Description:
  1649. The datagram protocol module will use this routine to find the interface
  1650. with out worrying about the transfer syntax. Datagram RPC does not support
  1651. more than a single transfer syntax.
  1652. Arguments:
  1653. InterfaceIdentifier - Supplies the identifier (UUID and version) of the
  1654. interface we are trying to find.
  1655. Return Value:
  1656. If the interface is found it will be returned; otherwise, zero will be
  1657. returned.
  1658. --*/
  1659. {
  1660. RPC_INTERFACE * RpcInterface;
  1661. DictionaryCursor cursor;
  1662. ServerMutex.Request();
  1663. RpcInterfaceDictionary.Reset(cursor);
  1664. while ( (RpcInterface = RpcInterfaceDictionary.Next(cursor)) != 0)
  1665. {
  1666. if ( RpcInterface->MatchInterfaceIdentifier(InterfaceIdentifier)
  1667. == 0 )
  1668. {
  1669. ServerMutex.Clear();
  1670. return(RpcInterface);
  1671. }
  1672. }
  1673. ServerMutex.Clear();
  1674. // The management interface is implicitly registered in all servers.
  1675. if ( (GlobalManagementInterface)
  1676. && (GlobalManagementInterface->MatchInterfaceIdentifier(
  1677. InterfaceIdentifier) == 0) )
  1678. {
  1679. return(GlobalManagementInterface);
  1680. }
  1681. return(0);
  1682. }
  1683. RPC_STATUS
  1684. RPC_SERVER::ServerListen (
  1685. IN unsigned int MinimumCallThreads,
  1686. IN unsigned int MaximumConcurrentCalls,
  1687. IN unsigned int DontWait
  1688. )
  1689. /*++
  1690. Routine Description:
  1691. This method is called to start this rpc server listening for remote
  1692. procedure calls. We do not return until after StopServerListening
  1693. has been called and all active calls complete, or an error occurs.
  1694. Arguments:
  1695. MinimumCallThreads - Supplies the minimum number of call threads
  1696. which should be created to service remote procedure calls.
  1697. MaximumConcurrentCalls - Supplies the maximum concurrent calls this
  1698. rpc server is willing to accept at one time.
  1699. DontWait - Supplies a flag indicating whether or not to wait until
  1700. RpcMgmtStopServerListening has been called and all calls have
  1701. completed. A non-zero value indicates not to wait.
  1702. Return Value:
  1703. RPC_S_OK - Everything worked out in the end. All active calls
  1704. completed successfully after RPC_SERVER::StopServerListening
  1705. was called. No errors occured in the transports.
  1706. RPC_S_ALREADY_LISTENING - This rpc server is already listening.
  1707. RPC_S_NO_PROTSEQS_REGISTERED - No protocol sequences have been
  1708. registered with this rpc server. As a consequence it is
  1709. impossible for this rpc server to receive any remote procedure
  1710. calls, hence, the error code.
  1711. RPC_S_MAX_CALLS_TOO_SMALL - MaximumConcurrentCalls is smaller than
  1712. MinimumCallThreads or MaximumConcurrentCalls is zero.
  1713. --*/
  1714. {
  1715. RPC_ADDRESS * RpcAddress;
  1716. RPC_STATUS Status;
  1717. DictionaryCursor cursor;
  1718. if ( ( MaximumConcurrentCalls < MinimumCallThreads )
  1719. || ( MaximumConcurrentCalls == 0 ) )
  1720. {
  1721. return(RPC_S_MAX_CALLS_TOO_SMALL);
  1722. }
  1723. if ( MaximumConcurrentCalls > 0x7FFFFFFF )
  1724. {
  1725. MaximumConcurrentCalls = 0x7FFFFFFF;
  1726. }
  1727. ServerMutex.Request();
  1728. if ( ListeningThreadFlag != 0 )
  1729. {
  1730. ServerMutex.Clear();
  1731. return(RPC_S_ALREADY_LISTENING);
  1732. }
  1733. if ( RpcAddressDictionary.Size() == 0
  1734. && RpcDormantAddresses.IsQueueEmpty())
  1735. {
  1736. ServerMutex.Clear();
  1737. return(RPC_S_NO_PROTSEQS_REGISTERED);
  1738. }
  1739. this->MaximumConcurrentCalls = MaximumConcurrentCalls;
  1740. // if we are provided the default number, then we don't really care -
  1741. // play for optimal performance
  1742. if (MaximumConcurrentCalls == RPC_C_LISTEN_MAX_CALLS_DEFAULT)
  1743. fAccountForMaxCalls = FALSE;
  1744. this->MinimumCallThreads = MinimumCallThreads;
  1745. AvailableCallCount.SetInteger( MaximumConcurrentCalls );
  1746. RpcAddressDictionary.Reset(cursor);
  1747. while ( (RpcAddress = RpcAddressDictionary.Next(cursor)) != 0 )
  1748. {
  1749. Status = RpcAddress->ServerStartingToListen(
  1750. MinimumCallThreads,
  1751. MaximumConcurrentCalls);
  1752. if (Status)
  1753. {
  1754. ServerMutex.Clear();
  1755. return(Status);
  1756. }
  1757. }
  1758. StopListeningEvent.Lower();
  1759. ServerListeningFlag = 1;
  1760. ListeningThreadFlag = 1;
  1761. if ( DontWait != 0 )
  1762. {
  1763. ServerMutex.Clear();
  1764. return(RPC_S_OK);
  1765. }
  1766. WaitingThreadFlag = 1;
  1767. ServerMutex.Clear();
  1768. return(WaitForStopServerListening());
  1769. }
  1770. RPC_STATUS
  1771. RPC_SERVER::WaitForStopServerListening (
  1772. )
  1773. /*++
  1774. Routine Description:
  1775. We wait for StopServerListening to be called and then for all active
  1776. remote procedure calls to complete before returning.
  1777. Return Value:
  1778. RPC_S_OK - Everything worked out in the end. All active calls
  1779. completed successfully after RPC_SERVER::StopServerListening
  1780. was called. No errors occured in the transports.
  1781. --*/
  1782. {
  1783. RPC_ADDRESS * RpcAddress;
  1784. DictionaryCursor cursor;
  1785. RPC_INTERFACE * RpcInterface;
  1786. StopListeningEvent.Wait();
  1787. if ( ListenStatusCode != RPC_S_OK )
  1788. {
  1789. ListeningThreadFlag = 0;
  1790. return(ListenStatusCode);
  1791. }
  1792. RpcAddressDictionary.Reset(cursor);
  1793. while ( (RpcAddress = RpcAddressDictionary.Next(cursor)) != 0 )
  1794. {
  1795. RpcAddress->ServerStoppedListening();
  1796. }
  1797. RpcAddressDictionary.Reset(cursor);
  1798. while ( (RpcAddress = RpcAddressDictionary.Next(cursor)) != 0 )
  1799. {
  1800. RpcAddress->WaitForCalls();
  1801. }
  1802. // Wait for calls on all interfaces to complete
  1803. RpcInterfaceDictionary.Reset(cursor);
  1804. while ((RpcInterface = RpcInterfaceDictionary.Next(cursor)) != 0)
  1805. {
  1806. RpcInterface->WaitForCalls();
  1807. }
  1808. ServerMutex.Request();
  1809. WaitingThreadFlag = 0;
  1810. ListeningThreadFlag = 0;
  1811. ServerMutex.Clear();
  1812. return(RPC_S_OK);
  1813. }
  1814. RPC_STATUS
  1815. RPC_SERVER::WaitServerListen (
  1816. )
  1817. /*++
  1818. Routine Description:
  1819. This routine performs the wait that ServerListen normally performs
  1820. when the DontWait flag is not set. An application must call this
  1821. routine only after RpcServerListen has been called with the DontWait
  1822. flag set. We do not return until RpcMgmtStopServerListening is called
  1823. and all active remote procedure calls complete, or a fatal error occurs
  1824. in the runtime.
  1825. Return Value:
  1826. RPC_S_OK - Everything worked as expected. All active remote procedure
  1827. calls have completed. It is now safe to exit this process.
  1828. RPC_S_ALREADY_LISTENING - Another thread has already called
  1829. WaitServerListen and has not yet returned.
  1830. RPC_S_NOT_LISTENING - ServerListen has not yet been called.
  1831. --*/
  1832. {
  1833. ServerMutex.Request();
  1834. if ( ListeningThreadFlag == 0 )
  1835. {
  1836. ServerMutex.Clear();
  1837. return(RPC_S_NOT_LISTENING);
  1838. }
  1839. if ( WaitingThreadFlag != 0 )
  1840. {
  1841. ServerMutex.Clear();
  1842. return(RPC_S_ALREADY_LISTENING);
  1843. }
  1844. WaitingThreadFlag = 1;
  1845. ServerMutex.Clear();
  1846. return(WaitForStopServerListening());
  1847. }
  1848. void
  1849. RPC_SERVER::InquireStatistics (
  1850. OUT RPC_STATS_VECTOR * Statistics
  1851. )
  1852. /*++
  1853. Routine Description:
  1854. This method is used to obtain the statistics for this rpc server.
  1855. Arguments:
  1856. Statistics - Returns the statistics for this rpc server.
  1857. --*/
  1858. {
  1859. Statistics->Stats[RPC_C_STATS_CALLS_IN] = IncomingRpcCount;
  1860. Statistics->Stats[RPC_C_STATS_CALLS_OUT] = OutgoingRpcCount;
  1861. Statistics->Stats[RPC_C_STATS_PKTS_IN] = ReceivedPacketCount;
  1862. Statistics->Stats[RPC_C_STATS_PKTS_OUT] = SentPacketCount;
  1863. }
  1864. RPC_STATUS
  1865. RPC_SERVER::StopServerListening (
  1866. )
  1867. /*++
  1868. Routine Description:
  1869. This method is called to stop this rpc server from listening for
  1870. more remote procedure calls. Active calls are allowed to complete
  1871. (including callbacks). The thread which called ServerListen will
  1872. return when all active calls complete.
  1873. Return Value:
  1874. RPC_S_OK - The thread that called ServerListen has successfully been
  1875. notified that it should shutdown.
  1876. RPC_S_NOT_LISTENING - There is no thread currently listening.
  1877. --*/
  1878. {
  1879. if (ListeningThreadFlag == 0)
  1880. return(RPC_S_NOT_LISTENING);
  1881. ListenStatusCode = RPC_S_OK;
  1882. ServerListeningFlag = 0;
  1883. StopListeningEvent.Raise();
  1884. return(RPC_S_OK);
  1885. }
  1886. RPC_STATUS
  1887. RPC_SERVER::UseRpcProtocolSequence (
  1888. IN RPC_CHAR PAPI * NetworkAddress,
  1889. IN RPC_CHAR PAPI * RpcProtocolSequence,
  1890. IN unsigned int PendingQueueSize,
  1891. IN RPC_CHAR PAPI *Endpoint,
  1892. IN void PAPI * SecurityDescriptor,
  1893. IN unsigned long EndpointFlags,
  1894. IN unsigned long NICFlags,
  1895. IN RPC_CHAR PAPI **pEndpointListenedOn, OPTIONAL
  1896. IN BOOL fUseDuplicateEndpoints OPTIONAL
  1897. )
  1898. /*++
  1899. Routine Description:
  1900. This method is who does the work of creating new address (they
  1901. are called protocol sequences in the DCE lingo) and adding them to
  1902. this rpc server.
  1903. Arguments:
  1904. RpcProtocolSequence - Supplies the rpc protocol sequence we wish
  1905. to add to this rpc server.
  1906. PendingQueueSize - Supplies the size of the queue of pending
  1907. requests which should be created by the transport. Some transports
  1908. will not be able to make use of this value, while others will.
  1909. Endpoint - Optionally supplies an endpoint to be used for the new
  1910. address. If an endpoint is not specified, then we will let
  1911. the transport specify the endpoint.
  1912. SecurityDescriptor - Optionally supplies a security descriptor to
  1913. be placed on the rpc protocol sequence (address) we are adding
  1914. to this rpc server.
  1915. pEndpointListenedOn - Optionally allows the return of the endpoint on
  1916. which we choose to listen. Used when listening on a UDP dynamic
  1917. endpoint on a multi-homed machine with dynamic binding enabled.
  1918. First, we will pick a dynamic endpoint for the loopback address
  1919. and then use it with the other enabled interfaces.
  1920. On success, the returned value will point to the Endpoint member of an
  1921. address object. Therefore the returned value is read-only and the
  1922. undelrying string is owned by the address. We will only use the
  1923. pointer to copy the string.
  1924. fUseDuplicateEndpoints - Optionally tells the API to supress
  1925. RPC_S_DUPLICATE_ENDPOINT when an address already exists for
  1926. a given protseq and ep.
  1927. Return Value:
  1928. RPC_S_OK - The requested rpc protocol sequence has been added to
  1929. this rpc server.
  1930. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to add the
  1931. requested rpc protocol sequence to this rpc server.
  1932. RPC_S_PROTSEQ_NOT_SUPPORTED - The specified rpc protocol sequence
  1933. is not supported (but it appears to be valid).
  1934. RPC_S_INVALID_RPC_PROTSEQ - The specified rpc protocol sequence is
  1935. syntactically invalid.
  1936. RPC_S_DUPLICATE_ENDPOINT - The supplied endpoint has already been
  1937. added to this rpc server.
  1938. RPC_S_INVALID_SECURITY_DESC - The supplied security descriptor is
  1939. invalid.
  1940. --*/
  1941. {
  1942. TRANS_INFO *ServerTransInfo ;
  1943. RPC_STATUS Status;
  1944. RPC_ADDRESS * RpcAddress;
  1945. RPC_ADDRESS * Address;
  1946. unsigned int StaticEndpointFlag;
  1947. int Key;
  1948. DictionaryCursor cursor;
  1949. THREAD *ThisThread;
  1950. BOOL IsEqual;
  1951. FIREWALL_INFO *pCopyOfFirewallTable = NULL;
  1952. ThisThread = ThreadSelf();
  1953. if (ThisThread == NULL)
  1954. return RPC_S_OUT_OF_MEMORY;
  1955. // remove old EEInfo
  1956. RpcpPurgeEEInfo();
  1957. if (IsServerSideDebugInfoEnabled())
  1958. {
  1959. Status = InitializeServerSideCellHeapIfNecessary();
  1960. if (Status != RPC_S_OK)
  1961. return Status;
  1962. }
  1963. // This is a local protseq
  1964. if ( RpcpStringCompare(RpcProtocolSequence,
  1965. RPC_CONST_STRING("ncalrpc")) == 0 )
  1966. {
  1967. RpcAddress = LrpcCreateRpcAddress();
  1968. }
  1969. // This is a remote protseq
  1970. else
  1971. {
  1972. // Check for sound security practices if the RPC verifier is enabled.
  1973. if (gfRPCVerifierEnabledWithBreaks)
  1974. {
  1975. // Check if an unsafe protseq is being used.
  1976. if (IsProtseqUnsafe(RpcProtocolSequence))
  1977. {
  1978. // If the RPC verifier is enabled, issue a warning for the use of
  1979. // an unsecure protocol.
  1980. RPC_VERIFIER_WARNING_MSG("Possible security threat: Server is listening on an unsafe protseq",
  1981. RPC_VERIFIER_UNSAFE_PROTOCOL);
  1982. DbgPrint("RPC: Listening on protseq: %S endpoint: %S\n",
  1983. RpcProtocolSequence,
  1984. Endpoint);
  1985. RPC_VERIFIER_PRINT_OFFENDING_STACK(2, 4);
  1986. }
  1987. // Print out warnings only the first time insecure interfaces become exposed.
  1988. if (!gfRemoteProtseqRegistered)
  1989. {
  1990. if (gfUnsecureInterfaceRegistered)
  1991. {
  1992. RPC_INTERFACE *RpcInterface;
  1993. RPC_VERIFIER_WARNING_MSG("Possible security threat: Unsecure interface becomes remotely accessible",
  1994. RPC_VERIFIER_UNSECURE_IF_REMOTELY_ACCESSIBLE);
  1995. // Print the endpoint that is being registered.
  1996. DbgPrint("RPC: Starting to listen on protseq: %S endpoint: %S\n",
  1997. RpcProtocolSequence,
  1998. Endpoint);
  1999. // Print a list of unsecure interfaces registered that are
  2000. // now being exposed.
  2001. ServerMutex.Request();
  2002. RpcInterfaceDictionary.Reset(cursor);
  2003. while ((RpcInterface = RpcInterfaceDictionary.Next(cursor)) != 0)
  2004. {
  2005. // Check if this interface is not secure.
  2006. if (!RpcInterface->IsSecure() &&
  2007. !RpcInterface->IsOle() &&
  2008. !IsInterfaceExempt(&(RpcInterface->InqInterfaceInformation()->InterfaceId.SyntaxGUID),
  2009. ALLOW_UNSECURE_REMOTE_ACCESS))
  2010. {
  2011. DbgPrint("RPC: Unsecure interface UUID: ");
  2012. PrintUUID(&(RpcInterface->InqInterfaceInformation()->InterfaceId.SyntaxGUID));
  2013. DbgPrint("\n");
  2014. }
  2015. }
  2016. ServerMutex.Clear();
  2017. }
  2018. // Remember that a remote protseq has been registered so that we do
  2019. // not duplicate checks and warnings in the future.
  2020. gfRemoteProtseqRegistered = true;
  2021. }
  2022. }
  2023. // Init the firewall address table so that we can check if selective
  2024. // bindings are being used.
  2025. // DoFirewallInit() is not thread safe we will take the global mutex.
  2026. RequestGlobalMutex();
  2027. if (DoFirewallInit() == FALSE)
  2028. {
  2029. ClearGlobalMutex();
  2030. return RPC_S_OUT_OF_MEMORY;
  2031. }
  2032. // Also, get a copy of pFirewallTable while in the critical section
  2033. // to protect against a race with the PnP table update.
  2034. pCopyOfFirewallTable = GetFirewallTableCopy();
  2035. if (pFirewallTable != NULL &&
  2036. pCopyOfFirewallTable == NULL)
  2037. {
  2038. ClearGlobalMutex();
  2039. return RPC_S_OUT_OF_MEMORY;
  2040. }
  2041. ClearGlobalMutex();
  2042. // Check if selective bindings are enabled but the user requests us to bind
  2043. // to all interfaces. This is dangerous and can be done by administrator only.
  2044. if (NetworkAddress == NULL &&
  2045. pCopyOfFirewallTable != 0 &&
  2046. NICFlags == RPC_C_BIND_TO_ALL_NICS)
  2047. {
  2048. // If we are running with RPC verifier, warn
  2049. // that selective bindings are being circumvented.
  2050. if (gfRPCVerifierEnabledWithBreaks)
  2051. {
  2052. RPC_VERIFIER_WARNING_MSG("Possible security threat: Server is forced to listen on all interfaces circumventing the firewall",
  2053. RPC_VERIFIER_DISABLING_SELECTIVE_BINDING);
  2054. RPC_VERIFIER_PRINT_OFFENDING_STACK(2, 4);
  2055. }
  2056. // Fail if this is not an admin.
  2057. if (IsCurrentUserAdmin() != RPC_S_OK)
  2058. {
  2059. delete pCopyOfFirewallTable;
  2060. return (RPC_S_ACCESS_DENIED);
  2061. }
  2062. }
  2063. if ( RpcpStringNCompare(RPC_CONST_STRING("ncadg_"),
  2064. RpcProtocolSequence,
  2065. 6) == 0 )
  2066. {
  2067. //
  2068. // If we are using selective binding we will create a DG_ADDRESS
  2069. // to listen on each of the interfaces that are allowed by the
  2070. // firewall table. To do this we will call this function recursively.
  2071. //
  2072. // We do not implement this functionality for the cluster addresses.
  2073. //
  2074. // We will listen on the interfaces from the firewall address table iff:
  2075. // - the user did not specify a specific interface to listen on (this also
  2076. // takes care of the recursive case)
  2077. // - firewall address table is configured
  2078. // - the user does not explicitly wish to listen on all the interfaces.
  2079. // We are listening on a subset of all interfaces.
  2080. if (NetworkAddress == NULL &&
  2081. pCopyOfFirewallTable != 0 &&
  2082. NICFlags != RPC_C_BIND_TO_ALL_NICS &&
  2083. RpcpStringNCompare(RPC_CONST_STRING("ncadg_cluster"),
  2084. RpcProtocolSequence,
  2085. 13) != 0)
  2086. {
  2087. // Set when we find the loopback address in the firewall address table.
  2088. BOOL bLoopbackAddressProcessed = FALSE;
  2089. // The string representation of the IP address to listen on: xxx.xxx.xxx.xxx\0
  2090. RPC_SCHAR StrAddr[16];
  2091. // The array of 4 uchars contained in a DWORD that represents an IP address:
  2092. // ddccbbaa -> aa.bb.cc.dd
  2093. unsigned char *InAddr;
  2094. // The endpoint on which the loopback interface chose to listen. We will
  2095. // use it with all the other ones.
  2096. RPC_CHAR *EndpointListenedOn;
  2097. // Listen on the loopback address.
  2098. if ((Status = UseRpcProtocolSequence (RPC_STRING_LITERAL("127.0.0.1"),
  2099. RpcProtocolSequence,
  2100. PendingQueueSize,
  2101. Endpoint,
  2102. SecurityDescriptor,
  2103. EndpointFlags,
  2104. NICFlags,
  2105. &EndpointListenedOn)) != RPC_S_OK)
  2106. {
  2107. delete pCopyOfFirewallTable;
  2108. return Status;
  2109. }
  2110. // EndpointListenedOn should have been initialized and should point to
  2111. // the Endpoint for the RpcAddress created by the preceeding call to
  2112. // UseRpcProtocolSequence. Thus, we do not own this memory and must
  2113. // _not_ free it. This is fine, since the following calls to
  2114. // UseRpcProtocolSequence duplicate Endpoint before partying on it.
  2115. ASSERT(EndpointListenedOn);
  2116. // Walk the list of interfaces that we want to listen on.
  2117. for (unsigned i = 0; i < pCopyOfFirewallTable->NumAddresses; i ++)
  2118. {
  2119. // We always want to listen on the loopback address. Since we
  2120. // chose to listen on it above, we should skip it here.
  2121. if (pCopyOfFirewallTable->Entries[i].Address == 0x0100007f)
  2122. {
  2123. continue;
  2124. }
  2125. // Listen only on the addresses that are enabled for listening
  2126. // in the selective binding settings.
  2127. if (pCopyOfFirewallTable->Entries[i].fEnabled)
  2128. {
  2129. // Extract the array of address components from the table.
  2130. InAddr = (unsigned char *) &(pCopyOfFirewallTable->Entries[i].Address);
  2131. // Compose the string representation of the IP address.
  2132. swprintf((RPC_SCHAR *)StrAddr, RPC_CONST_SSTRING("%d.%d.%d.%d"),
  2133. InAddr[0], InAddr[1], InAddr[2], InAddr[3]);
  2134. // Call this function recursively to listen on the address.
  2135. Status = UseRpcProtocolSequence (StrAddr,
  2136. RpcProtocolSequence,
  2137. PendingQueueSize,
  2138. EndpointListenedOn,
  2139. SecurityDescriptor,
  2140. EndpointFlags,
  2141. NICFlags,
  2142. NULL,
  2143. TRUE); // Ignore the error if RPC is already listening on the ep.
  2144. if (Status != RPC_S_OK)
  2145. {
  2146. delete pCopyOfFirewallTable;
  2147. return Status;
  2148. }
  2149. }
  2150. }
  2151. delete pCopyOfFirewallTable;
  2152. return RPC_S_OK;
  2153. }
  2154. //
  2155. // Just use the osf mapping...it simply calls the
  2156. // protocol-independent ones.
  2157. //
  2158. Status = OsfMapRpcProtocolSequence(1,
  2159. RpcProtocolSequence,
  2160. &ServerTransInfo);
  2161. if (Status != RPC_S_OK)
  2162. {
  2163. delete pCopyOfFirewallTable;
  2164. return Status;
  2165. }
  2166. RpcAddress = DgCreateRpcAddress(ServerTransInfo);
  2167. }
  2168. else if ( RpcpStringNCompare(
  2169. RPC_CONST_STRING("ncacn_"),
  2170. RpcProtocolSequence,
  2171. 6) == 0)
  2172. {
  2173. Status = OsfMapRpcProtocolSequence(1,
  2174. RpcProtocolSequence,
  2175. &ServerTransInfo);
  2176. if (Status != RPC_S_OK)
  2177. {
  2178. delete pCopyOfFirewallTable;
  2179. return(Status);
  2180. }
  2181. RpcAddress = OsfCreateRpcAddress(ServerTransInfo);
  2182. }
  2183. else
  2184. {
  2185. delete pCopyOfFirewallTable;
  2186. return(RPC_S_PROTSEQ_NOT_SUPPORTED);
  2187. }
  2188. } // else This is a remote protseq
  2189. delete pCopyOfFirewallTable;
  2190. if (RpcAddress == 0)
  2191. {
  2192. return(RPC_S_OUT_OF_MEMORY);
  2193. }
  2194. if (ARGUMENT_PRESENT(Endpoint))
  2195. {
  2196. ServerMutex.Request();
  2197. RpcAddressDictionary.Reset(cursor);
  2198. while ((Address = RpcAddressDictionary.Next(cursor)) != 0)
  2199. {
  2200. if ( Address->SameEndpointAndProtocolSequence(
  2201. NetworkAddress,
  2202. RpcProtocolSequence,
  2203. Endpoint) != 0 )
  2204. {
  2205. ServerMutex.Clear();
  2206. delete RpcAddress;
  2207. // Check whether the caller does not mind using an existing address if
  2208. // it matches the protseq and ep specified.
  2209. if (fUseDuplicateEndpoints)
  2210. {
  2211. // This only happens with DG selective binding when listening
  2212. // on non-loopback addresses. The caller does not ask for pEndpointListenedOn
  2213. // in this case.
  2214. ASSERT(!ARGUMENT_PRESENT(pEndpointListenedOn));
  2215. return RPC_S_OK;
  2216. }
  2217. else
  2218. {
  2219. return(RPC_S_DUPLICATE_ENDPOINT);
  2220. }
  2221. }
  2222. }
  2223. ServerMutex.Clear();
  2224. Endpoint = DuplicateString(Endpoint);
  2225. if (Endpoint == 0)
  2226. {
  2227. delete RpcAddress;
  2228. return(RPC_S_OUT_OF_MEMORY);
  2229. }
  2230. StaticEndpointFlag = 1;
  2231. }
  2232. else
  2233. {
  2234. //
  2235. // MACBUG:
  2236. // We need to include this for Macintosh/Win95 also...
  2237. //
  2238. ServerMutex.Request() ;
  2239. RpcAddressDictionary.Reset(cursor) ;
  2240. while ((Address = RpcAddressDictionary.Next(cursor)) != 0)
  2241. {
  2242. Status = Address->SameProtocolSequenceAndSD(NetworkAddress,
  2243. RpcProtocolSequence,
  2244. (SECURITY_DESCRIPTOR *)SecurityDescriptor,
  2245. &IsEqual);
  2246. // if we either failed, or succeeded and they are equal,
  2247. // return
  2248. if ((Status != RPC_S_OK) || IsEqual)
  2249. {
  2250. ServerMutex.Clear();
  2251. // Return the endpoint listened on if the caller requested it.
  2252. // We must always return it on sucess.
  2253. if (Status == RPC_S_OK && ARGUMENT_PRESENT(pEndpointListenedOn))
  2254. {
  2255. ASSERT(Address->InqEndpoint());
  2256. *pEndpointListenedOn = Address->InqEndpoint();
  2257. }
  2258. delete RpcAddress;
  2259. return(Status);
  2260. }
  2261. }
  2262. ServerMutex.Clear();
  2263. StaticEndpointFlag = 0;
  2264. } // else
  2265. if (EndpointFlags & RPC_C_DONT_FAIL)
  2266. {
  2267. RpcAddress->PnpNotify();
  2268. }
  2269. // If Endpoint == NULL, then on return it will contain the
  2270. // dynamic endpoint listened on. We will own that memory.
  2271. // If Endpoint != NULL, then on return it will be unchanged.
  2272. // We will continue to own that memory.
  2273. Status = RpcAddress->ServerSetupAddress(
  2274. NetworkAddress,
  2275. &Endpoint,
  2276. PendingQueueSize,
  2277. SecurityDescriptor,
  2278. EndpointFlags,
  2279. NICFlags);
  2280. if (Status == RPC_S_OK)
  2281. {
  2282. RPC_CHAR *MyNetworkAddress = NULL;
  2283. // If the caller wants to know what endpoint we used, return it.
  2284. if (ARGUMENT_PRESENT(pEndpointListenedOn))
  2285. {
  2286. // The only case when we should get called with pEndpointListenedOn
  2287. // is when using selective binding with DG and listening on several
  2288. // interfaces. In this case, NetworkAddress is specified.
  2289. ASSERT(NetworkAddress);
  2290. ASSERT(Endpoint);
  2291. *pEndpointListenedOn = Endpoint;
  2292. }
  2293. RpcProtocolSequence = DuplicateString(RpcProtocolSequence);
  2294. if (RpcProtocolSequence == 0)
  2295. {
  2296. delete Endpoint;
  2297. delete RpcAddress;
  2298. return(RPC_S_OUT_OF_MEMORY);
  2299. }
  2300. if (ARGUMENT_PRESENT(NetworkAddress))
  2301. {
  2302. MyNetworkAddress = DuplicateString(NetworkAddress);
  2303. if (MyNetworkAddress == 0)
  2304. {
  2305. delete Endpoint;
  2306. delete RpcAddress;
  2307. delete RpcProtocolSequence;
  2308. return(RPC_S_OUT_OF_MEMORY);
  2309. }
  2310. }
  2311. Status = RpcAddress->SetEndpointAndStuff(
  2312. MyNetworkAddress,
  2313. Endpoint,
  2314. RpcProtocolSequence,
  2315. this,
  2316. StaticEndpointFlag,
  2317. PendingQueueSize,
  2318. SecurityDescriptor,
  2319. EndpointFlags,
  2320. NICFlags);
  2321. if (Status != RPC_S_OK)
  2322. {
  2323. delete RpcAddress;
  2324. return Status;
  2325. }
  2326. }
  2327. else
  2328. {
  2329. // Mask the failure if RPC_C_DONT_FAIL was specified.
  2330. // We can't mask the failure when using selective bidings and the caller
  2331. // expects us to define pEndpointListenedOn.
  2332. //
  2333. // RPC_C_DONT_FAIL will not work when listening on a UDP dynamic
  2334. // endpoint with selective binding enabled.
  2335. if ((EndpointFlags & RPC_C_DONT_FAIL)
  2336. && !ARGUMENT_PRESENT(pEndpointListenedOn))
  2337. {
  2338. int retval;
  2339. RPC_CHAR *MyNetworkAddress = NULL;
  2340. RpcProtocolSequence = DuplicateString(RpcProtocolSequence);
  2341. if (RpcProtocolSequence == 0)
  2342. {
  2343. delete Endpoint;
  2344. delete RpcAddress;
  2345. return(RPC_S_OUT_OF_MEMORY);
  2346. }
  2347. if (ARGUMENT_PRESENT(NetworkAddress))
  2348. {
  2349. MyNetworkAddress = DuplicateString(NetworkAddress);
  2350. if (MyNetworkAddress == 0)
  2351. {
  2352. delete Endpoint;
  2353. delete RpcAddress;
  2354. delete RpcProtocolSequence;
  2355. return(RPC_S_OUT_OF_MEMORY);
  2356. }
  2357. }
  2358. Status = RpcAddress->SetEndpointAndStuff(
  2359. MyNetworkAddress,
  2360. Endpoint,
  2361. RpcProtocolSequence,
  2362. this,
  2363. StaticEndpointFlag,
  2364. PendingQueueSize,
  2365. SecurityDescriptor,
  2366. EndpointFlags,
  2367. NICFlags);
  2368. if (Status != RPC_S_OK)
  2369. {
  2370. delete Endpoint;
  2371. delete RpcAddress;
  2372. return Status;
  2373. }
  2374. ServerMutex.Request();
  2375. retval = RpcDormantAddresses.PutOnQueue(RpcAddress, 0);
  2376. ServerMutex.Clear();
  2377. if (retval == 1)
  2378. {
  2379. delete Endpoint;
  2380. delete RpcAddress;
  2381. return RPC_S_OUT_OF_MEMORY;
  2382. }
  2383. ServerMutex.Request();
  2384. Status = RpcAddress->ServerStartingToListen(
  2385. MinimumCallThreads,
  2386. MaximumConcurrentCalls);
  2387. ServerMutex.Clear();
  2388. return(Status);
  2389. }
  2390. else
  2391. {
  2392. ASSERT(Status != RPC_S_OK);
  2393. delete RpcAddress;
  2394. return(Status);
  2395. }
  2396. }
  2397. Key = AddAddress(RpcAddress);
  2398. if (Key == -1)
  2399. {
  2400. delete RpcAddress;
  2401. return(RPC_S_OUT_OF_MEMORY);
  2402. }
  2403. RpcAddress->DictKey = Key;
  2404. ServerMutex.Request();
  2405. Status = RpcAddress->ServerStartingToListen(
  2406. MinimumCallThreads,
  2407. MaximumConcurrentCalls);
  2408. ServerMutex.Clear();
  2409. if (Status != RPC_S_OK)
  2410. {
  2411. return(Status);
  2412. }
  2413. //
  2414. // Inform the transport that it can start.
  2415. //
  2416. RpcAddress->CompleteListen() ;
  2417. // Verify that pEndpointListenedOn is being returned on success
  2418. // if the caller asked for it.
  2419. if (ARGUMENT_PRESENT(pEndpointListenedOn))
  2420. {
  2421. ASSERT(*pEndpointListenedOn);
  2422. }
  2423. return(RPC_S_OK);
  2424. }
  2425. int
  2426. RPC_SERVER::AddAddress (
  2427. IN RPC_ADDRESS * RpcAddress
  2428. )
  2429. /*++
  2430. Routine Description:
  2431. This method is used to add an rpc address to the dictionary of
  2432. rpc addresses know about by this rpc server.
  2433. Arguments:
  2434. RpcAddress - Supplies the rpc address to be inserted into the
  2435. dictionary of rpc addresses.
  2436. Return Value:
  2437. RPC_S_OK - The supplied rpc address has been successfully added
  2438. to the dictionary.
  2439. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to insert
  2440. the rpc address into the dictionary.
  2441. --*/
  2442. {
  2443. int Key;
  2444. ServerMutex.Request();
  2445. Key = RpcAddressDictionary.Insert(RpcAddress);
  2446. ServerMutex.Clear();
  2447. return(Key);
  2448. }
  2449. RPC_STATUS
  2450. RPC_SERVER::UnregisterIf (
  2451. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation OPTIONAL,
  2452. IN RPC_UUID PAPI * ManagerTypeUuid OPTIONAL,
  2453. IN unsigned int WaitForCallsToComplete
  2454. )
  2455. /*++
  2456. Routine Description:
  2457. This method does the work of unregistering an interface from this
  2458. rpc server. We actually do not remove the interface; what we do
  2459. is to one or all of the manager entry point vector depending upon
  2460. the type uuid argument supplied.
  2461. Arguments:
  2462. RpcInterfaceInformation - Supplies a description of the interface
  2463. for which we want to unregister one or all manager entry point
  2464. vectors.
  2465. ManagerTypeUuid - Optionally supplies the type uuid of the manager
  2466. entry point vector to be removed. If this argument is not supplied,
  2467. then all manager entry point vectors for this interface will
  2468. be removed.
  2469. WaitForCallsToComplete - Supplies a flag indicating whether or not
  2470. this routine should wait for all calls to complete using the
  2471. interface and manager being unregistered. A non-zero value
  2472. indicates to wait.
  2473. Return Value:
  2474. RPC_S_OK - The manager entry point vector(s) are(were) successfully
  2475. removed from the specified interface.
  2476. RPC_S_UNKNOWN_MGR_TYPE - The specified type uuid is not registered
  2477. with the interface.
  2478. RPC_S_UNKNOWN_IF - The specified interface is not registered with
  2479. the rpc server.
  2480. --*/
  2481. {
  2482. RPC_INTERFACE * RpcInterface;
  2483. RPC_STATUS RpcStatus;
  2484. RPC_STATUS Status;
  2485. int i;
  2486. DictionaryCursor cursor;
  2487. UNUSED(WaitForCallsToComplete);
  2488. if (ARGUMENT_PRESENT(RpcInterfaceInformation))
  2489. {
  2490. ServerMutex.Request();
  2491. RpcInterface = FindInterface(RpcInterfaceInformation);
  2492. ServerMutex.Clear();
  2493. if (RpcInterface == 0)
  2494. return(RPC_S_UNKNOWN_IF);
  2495. if (RpcInterface->IsAutoListenInterface())
  2496. {
  2497. GlobalRpcServer->DecrementAutoListenInterfaceCount() ;
  2498. }
  2499. // We need to wait for all auto-listen calls to complete regardless
  2500. // of whether this is autolisten or non-autolisten interface.
  2501. // This is necessary because security callbacks increment the
  2502. // AutoListenCallCount on dispatch to protect interface against being unregistered.
  2503. while ( RpcInterface->InqAutoListenCallCount() )
  2504. {
  2505. RPC_ADDRESS * Address;
  2506. ServerMutex.Request();
  2507. RpcAddressDictionary.Reset(cursor);
  2508. while (0 != (Address = RpcAddressDictionary.Next(cursor)))
  2509. {
  2510. Address->EncourageCallCleanup(RpcInterface);
  2511. }
  2512. ServerMutex.Clear();
  2513. PauseExecution(500);
  2514. }
  2515. return(RpcInterface->UnregisterManagerEpv(ManagerTypeUuid,
  2516. WaitForCallsToComplete));
  2517. }
  2518. Status = RPC_S_UNKNOWN_MGR_TYPE;
  2519. ServerMutex.Request();
  2520. RpcInterfaceDictionary.Reset(cursor);
  2521. while ((RpcInterface = RpcInterfaceDictionary.Next(cursor)) != 0)
  2522. {
  2523. // auto-listen intefaces have to be individually unregistered
  2524. if (RpcInterface->IsAutoListenInterface())
  2525. {
  2526. continue;
  2527. }
  2528. RpcStatus = RpcInterface->UnregisterManagerEpv(ManagerTypeUuid,
  2529. WaitForCallsToComplete);
  2530. if (RpcStatus == RPC_S_OK)
  2531. {
  2532. Status = RPC_S_OK;
  2533. }
  2534. }
  2535. ServerMutex.Clear();
  2536. return(Status);
  2537. }
  2538. RPC_STATUS
  2539. RPC_SERVER::InquireManagerEpv (
  2540. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
  2541. IN RPC_UUID PAPI * ManagerTypeUuid, OPTIONAL
  2542. OUT RPC_MGR_EPV PAPI * PAPI * ManagerEpv
  2543. )
  2544. /*++
  2545. Routine Description:
  2546. This method is used to obtain the manager entry point vector for
  2547. an interface supported by this rpc server. A type uuid argument
  2548. specifies which manager entry point vector is to be obtained.
  2549. Arguments:
  2550. RpcInterfaceInformation - Supplies a description of the interface.
  2551. ManagerTypeUuid - Optionally supplies the type uuid of the manager
  2552. entry point vector we want returned. If no manager type uuid
  2553. is specified, then the null uuid is assumed.
  2554. ManagerEpv - Returns the manager entry point vector.
  2555. Return Value:
  2556. RPC_S_OK - The manager entry point vector has successfully been
  2557. returned.
  2558. RPC_S_UNKNOWN_MGR_TYPE - The specified type uuid is not registered
  2559. with the interface.
  2560. RPC_S_UNKNOWN_IF - The specified interface is not registered with
  2561. the rpc server.
  2562. --*/
  2563. {
  2564. RPC_INTERFACE * RpcInterface;
  2565. ServerMutex.Request();
  2566. RpcInterface = FindInterface(RpcInterfaceInformation);
  2567. ServerMutex.Clear();
  2568. if (RpcInterface == 0)
  2569. return(RPC_S_UNKNOWN_IF);
  2570. return(RpcInterface->InquireManagerEpv(ManagerTypeUuid, ManagerEpv));
  2571. }
  2572. RPC_STATUS
  2573. RPC_SERVER::InquireBindings (
  2574. OUT RPC_BINDING_VECTOR PAPI * PAPI * BindingVector
  2575. )
  2576. /*++
  2577. Routine Description:
  2578. For each rpc protocol sequence registered with this rpc server
  2579. we want to create a binding handle which can be used to make
  2580. remote procedure calls using the registered rpc protocol sequence.
  2581. We return a vector of these binding handles.
  2582. Arguments:
  2583. BindingVector - Returns the vector of binding handles.
  2584. Return Value:
  2585. RPC_S_OK - At least one rpc protocol sequence has been registered
  2586. with this rpc server, and the operation completed successfully.
  2587. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete
  2588. the operation.
  2589. RPC_S_NO_BINDINGS - No rpc protocol sequences have been successfully
  2590. registered with this rpc server.
  2591. --*/
  2592. {
  2593. RPC_BINDING_VECTOR PAPI * RpcBindingVector;
  2594. unsigned int Index, RpcAddressIndex;
  2595. RPC_ADDRESS * RpcAddress;
  2596. BINDING_HANDLE * BindingHandle;
  2597. int i ;
  2598. RPC_CHAR PAPI * LocalNetworkAddress;
  2599. int count = 0 ;
  2600. DictionaryCursor cursor;
  2601. ServerMutex.Request();
  2602. if (RpcAddressDictionary.Size() == 0
  2603. && RpcDormantAddresses.IsQueueEmpty())
  2604. {
  2605. ServerMutex.Clear();
  2606. return(RPC_S_NO_BINDINGS);
  2607. }
  2608. RpcAddressDictionary.Reset(cursor);
  2609. while ((RpcAddress = RpcAddressDictionary.Next(cursor)) != 0)
  2610. {
  2611. count += RpcAddress->InqNumNetworkAddress();
  2612. }
  2613. RpcBindingVector = (RPC_BINDING_VECTOR PAPI *) RpcpFarAllocate(
  2614. sizeof(RPC_BINDING_VECTOR) + (count -1 )
  2615. * sizeof(RPC_BINDING_HANDLE) );
  2616. if (RpcBindingVector == 0)
  2617. {
  2618. ServerMutex.Clear();
  2619. return(RPC_S_OUT_OF_MEMORY);
  2620. }
  2621. RpcBindingVector->Count = count;
  2622. for (Index = 0; Index < RpcBindingVector->Count; Index++)
  2623. RpcBindingVector->BindingH[Index] = 0;
  2624. Index = 0;
  2625. RpcAddressDictionary.Reset(cursor);
  2626. while ((RpcAddress = RpcAddressDictionary.Next(cursor)) != 0)
  2627. {
  2628. RpcAddressIndex = 0;
  2629. LocalNetworkAddress = RpcAddress->
  2630. GetListNetworkAddress(RpcAddressIndex) ;
  2631. while(LocalNetworkAddress != NULL)
  2632. {
  2633. BindingHandle = RpcAddress->
  2634. InquireBinding(LocalNetworkAddress);
  2635. if (BindingHandle == 0)
  2636. {
  2637. ServerMutex.Clear();
  2638. RpcBindingVectorFree(&RpcBindingVector);
  2639. return(RPC_S_OUT_OF_MEMORY);
  2640. }
  2641. RpcBindingVector->BindingH[Index] = BindingHandle;
  2642. Index += 1;
  2643. RpcAddressIndex += 1;
  2644. LocalNetworkAddress = RpcAddress->
  2645. GetListNetworkAddress(RpcAddressIndex) ;
  2646. }
  2647. }
  2648. ServerMutex.Clear();
  2649. ASSERT(Index == RpcBindingVector->Count);
  2650. *BindingVector = RpcBindingVector;
  2651. return(RPC_S_OK);
  2652. }
  2653. RPC_STATUS
  2654. RPC_SERVER::RegisterAuthInfoHelper (
  2655. IN RPC_CHAR PAPI * ServerPrincipalName,
  2656. IN unsigned long AuthenticationService,
  2657. IN RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFunction, OPTIONAL
  2658. IN void PAPI * Argument OPTIONAL
  2659. )
  2660. {
  2661. RPC_AUTHENTICATION * Service;
  2662. RPC_STATUS RpcStatus;
  2663. RPC_CHAR __RPC_FAR * PrincipalName;
  2664. DictionaryCursor cursor;
  2665. BOOL EmptySPNAllocated = FALSE;
  2666. if (ServerPrincipalName == NULL)
  2667. {
  2668. ServerPrincipalName = new RPC_CHAR[1];
  2669. if (ServerPrincipalName == NULL)
  2670. {
  2671. return (RPC_S_OUT_OF_MEMORY);
  2672. }
  2673. EmptySPNAllocated = TRUE;
  2674. ServerPrincipalName[0] = '\0';
  2675. }
  2676. if ( AuthenticationService == 0 )
  2677. {
  2678. return(RPC_S_UNKNOWN_AUTHN_SERVICE);
  2679. }
  2680. if (AuthenticationService == RPC_C_AUTHN_DEFAULT)
  2681. {
  2682. RpcpGetDefaultSecurityProviderInfo();
  2683. AuthenticationService = DefaultProviderId;
  2684. }
  2685. ServerMutex.Request();
  2686. AuthenticationDictionary.Reset(cursor);
  2687. while ( (Service = AuthenticationDictionary.Next(cursor)) != 0 )
  2688. {
  2689. if ( Service->AuthenticationService == AuthenticationService &&
  2690. 0 == RpcpStringCompare(Service->ServerPrincipalName, ServerPrincipalName))
  2691. {
  2692. Service->GetKeyFunction = GetKeyFunction;
  2693. Service->Argument = Argument;
  2694. ServerMutex.Clear();
  2695. if (EmptySPNAllocated)
  2696. delete [] ServerPrincipalName;
  2697. // Flush the server-credentials cache
  2698. RpcStatus = RemoveCredentialsFromCache(AuthenticationService);
  2699. return (RpcStatus);
  2700. }
  2701. }
  2702. RpcStatus = IsAuthenticationServiceSupported(AuthenticationService);
  2703. if ( RpcStatus != RPC_S_OK )
  2704. {
  2705. ServerMutex.Clear();
  2706. if ( (RpcStatus == RPC_S_UNKNOWN_AUTHN_SERVICE) ||
  2707. (RpcStatus == RPC_S_UNKNOWN_AUTHN_LEVEL) )
  2708. {
  2709. return (RPC_S_UNKNOWN_AUTHN_SERVICE);
  2710. }
  2711. else
  2712. {
  2713. return (RPC_S_OUT_OF_MEMORY);
  2714. }
  2715. }
  2716. Service = new RPC_AUTHENTICATION;
  2717. if ( Service == 0 )
  2718. {
  2719. ServerMutex.Clear();
  2720. return(RPC_S_OUT_OF_MEMORY);
  2721. }
  2722. Service->AuthenticationService = AuthenticationService;
  2723. Service->ServerPrincipalName = DuplicateString(ServerPrincipalName);
  2724. Service->GetKeyFunction = GetKeyFunction;
  2725. Service->Argument = Argument;
  2726. if ( Service->ServerPrincipalName == 0 )
  2727. {
  2728. ServerMutex.Clear();
  2729. delete Service;
  2730. return(RPC_S_OUT_OF_MEMORY);
  2731. }
  2732. if ( AuthenticationDictionary.Insert(Service) == -1 )
  2733. {
  2734. ServerMutex.Clear();
  2735. delete Service;
  2736. return(RPC_S_OUT_OF_MEMORY);
  2737. }
  2738. ServerMutex.Clear();
  2739. return(RPC_S_OK);
  2740. }
  2741. RPC_STATUS
  2742. RPC_SERVER::AutoRegisterAuthSvc(
  2743. IN RPC_CHAR * ServerPrincipalName,
  2744. IN unsigned long AuthenticationService
  2745. )
  2746. {
  2747. RPC_STATUS Status;
  2748. DictionaryCursor cursor;
  2749. RPC_AUTHENTICATION * Service;
  2750. //
  2751. // Don't need to auto-register the provider if it is already registered
  2752. //
  2753. ServerMutex.Request();
  2754. AuthenticationDictionary.Reset(cursor);
  2755. while ( (Service = AuthenticationDictionary.Next(cursor)) != 0 )
  2756. {
  2757. if ( Service->AuthenticationService == AuthenticationService)
  2758. {
  2759. ServerMutex.Clear();
  2760. return (RPC_S_OK);
  2761. }
  2762. }
  2763. ServerMutex.Clear();
  2764. Status = RegisterAuthInfoHelper(ServerPrincipalName,
  2765. AuthenticationService,
  2766. NULL,
  2767. NULL);
  2768. if (Status == RPC_S_UNKNOWN_AUTHN_SERVICE)
  2769. {
  2770. //
  2771. // Ok to not register provider if it is disabled
  2772. //
  2773. return RPC_S_OK;
  2774. }
  2775. return Status;
  2776. }
  2777. RPC_STATUS
  2778. RPC_SERVER::RegisterAuthInformation (
  2779. IN RPC_CHAR PAPI * ServerPrincipalName,
  2780. IN unsigned long AuthenticationService,
  2781. IN RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFunction, OPTIONAL
  2782. IN void PAPI * Argument OPTIONAL
  2783. )
  2784. /*++
  2785. Routine Description:
  2786. This method is used to register authentication, authorization, and
  2787. a server principal name to be used for security for this server. We
  2788. will use this information to authenticate remote procedure calls.
  2789. Arguments:
  2790. ServerPrincipalName - Supplies the principal name for the server.
  2791. AuthenticationService - Supplies an authentication service to use when
  2792. the server receives a remote procedure call.
  2793. GetKeyFunction - Optionally supplies a routine to be used when the runtime
  2794. needs an encryption key.
  2795. Argument - Optionally supplies an argument to be passed to the routine used
  2796. to get keys each time it is called.
  2797. Return Value:
  2798. RPC_S_OK - The authentication service and server principal name have
  2799. been registered with this RPC server.
  2800. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete the
  2801. operation.
  2802. RPC_S_UNKNOWN_AUTHN_SERVICE - The specified authentication service is
  2803. not supported.
  2804. --*/
  2805. {
  2806. RPC_STATUS Status;
  2807. RPC_CHAR *PrincName;
  2808. Status = RegisterAuthInfoHelper(ServerPrincipalName,
  2809. AuthenticationService,
  2810. GetKeyFunction,
  2811. Argument);
  2812. if (Status != RPC_S_OK)
  2813. {
  2814. return Status;
  2815. }
  2816. if (AuthenticationService != RPC_C_AUTHN_GSS_NEGOTIATE)
  2817. {
  2818. return RPC_S_OK;
  2819. }
  2820. Status = AutoRegisterAuthSvc(ServerPrincipalName, RPC_C_AUTHN_WINNT);
  2821. if (Status != RPC_S_OK)
  2822. {
  2823. return Status;
  2824. }
  2825. Status = AutoRegisterAuthSvc(ServerPrincipalName, RPC_C_AUTHN_GSS_KERBEROS);
  2826. return Status;
  2827. }
  2828. RPC_STATUS
  2829. RPC_SERVER::AcquireCredentials (
  2830. IN unsigned long AuthenticationService,
  2831. IN unsigned long AuthenticationLevel,
  2832. OUT SECURITY_CREDENTIALS ** SecurityCredentials
  2833. )
  2834. /*++
  2835. Routine Description:
  2836. The protocol modules will use this to obtain a set of credentials
  2837. for the specified authentication service, assuming that the server
  2838. supports them.
  2839. Arguments:
  2840. AuthenticationService - Supplies the authentication service for which
  2841. we hope to obtain credentials.
  2842. AuthenticationLevel - Supplies the authentication level to be used.
  2843. SecurityCredentials - Returns the security credentials.
  2844. Return Value:
  2845. RPC_S_OK - You have been given some security credentials, which you need
  2846. to free using RPC_SERVER::FreeCredentials when you are done with
  2847. them.
  2848. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete the
  2849. operation.
  2850. RPC_S_UNKNOWN_AUTHN_SERVICE - The specified authentication service is
  2851. not supported by the current configuration.
  2852. --*/
  2853. {
  2854. RPC_AUTHENTICATION * Service;
  2855. RPC_STATUS RpcStatus = RPC_S_OK;
  2856. DictionaryCursor cursor;
  2857. ServerMutex.Request();
  2858. AuthenticationDictionary.Reset(cursor);
  2859. while ( (Service = AuthenticationDictionary.Next(cursor)) != 0 )
  2860. {
  2861. if ( Service->AuthenticationService == AuthenticationService )
  2862. {
  2863. ServerMutex.Clear();
  2864. RpcStatus = FindServerCredentials(
  2865. Service->GetKeyFunction,
  2866. Service->Argument,
  2867. AuthenticationService,
  2868. AuthenticationLevel,
  2869. Service->ServerPrincipalName,
  2870. SecurityCredentials
  2871. );
  2872. VALIDATE(RpcStatus)
  2873. {
  2874. RPC_S_OK,
  2875. RPC_S_SEC_PKG_ERROR,
  2876. RPC_S_OUT_OF_MEMORY,
  2877. RPC_S_INVALID_AUTH_IDENTITY,
  2878. ERROR_SHUTDOWN_IN_PROGRESS,
  2879. RPC_S_UNKNOWN_AUTHN_SERVICE
  2880. } END_VALIDATE;
  2881. return(RpcStatus);
  2882. }
  2883. }
  2884. ServerMutex.Clear();
  2885. return(RPC_S_UNKNOWN_AUTHN_SERVICE);
  2886. }
  2887. void
  2888. RPC_SERVER::FreeCredentials (
  2889. IN SECURITY_CREDENTIALS * SecurityCredentials
  2890. )
  2891. /*++
  2892. Routine Description:
  2893. A protocol module will indicate that it is through using a set of
  2894. security credentials, obtained from RPC_SERVER::AcquireCredentials,
  2895. using this routine.
  2896. Arguments:
  2897. SecurityCredentials - Supplies the security credentials to be freed.
  2898. --*/
  2899. {
  2900. SecurityCredentials->FreeCredentials();
  2901. delete SecurityCredentials;
  2902. }
  2903. RPC_STATUS
  2904. RPC_SERVER::RegisterInterface (
  2905. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
  2906. IN RPC_UUID PAPI * ManagerTypeUuid,
  2907. IN RPC_MGR_EPV PAPI * ManagerEpv,
  2908. IN unsigned int Flags,
  2909. IN unsigned int MaxCalls,
  2910. IN unsigned int MaxRpcSize,
  2911. IN RPC_IF_CALLBACK_FN PAPI *IfCallbackFn
  2912. )
  2913. /*++
  2914. Routine Description:
  2915. This routine is used by server application to register a manager
  2916. entry point vector and optionally an interface. If the interface
  2917. has not been registered, then it will be registered. If it has
  2918. already been registered, the manager entry point vector will be
  2919. added to it under the specified type uuid.
  2920. Arguments:
  2921. RpcInterfaceInformation - Supplies a description of the interface to
  2922. be registered. We will make a copy of this information.
  2923. ManagerTypeUuid - Optionally supplies the type uuid for the specified
  2924. manager entry point vector. If no type uuid is supplied, then
  2925. the null uuid will be used as the type uuid.
  2926. ManagerEpv - Optionally supplies a manager entry point vector corresponding
  2927. to the type uuid. If a manager entry point vector is not supplied,
  2928. then the manager entry point vector in the interface will be
  2929. used.
  2930. Return Value:
  2931. RPC_S_OK - The specified rpc interface has been successfully
  2932. registered with the rpc server. It is now ready to accept
  2933. remote procedure calls.
  2934. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to register
  2935. the rpc interface with the rpc server.
  2936. RPC_S_TYPE_ALREADY_REGISTERED - A manager entry point vector has
  2937. already been registered for the supplied rpc interface and
  2938. manager type UUID.
  2939. --*/
  2940. {
  2941. RPC_STATUS RpcStatus;
  2942. RPC_INTERFACE * RpcInterface;
  2943. RPC_ADDRESS *RpcAddress ;
  2944. DictionaryCursor cursor;
  2945. BOOL fInterfaceFound;
  2946. if ( ManagerEpv == 0 )
  2947. {
  2948. ManagerEpv = RpcInterfaceInformation->DefaultManagerEpv;
  2949. if ( (PtrToUlong(ManagerEpv)) == 0xFFFFFFFF)
  2950. {
  2951. // Stub compiled with -no_default_epv.
  2952. return (RPC_S_INVALID_ARG);
  2953. }
  2954. }
  2955. ServerMutex.Request();
  2956. RpcInterface = FindOrCreateInterfaceInternal(RpcInterfaceInformation, Flags, MaxCalls,
  2957. MaxRpcSize, IfCallbackFn, &RpcStatus, &fInterfaceFound);
  2958. if (RpcInterface == NULL)
  2959. {
  2960. ServerMutex.Clear();
  2961. return RpcStatus;
  2962. }
  2963. if (fInterfaceFound)
  2964. {
  2965. // if it was found, update the information
  2966. RpcStatus = RpcInterface->UpdateRpcInterfaceInformation(RpcInterfaceInformation,
  2967. Flags, MaxCalls, MaxRpcSize, IfCallbackFn);
  2968. if (RpcStatus != RPC_S_OK)
  2969. {
  2970. ServerMutex.Clear();
  2971. return RpcStatus;
  2972. }
  2973. }
  2974. RpcStatus = RpcInterface->RegisterTypeManager(ManagerTypeUuid, ManagerEpv);
  2975. if (Flags & RPC_IF_AUTOLISTEN)
  2976. {
  2977. RpcAddressDictionary.Reset(cursor);
  2978. while ( (RpcAddress = RpcAddressDictionary.Next(cursor)) != 0 )
  2979. {
  2980. RpcStatus = RpcAddress->ServerStartingToListen(
  2981. this->MinimumCallThreads,
  2982. MaxCalls);
  2983. if (RpcStatus != RPC_S_OK)
  2984. {
  2985. break;
  2986. }
  2987. }
  2988. }
  2989. ServerMutex.Clear();
  2990. return(RpcStatus);
  2991. }
  2992. void RPC_SERVER::CreateOrUpdateAddresses (void)
  2993. /*++
  2994. Function Name: CreateOrUpdateAddresses
  2995. Parameters:
  2996. Description:
  2997. The runtime just received a notification that a new protocol was loaded. We need
  2998. to create an ADDRESS object, listen on it and update the RPCSS bindings
  2999. appropriately.
  3000. Returns:
  3001. --*/
  3002. {
  3003. RPC_STATUS Status;
  3004. RPC_BINDING_VECTOR *BindingVector = 0;
  3005. RPC_INTERFACE * RpcInterface;
  3006. BOOL fChanged = 0;
  3007. RPC_ADDRESS *Address;
  3008. QUEUE tempQueue;
  3009. BOOL fTempQueueHasContents = FALSE;
  3010. int i;
  3011. DictionaryCursor cursor;
  3012. while (1)
  3013. {
  3014. unsigned int Length;
  3015. ServerMutex.Request();
  3016. Address = (RPC_ADDRESS *) RpcDormantAddresses.TakeOffQueue(&Length);
  3017. ServerMutex.Clear();
  3018. if (Address == 0)
  3019. {
  3020. break;
  3021. }
  3022. ASSERT(Length == 0);
  3023. if (Address->RestartAddress(MinimumCallThreads,
  3024. MaximumConcurrentCalls) != RPC_S_OK)
  3025. {
  3026. fTempQueueHasContents = TRUE;
  3027. if (tempQueue.PutOnQueue(Address, 0) != 0)
  3028. {
  3029. // putting on the temporary queue failed - out of memory
  3030. // in this case we'd rather cut the PnP process for now, and we'll
  3031. // go with what we have
  3032. // return the address
  3033. ServerMutex.Request();
  3034. // guaranteed to succeed
  3035. RpcDormantAddresses.PutOnQueue(Address, 0);
  3036. ServerMutex.Clear();
  3037. // break into merging the temp queue with the permanent one
  3038. break;
  3039. }
  3040. }
  3041. else
  3042. {
  3043. fChanged = 1;
  3044. }
  3045. }
  3046. if (fTempQueueHasContents)
  3047. {
  3048. ServerMutex.Request();
  3049. // merge back the queues - this should succeed if we have only added protocols. If we have
  3050. // removed protocols, this will fail, and we'll have a bug. Nothing we can do about it here.
  3051. RpcDormantAddresses.MergeWithQueue(&tempQueue);
  3052. ServerMutex.Clear();
  3053. }
  3054. if (fChanged)
  3055. {
  3056. ServerMutex.Request();
  3057. //
  3058. // Inquire the new bindings, and update them in the endpoint mapper
  3059. //
  3060. Status = InquireBindings(&BindingVector);
  3061. if (Status != RPC_S_OK)
  3062. {
  3063. goto Cleanup;
  3064. }
  3065. RpcInterfaceDictionary.Reset(cursor);
  3066. while ((RpcInterface = RpcInterfaceDictionary.Next(cursor)) != 0)
  3067. {
  3068. if (RpcInterface->NeedToUpdateBindings())
  3069. {
  3070. // we know an interface never gets deleted, only marked as
  3071. // unregistered. Therefore, it is safe to release the mutex
  3072. // and do the slow UpdateBindings outside the mutex
  3073. ServerMutex.Clear();
  3074. if ((Status = RpcInterface->UpdateBindings(BindingVector))
  3075. != RPC_S_OK)
  3076. {
  3077. goto Cleanup;
  3078. }
  3079. ServerMutex.Request();
  3080. }
  3081. }
  3082. ServerMutex.Clear();
  3083. Status = RpcBindingVectorFree(&BindingVector);
  3084. ASSERT(Status == RPC_S_OK);
  3085. }
  3086. return;
  3087. Cleanup:
  3088. if (BindingVector)
  3089. {
  3090. Status = RpcBindingVectorFree(&BindingVector);
  3091. ASSERT(Status == RPC_S_OK);
  3092. }
  3093. }
  3094. // This is an external routine defined in NDR that can be used to
  3095. // determine whether a given interface has been compiled with /robust.
  3096. extern RPC_STATUS
  3097. CheckForRobust (
  3098. IN RPC_SERVER_INTERFACE * pServerIfInfo
  3099. );
  3100. RPC_INTERFACE *
  3101. RPC_SERVER::FindOrCreateInterfaceInternal (
  3102. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
  3103. IN unsigned int Flags,
  3104. IN unsigned int MaxCalls,
  3105. IN unsigned int MaxRpcSize,
  3106. IN RPC_IF_CALLBACK_FN PAPI *IfCallbackFn,
  3107. OUT RPC_STATUS *Status,
  3108. OUT BOOL *fInterfaceFound
  3109. )
  3110. /*++
  3111. Function Name: FindOrCreateInterfaceInternal
  3112. Parameters:
  3113. RpcInterfaceInformation
  3114. Flags
  3115. MaxCalls
  3116. MaxRpcSize
  3117. IfCallbackFn
  3118. Status - meaningless if the return value is not NULL.
  3119. fInterfaceFound - TRUE if the interface was found, FALSE if it was created
  3120. Description:
  3121. Find or creates an interface with the appropriate parameters
  3122. Returns:
  3123. --*/
  3124. {
  3125. RPC_INTERFACE * RpcInterface;
  3126. DictionaryCursor cursor;
  3127. ServerMutex.VerifyOwned();
  3128. RpcInterface = FindInterface(RpcInterfaceInformation);
  3129. if ( RpcInterface == 0 )
  3130. {
  3131. RpcInterface = new RPC_INTERFACE(RpcInterfaceInformation,
  3132. this, Flags, MaxCalls, MaxRpcSize, IfCallbackFn, Status);
  3133. if ( RpcInterface == 0 )
  3134. {
  3135. *Status = RPC_S_OUT_OF_MEMORY;
  3136. return NULL;
  3137. }
  3138. if ( AddInterface(RpcInterface) != 0 )
  3139. {
  3140. delete RpcInterface;
  3141. *Status = RPC_S_OUT_OF_MEMORY;
  3142. return NULL;
  3143. }
  3144. if (Flags & RPC_IF_AUTOLISTEN)
  3145. {
  3146. GlobalRpcServer->IncrementAutoListenInterfaceCount() ;
  3147. }
  3148. *fInterfaceFound = FALSE;
  3149. }
  3150. else
  3151. {
  3152. *fInterfaceFound = TRUE;
  3153. }
  3154. *Status = RPC_S_OK;
  3155. // If we have created a new interface we may need to do some security checks.
  3156. // When RPC verifier is enabled, check to see if this interface is
  3157. // unsecure and whether the server is remotely accessible.
  3158. // Make sure we only check or warn the first time an IF is registered.
  3159. if (gfRPCVerifierEnabledWithBreaks && (*fInterfaceFound == FALSE))
  3160. {
  3161. UUID *IfUuid = &(RpcInterface->InqInterfaceInformation()->InterfaceId.SyntaxGUID);
  3162. // An interface is unsecure when it is registered without a security callback,
  3163. // allows un-authenticated access, and is not exempt.
  3164. // We do not flag COM interfaces registered with RPC_IF_OLE flag because
  3165. // they do their own things.
  3166. if (!RpcInterface->IsSecure() &&
  3167. !(Flags & RPC_IF_OLE) &&
  3168. !IsInterfaceExempt(IfUuid, ALLOW_UNSECURE_REMOTE_ACCESS)
  3169. )
  3170. {
  3171. gfUnsecureInterfaceRegistered = true;
  3172. // If the server is remotely accessible, print a warning, listing
  3173. // the endpoints on which the server is listening.
  3174. if (gfRemoteProtseqRegistered)
  3175. {
  3176. RPC_ADDRESS *Address;
  3177. RPC_VERIFIER_WARNING_MSG("Possible security threat: Server that is remotely accessible is registering an unsecure interface",
  3178. RPC_VERIFIER_UNSECURE_IF_REMOTELY_ACCESSIBLE);
  3179. // Print the unsecure IF that is being registred.
  3180. DbgPrint("RPC: Unsecure interface UUID: ");
  3181. PrintUUID(IfUuid);
  3182. DbgPrint("\n");
  3183. // Print the list of remotely accessible endpoints
  3184. // the server is listening on.
  3185. ServerMutex.Request();
  3186. RpcAddressDictionary.Reset(cursor);
  3187. while ((Address = RpcAddressDictionary.Next(cursor)) != 0)
  3188. {
  3189. // Check if the address is a remote one.
  3190. if (RpcpStringCompare(Address->InqRpcProtocolSequence(),
  3191. RPC_CONST_STRING("ncalrpc")) != 0)
  3192. {
  3193. DbgPrint("RPC: Listening on protseq: %S endpoint: %S\n",
  3194. Address->InqRpcProtocolSequence(),
  3195. Address->InqEndpoint());
  3196. }
  3197. }
  3198. ServerMutex.Clear();
  3199. RPC_VERIFIER_PRINT_OFFENDING_STACK(2, 4);
  3200. }
  3201. }
  3202. // Do not do /robust check for COM interfaces.
  3203. // It will be done on the NDR level during the proxy registration.
  3204. if (!(Flags & RPC_IF_OLE))
  3205. {
  3206. // Check whether the interface has been compiled with /robust switch.
  3207. // We will call into NDR to perform the check.
  3208. if (CheckForRobust(RpcInterface->InqInterfaceInformation()) != RPC_S_OK)
  3209. {
  3210. RPC_VERIFIER_WARNING_MSG("Possible security threat: Server registers an interface compiled without /robust option",
  3211. RPC_VERIFIER_REGISTERING_NONROBUST_IF);
  3212. DbgPrint("RPC: Unsecure interface UUID: ");
  3213. PrintUUID(&(RpcInterface->InqInterfaceInformation()->InterfaceId.SyntaxGUID));
  3214. DbgPrint("\n");
  3215. RPC_VERIFIER_PRINT_OFFENDING_STACK(2, 4);
  3216. }
  3217. }
  3218. }
  3219. return RpcInterface;
  3220. }
  3221. RPC_INTERFACE *
  3222. RPC_SERVER::FindOrCreateInterface (
  3223. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
  3224. OUT RPC_STATUS *Status
  3225. )
  3226. {
  3227. RPC_INTERFACE * RpcInterface;
  3228. BOOL fIgnored;
  3229. ServerMutex.Request();
  3230. RpcInterface = FindOrCreateInterfaceInternal(RpcInterfaceInformation,
  3231. RPC_IF_ALLOW_SECURE_ONLY, 0, gMaxRpcSize, NULL, Status, &fIgnored);
  3232. ServerMutex.Clear();
  3233. return RpcInterface;
  3234. }
  3235. RPC_STATUS
  3236. RPC_SERVER::InterfaceExported (
  3237. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
  3238. IN UUID_VECTOR *MyObjectUuidVector,
  3239. IN unsigned char *MyAnnotation,
  3240. IN BOOL MyfReplace
  3241. )
  3242. /*++
  3243. Function Name:InterfaceExported
  3244. Parameters:
  3245. Description:
  3246. RpcEpRegister was called on this interface. We need to keep track
  3247. of the parameters, so that if we get a PNP notification, we can update
  3248. the bindings using there params
  3249. Returns:
  3250. --*/
  3251. {
  3252. RPC_INTERFACE * RpcInterface;
  3253. RPC_STATUS Status;
  3254. RpcInterface = FindOrCreateInterface (RpcInterfaceInformation, &Status);
  3255. if (RpcInterface == NULL)
  3256. {
  3257. return Status;
  3258. }
  3259. return RpcInterface->InterfaceExported(
  3260. MyObjectUuidVector,
  3261. MyAnnotation,
  3262. MyfReplace);
  3263. }
  3264. #if !defined(NO_LOCATOR_CODE)
  3265. RPC_STATUS
  3266. RPC_SERVER::NsInterfaceExported (
  3267. IN unsigned long EntryNameSyntax,
  3268. IN RPC_CHAR *EntryName,
  3269. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
  3270. IN BOOL fUnexport
  3271. )
  3272. {
  3273. RPC_INTERFACE * RpcInterface;
  3274. RPC_STATUS Status;
  3275. HMODULE hLocator;
  3276. if (pNsBindingExport == 0)
  3277. {
  3278. hLocator = LoadLibrary ((const RPC_SCHAR *)RPC_CONST_STRING("rpcns4.dll"));
  3279. if (hLocator == 0)
  3280. {
  3281. return RPC_S_OUT_OF_MEMORY;
  3282. }
  3283. pNsBindingExport = (NS_EXPORT_FUNC) GetProcAddress(hLocator,
  3284. "RpcNsBindingExportW");
  3285. if (pNsBindingExport == 0)
  3286. {
  3287. return RPC_S_OUT_OF_MEMORY;
  3288. }
  3289. pNsBindingUnexport = (NS_UNEXPORT_FUNC) GetProcAddress(hLocator,
  3290. "RpcNsBindingUnexportW");
  3291. if (pNsBindingUnexport == 0)
  3292. {
  3293. pNsBindingExport = 0;
  3294. return RPC_S_OUT_OF_MEMORY;
  3295. }
  3296. }
  3297. RpcInterface = FindOrCreateInterface (RpcInterfaceInformation, &Status);
  3298. if (RpcInterface == NULL)
  3299. {
  3300. return Status;
  3301. }
  3302. if (fUnexport == 0)
  3303. {
  3304. return RpcInterface->NsInterfaceExported(
  3305. EntryNameSyntax,
  3306. EntryName);
  3307. }
  3308. else
  3309. {
  3310. return RpcInterface->NsInterfaceUnexported(
  3311. EntryNameSyntax,
  3312. EntryName);
  3313. }
  3314. }
  3315. #endif
  3316. RPC_STATUS
  3317. RPC_SERVER::EnumerateAndCallEachAddress (
  3318. IN AddressCallbackType actType,
  3319. IN OUT void *Context OPTIONAL
  3320. )
  3321. /*++
  3322. Function Name: DestroyContextHandlesForInterface
  3323. Parameters:
  3324. actType - the type of callback.
  3325. Context - opaque memory block to be passed to the callback.
  3326. Description:
  3327. This function is called when we want to invoke a specific method
  3328. on each address.
  3329. Returns:
  3330. RPC_S_OK for success or RPC_S_* for error
  3331. --*/
  3332. {
  3333. RPC_ADDRESS_DICT AddressDict;
  3334. RPC_ADDRESS_DICT *AddressDictToUse;
  3335. RPC_ADDRESS *CurrentAddress;
  3336. BOOL UsingAddressDictionaryCopy;
  3337. int Result;
  3338. DictionaryCursor cursor;
  3339. DestroyContextHandleCallbackContext *ContextHandleContext;
  3340. // try to copy all entries in the address dictionary to the local
  3341. // dictionary. We will walk the address list from there to avoid
  3342. // holding the server mutex while walking potentially large tree.
  3343. // If we do that, only the page faults will be enough to kill the
  3344. // server. On the other hand, we can't rely that the memory will be
  3345. // there. Therefore, we attempt to copy the dictionary under the
  3346. // mutex, but if this fails, we will retain the mutex and go ahead
  3347. // with the cleanup. The logic behind this is that if we don't have
  3348. // the few bytes to copy the dictionary, probably the server isn't
  3349. // doing anything, and holding the mutex won't hurt it anymore
  3350. ServerMutex.Request();
  3351. #if DBG
  3352. if (actType == actDestroyContextHandle)
  3353. {
  3354. RPC_INTERFACE *Interface;
  3355. ContextHandleContext = (DestroyContextHandleCallbackContext *)Context;
  3356. Interface = FindInterface(ContextHandleContext->RpcInterfaceInformation);
  3357. ASSERT(Interface);
  3358. // the interface must use strict context handles
  3359. ASSERT(Interface->DoesInterfaceUseNonStrict() == FALSE);
  3360. }
  3361. #endif
  3362. UsingAddressDictionaryCopy = AddressDict.ExpandToSize(RpcAddressDictionary.Size());
  3363. if (UsingAddressDictionaryCopy)
  3364. {
  3365. AddressDictToUse = &AddressDict;
  3366. RpcAddressDictionary.Reset(cursor);
  3367. while ( (CurrentAddress = RpcAddressDictionary.Next(cursor)) != 0 )
  3368. {
  3369. // we never destroy addresses. Therefore, we don't need to mark
  3370. // those addresses as used in any way
  3371. Result = AddressDict.Insert(CurrentAddress);
  3372. // this must succeed as we have reserved enough size
  3373. ASSERT(Result != -1);
  3374. }
  3375. ServerMutex.Clear();
  3376. }
  3377. else
  3378. {
  3379. AddressDictToUse = &RpcAddressDictionary;
  3380. }
  3381. // N.B. We may, or may not have the ServerMutex here - depending on how
  3382. // we were doing with memory
  3383. AddressDictToUse->Reset(cursor);
  3384. while ( (CurrentAddress = AddressDictToUse->Next(cursor)) != 0 )
  3385. {
  3386. switch (actType)
  3387. {
  3388. case actDestroyContextHandle:
  3389. ContextHandleContext = (DestroyContextHandleCallbackContext *)Context;
  3390. CurrentAddress->DestroyContextHandlesForInterface(
  3391. ContextHandleContext->RpcInterfaceInformation,
  3392. ContextHandleContext->RundownContextHandles
  3393. );
  3394. break;
  3395. case actCleanupIdleSContext:
  3396. CurrentAddress->CleanupIdleSContexts();
  3397. break;
  3398. default:
  3399. ASSERT(0);
  3400. }
  3401. }
  3402. if (!UsingAddressDictionaryCopy)
  3403. {
  3404. ServerMutex.Clear();
  3405. }
  3406. return RPC_S_OK;
  3407. }
  3408. RPC_STATUS
  3409. RPC_ENTRY
  3410. I_RpcNsInterfaceExported (
  3411. IN unsigned long EntryNameSyntax,
  3412. IN unsigned short *EntryName,
  3413. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation
  3414. )
  3415. {
  3416. #if !defined(NO_LOCATOR_CODE)
  3417. InitializeIfNecessary();
  3418. if (gfRPCVerifierEnabledWithBreaks)
  3419. {
  3420. // Locator is an unsafe feature to use. We should flag it in the verifier.
  3421. RPC_VERIFIER_WARNING_MSG("Possible security threat: Client is using the locator name service",
  3422. RPC_VERIFIER_UNSAFE_FEATURE);
  3423. RPC_VERIFIER_PRINT_OFFENDING_STACK(1, 4);
  3424. }
  3425. return (GlobalRpcServer->NsInterfaceExported(
  3426. EntryNameSyntax,
  3427. EntryName,
  3428. RpcInterfaceInformation, 0));
  3429. #else
  3430. return RPC_S_CANNOT_SUPPORT;
  3431. #endif
  3432. }
  3433. RPC_STATUS
  3434. RPC_ENTRY
  3435. I_RpcNsInterfaceUnexported (
  3436. IN unsigned long EntryNameSyntax,
  3437. IN unsigned short *EntryName,
  3438. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation
  3439. )
  3440. {
  3441. #if !defined(NO_LOCATOR_CODE)
  3442. InitializeIfNecessary();
  3443. if (gfRPCVerifierEnabledWithBreaks)
  3444. {
  3445. // Locator is an unsafe feature to use. We should flag it in the verifier.
  3446. RPC_VERIFIER_WARNING_MSG("Possible security threat: Client is using the locator name service",
  3447. RPC_VERIFIER_UNSAFE_FEATURE);
  3448. RPC_VERIFIER_PRINT_OFFENDING_STACK(1, 4);
  3449. }
  3450. return (GlobalRpcServer->NsInterfaceExported(
  3451. EntryNameSyntax,
  3452. EntryName,
  3453. RpcInterfaceInformation, 1));
  3454. #else
  3455. return RPC_S_CANNOT_SUPPORT;
  3456. #endif
  3457. }
  3458. #define MAXIMUM_CACHED_THREAD_TIMEOUT (1000L * 60L * 60L)
  3459. void
  3460. BaseCachedThreadRoutine (
  3461. IN CACHED_THREAD * CachedThread
  3462. )
  3463. /*++
  3464. Routine Description:
  3465. Each thread will execute this routine. When it first gets called, it
  3466. will immediately call the procedure and parameter specified in the
  3467. cached thread object. After that it will wait on its event and then
  3468. execute the specified routine everytime it gets woken up. If the wait
  3469. on the event times out, the thread will exit unless it has been protected.
  3470. Arguments:
  3471. CachedThread - Supplies the cached thread object to be used by this
  3472. thread.
  3473. --*/
  3474. {
  3475. RPC_SERVER * RpcServer = CachedThread->OwningRpcServer;
  3476. THREAD *pThread = RpcpGetThreadPointer();
  3477. long WaitTimeout;
  3478. ASSERT(pThread);
  3479. while (pThread->ThreadHandle() == (void *) -1)
  3480. {
  3481. Sleep(1);
  3482. }
  3483. ASSERT(pThread->ThreadHandle());
  3484. CachedThread->SetThread(pThread);
  3485. if (pThread->DebugCell)
  3486. {
  3487. pThread->DebugCell->TID = (unsigned short)GetCurrentThreadId();
  3488. pThread->DebugCell->LastUpdateTime = NtGetTickCount();
  3489. }
  3490. for(;;)
  3491. {
  3492. if (CachedThread->CallProcedure())
  3493. {
  3494. #ifdef RPC_OLD_IO_PROTECTION
  3495. // This thread has already timed-out waiting on
  3496. // a transport level cache. Let it go now...
  3497. ASSERT(pThread->InqProtectCount() == 1);
  3498. #endif
  3499. if (pThread->IsIOPending() == FALSE)
  3500. {
  3501. delete CachedThread;
  3502. return;
  3503. }
  3504. // we're a cached IOCP thread - we need to unjoin the IOCP
  3505. UnjoinCompletionPort();
  3506. }
  3507. WaitTimeout = gThreadTimeout;
  3508. // Now we cache this thread. This consists of clearing the
  3509. // work available flag and inserting the thread cache object into
  3510. // the list thread cache objects.
  3511. CachedThread->WorkAvailableFlag = WorkIsNotAvailable;
  3512. RpcServer->ThreadCacheMutex.Request();
  3513. RpcServer->InsertIntoFreeList(CachedThread);
  3514. RpcServer->ThreadCacheMutex.Clear();
  3515. // Now we loop waiting for work. We get out of the loop in three
  3516. // ways: (1) a timeout occurs and there is work to do, (2) the
  3517. // event gets kicked because there is work to do, (3) a timeout
  3518. // occurs, there is no work to do, and the thread is not protected.
  3519. for (;;)
  3520. {
  3521. // Ignore spurious signals.
  3522. while( (CachedThread->WaitForWorkEvent.Wait(WaitTimeout) == 0)
  3523. && (CachedThread->WorkAvailableFlag == WorkIsNotAvailable) )
  3524. ;
  3525. if (CachedThread->WorkAvailableFlag == WorkIsAvailable)
  3526. {
  3527. break;
  3528. }
  3529. // We must take the lock to avoid a race condition where another
  3530. // thread is trying to signal us right now.
  3531. RpcServer->ThreadCacheMutex.Request();
  3532. if (CachedThread->WorkAvailableFlag)
  3533. {
  3534. RpcServer->ThreadCacheMutex.Clear();
  3535. break;
  3536. }
  3537. if (pThread->IsIOPending())
  3538. {
  3539. // If we reach here, there is no work available, and the thread
  3540. // is protected. We just need to wait again. There is no need to
  3541. // busy wait if the thread is protected and it keeps timing out.
  3542. if (WaitTimeout < MAXIMUM_CACHED_THREAD_TIMEOUT/2)
  3543. {
  3544. WaitTimeout = WaitTimeout * 2;
  3545. }
  3546. // Since this thread can't exit anyway, move it to the front of the
  3547. // free list so it will be reused first.
  3548. RpcServer->RemoveFromFreeList(CachedThread);
  3549. RpcServer->InsertIntoFreeList(CachedThread);
  3550. RpcServer->ThreadCacheMutex.Clear();
  3551. continue;
  3552. }
  3553. // No work available.
  3554. #ifdef RPC_OLD_IO_PROTECTION
  3555. ASSERT(pThread->InqProtectCount() == 1);
  3556. #endif
  3557. // There is no work available, and this thread is not
  3558. // protected, so we can safely let it commit suicide.
  3559. RpcServer->RemoveFromFreeList(CachedThread);
  3560. RpcServer->ThreadCacheMutex.Clear();
  3561. delete CachedThread;
  3562. return;
  3563. }
  3564. ASSERT(CachedThread->WorkAvailableFlag == WorkIsAvailable);
  3565. }
  3566. NO_RETURN;
  3567. }
  3568. C_ASSERT(ERROR_MAX_THRDS_REACHED == RPC_S_OUT_OF_THREADS);
  3569. RPC_STATUS
  3570. RPC_SERVER::CreateThread (
  3571. IN THREAD_PROC Procedure,
  3572. IN void * Parameter
  3573. )
  3574. /*++
  3575. Routine Description:
  3576. This routine is used to create a new thread which will begin
  3577. executing the specified procedure. The procedure will be passed
  3578. parameter as the argument.
  3579. Arguments:
  3580. Procedure - Supplies the procedure which the new thread should
  3581. begin executing.
  3582. Parameter - Supplies the argument to be passed to the procedure.
  3583. Return Value:
  3584. RPC_S_OK - We successfully created a new thread and started it
  3585. executing the supplied procedure.
  3586. RPC_S_OUT_OF_THREADS - We could not create another thread.
  3587. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate
  3588. the data structures we need to complete this operation.
  3589. --*/
  3590. {
  3591. THREAD * Thread;
  3592. CACHED_THREAD * CachedThread;
  3593. RPC_STATUS RpcStatus = RPC_S_OK;
  3594. ThreadCacheMutex.Request();
  3595. CachedThread = RemoveHeadFromFreeList();
  3596. if (CachedThread)
  3597. {
  3598. // set all parameters within the mutex to avoid races
  3599. CachedThread->SetWakeUpThreadParams(Procedure, Parameter);
  3600. ThreadCacheMutex.Clear();
  3601. CachedThread->WakeUpThread();
  3602. return(RPC_S_OK);
  3603. }
  3604. ThreadCacheMutex.Clear();
  3605. if (IsServerSideDebugInfoEnabled())
  3606. {
  3607. RpcStatus = InitializeServerSideCellHeapIfNecessary();
  3608. if (RpcStatus != RPC_S_OK)
  3609. return RpcStatus;
  3610. }
  3611. CachedThread = new CACHED_THREAD(Procedure, Parameter, this, &RpcStatus);
  3612. if ( CachedThread == 0 )
  3613. {
  3614. return(RPC_S_OUT_OF_MEMORY);
  3615. }
  3616. if ( RpcStatus != RPC_S_OK )
  3617. {
  3618. delete CachedThread;
  3619. return(RpcStatus);
  3620. }
  3621. ASSERT( RpcStatus == RPC_S_OK );
  3622. Thread = new THREAD((THREAD_PROC) BaseCachedThreadRoutine, CachedThread,
  3623. &RpcStatus);
  3624. if (Thread == 0)
  3625. {
  3626. delete CachedThread;
  3627. return(RPC_S_OUT_OF_THREADS);
  3628. }
  3629. if (RpcStatus != RPC_S_OK)
  3630. {
  3631. delete CachedThread;
  3632. delete Thread;
  3633. }
  3634. return(RpcStatus);
  3635. }
  3636. RPC_STATUS
  3637. RPC_SERVER::InquireInterfaceIds (
  3638. OUT RPC_IF_ID_VECTOR __RPC_FAR * __RPC_FAR * InterfaceIdVector
  3639. )
  3640. /*++
  3641. Routine Description:
  3642. This routine is used to obtain a vector of the interface identifiers of
  3643. the interfaces supported by this server.
  3644. Arguments:
  3645. IfIdVector - Returns a vector of the interfaces supported by this server.
  3646. Return Value:
  3647. RPC_S_OK - Everything worked out just great.
  3648. RPC_S_NO_INTERFACES - No interfaces have been registered with the runtime.
  3649. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate
  3650. the interface id vector.
  3651. --*/
  3652. {
  3653. DictionaryCursor cursor;
  3654. ServerMutex.Request();
  3655. if (RpcInterfaceDictionary.Size() == 0)
  3656. {
  3657. ServerMutex.Clear();
  3658. *InterfaceIdVector = 0;
  3659. return RPC_S_NO_INTERFACES;
  3660. }
  3661. *InterfaceIdVector = (RPC_IF_ID_VECTOR __RPC_FAR *) RpcpFarAllocate(
  3662. sizeof(RPC_IF_ID_VECTOR) + (RpcInterfaceDictionary.Size() - 1)
  3663. * sizeof(RPC_IF_ID __RPC_FAR *));
  3664. if ( *InterfaceIdVector == 0 )
  3665. {
  3666. ServerMutex.Clear();
  3667. return(RPC_S_OUT_OF_MEMORY);
  3668. }
  3669. (*InterfaceIdVector)->Count = 0;
  3670. (*InterfaceIdVector)->IfId[0] = (RPC_IF_ID __RPC_FAR *) RpcpFarAllocate(
  3671. sizeof(RPC_IF_ID));
  3672. RpcInterfaceDictionary.Reset(cursor);
  3673. RPC_INTERFACE * RpcInterface;
  3674. while ((RpcInterface = RpcInterfaceDictionary.Next(cursor)) != 0)
  3675. {
  3676. (*InterfaceIdVector)->IfId[(*InterfaceIdVector)->Count] =
  3677. RpcInterface->InquireInterfaceId();
  3678. if ( (*InterfaceIdVector)->IfId[(*InterfaceIdVector)->Count] != 0 )
  3679. {
  3680. RPC_IF_ID * Interface = (*InterfaceIdVector)->IfId[(*InterfaceIdVector)->Count];
  3681. (*InterfaceIdVector)->Count += 1;
  3682. }
  3683. }
  3684. ServerMutex.Clear();
  3685. if (0 == (*InterfaceIdVector)->Count)
  3686. {
  3687. RpcpFarFree(*InterfaceIdVector);
  3688. *InterfaceIdVector = 0;
  3689. return RPC_S_NO_INTERFACES;
  3690. }
  3691. return(RPC_S_OK);
  3692. }
  3693. RPC_STATUS
  3694. RPC_SERVER::InquirePrincipalName (
  3695. IN unsigned long AuthenticationService,
  3696. OUT RPC_CHAR __RPC_FAR * __RPC_FAR * ServerPrincipalName
  3697. )
  3698. /*++
  3699. Routine Description:
  3700. Arguments:
  3701. Return Value:
  3702. RPC_S_OK - The operation completed successfully.
  3703. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete the
  3704. operation.
  3705. RPC_S_UNKNOWN_AUTHN_SERVICE - The specified authentication service is
  3706. not supported.
  3707. --*/
  3708. {
  3709. RPC_AUTHENTICATION * Service;
  3710. DictionaryCursor cursor;
  3711. ServerMutex.Request();
  3712. AuthenticationDictionary.Reset(cursor);
  3713. while ( (Service = AuthenticationDictionary.Next(cursor)) != 0 )
  3714. {
  3715. if ( Service->AuthenticationService == AuthenticationService )
  3716. {
  3717. ServerMutex.Clear();
  3718. *ServerPrincipalName = DuplicateString(
  3719. Service->ServerPrincipalName);
  3720. if ( *ServerPrincipalName == 0 )
  3721. {
  3722. return(RPC_S_OUT_OF_MEMORY);
  3723. }
  3724. return(RPC_S_OK);
  3725. }
  3726. }
  3727. ServerMutex.Clear();
  3728. return(RPC_S_UNKNOWN_AUTHN_SERVICE);
  3729. }
  3730. void
  3731. RPC_SERVER::RegisterRpcForwardFunction (
  3732. RPC_FORWARD_FUNCTION * pForwardFunction
  3733. )
  3734. /*++
  3735. Routine Description:
  3736. Sets the RPC_SERVER pEpmapperForwardFunction. (The pEpmapperForwardFunction
  3737. is the function the runtime can call when it receives a pkt for a
  3738. dynamic endpoint. pEpmapperForwardFunction will return endpoint of
  3739. the server to forward the pkt to).
  3740. Arguments:
  3741. pForwardFunction - pointer to the epmapper forward function.
  3742. Return Value:
  3743. none
  3744. --*/
  3745. {
  3746. pRpcForwardFunction = pForwardFunction;
  3747. }
  3748. RPC_STATUS
  3749. RPC_SERVER::UnregisterEndpoint (
  3750. IN RPC_CHAR __RPC_FAR * Protseq,
  3751. IN RPC_CHAR __RPC_FAR * Endpoint
  3752. )
  3753. {
  3754. return (RPC_S_CANNOT_SUPPORT);
  3755. }
  3756. RPC_ADDRESS::RPC_ADDRESS (
  3757. IN OUT RPC_STATUS PAPI * RpcStatus
  3758. ) : AddressMutex(RpcStatus,
  3759. TRUE // pre-allocate semaphore
  3760. )
  3761. /*++
  3762. Routine Description:
  3763. We just need to initialization some stuff to zero. That way if we
  3764. later have to delete this address because of an error in initialization
  3765. we can tell what instance variables need to be freed.
  3766. --*/
  3767. {
  3768. NetworkAddress = 0;
  3769. Endpoint = 0;
  3770. RpcProtocolSequence = 0;
  3771. }
  3772. RPC_ADDRESS::~RPC_ADDRESS (
  3773. )
  3774. /*++
  3775. Routine Description:
  3776. This routine will only get called if part way through initialization
  3777. an error occurs. We just need to free up any memory used by instance
  3778. variables. Once FireUpManager has been called and succeeds, the
  3779. address will never be destroyed.
  3780. --*/
  3781. {
  3782. if (Endpoint != 0)
  3783. delete Endpoint;
  3784. if (RpcProtocolSequence != 0)
  3785. delete RpcProtocolSequence;
  3786. }
  3787. RPC_CHAR *
  3788. RPC_ADDRESS::GetListNetworkAddress (
  3789. IN unsigned int Index
  3790. )
  3791. /*++
  3792. Routine Description:
  3793. A pointer to the network address for this address is returned.
  3794. --*/
  3795. {
  3796. if (Index >= GetNetworkAddressVector()->Count)
  3797. {
  3798. return (NULL);
  3799. }
  3800. return(GetNetworkAddressVector()->NetworkAddresses[Index]);
  3801. }
  3802. RPC_STATUS
  3803. RPC_ADDRESS::CopyDescriptor (
  3804. IN void *SecurityDescriptor,
  3805. OUT void **OutDescriptor
  3806. )
  3807. {
  3808. BOOL b;
  3809. SECURITY_DESCRIPTOR_CONTROL Control;
  3810. DWORD Revision;
  3811. DWORD BufferLength;
  3812. if ( IsValidSecurityDescriptor(SecurityDescriptor) == FALSE )
  3813. {
  3814. return(RPC_S_INVALID_SECURITY_DESC);
  3815. }
  3816. if (FALSE == GetSecurityDescriptorControl(SecurityDescriptor, &Control, &Revision))
  3817. {
  3818. return(RPC_S_INVALID_SECURITY_DESC);
  3819. }
  3820. if (Control & SE_SELF_RELATIVE)
  3821. {
  3822. //
  3823. // Already self-relative, just copy it.
  3824. //
  3825. BufferLength = GetSecurityDescriptorLength(SecurityDescriptor);
  3826. ASSERT(BufferLength >= sizeof(SECURITY_DESCRIPTOR));
  3827. *OutDescriptor = RpcpFarAllocate(BufferLength);
  3828. if (*OutDescriptor == 0)
  3829. {
  3830. return(RPC_S_OUT_OF_MEMORY);
  3831. }
  3832. memcpy(*OutDescriptor, SecurityDescriptor, BufferLength);
  3833. return(RPC_S_OK);
  3834. }
  3835. //
  3836. // Make self-relative and copy it.
  3837. //
  3838. BufferLength = 0;
  3839. b = MakeSelfRelativeSD(SecurityDescriptor, 0, &BufferLength);
  3840. ASSERT(b == FALSE);
  3841. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  3842. {
  3843. return(RPC_S_INVALID_SECURITY_DESC);
  3844. }
  3845. ASSERT(BufferLength >= sizeof(SECURITY_DESCRIPTOR_RELATIVE));
  3846. *OutDescriptor = RpcpFarAllocate(BufferLength);
  3847. if (*OutDescriptor == 0)
  3848. {
  3849. return(RPC_S_OUT_OF_MEMORY);
  3850. }
  3851. b = MakeSelfRelativeSD(SecurityDescriptor,
  3852. *OutDescriptor,
  3853. &BufferLength);
  3854. if (b == FALSE)
  3855. {
  3856. ASSERT(GetLastError() != ERROR_INSUFFICIENT_BUFFER);
  3857. delete *OutDescriptor;
  3858. return(RPC_S_OUT_OF_MEMORY);
  3859. }
  3860. return(RPC_S_OK);
  3861. }
  3862. RPC_STATUS
  3863. RPC_ADDRESS::SetEndpointAndStuff (
  3864. IN RPC_CHAR PAPI * NetworkAddress,
  3865. IN RPC_CHAR PAPI * Endpoint,
  3866. IN RPC_CHAR PAPI * RpcProtocolSequence,
  3867. IN RPC_SERVER * Server,
  3868. IN unsigned int StaticEndpointFlag,
  3869. IN unsigned int PendingQueueSize,
  3870. IN void PAPI *SecurityDescriptor,
  3871. IN unsigned long EndpointFlags,
  3872. IN unsigned long NICFlags
  3873. )
  3874. /*++
  3875. Routine Description:
  3876. We just need to set some instance variables of this rpc address.
  3877. Arguments:
  3878. Endpoint - Supplies the endpoint for this rpc address.
  3879. RpcProtocolSequence - Supplies the rpc protocol sequence for this
  3880. rpc address.
  3881. Server - Supplies the rpc server which owns this rpc address.
  3882. StaticEndpointFlag - Supplies a flag which specifies whether this
  3883. address has a static endpoint or a dynamic endpoint.
  3884. --*/
  3885. {
  3886. RPC_STATUS Status;
  3887. this->NetworkAddress = NetworkAddress;
  3888. this->Endpoint = Endpoint;
  3889. this->RpcProtocolSequence = RpcProtocolSequence;
  3890. this->Server = Server;
  3891. this->StaticEndpointFlag = StaticEndpointFlag;
  3892. this->PendingQueueSize = PendingQueueSize;
  3893. this->EndpointFlags = EndpointFlags;
  3894. this->NICFlags = NICFlags;
  3895. if (SecurityDescriptor)
  3896. {
  3897. Status = CopyDescriptor(SecurityDescriptor,
  3898. &this->SecurityDescriptor);
  3899. if (Status != RPC_S_OK)
  3900. {
  3901. return Status;
  3902. }
  3903. }
  3904. else
  3905. {
  3906. this->SecurityDescriptor = NULL;
  3907. }
  3908. return RPC_S_OK;
  3909. }
  3910. RPC_STATUS
  3911. RPC_ADDRESS::FindInterfaceTransfer (
  3912. IN PRPC_SYNTAX_IDENTIFIER InterfaceIdentifier,
  3913. IN PRPC_SYNTAX_IDENTIFIER ProposedTransferSyntaxes,
  3914. IN unsigned int NumberOfTransferSyntaxes,
  3915. OUT PRPC_SYNTAX_IDENTIFIER AcceptedTransferSyntax,
  3916. OUT RPC_INTERFACE ** RpcInterface,
  3917. OUT BOOL *fIsInterfaceTransferPreferred,
  3918. OUT int *ProposedTransferSyntaxIndex,
  3919. OUT int *AvailableTransferSyntaxIndex
  3920. )
  3921. /*++
  3922. Routine Description:
  3923. This method is used to determine if a client bind request can be
  3924. accepted or not. All we have got to do here is hand off to the
  3925. server which owns this address.
  3926. Arguments:
  3927. InterfaceIdentifier - Supplies the syntax identifier for the
  3928. interface; this is the interface uuid and version.
  3929. ProposedTransferSyntaxes - Supplies a list of one or more transfer
  3930. syntaxes which the client initiating the binding supports. The
  3931. server should pick one of these which is supported by the
  3932. interface.
  3933. NumberOfTransferSyntaxes - Supplies the number of transfer syntaxes
  3934. specified in the proposed transfer syntaxes argument.
  3935. AcceptedTransferSyntax - Returns the transfer syntax which the
  3936. server accepted.
  3937. RpcInterface - Returns a pointer to the rpc interface found which
  3938. supports the requested interface and one of the requested transfer
  3939. syntaxes.
  3940. Return Value:
  3941. RPC_S_OK - The requested interface exists and it supports at least
  3942. one of the proposed transfer syntaxes. We are all set, now we
  3943. can make remote procedure calls.
  3944. RPC_P_UNSUPPORTED_TRANSFER_SYNTAX - The requested interface exists,
  3945. but it does not support any of the proposed transfer syntaxes.
  3946. RPC_P_UNSUPPORTED_INTERFACE - The requested interface is not supported
  3947. by this rpc server.
  3948. --*/
  3949. {
  3950. return Server->FindInterfaceTransfer(
  3951. InterfaceIdentifier,
  3952. ProposedTransferSyntaxes,
  3953. NumberOfTransferSyntaxes,
  3954. AcceptedTransferSyntax,
  3955. RpcInterface,
  3956. fIsInterfaceTransferPreferred,
  3957. ProposedTransferSyntaxIndex,
  3958. AvailableTransferSyntaxIndex);
  3959. }
  3960. BINDING_HANDLE *
  3961. RPC_ADDRESS::InquireBinding (
  3962. RPC_CHAR * LocalNetworkAddress
  3963. )
  3964. /*++
  3965. Routine Description:
  3966. We need to return create and return a binding handle which can
  3967. be used by a client to make remote procedure calls to this rpc
  3968. address.
  3969. Return Value:
  3970. A newly created binding handle will be returned, inless an out
  3971. of memory error occurs, in which case zero will be returned.
  3972. --*/
  3973. {
  3974. RPC_STATUS Status;
  3975. DCE_BINDING * DceBinding;
  3976. BINDING_HANDLE * BindingHandle;
  3977. RPC_CHAR * DynamicEndpoint = 0;
  3978. RPC_CHAR * PAPI * tmpPtr;
  3979. if(LocalNetworkAddress == 0)
  3980. {
  3981. ASSERT(GetNetworkAddressVector()->Count > 0);
  3982. LocalNetworkAddress = GetNetworkAddressVector()->NetworkAddresses[0];
  3983. }
  3984. DceBinding = new DCE_BINDING(
  3985. 0,
  3986. RpcProtocolSequence,
  3987. LocalNetworkAddress,
  3988. (StaticEndpointFlag != 0 ? Endpoint : 0),
  3989. 0,
  3990. &Status);
  3991. if ((DceBinding == 0)
  3992. || (Status != RPC_S_OK))
  3993. {
  3994. delete DceBinding;
  3995. return(0);
  3996. }
  3997. if (StaticEndpointFlag == 0)
  3998. {
  3999. DynamicEndpoint = DuplicateString(Endpoint);
  4000. if (DynamicEndpoint == 0)
  4001. {
  4002. delete DceBinding;
  4003. return(0);
  4004. }
  4005. }
  4006. BindingHandle = new SVR_BINDING_HANDLE(DceBinding, DynamicEndpoint, &Status);
  4007. if (BindingHandle == 0)
  4008. {
  4009. delete DceBinding;
  4010. }
  4011. return(BindingHandle);
  4012. }
  4013. RPC_STATUS
  4014. RPC_ADDRESS::ServerStartingToListen (
  4015. IN unsigned int MinimumCallThreads,
  4016. IN unsigned int MaximumConcurrentCalls
  4017. )
  4018. /*++
  4019. Routine Description:
  4020. This method will be called for each address when the server starts
  4021. listening. In addition, if an address is added while the server is
  4022. listening, then this method will be called. The purpose of the method
  4023. is to notify the address about the minimum number of call threads
  4024. required; the maximum concurrent calls can safely be ignored, but it
  4025. can be used to set an upper bound on the number of call threads.
  4026. Arguments:
  4027. MinimumCallThreads - Supplies a number indicating the minimum number
  4028. of call threads which should be created for this address.
  4029. MaximumConcurrentCalls - Supplies the maximum number of concurrent
  4030. calls which this server will support.
  4031. Return Value:
  4032. RPC_S_OK - This routine will always return this value. Protocol
  4033. support modules may return other values.
  4034. --*/
  4035. {
  4036. UNUSED(MinimumCallThreads);
  4037. UNUSED(MaximumConcurrentCalls);
  4038. return(RPC_S_OK);
  4039. }
  4040. void
  4041. RPC_ADDRESS::ServerStoppedListening (
  4042. )
  4043. /*++
  4044. Routine Description:
  4045. This routine will be called to notify an address that the server has
  4046. stopped listening for remote procedure calls. Each protocol module
  4047. may override this routine; it is safe not too, but not as efficient.
  4048. Note that this routine will be called before all calls using the
  4049. server have been allowed to complete.
  4050. --*/
  4051. {
  4052. }
  4053. RPC_STATUS
  4054. RPC_ADDRESS::SameProtocolSequenceAndSD (
  4055. IN RPC_CHAR PAPI * NetworkAddress,
  4056. IN RPC_CHAR PAPI * ProtocolSequence,
  4057. IN SECURITY_DESCRIPTOR *SecurityDescriptor OPTIONAL,
  4058. OUT BOOL *IsEqual
  4059. )
  4060. /*++
  4061. Routine Description:
  4062. This routine is used to determine if the rpc address has the same
  4063. protocol sequence as the protocol sequence
  4064. supplied as the argument.
  4065. Arguments:
  4066. NetworkAddress - the server address on which the server listens
  4067. ProtocolSequence - Supplies the protocol sequence to compare against
  4068. the protocol sequence of this address.
  4069. SecurityDescriptor - optional security descriptor to compare against
  4070. IsEqual - on output will contain non-zero if this address and the supplied
  4071. protocol sequence and security descriptor are the same. Otherwise, zero
  4072. will be returned in this argument. Undefined on failure.
  4073. Return Value:
  4074. Non-zero will be returned if this address and the supplied endpoint and
  4075. protocol sequence are the same, otherwise, zero will be returned.
  4076. --*/
  4077. {
  4078. RPC_CHAR *SecurityDescriptor1String;
  4079. RPC_CHAR *SecurityDescriptor2String;
  4080. BOOL Res;
  4081. ULONG LastError;
  4082. // assume not equal for now
  4083. *IsEqual = FALSE;
  4084. // figure out the network address first.
  4085. if (NetworkAddress == NULL)
  4086. {
  4087. if (this->NetworkAddress != NULL)
  4088. return RPC_S_OK;
  4089. }
  4090. else
  4091. {
  4092. if (this->NetworkAddress == NULL)
  4093. return RPC_S_OK;
  4094. if (RpcpStringCompare(this->NetworkAddress, NetworkAddress))
  4095. return RPC_S_OK;
  4096. }
  4097. // figure out the protocol sequence. It cannot be empty here
  4098. ASSERT(ProtocolSequence != NULL);
  4099. if (RpcpStringCompare(this->RpcProtocolSequence, ProtocolSequence))
  4100. return RPC_S_OK;
  4101. if (SecurityDescriptor == NULL)
  4102. {
  4103. if (this->SecurityDescriptor != NULL)
  4104. return RPC_S_OK;
  4105. }
  4106. else
  4107. {
  4108. if (this->SecurityDescriptor == NULL)
  4109. return RPC_S_OK;
  4110. // compare the two security descriptors. Convert them to strings for
  4111. // the sake of comparison
  4112. Res = ConvertSecurityDescriptorToStringSecurityDescriptor (SecurityDescriptor,
  4113. SDDL_REVISION_1,
  4114. OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
  4115. &SecurityDescriptor1String,
  4116. NULL // StringSecurityDescriptorLen
  4117. );
  4118. if (Res == FALSE)
  4119. {
  4120. LastError = GetLastError();
  4121. ASSERT(LastError != ERROR_INVALID_PARAMETER
  4122. && LastError != ERROR_UNKNOWN_REVISION
  4123. && LastError != ERROR_INVALID_ACL
  4124. && LastError != ERROR_NONE_MAPPED );
  4125. #if DBG
  4126. DbgPrint("%d: Could not convert security descriptor to string: %X\n", GetCurrentProcessId(),
  4127. LastError);
  4128. #endif // DBG
  4129. return RPC_S_OUT_OF_MEMORY;
  4130. }
  4131. Res = ConvertSecurityDescriptorToStringSecurityDescriptor (this->SecurityDescriptor,
  4132. SDDL_REVISION_1,
  4133. OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
  4134. &SecurityDescriptor2String,
  4135. NULL // StringSecurityDescriptorLen
  4136. );
  4137. if (Res == FALSE)
  4138. {
  4139. LastError = GetLastError();
  4140. ASSERT(LastError != ERROR_INVALID_PARAMETER
  4141. && LastError != ERROR_UNKNOWN_REVISION
  4142. && LastError != ERROR_INVALID_ACL
  4143. && LastError != ERROR_NONE_MAPPED );
  4144. LocalFree(SecurityDescriptor1String);
  4145. #if DBG
  4146. DbgPrint("%d: Could not convert security descriptor to string: %X\n", GetCurrentProcessId(),
  4147. LastError);
  4148. #endif // DBG
  4149. return RPC_S_OUT_OF_MEMORY;
  4150. }
  4151. // both security descriptors are available as strings. Compare the strings and free them
  4152. if (RpcpStringCompare(SecurityDescriptor1String, SecurityDescriptor2String) == 0)
  4153. *IsEqual = TRUE;
  4154. LocalFree(SecurityDescriptor1String);
  4155. LocalFree(SecurityDescriptor2String);
  4156. return RPC_S_OK;
  4157. }
  4158. // all elements match - return match
  4159. *IsEqual = TRUE;
  4160. return RPC_S_OK;
  4161. }
  4162. long
  4163. RPC_ADDRESS::InqNumberOfActiveCalls (
  4164. )
  4165. /*++
  4166. Return Value:
  4167. Each protocol module will define this routine. We will use this
  4168. functionality when the server has stopped listening and is waiting
  4169. for all remote procedure calls to complete. The number of active calls
  4170. for the address will be returned.
  4171. --*/
  4172. {
  4173. return(ActiveCallCount);
  4174. }
  4175. RPC_STATUS
  4176. RPC_ADDRESS::RestartAddress (
  4177. IN unsigned int MinThreads,
  4178. IN unsigned int MaxCalls
  4179. )
  4180. {
  4181. RPC_STATUS Status;
  4182. int Key;
  4183. Status = ServerSetupAddress(
  4184. NetworkAddress,
  4185. &Endpoint,
  4186. PendingQueueSize,
  4187. SecurityDescriptor,
  4188. EndpointFlags,
  4189. NICFlags);
  4190. if (Status != RPC_S_OK)
  4191. {
  4192. return Status;
  4193. }
  4194. Key = Server->AddAddress(this);
  4195. if (Key == -1)
  4196. {
  4197. return RPC_S_OUT_OF_MEMORY;
  4198. }
  4199. Server->ServerMutex.Request();
  4200. Status = ServerStartingToListen(MinThreads, MaxCalls);
  4201. Server->ServerMutex.Clear();
  4202. if (Status != RPC_S_OK)
  4203. {
  4204. return Status;
  4205. }
  4206. CompleteListen();
  4207. return RPC_S_OK;
  4208. }
  4209. void
  4210. RPC_ADDRESS::DestroyContextHandlesForInterface (
  4211. IN RPC_SERVER_INTERFACE PAPI * ,
  4212. IN BOOL
  4213. )
  4214. /*++
  4215. Function Name: DestroyContextHandlesForInterface
  4216. Parameters:
  4217. RpcInterfaceInformation - the interface for which context handles
  4218. are to be unregistered
  4219. RundownContextHandles - if non-zero, rundown the context handles. If
  4220. FALSE, destroy the runtime portion of the context handle resource,
  4221. but don't call the user rundown routine.
  4222. Description:
  4223. Each protocol engine will implement its own version of this routine,
  4224. if it supports the feature. For those who don't, this routine provides
  4225. default no-op behaviour
  4226. Returns:
  4227. --*/
  4228. {
  4229. }
  4230. void
  4231. RPC_ADDRESS::CleanupIdleSContexts (
  4232. void
  4233. )
  4234. /*++
  4235. Function Name: CleanupIdleSContexts
  4236. Parameters:
  4237. Description:
  4238. Each protocol engine will implement its own version of this routine,
  4239. if it supports the feature. For those who don't, this routine provides
  4240. default no-op behaviour
  4241. Returns:
  4242. --*/
  4243. {
  4244. }
  4245. NETWORK_ADDRESS_VECTOR *
  4246. RPC_ADDRESS::GetNetworkAddressVector (
  4247. void
  4248. )
  4249. /*++
  4250. Function Name: GetNetworkAddressVector
  4251. Parameters:
  4252. Description:
  4253. Each protocol engine will implement its own version of this routine
  4254. It will return the vector of network addresses listened-on by this address object.
  4255. --*/
  4256. {
  4257. ASSERT(0);
  4258. return NULL;
  4259. }
  4260. /*====================================================================
  4261. SCONNECTION
  4262. ==================================================================== */
  4263. RPC_STATUS
  4264. SetThreadSecurityContext(
  4265. SECURITY_CONTEXT * Context
  4266. )
  4267. /*++
  4268. Routine Description:
  4269. RpcImpersonateClient() takes a handle_t, so many threads can impersonate
  4270. the client of a single SCONNECTION. RPC needs to record which context
  4271. each thread is using. It is logical to place this in the TLS, but threads
  4272. not created by RPC lack the THREAD structure in their TLS. This wrapper
  4273. function will store the security context in the TLS if available, or
  4274. place the context in a dictionary if not.
  4275. Arguments:
  4276. Context - the security context to associate with this thread
  4277. Return Value:
  4278. RPC_S_OK if successful
  4279. RPC_S_OUT_OF_MEMORY if the dictionary insertion failed
  4280. --*/
  4281. {
  4282. THREAD * ThreadInfo = ThreadSelf();
  4283. if (ThreadInfo)
  4284. {
  4285. ThreadInfo->SecurityContext = Context;
  4286. return RPC_S_OK;
  4287. }
  4288. return RPC_S_OUT_OF_MEMORY;
  4289. }
  4290. SECURITY_CONTEXT *
  4291. QueryThreadSecurityContext(
  4292. )
  4293. /*++
  4294. Routine Description:
  4295. Fetches the security context associated with this thread for this
  4296. connection. We check the TLS if available; if nothing is there
  4297. then we scan the connection's dictionary.
  4298. Arguments:
  4299. none
  4300. Return Value:
  4301. the associated security context, or zero if none is found
  4302. --*/
  4303. {
  4304. THREAD * ThreadInfo = ThreadSelf();
  4305. if (ThreadInfo)
  4306. {
  4307. if (ThreadInfo->SecurityContext)
  4308. {
  4309. return (SECURITY_CONTEXT *) ThreadInfo->SecurityContext;
  4310. }
  4311. }
  4312. return 0;
  4313. }
  4314. SECURITY_CONTEXT *
  4315. ClearThreadSecurityContext(
  4316. )
  4317. /*++
  4318. Routine Description:
  4319. Clears the association between this thread and its security context
  4320. for this connection.
  4321. Arguments:
  4322. none
  4323. Return Value:
  4324. the formerly associated security context, or zero if none was found
  4325. --*/
  4326. {
  4327. THREAD * ThreadInfo = ThreadSelf();
  4328. if (ThreadInfo)
  4329. {
  4330. SECURITY_CONTEXT * Context =
  4331. (SECURITY_CONTEXT *) ThreadInfo->SecurityContext;
  4332. if (Context)
  4333. {
  4334. ThreadInfo->SecurityContext = 0;
  4335. return Context;
  4336. }
  4337. }
  4338. return 0;
  4339. }
  4340. typedef union {
  4341. struct {
  4342. USHORT Count;
  4343. USHORT Order;
  4344. } s;
  4345. ULONG Value;
  4346. } DTAG, *PDTAG;
  4347. USHORT
  4348. UpdateTargetResource(
  4349. IN volatile long *Target,
  4350. IN USHORT CurrentOrder
  4351. )
  4352. /*++
  4353. Routine Description:
  4354. Helper used by AcquireDeadlockProtection. The logic is as follows:
  4355. If the Target is not owned (Target Count == 0)
  4356. Set the Target Order to CurrentOrder + 1
  4357. Increment the Target Count
  4358. Else (The Target is currently owned)
  4359. If the CurrentOrder is greater than the Target Order
  4360. return 0 (no change to Target)
  4361. Else (The CurrentOrder is not greater than the Target Order)
  4362. Increment the Target Count
  4363. Arguments:
  4364. Target - Pointer to the tag which is to be updated.
  4365. CurrentOrder - This value is the Order value of the last resource
  4366. acquired by the caller in the chain of resources.
  4367. The Target, if unowned (that is Count == 0), will
  4368. have its Order set to CurrentOrder + 1;
  4369. Return Value:
  4370. If the Target is successfully updated, then the return value is the value
  4371. of Target Order. If a possible deadlock was detected or if an internal field
  4372. has wrapped (the Count or Order), the return value is zero.
  4373. --*/
  4374. {
  4375. DTAG Update;
  4376. ULONG LocalTag;
  4377. do {
  4378. LocalTag = *Target;
  4379. Update.Value = LocalTag;
  4380. if (Update.s.Count == 0){
  4381. // We are the first one to tag him, so he gets our Order
  4382. Update.s.Order = CurrentOrder+1;
  4383. }
  4384. else if (Update.s.Order <= CurrentOrder) {
  4385. // The resource is already taged, and its order is not higher than ours,
  4386. // so deadlock is possible, return 0.
  4387. return 0;
  4388. }
  4389. Update.s.Count++;
  4390. if ((Update.s.Order == 0) || (Update.s.Count == 0)){
  4391. // One or both of the values have wrapped, we must fail this opperation.
  4392. return 0;
  4393. }
  4394. } while(LocalTag != InterlockedCompareExchange(Target, Update.Value, LocalTag));
  4395. return Update.s.Order;
  4396. }
  4397. BOOL
  4398. AcquireDeadlockProtection(
  4399. IN BOOL FirstCall,
  4400. IN volatile long *PrevTarget,
  4401. IN volatile long *Target
  4402. )
  4403. /*++
  4404. Routine Description:
  4405. One way to prevent deadlock is to follow a lock hierarchy. The set of resources
  4406. which may be acquired are ordered and anyone who attempts to acquire multiple
  4407. resources must acquire them in order.
  4408. In the case of context handles, the user can impose there own lock hierarchy to
  4409. avoid deadlock among multiple calls with each call possibly using multiple context
  4410. handles. A malicious user may intentionally break this lock hierarchy, resulting
  4411. in deadlocked server threads.
  4412. This API provides a way to detect if waiting on a particular resource may possibly
  4413. result in deadlock. Whenever you want to take a lock on the resource, you first
  4414. pass in the tag for the previous resource you have taken and the tag for the resource
  4415. you would like to take. The tag fields are used to dynamically generate a lock
  4416. hierarchy based on the order in which locks are actually being acquired. If its safe
  4417. to wait on the resource, AcquireDeadlockProtection will return TRUE. Otherwise
  4418. it will return FALSE and you should release all the resources you have taken.
  4419. Most of the logic for this algorithm is in UpdateTargetResource.
  4420. Arguments:
  4421. FirstCall - TRUE indicates that this is the first call to AcquireDeadlockProtection
  4422. for the set of resources the user is interested in acquiring. Typically,
  4423. when the user wishes to lock the second resource in the set, they call
  4424. AcquireDeadlockProtection for the first time, with FirstCall set to TRUE.
  4425. PrevTarget - Pointer to the tag of the previously locked resource.
  4426. Target - Pointer to the tag of the resource which the caller would like to
  4427. wait on. This function determines if it is safe to wait on this resource.
  4428. Return Value:
  4429. If the resource can be acquired without a deadlock occurring, the return
  4430. value is TRUE.
  4431. --*/
  4432. {
  4433. USHORT PrevOrder;
  4434. if (FirstCall){
  4435. PrevOrder = UpdateTargetResource(PrevTarget, 0);
  4436. }
  4437. else {
  4438. PrevOrder = ((PDTAG)PrevTarget)->s.Order;
  4439. }
  4440. if (PrevOrder == 0){
  4441. // We must be overflowing one of the internal fields,
  4442. // this means we have not successfully protected
  4443. // this resource and the caller should not lock it.
  4444. return FALSE;
  4445. }
  4446. return (BOOL) UpdateTargetResource(Target, PrevOrder);
  4447. }
  4448. void
  4449. ReleaseDeadlockProtection(
  4450. IN volatile long *Target
  4451. )
  4452. /*++
  4453. Routine Description:
  4454. This function is called before the lock on a resource has been released. It must
  4455. be called once for every Target which has had AcquireDeadlockProtection succesfully
  4456. called on it. Also, it must be called on the first Target if any calls to
  4457. AcquireDeadlockProtection, regardless of success of failure.
  4458. Arguments:
  4459. Target - A pointer to the tag of the resource which the caller will be releasing.
  4460. --*/
  4461. {
  4462. DTAG DeadlockUpdate;
  4463. ULONG LocalDeadlockTag;
  4464. do {
  4465. LocalDeadlockTag = *Target;
  4466. DeadlockUpdate.Value = LocalDeadlockTag;
  4467. if (DeadlockUpdate.s.Count == 0){
  4468. // The count is already zero, there is nothing for us to do.
  4469. return;
  4470. }
  4471. DeadlockUpdate.s.Count--;
  4472. } while(LocalDeadlockTag != InterlockedCompareExchange(Target, DeadlockUpdate.Value, LocalDeadlockTag));
  4473. }
  4474. RPC_STATUS
  4475. SCALL::AddToActiveContextHandles (
  4476. ServerContextHandle *ContextHandle
  4477. )
  4478. /*++
  4479. Routine Description:
  4480. Adds a context handle to the dictionary of active context handles
  4481. for this call.
  4482. Note: Context handles are added to a SIMPLE_DICT based collection.
  4483. Currently, the SIMPLE_DICT will be corrupted if you add
  4484. more than MAX_ULONG elements to it (its internal size will wrap).
  4485. This code does not provide any protection against wrapping the
  4486. dictionary.
  4487. Note: We make the following assumptions about the behavior of the
  4488. SIMPLE_DICT (ActiveContextHandles) in this routine.
  4489. 1) The key of the first item added to the dictionary is always 0.
  4490. 2) If items are only Inserted, then the key increases by one for each
  4491. subsequent item. This means that the item Inserted previously to
  4492. 'Find(key)' would be 'Find(key-1)'.
  4493. Arguments:
  4494. ContextHandle - the context handle to add to the dictionary
  4495. Return Value:
  4496. RPC_S_OK - For anything but OK, the handle will not be present
  4497. in the ActiveContextHandles dictionary.
  4498. RPC_S_OUT_OF_MEMORY
  4499. RPC_S_XX_CONTEXT_MISMATCH - Indicates the context handle cannot
  4500. be locked because a deadlock may occur.
  4501. --*/
  4502. {
  4503. unsigned int Key;
  4504. Key = ActiveContextHandles.Insert(ContextHandle);
  4505. if (Key == -1)
  4506. return RPC_S_OUT_OF_MEMORY;
  4507. if ( Key &&
  4508. (((ULONG_PTR)ContextHandle & SCALL::DictionaryEntryIsBuffer) == 0)
  4509. ){
  4510. // We are adding a non-first context handle (not a newly created buffer)
  4511. // to the dictionary, we need to check for deadlock
  4512. BOOL SafeToLock = FALSE;
  4513. if (!IsMultiContextHandleCall){
  4514. IsMultiContextHandleCall = TRUE;
  4515. }
  4516. ServerContextHandle *PrevHandle = ActiveContextHandles.Find(Key-1);
  4517. SafeToLock = AcquireDeadlockProtection(
  4518. (Key == 1),
  4519. &(PrevHandle->DeadlockTag),
  4520. &(ContextHandle->DeadlockTag)
  4521. );
  4522. if (!SafeToLock){
  4523. // This will help catch possible false positives.
  4524. CORRUPTION_ASSERT(0);
  4525. ActiveContextHandles.Delete(Key);
  4526. return RPC_X_SS_CONTEXT_MISMATCH;
  4527. }
  4528. }
  4529. return RPC_S_OK;
  4530. }
  4531. ServerContextHandle *
  4532. SCALL::RemoveFromActiveContextHandles (
  4533. ServerContextHandle *ContextHandle
  4534. )
  4535. /*++
  4536. Routine Description:
  4537. Removes a context handle from the active context handle
  4538. dictionary. If the context handle is not there, this is
  4539. just a no-op
  4540. Arguments:
  4541. ContextHandle - the context handle to remove from the dictionary
  4542. Return Value:
  4543. NULL if the context handle is not found. The context handle if it
  4544. is found
  4545. --*/
  4546. {
  4547. // We should not call RemoveFromActiveContextHandles on a buffer
  4548. ASSERT (((ULONG_PTR)ContextHandle & SCALL::DictionaryEntryIsBuffer) == 0);
  4549. ServerContextHandle* RemovedHandle = (ServerContextHandle*) ActiveContextHandles.DeleteItemByBruteForce(ContextHandle);
  4550. if (RemovedHandle && IsMultiContextHandleCall)
  4551. {
  4552. ReleaseDeadlockProtection(&(RemovedHandle->DeadlockTag));
  4553. if (ActiveContextHandles.Size() == 0){
  4554. IsMultiContextHandleCall = FALSE;
  4555. }
  4556. }
  4557. return RemovedHandle;
  4558. }
  4559. RPC_STATUS
  4560. SCALL::ImpersonateClient (
  4561. )
  4562. // This routine just returns RPC_CANNOT_SUPPORT indicating that this
  4563. // particular connection does not support impersonation.
  4564. {
  4565. ASSERT(0 && "improper SCALL member called\n");
  4566. return(RPC_S_CANNOT_SUPPORT);
  4567. }
  4568. RPC_STATUS
  4569. SCALL::RevertToSelf (
  4570. )
  4571. // We always return RPC_CANNOT_SUPPORT indicating that the particular
  4572. // connection does not support impersonation.
  4573. {
  4574. ASSERT(0 && "improper SCALL member called\n");
  4575. return(RPC_S_CANNOT_SUPPORT);
  4576. }
  4577. void
  4578. NDRSContextHandlePostDispatchProcessing (
  4579. IN SCALL *SCall,
  4580. ServerContextHandle *CtxHandle
  4581. );
  4582. void
  4583. SCALL::DoPostDispatchProcessing (
  4584. void
  4585. )
  4586. {
  4587. DictionaryCursor cursor;
  4588. ServerContextHandle *CtxHandle;
  4589. ServerContextHandle *RetrievedCtxHandle;
  4590. unsigned int Key;
  4591. // the list will contain all in-only context
  4592. // handles, as they don't get marshalled. It will also
  4593. // contain the marshalling buffers for the newly
  4594. // created context handles
  4595. if (ActiveContextHandles.Size() > 0)
  4596. {
  4597. // no need to synchronize access to the
  4598. // dictionary - only this call will be
  4599. // touching it
  4600. ActiveContextHandles.Reset(cursor);
  4601. while ((CtxHandle = ActiveContextHandles.NextWithKey(cursor, &Key)) != 0)
  4602. {
  4603. // ignore buffers
  4604. if ((ULONG_PTR)CtxHandle & SCALL::DictionaryEntryIsBuffer)
  4605. {
  4606. RetrievedCtxHandle = ActiveContextHandles.Delete(Key);
  4607. ASSERT(RetrievedCtxHandle == CtxHandle);
  4608. continue;
  4609. }
  4610. // NDRSContextHandlePostDispatchProcessing will remove the context handle
  4611. // from the dictionary - this doesn't interfere with our
  4612. // enumeration
  4613. NDRSContextHandlePostDispatchProcessing(this,
  4614. CtxHandle
  4615. );
  4616. }
  4617. }
  4618. }
  4619. RPC_STATUS
  4620. SCONNECTION::IsClientLocal (
  4621. OUT unsigned int PAPI * ClientLocalFlag
  4622. )
  4623. /*++
  4624. Routine Description:
  4625. The connection oriented protocol module will override this method;
  4626. all other protocol modules should just use this routine. We need this
  4627. support so that the security system can tell if a client is local or
  4628. remote.
  4629. Arguments:
  4630. ClientLocalFlag - Returns an indication of whether or not the client is
  4631. local (ie. on the same machine as the server). This field will be
  4632. set to a non-zero value to indicate that the client is local;
  4633. otherwise, the client is remote.
  4634. Return Value:
  4635. RPC_S_CANNOT_SUPPORT - This will always be used.
  4636. --*/
  4637. {
  4638. UNUSED(ClientLocalFlag);
  4639. ASSERT(0 && "improper SCALL member called\n");
  4640. return(RPC_S_CANNOT_SUPPORT);
  4641. }
  4642. RPC_STATUS
  4643. SCALL::CreateAndSaveAuthzContextFromToken (
  4644. IN OUT PAUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContextPlaceholder OPTIONAL,
  4645. IN HANDLE ImpersonationToken,
  4646. IN AUTHZ_RESOURCE_MANAGER_HANDLE AuthzResourceManager,
  4647. IN PLARGE_INTEGER pExpirationTime OPTIONAL,
  4648. IN LUID Identifier,
  4649. IN DWORD Flags,
  4650. IN PVOID DynamicGroupArgs OPTIONAL,
  4651. OUT PAUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContext
  4652. )
  4653. /*++
  4654. Routine Description:
  4655. Creates an Authz context from token. If saving is requested, it
  4656. tries to save it in a thread-safe manner and duplicates it before
  4657. returning. If saving is not requested, the resulting authz context
  4658. is simply returned. In both cases caller owns the returned auth
  4659. context.
  4660. Arguments:
  4661. pAuthzClientContextPlaceholder - contains a pointer to an authz placeholder.
  4662. If NULL, out of the ImpersonationToken an authz context will
  4663. be made and will be returned. If non-NULL, it must contain
  4664. NULL. In this case an authz context will be created from the token,
  4665. and it will be stored in the placeholder in a thread safe manner and a
  4666. duplicate will be made and returned in pAuthzClientContext.
  4667. ImpersonationToken - the impersonation token to use.
  4668. AuthzResourceManager - authz parameters (not interpreted)
  4669. pExpirationTime - authz parameters (not interpreted)
  4670. Identifier - authz parameters (not interpreted)
  4671. Flags - authz parameters (not interpreted)
  4672. DynamicGroupArgs - authz parameters (not interpreted)
  4673. pAuthzClientContext - contains the output authz context on success
  4674. Return Value:
  4675. Win32 error code. EEInfo has been added.
  4676. --*/
  4677. {
  4678. RPC_STATUS Status = RPC_S_OK;
  4679. BOOL Result;
  4680. AUTHZ_CLIENT_CONTEXT_HANDLE AuthzClientContext;
  4681. Result = AuthzInitializeContextFromTokenFn(
  4682. Flags,
  4683. ImpersonationToken,
  4684. AuthzResourceManager,
  4685. pExpirationTime,
  4686. Identifier,
  4687. DynamicGroupArgs,
  4688. &AuthzClientContext);
  4689. if (!Result)
  4690. {
  4691. Status = GetLastError();
  4692. RpcpErrorAddRecord(EEInfoGCAuthz,
  4693. Status,
  4694. EEInfoDLSCALL__CreateAndSaveAuthzContextFromToken10,
  4695. GetCurrentThreadId(),
  4696. (ULONGLONG)AuthzResourceManager);
  4697. return Status;
  4698. }
  4699. if (pAuthzClientContextPlaceholder)
  4700. {
  4701. if (InterlockedCompareExchangePointer((PVOID *)pAuthzClientContextPlaceholder,
  4702. AuthzClientContext,
  4703. NULL) != NULL)
  4704. {
  4705. // somebody beat us to the punch - free the context we obtained
  4706. AuthzFreeContextFn(AuthzClientContext);
  4707. // use the context that has been provided
  4708. AuthzClientContext = *pAuthzClientContextPlaceholder;
  4709. }
  4710. Status = DuplicateAuthzContext(AuthzClientContext,
  4711. pExpirationTime,
  4712. Identifier,
  4713. Flags,
  4714. DynamicGroupArgs,
  4715. pAuthzClientContext);
  4716. if (Status)
  4717. {
  4718. // EEInfo has already been added
  4719. return Status;
  4720. }
  4721. }
  4722. else
  4723. {
  4724. *pAuthzClientContext = AuthzClientContext;
  4725. }
  4726. return Status;
  4727. }
  4728. RPC_STATUS
  4729. SCALL::DuplicateAuthzContext (
  4730. IN AUTHZ_CLIENT_CONTEXT_HANDLE AuthzClientContext,
  4731. IN PLARGE_INTEGER pExpirationTime OPTIONAL,
  4732. IN LUID Identifier,
  4733. IN DWORD Flags,
  4734. IN PVOID DynamicGroupArgs OPTIONAL,
  4735. OUT PAUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContext
  4736. )
  4737. /*++
  4738. Routine Description:
  4739. Take an Authz context, and make a duplicate of it, using the
  4740. specified parameters. This method is a wrapper for
  4741. AuthzInitializeContextFromContext, mainly adding error handling.
  4742. Arguments:
  4743. AuthzClientContext - source authz context
  4744. pExpirationTime - authz parameters (not interpreted)
  4745. Identifier - authz parameters (not interpreted)
  4746. Flags - authz parameters (not interpreted)
  4747. DynamicGroupArgs - authz parameters (not interpreted)
  4748. pAuthzClientContext - target authz context pointer
  4749. Return Value:
  4750. Win32 error code.
  4751. --*/
  4752. {
  4753. RPC_STATUS Status;
  4754. BOOL Result;
  4755. // Copy the authz context. We must do a copy,
  4756. // to avoid lifetime issues b/n our copy
  4757. // and the client copy
  4758. Result = AuthzInitializeContextFromAuthzContextFn(
  4759. Flags,
  4760. AuthzClientContext,
  4761. pExpirationTime,
  4762. Identifier,
  4763. DynamicGroupArgs,
  4764. pAuthzClientContext);
  4765. if (!Result)
  4766. {
  4767. Status = GetLastError();
  4768. RpcpErrorAddRecord(EEInfoGCAuthz,
  4769. Status,
  4770. EEInfoDLSCALL__DuplicateAuthzContext10,
  4771. GetCurrentThreadId(),
  4772. (ULONGLONG)AuthzClientContext);
  4773. }
  4774. else
  4775. Status = RPC_S_OK;
  4776. return Status;
  4777. }
  4778. /* ====================================================================
  4779. ASSOCIATION_HANDLE :
  4780. ==================================================================== */
  4781. static long AssociationIdCount = 0L;
  4782. void
  4783. DestroyContextCollection (
  4784. IN ContextCollection *CtxCollection
  4785. );
  4786. ASSOCIATION_HANDLE::ASSOCIATION_HANDLE (
  4787. void
  4788. )
  4789. {
  4790. CtxCollection = NULL;
  4791. AssociationID = InterlockedIncrement(&AssociationIdCount);
  4792. }
  4793. ASSOCIATION_HANDLE::~ASSOCIATION_HANDLE (
  4794. )
  4795. // We finally get to use the rundown routines for somethings. The association
  4796. // is being deleted which is the event that the rundown routines were waiting
  4797. // for.
  4798. {
  4799. FireRundown();
  4800. }
  4801. // Returns the context handle collection for this association.
  4802. RPC_STATUS
  4803. ASSOCIATION_HANDLE::GetAssociationContextCollection (
  4804. ContextCollection **CtxCollectionPlaceholder
  4805. )
  4806. /*++
  4807. Function Name: GetAssociationContextCollection
  4808. Parameters:
  4809. CtxCollectionPlaceholder - a placeholder where to put the pointer to
  4810. the context collection.
  4811. Description:
  4812. The context handle code will call the SCALL to get the collection
  4813. of context handles for this association. The SCALL method will
  4814. simply delegate to this.
  4815. This routine will check if the context handle collection was created
  4816. and if so, it will just return it. If it wasn't created, it will try
  4817. to create it.
  4818. Returns:
  4819. RPC_S_OK for success or RPC_S_* for error.
  4820. --*/
  4821. {
  4822. RPC_STATUS RpcStatus;
  4823. if (CtxCollection)
  4824. {
  4825. *CtxCollectionPlaceholder = CtxCollection;
  4826. return RPC_S_OK;
  4827. }
  4828. RpcStatus = NDRSContextInitializeCollection(&CtxCollection);
  4829. if (RpcStatus != RPC_S_OK)
  4830. return RpcStatus;
  4831. *CtxCollectionPlaceholder = CtxCollection;
  4832. return RpcStatus;
  4833. }
  4834. void
  4835. ASSOCIATION_HANDLE::FireRundown (
  4836. void
  4837. )
  4838. {
  4839. int nRetries = 20;
  4840. RPC_STATUS status;
  4841. if (CtxCollection)
  4842. {
  4843. // make a best effort to make sure there is another listening thread
  4844. // besides this one. If we repeatedly fail, we fire the rundown
  4845. // anyway - currently few servers use outgoing RPC callbacks into the
  4846. // same process, so we'd rather risk an unlikely deadlock than cause
  4847. // a sure leak
  4848. while (nRetries > 0)
  4849. {
  4850. status = CreateThread();
  4851. if (status == RPC_S_OK)
  4852. break;
  4853. Sleep(10);
  4854. nRetries --;
  4855. }
  4856. DestroyContextCollection(CtxCollection);
  4857. if (status == RPC_S_OK)
  4858. RundownNotificationCompleted();
  4859. }
  4860. }
  4861. // do nothing in the base case
  4862. RPC_STATUS ASSOCIATION_HANDLE::CreateThread(void)
  4863. {
  4864. return RPC_S_OK;
  4865. }
  4866. void ASSOCIATION_HANDLE::RundownNotificationCompleted(void)
  4867. {
  4868. }
  4869. void
  4870. ASSOCIATION_HANDLE::DestroyContextHandlesForInterface (
  4871. IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
  4872. IN BOOL RundownContextHandles
  4873. )
  4874. /*++
  4875. Function Name: DestroyContextHandlesForInterface
  4876. Parameters:
  4877. RpcInterfaceInformation - the interface for which context handles
  4878. are to be unregistered
  4879. RundownContextHandles - if non-zero, rundown the context handles. If
  4880. FALSE, destroy the runtime portion of the context handle resource,
  4881. but don't call the user rundown routine.
  4882. Description:
  4883. The association will call into NDR to destroy the specified context
  4884. handles. It will either have a reference on the association, or the
  4885. association mutex. Both ways, we're safe from destruction, and NDR
  4886. will synchronize access to the list internally. The address has made
  4887. a best effort not to hold the association mutex. If memory is low,
  4888. it may end up doing so, however.
  4889. Returns:
  4890. --*/
  4891. {
  4892. ContextCollection *LocalCtxCollection;
  4893. void *pGuard;
  4894. // N.B. An association mutex may be held on entry for this
  4895. // function. The server mutex may be held as well
  4896. LocalCtxCollection = CtxCollection;
  4897. // shortcut the common path
  4898. if (!LocalCtxCollection)
  4899. return;
  4900. pGuard = &RpcInterfaceInformation->InterfaceId;
  4901. // call into NDR to destroy the context handles
  4902. DestroyContextHandlesForGuard(LocalCtxCollection,
  4903. RundownContextHandles,
  4904. pGuard);
  4905. }
  4906. /* ====================================================================
  4907. Routine to initialize the server DLL.
  4908. ==================================================================== */
  4909. int
  4910. InitializeServerDLL (
  4911. )
  4912. {
  4913. GetMaxRpcSizeAndThreadPoolParameters();
  4914. if (InitializeClientDLL() != 0)
  4915. return(1);
  4916. if (InitializeObjectDictionary() != 0)
  4917. return(1);
  4918. if (InitializeRpcServer() != 0)
  4919. return(1);
  4920. if (InitializeRpcProtocolLrpc() != 0)
  4921. return(1);
  4922. return(0);
  4923. }
  4924. #if DBG
  4925. void
  4926. RpcpInterfaceForCallDoesNotUseStrict (
  4927. IN RPC_BINDING_HANDLE BindingHandle
  4928. )
  4929. {
  4930. SCALL *SCall;
  4931. if (((MESSAGE_OBJECT *)BindingHandle)->Type(SCALL_TYPE))
  4932. {
  4933. SCall = (SCALL *)BindingHandle;
  4934. SCall->InterfaceForCallDoesNotUseStrict();
  4935. }
  4936. }
  4937. #endif
  4938. RPC_STATUS
  4939. InqLocalConnAddress (
  4940. IN SCALL *SCall,
  4941. IN OUT void *Buffer,
  4942. IN OUT unsigned long *BufferSize,
  4943. OUT unsigned long *AddressFormat
  4944. )
  4945. /*++
  4946. Routine Description:
  4947. This routine is used by a server application to inquire about the local
  4948. address on which a call is made.
  4949. Arguments:
  4950. Binding - Supplies a valid server binding. The binding must have been
  4951. verified to be an SCALL by the caller.
  4952. Buffer - The buffer that will receive the output address
  4953. BufferSize - the size of the supplied Buffer on input. On output the
  4954. number of bytes written to the buffer. If the buffer is too small
  4955. to receive all the output data, ERROR_MORE_DATA is returned,
  4956. nothing is written to the buffer, and BufferSize is set to
  4957. the size of the buffer needed to return all the data.
  4958. AddressFormat - a constant indicating the format of the returned address.
  4959. Currently supported are RPC_P_ADDR_FORMAT_TCP_IPV4 and
  4960. RPC_P_ADDR_FORMAT_TCP_IPV6.
  4961. Return Values:
  4962. RPC_S_OK - success.
  4963. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete this
  4964. operation.
  4965. RPC_S_INVALID_BINDING - The supplied client binding is invalid.
  4966. RPC_S_CANNOT_SUPPORT - The local address was inquired for a protocol
  4967. sequence that doesn't support this type of functionality. Currently
  4968. only ncacn_ip_tcp supports it.
  4969. RPC_S_* or Win32 error for other errors
  4970. --*/
  4971. {
  4972. // is this an osf scall?
  4973. if (!SCall->InvalidHandle(OSF_SCALL_TYPE))
  4974. {
  4975. OSF_SCALL *OsfSCall;
  4976. OsfSCall = (OSF_SCALL *)SCall;
  4977. return OsfSCall->InqLocalConnAddress(
  4978. Buffer,
  4979. BufferSize,
  4980. AddressFormat);
  4981. }
  4982. else if (!SCall->InvalidHandle(DG_SCALL_TYPE))
  4983. {
  4984. // this is a dg call
  4985. DG_SCALL *DgSCall;
  4986. DgSCall = (DG_SCALL *)SCall;
  4987. return DgSCall->InqLocalConnAddress(
  4988. Buffer,
  4989. BufferSize,
  4990. AddressFormat);
  4991. }
  4992. else
  4993. {
  4994. // the others don't support it
  4995. return RPC_S_CANNOT_SUPPORT;
  4996. }
  4997. }
  4998. BOOL
  4999. IsCallbackMessage (
  5000. IN PRPC_MESSAGE Message
  5001. )
  5002. /*++
  5003. Routine Description:
  5004. Checks whether a given message corresponds to a callback
  5005. Arguments:
  5006. Return Value:
  5007. --*/
  5008. {
  5009. MESSAGE_OBJECT *obj = (MESSAGE_OBJECT *)Message->Handle;
  5010. // Check if this is a DG callback or a non-DG callback.
  5011. // If the object is a LPC/OSF_CCALL, then it must be a callback.
  5012. return ( !(obj->InvalidHandle(DG_CALLBACK_TYPE)) ||
  5013. !(obj->InvalidHandle(OSF_CCALL_TYPE)) ||
  5014. !(obj->InvalidHandle(LRPC_CCALL_TYPE)) );
  5015. }
  5016. BOOL CheckVerificationTrailer (
  5017. IN void *BufferStart,
  5018. IN void *BufferEnd,
  5019. IN void *RpcMessage
  5020. )
  5021. /*++
  5022. Routine Description:
  5023. Checks the integrity of the verification header.
  5024. Arguments:
  5025. BufferStart - current buffer position.
  5026. BufferEnd - end of buffer. Note that BufferStart may already be beyond
  5027. the end of the buffer!!!!
  5028. RpcMessage - the current RPC Message
  5029. Return Value:
  5030. Non-zero means check passed. 0 means check failed.
  5031. Notes:
  5032. This function is very performance sensitive. It will be executed on
  5033. every unmarshalling operation. It may be called after pipe chunks are
  5034. unmarshalled as well.
  5035. --*/
  5036. {
  5037. THREAD *Thread;
  5038. SCALL *SCall;
  5039. OSF_SCALL *OsfSCall;
  5040. unsigned char *LocalBufferStart = (unsigned char *)BufferStart;
  5041. unsigned char *LocalBufferEnd = (unsigned char *)BufferEnd;
  5042. // if there is not enough stuff at the end, there is no verification trailer.
  5043. // This is the quickest check that will weed out the largest percentage of
  5044. // packets.
  5045. if (LocalBufferStart + sizeof(rpc_sec_verification_trailer) >= LocalBufferEnd)
  5046. return TRUE;
  5047. SCall = (SCALL *)RpcpGetThreadContext();
  5048. if (SCall->InvalidHandle(OSF_SCALL_TYPE))
  5049. return TRUE;
  5050. OsfSCall = (OSF_SCALL *)SCall;
  5051. return OsfSCall->CheckVerificationTrailer(LocalBufferStart, LocalBufferEnd, (RPC_MESSAGE *)RpcMessage);
  5052. }