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.

3463 lines
107 KiB

  1. /*++
  2. Copyright (c) 1995-1996 Microsoft Corporation
  3. Module Name:
  4. Manager.cxx
  5. Abstract:
  6. Stub/OR interface
  7. Author:
  8. Mario Goertzel [mariogo] Feb-02-1995
  9. Revision Hist:
  10. MarioGo 02-10-95 Bits 'n pieces
  11. MarioGo 01-31-96 New local and remote interfaces
  12. TarunA 10-12-98 OXIDs are referenced on OID basis (Client side)
  13. TarunA 10-31-98 Added PID of the process connecting
  14. a-sergiv 07-09-99 Impersonate for the entire duration of
  15. ResolveClientOXID for ncacn_http protocol
  16. (to fix a bad COM Internet Services bug)
  17. --*/
  18. #include <or.hxx>
  19. extern "C"
  20. {
  21. #include <inc.hxx>
  22. #define SECURITY_WIN32 // Used by security.h
  23. #include <security.h>
  24. }
  25. // These variables hold the list of channel hooks registered for the machine.
  26. // They are updated as the registry changes.
  27. LONG s_cChannelHook = 0;
  28. GUID *s_aChannelHook = NULL;
  29. HANDLE s_hChannelHook = NULL;
  30. // Definition of single instance of this class:
  31. CRpcSecurityCallbackManager* gpCRpcSecurityCallbackMgr;
  32. CPingSetQuotaManager* gpPingSetQuotaManager;
  33. extern BOOL gbDynamicIPChangesEnabled;
  34. // forward declaration
  35. error_status_t
  36. AllocateReservedIdsInternal(IN ULONG cIdsToAlloc,
  37. OUT ID aIdsAllocated[],
  38. OUT ULONG* pcIdsAllocated);
  39. BOOL
  40. CheckLocalCall(
  41. IN handle_t hClient
  42. )
  43. /*++
  44. Routine Description:
  45. Checks that the RPC client calling us on the specified
  46. binding handle is calling from a process on the local
  47. machine.
  48. Arguments:
  49. hClient - Rpc binding handle of the call in progress.
  50. Return Value:
  51. TRUE -- client is local to this machine
  52. FALSE -- client is not local or an error occurred
  53. --*/
  54. {
  55. UINT type;
  56. RPC_STATUS status;
  57. if (!hClient)
  58. return FALSE;
  59. status = I_RpcBindingInqTransportType(hClient, &type);
  60. if (status != RPC_S_OK)
  61. return FALSE;
  62. // The original CheckLocalCall implementation allowed for
  63. // TRANSPORT_TYPE_WMSG. I'm sure we shouldn't accept them,
  64. // but I'd like to know if we ever receive such a call so
  65. // I can investigate. Hence this assert.
  66. ASSERT(type != TRANSPORT_TYPE_WMSG);
  67. if (type != TRANSPORT_TYPE_LPC)
  68. return FALSE;
  69. return TRUE;
  70. }
  71. BOOL
  72. RetrievePIDForLocalClient(
  73. IN handle_t hClient,
  74. IN DWORD* pdwPid)
  75. /*++
  76. Routine Description:
  77. Queries RPC for the process id of a local client.
  78. Arguments:
  79. hClient - Rpc binding handle of the call in progress.
  80. pdwPid - where to store the process id of the client
  81. Return Value:
  82. TRUE -- success, client's pid is stored in *pdwPid
  83. FALSE -- error occurred
  84. --*/
  85. {
  86. RPC_STATUS status;
  87. ASSERT(pdwPid);
  88. status = I_RpcBindingInqLocalClientPID(hClient, pdwPid);
  89. if (status != RPC_S_OK)
  90. return FALSE;
  91. return TRUE;
  92. }
  93. CProcess*
  94. CheckLocalSecurity(
  95. IN handle_t hClient,
  96. IN PHPROCESS phProcess,
  97. IN BOOL fNotContext
  98. )
  99. /*++
  100. Routine Description:
  101. Checks that a local client is correctly calling one of RPCSS RPC
  102. entry points. "Correct" is defined by: 1) is using a local
  103. transport, ie, LPC, and 2) is a registered COM client (ie, has
  104. previously called _Connect and obtained a valid context handle).
  105. Arguments:
  106. hClient - Rpc binding handle of the call in progress.
  107. pProcess - Context handle passed in by the client. Must not be zero.
  108. fNotContext - should be FALSE if the context handle was not passed as an
  109. explicit context_handle attribute in an RPC call to RPCSS. It should be
  110. TRUE otherwise. If TRUE is passed here, the returned CProcess* ptr will
  111. have an extra refcount added to it which the client must later release
  112. using the ReleaseProcess function.
  113. Return Value:
  114. Either
  115. A validated CProcess* pointer for the client.
  116. -- OR --
  117. NULL -- something is wrong or client cannot be trusted.
  118. --*/
  119. {
  120. //
  121. // RPC security callback function has already checked by this point that
  122. // the call is coming from a local client.
  123. //
  124. ASSERT(hClient);
  125. // Validate client's context handle.
  126. CProcess* pProcess = ReferenceProcess(phProcess, fNotContext);
  127. if (pProcess)
  128. {
  129. DWORD dwPid;
  130. if (!RetrievePIDForLocalClient(hClient, &dwPid))
  131. {
  132. if (fNotContext)
  133. ReleaseProcess(pProcess);
  134. return NULL;
  135. }
  136. // This check is overkill, RPC does something much like
  137. // this in their internal context_handle checks. But
  138. // hey, defense-in-depth right? (and it's cheap to check)
  139. if (dwPid != pProcess->GetPID())
  140. {
  141. ASSERT(!"Should not get here");
  142. if (fNotContext)
  143. ReleaseProcess(pProcess);
  144. return NULL;
  145. }
  146. }
  147. return pProcess;
  148. }
  149. //
  150. // LocalInterfaceOnlySecCallback
  151. //
  152. // RPC security callback function for RPC interfaces that should
  153. // only ever be called by local clients (this is our semantic, not
  154. // RPC's).
  155. //
  156. RPC_STATUS RPC_ENTRY LocalInterfaceOnlySecCallback(
  157. IN RPC_IF_HANDLE Interface,
  158. IN void *Context
  159. )
  160. {
  161. ASSERT(Interface);
  162. ASSERT(Context);
  163. if (!CheckLocalCall(Context))
  164. return RPC_S_ACCESS_DENIED;
  165. return RPC_S_OK;
  166. }
  167. //
  168. // Update the channel hook list if it has changed in the registry.
  169. //
  170. void UpdateChannelHooks( LONG *pcChannelHook, GUID **paChannelHook )
  171. {
  172. BOOL fSuccess;
  173. BOOL fUpdate = FALSE;
  174. DWORD result;
  175. HKEY hKey;
  176. DWORD lType;
  177. DWORD lDataSize;
  178. GUID *aChannelHook;
  179. LONG cChannelHook;
  180. DWORD i;
  181. DWORD lExtent;
  182. WCHAR wExtent[39];
  183. DWORD j;
  184. // Lock
  185. gpClientLock->LockExclusive();
  186. // If the handle hasn't been created, create it.
  187. if (s_hChannelHook == NULL)
  188. {
  189. // Nothing can be done if the event can't be created.
  190. s_hChannelHook = CreateEvent(NULL, FALSE, FALSE, NULL);
  191. fUpdate = TRUE;
  192. }
  193. // If the handle has been created, see if it has been signalled.
  194. else
  195. {
  196. result = WaitForSingleObject(s_hChannelHook, 0);
  197. fUpdate = result == WAIT_OBJECT_0;
  198. }
  199. // Reread the registry if necessary.
  200. if (fUpdate)
  201. {
  202. // Register for changes.
  203. RegNotifyChangeKeyValue( s_hOle, TRUE,
  204. REG_NOTIFY_CHANGE_NAME |
  205. REG_NOTIFY_CHANGE_ATTRIBUTES |
  206. REG_NOTIFY_CHANGE_LAST_SET |
  207. REG_NOTIFY_CHANGE_SECURITY,
  208. s_hChannelHook, TRUE );
  209. // Open the channel hook key.
  210. result = RegOpenKeyEx( s_hOle, L"ChannelHook",
  211. NULL, KEY_QUERY_VALUE, &hKey );
  212. if (result == ERROR_SUCCESS)
  213. {
  214. // Find out how many values exist.
  215. cChannelHook = 0;
  216. RegQueryInfoKey( hKey, NULL, NULL, NULL, NULL, NULL, NULL,
  217. (DWORD *) &cChannelHook, NULL, NULL, NULL, NULL );
  218. // If there are no channel hooks, throw away the old data.
  219. if (cChannelHook == 0)
  220. {
  221. delete s_aChannelHook;
  222. s_aChannelHook = NULL;
  223. s_cChannelHook = 0;
  224. aChannelHook = NULL;
  225. }
  226. // Reuse the existing array.
  227. else if (cChannelHook <= s_cChannelHook)
  228. aChannelHook = s_aChannelHook;
  229. // Allocate memory for them.
  230. else
  231. aChannelHook = new GUID[cChannelHook];
  232. // If there is not enough memory, don't make changes.
  233. if (aChannelHook != NULL)
  234. {
  235. // Enumerate over the channel hook ids.
  236. j = 0;
  237. for (i = 0; i < (DWORD)cChannelHook; i++)
  238. {
  239. // Get the next key.
  240. lExtent = sizeof(wExtent) / sizeof(WCHAR);
  241. result = RegEnumValueW( hKey, i, wExtent, &lExtent, NULL,
  242. &lType, NULL, NULL );
  243. // Convert it to a GUID. Note that lExtent is set to
  244. // the length in characters not bytes despite what
  245. // the documentation says.
  246. if (result == ERROR_SUCCESS && lExtent == 38 &&
  247. lType == REG_SZ &&
  248. GUIDFromString( wExtent, &aChannelHook[j] ))
  249. j += 1;
  250. }
  251. // Save the new channel hook array.
  252. if (aChannelHook != s_aChannelHook)
  253. delete s_aChannelHook;
  254. s_aChannelHook = aChannelHook;
  255. s_cChannelHook = j;
  256. }
  257. // Close the registry key.
  258. RegCloseKey( hKey );
  259. }
  260. // There are no channel hooks. Throw away the old data.
  261. else
  262. {
  263. delete s_aChannelHook;
  264. s_aChannelHook = NULL;
  265. s_cChannelHook = 0;
  266. }
  267. }
  268. // Return the current channel hook list.
  269. *paChannelHook = (GUID *) MIDL_user_allocate( s_cChannelHook * sizeof(GUID) );
  270. if (*paChannelHook != NULL)
  271. {
  272. *pcChannelHook = s_cChannelHook;
  273. memcpy( *paChannelHook, s_aChannelHook, s_cChannelHook * sizeof(GUID) );
  274. }
  275. else
  276. *pcChannelHook = 0;
  277. // Unlock
  278. gpClientLock->UnlockExclusive();
  279. }
  280. //
  281. // Manager (server-side) calls to the local OR interface. lclor.idl
  282. //
  283. error_status_t
  284. _Connect(
  285. IN handle_t hClient,
  286. IN WCHAR *pwszWinstaDesktop,
  287. OUT PHPROCESS *phProcess,
  288. OUT DWORD *pTimeoutInSeconds,
  289. OUT DUALSTRINGARRAY **ppdsaOrBindings,
  290. OUT MID *pLocalMid,
  291. IN ULONG cIdsToReserve,
  292. OUT ID aIdsReserved[],
  293. OUT ULONG *pcIdsReserved,
  294. OUT DWORD *pfConnectFlags,
  295. OUT WCHAR **pLegacySecurity,
  296. OUT DWORD *pAuthnLevel,
  297. OUT DWORD *pImpLevel,
  298. OUT DWORD *pcServerSvc,
  299. OUT USHORT **aServerSvc,
  300. OUT DWORD *pcClientSvc,
  301. OUT SECPKG **aClientSvc,
  302. OUT LONG *pcChannelHook,
  303. OUT GUID **paChannelHook,
  304. OUT DWORD *pThreadID,
  305. OUT DWORD *pScmProcessID,
  306. OUT ULONG64 *pSignature,
  307. OUT GUID *pguidRPCSSProcessIdentifier
  308. )
  309. {
  310. ORSTATUS status;
  311. CProcess *pProcess;
  312. CToken *pToken;
  313. BOOL fRet;
  314. DWORD dwClientPid;
  315. // Ensure this is a local client calling
  316. if (!CheckLocalCall(hClient))
  317. return OR_NOACCESS;
  318. // Get PID of the caller
  319. if (!RetrievePIDForLocalClient(hClient, &dwClientPid))
  320. return OR_NOACCESS;
  321. // Parameter validation
  322. if (!pwszWinstaDesktop || !phProcess || !pTimeoutInSeconds ||
  323. !ppdsaOrBindings || !pLocalMid || !aIdsReserved || !pcIdsReserved ||
  324. !pfConnectFlags || !pLegacySecurity || !pAuthnLevel ||
  325. !pImpLevel || !pcServerSvc || !aServerSvc || !pcClientSvc ||
  326. !aClientSvc ||!pcChannelHook || !paChannelHook || !pThreadID ||
  327. !pScmProcessID || !pSignature)
  328. {
  329. return OR_BADPARAM;
  330. }
  331. KdPrintEx((DPFLTR_DCOMSS_ID,
  332. DPFLTR_INFO_LEVEL,
  333. "OR: Client connected\n"));
  334. *pfConnectFlags = 0;
  335. *pSignature = 0;
  336. // Fill in security parameters.
  337. if (s_fEnableDCOM == FALSE) *pfConnectFlags |= CONNECT_DISABLEDCOM;
  338. if (s_fCatchServerExceptions) *pfConnectFlags |= CONNECT_CATCH_SERVER_EXCEPTIONS;
  339. if (s_fBreakOnSilencedServerExceptions) *pfConnectFlags |= CONNECT_BREAK_ON_SILENCED_SERVER_EXCEPTIONS;
  340. if (s_fMutualAuth) *pfConnectFlags |= CONNECT_MUTUALAUTH;
  341. if (s_fSecureRefs) *pfConnectFlags |= CONNECT_SECUREREF;
  342. *pAuthnLevel = s_lAuthnLevel;
  343. *pImpLevel = s_lImpLevel;
  344. // Get legacy security settings
  345. fRet = GetLegacySecurity(pLegacySecurity);
  346. if (!fRet)
  347. {
  348. return OR_NOMEM;
  349. }
  350. // Get client\server svcs
  351. fRet = GetClientServerSvcs(pcClientSvc, aClientSvc, pcServerSvc, aServerSvc);
  352. if (!fRet)
  353. {
  354. return OR_NOMEM;
  355. }
  356. // Fill in channel hooks.
  357. UpdateChannelHooks( pcChannelHook, paChannelHook );
  358. // This fails during setup but RPCSS can function anyway.
  359. RegisterAuthInfoIfNecessary();
  360. status = StartListeningIfNecessary();
  361. if (status != OR_OK)
  362. {
  363. return(status);
  364. }
  365. // Do client specific stuff
  366. status = CopyMyOrBindings(ppdsaOrBindings, NULL);
  367. if (status != OR_OK)
  368. {
  369. return(status);
  370. }
  371. status = LookupOrCreateTokenForRPCClient(hClient, FALSE, &pToken, NULL);
  372. if (status != OR_OK)
  373. {
  374. MIDL_user_free(*ppdsaOrBindings);
  375. *ppdsaOrBindings = 0;
  376. return(status);
  377. }
  378. pProcess = new CProcess(pToken, pwszWinstaDesktop, dwClientPid, status);
  379. if (pProcess && status == OR_OK)
  380. {
  381. *phProcess = (void *)pProcess;
  382. }
  383. else
  384. {
  385. if (pProcess)
  386. {
  387. ReleaseProcess(pProcess);
  388. }
  389. else
  390. {
  391. status = OR_NOMEM;
  392. }
  393. }
  394. if (status != OR_OK)
  395. {
  396. MIDL_user_free(*ppdsaOrBindings);
  397. *ppdsaOrBindings = 0;
  398. *phProcess = 0;
  399. *pSignature = 0;
  400. if (pToken)
  401. pToken->Release();
  402. return(status);
  403. }
  404. *pSignature = (ULONG64)pProcess;
  405. *pTimeoutInSeconds = BaseTimeoutInterval;
  406. *pLocalMid = gLocalMid;
  407. ASSERT( (*phProcess == 0 && *ppdsaOrBindings == 0) || status == OR_OK);
  408. AllocateReservedIdsInternal(cIdsToReserve,
  409. aIdsReserved,
  410. pcIdsReserved);
  411. *pThreadID = InterlockedExchangeAdd((long *)&gNextThreadID,1);
  412. *pScmProcessID = GetCurrentProcessId();
  413. *pguidRPCSSProcessIdentifier = *(pProcess->GetGuidProcessIdentifier());
  414. return(status);
  415. }
  416. error_status_t
  417. AllocateReservedIdsInternal(
  418. IN ULONG cIdsToAlloc,
  419. OUT ID aIdsAllocated[],
  420. OUT ULONG* pcIdsAllocated)
  421. {
  422. DWORD i;
  423. BOOL fResult;
  424. if (cIdsToAlloc > 10) // || cIdsToAlloc < 0)
  425. {
  426. cIdsToAlloc = 10;
  427. }
  428. for (i = 0; i < cIdsToAlloc; i++)
  429. {
  430. fResult = AllocateId(&(aIdsAllocated[i]));
  431. if (!fResult)
  432. break;
  433. }
  434. *pcIdsAllocated = i;
  435. // Return OR_OK as long as we were able to allocate
  436. // at least one id. Callers must recognize via *pcIdsAllocated
  437. // that not all requested ids were allocated.
  438. return (i > 0) ? OR_OK : OR_NOMEM;
  439. }
  440. error_status_t
  441. _AllocateReservedIds(
  442. IN handle_t hClient,
  443. IN PHPROCESS phProcess,
  444. IN ULONG cIdsToAlloc,
  445. OUT ID aIdsAllocated[],
  446. OUT ULONG *pcIdsAllocated
  447. )
  448. /*++
  449. Routine Description:
  450. // Called by local clients to reserve a range of IDs which will
  451. // not conflict with any other local IDs.
  452. Arguments:
  453. hClient - the connection of the client.
  454. phProcess - context handle of the caller
  455. cIdsToReserve - Number of IDs to reserve.
  456. pidReservedBase - Starting value of the reserved IDs. The
  457. lower DWORD of this can be increatmented to generate
  458. cIdsToReserve unique IDs.
  459. Return Value:
  460. OR_OK
  461. --*/
  462. {
  463. // Ensure this is a local client calling
  464. CProcess* pProcess = CheckLocalSecurity(hClient, phProcess);
  465. if (!pProcess)
  466. return OR_NOACCESS;
  467. // Parameter validation
  468. if (!aIdsAllocated || !pcIdsAllocated)
  469. return OR_BADPARAM;
  470. return AllocateReservedIdsInternal(
  471. cIdsToAlloc,
  472. aIdsAllocated,
  473. pcIdsAllocated);
  474. }
  475. RPC_STATUS
  476. NegotiateDCOMVersion(
  477. IN OUT COMVERSION *pVersion
  478. )
  479. /*++
  480. Routine Description:
  481. // Called when we receive a COMVERSION from a remote machine
  482. // to determine which DCOM protocol level to talk.
  483. Arguments:
  484. pVersion - version of the remote machine. Modified if necessary
  485. by this routine to be the lower of the two versions.
  486. Return Value:
  487. OR_OK
  488. --*/
  489. {
  490. // Parameter validation
  491. if (!pVersion)
  492. return OR_BADPARAM;
  493. if (pVersion->MajorVersion == COM_MAJOR_VERSION)
  494. {
  495. if (pVersion->MinorVersion > COM_MINOR_VERSION)
  496. {
  497. // since the client has a lower minor version number,
  498. // use the lower of the two.
  499. pVersion->MinorVersion = COM_MINOR_VERSION;
  500. }
  501. return OR_OK;
  502. }
  503. return RPC_E_VERSION_MISMATCH;
  504. }
  505. error_status_t
  506. _ClientResolveOXID(
  507. IN handle_t hClient,
  508. IN PHPROCESS phProcess,
  509. IN OXID *poxidServer,
  510. IN DUALSTRINGARRAY *pdsaServerBindings,
  511. IN LONG fApartment,
  512. OUT OXID_INFO *poxidInfo,
  513. OUT MID *pDestinationMid,
  514. OUT unsigned long *pulMarshaledTargetInfoLength,
  515. OUT unsigned char **pucMarshaledTargetInfo,
  516. OUT USHORT *pusAuthnSvc
  517. )
  518. /*++
  519. Routine Description:
  520. Discovers the OXID_INFO for an oxid. Will find local
  521. OXIDs without any help. It needs OR bindings in order
  522. to discover remote OXIDs.
  523. Arguments:
  524. phProcess - The context handle of the process.
  525. poxidServer - The OXID (a uuid) to resolve.
  526. pdsaServerBindings - Compressed string bindings to
  527. the OR on the server's machine.
  528. fApartment - non-zero if the client is aparment model.
  529. REVIEW: What to do with mixed model clients?
  530. What to do when auto registering an OID?
  531. poxidInfo - If successful this will contain information about the oxid and
  532. an expanded string binding to the server oxid's process.
  533. pulAuthnSvc - if successful this will contain the exact id (ie, will not be snego)
  534. of the authn svc used to talk to the server.
  535. Return Value:
  536. OR_NOMEM - Common.
  537. OR_BADOXID - Unable to resolve it.
  538. OR_OK - Success.
  539. --*/
  540. {
  541. CProcess* pProcess = CheckLocalSecurity(hClient, phProcess);
  542. if (!pProcess)
  543. return OR_NOACCESS;
  544. // Parameter validation done below in ResolveClientOXID
  545. return ResolveClientOXID( hClient,
  546. poxidServer,
  547. pdsaServerBindings,
  548. fApartment,
  549. 0,
  550. NULL,
  551. poxidInfo,
  552. pDestinationMid,
  553. FALSE,
  554. RPC_C_AUTHN_NONE,
  555. 0,
  556. NULL,
  557. NULL,
  558. pulMarshaledTargetInfoLength,
  559. pucMarshaledTargetInfo,
  560. pusAuthnSvc);
  561. }
  562. error_status_t
  563. ResolveClientOXID(
  564. handle_t hClient,
  565. OXID *poxidServer,
  566. DUALSTRINGARRAY *pdsaServerBindings,
  567. LONG fApartment,
  568. USHORT wProtseqId,
  569. WCHAR *pMachineName,
  570. OXID_INFO *poxidInfo,
  571. MID *pDestinationMid,
  572. BOOL fUnsecure,
  573. USHORT wAuthnSvc,
  574. unsigned long ulMarshaledTargetInfoLengthIn,
  575. unsigned char *pMarshaledTargetInfoIn,
  576. BOOL* pIsLocalOxid,
  577. unsigned long *pulMarshaledTargetInfoLength,
  578. unsigned char **pucMarshaledTargetInfo,
  579. USHORT* pusAuthnSvc
  580. )
  581. /*++
  582. Routine Description:
  583. Discovers the OXID_INFO for an oxid. Will find local
  584. OXIDs without any help. It needs OR bindings in order
  585. to discover remote OXIDs.
  586. Arguments:
  587. hClient - rpc handle of the client (caller has already been verified
  588. as being a valid local client)
  589. poxidServer - The OXID (a uuid) to resolve.
  590. pdsaServerBindings - Compressed string bindings to
  591. the OR on the server's machine.
  592. fApartment - non-zero if the client is aparment model.
  593. REVIEW: What to do with mixed model clients?
  594. What to do when auto registering an OID?
  595. poxidInfo - If successful this will contain information about the oxid and
  596. an expanded string binding to the server oxid's process.
  597. fUnsecure - if TRUE, activation was done unsecurely so set
  598. MID appropriately.
  599. wAuthnSvc - Hint of authentication service that might work or
  600. RPC_C_AUTHN_NONE if no hint.
  601. pusAuthnSvc - if successful this will contain the exact id (ie, will not be snego)
  602. of the authn svc used to talk to the server.
  603. Return Value:
  604. OR_NOMEM - Common.
  605. OR_BADOXID - Unable to resolve it.
  606. OR_OK - Success.
  607. --*/
  608. {
  609. CClientOxid *pOxid = NULL;
  610. CServerOxid *pServerOxid;
  611. CMid *pMid;
  612. ORSTATUS status = OR_OK;
  613. BOOL fReference;
  614. BOOL fServerApartment = FALSE;
  615. BOOL fResolved = FALSE;
  616. BOOL fLazyReleaseNewCopyOfpOxid = FALSE;
  617. DWORD i = 0;
  618. WCHAR *pPrincipal = NULL;
  619. WCHAR *pMachineNameFromBindings = NULL;
  620. BOOL fImpersonating = FALSE;
  621. unsigned long ulMarshaledTargetInfoLength = 0;
  622. unsigned char* pMarshaledTargetInfo = NULL;
  623. // Parameter validation
  624. if (!poxidServer || !pdsaServerBindings || !poxidInfo ||
  625. !pDestinationMid || !pusAuthnSvc)
  626. {
  627. return OR_BADPARAM;
  628. }
  629. if (! dsaValid(pdsaServerBindings))
  630. {
  631. return(OR_BADPARAM);
  632. }
  633. // If wProtseqId == ID_DCOMHTTP, we should impersonate
  634. // because RPC will read some info from HKEY_CURRENT_USER.
  635. // Sometimes ole32 will call us with 0 wProtseqId, in
  636. // which cases we'll have to look at pdsaServerBindings.
  637. if(wProtseqId == ID_DCOMHTTP)
  638. {
  639. fImpersonating = (RpcImpersonateClient(hClient) == RPC_S_OK);
  640. }
  641. else if(wProtseqId == 0)
  642. {
  643. if(pdsaServerBindings && pdsaServerBindings->aStringArray
  644. && *(pdsaServerBindings->aStringArray) == ID_DCOMHTTP)
  645. {
  646. fImpersonating = (RpcImpersonateClient(hClient) == RPC_S_OK);
  647. }
  648. }
  649. // Attempt to lookup MID and OXID
  650. gpClientLock->LockExclusive();
  651. CMidKey midkey(pdsaServerBindings);
  652. pMid = (CMid *)gpMidTable->Lookup(midkey);
  653. if (0 == pMid)
  654. {
  655. BOOL fMidInitOkay = FALSE;
  656. fReference = TRUE;
  657. pMid = new(pdsaServerBindings->wNumEntries * sizeof(WCHAR)) CMid(pdsaServerBindings, FALSE, 0, &fMidInitOkay);
  658. if (pMid && fMidInitOkay)
  659. {
  660. gpMidTable->Add(pMid);
  661. pMid->SetAuthnSvc(wAuthnSvc);
  662. status = pMid->SetMarshaledTargetInfo(ulMarshaledTargetInfoLengthIn, pMarshaledTargetInfoIn);
  663. }
  664. else
  665. {
  666. // No mem, or failed to init
  667. if (pMid)
  668. {
  669. delete pMid;
  670. pMid = NULL;
  671. }
  672. status = OR_NOMEM;
  673. }
  674. }
  675. else
  676. {
  677. fReference = FALSE;
  678. }
  679. if (status == OR_OK)
  680. {
  681. CId2Key oxidkey(*poxidServer, pMid->Id());
  682. pOxid = (CClientOxid *)gpClientOxidTable->Lookup(oxidkey);
  683. if (0 == pOxid)
  684. {
  685. if (!fReference)
  686. {
  687. pMid->Reference();
  688. fReference = TRUE;
  689. }
  690. // Need to allocate the OXID. First step is too resolve it
  691. // either locally or remotely.
  692. gpClientLock->UnlockExclusive();
  693. if (pMid->IsLocal())
  694. {
  695. // Local OXID, lookup directly
  696. gpServerLock->LockShared();
  697. CIdKey key(*poxidServer);
  698. pServerOxid = (CServerOxid *)gpServerOxidTable->Lookup(key);
  699. if (pServerOxid)
  700. {
  701. status = pServerOxid->GetInfo(poxidInfo, TRUE);
  702. fServerApartment = pServerOxid->Apartment();
  703. // reset the protseq id so we use LRPC.
  704. wProtseqId = 0;
  705. pMachineName = NULL;
  706. }
  707. else
  708. {
  709. status = OR_BADOXID;
  710. }
  711. ASSERT(status != OR_OK || dsaValid(poxidInfo->psa));
  712. gpServerLock->UnlockShared();
  713. }
  714. else if (0 == poxidInfo->psa)
  715. {
  716. // Remote OXID, call ResolveOxid
  717. handle_t hRemoteOr;
  718. USHORT iBinding;
  719. poxidInfo->psa = 0;
  720. ASSERT(!pMachineName);
  721. status = OR_NOMEM;
  722. hRemoteOr = pMid->GetBinding();
  723. if (hRemoteOr)
  724. {
  725. if (pMid->IsSecure())
  726. {
  727. i = 0;
  728. // Form server principal name
  729. pMachineNameFromBindings = ExtractMachineName( pMid->GetStringBinding() );
  730. if (pMachineNameFromBindings)
  731. {
  732. pPrincipal = new WCHAR[lstrlenW(pMachineNameFromBindings) +
  733. (sizeof(RPCSS_SPN_PREFIX) / sizeof(WCHAR)) + 1];
  734. if (pPrincipal)
  735. {
  736. lstrcpyW(pPrincipal, RPCSS_SPN_PREFIX);
  737. lstrcatW(pPrincipal, pMachineNameFromBindings);
  738. }
  739. delete pMachineNameFromBindings;
  740. }
  741. // It is possible that we already impersonated above,
  742. // so it might be unnecessary to do it here.
  743. if(!fImpersonating)
  744. {
  745. status = RpcImpersonateClient(hClient);
  746. if (status != RPC_S_OK)
  747. {
  748. KdPrintEx((DPFLTR_DCOMSS_ID,
  749. DPFLTR_WARNING_LEVEL,
  750. "OR: Unable to impersonate for resolve %d\n",
  751. status));
  752. }
  753. }
  754. }
  755. else
  756. {
  757. i = s_cRpcssSvc+1;
  758. }
  759. // The loop index has the following meanings:
  760. // 0 - Try pMid->GetAuthnSvc
  761. // 1 through s_cRpcssSvc - Try s_aRpcssSvc
  762. // s_cRpcssSvc+1 - Try unsecure
  763. USHORT wFirstSvc = pMid->GetAuthnSvc();
  764. for (; i < s_cRpcssSvc + 2; i++)
  765. {
  766. BOOL bSetSecurityCallBack = FALSE;
  767. USHORT usAuthSvcFromCallback;
  768. // Choose an authentication service.
  769. if (i < s_cRpcssSvc+1)
  770. {
  771. if (i == 0)
  772. wAuthnSvc = wFirstSvc;
  773. else
  774. {
  775. // Skip this authentication service if already
  776. // tried.
  777. wAuthnSvc = s_aRpcssSvc[i-1].wId;
  778. if (wAuthnSvc == wFirstSvc)
  779. continue;
  780. }
  781. // See if the server uses this authentication service.
  782. if (ValidAuthnSvc( pMid->GetStrings(), wAuthnSvc ))
  783. {
  784. RPC_SECURITY_QOS qos;
  785. qos.Version = RPC_C_SECURITY_QOS_VERSION;
  786. qos.Capabilities = RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH;
  787. qos.IdentityTracking = RPC_C_QOS_IDENTITY_DYNAMIC;
  788. qos.ImpersonationType = RPC_C_IMP_LEVEL_IMPERSONATE;
  789. if (wAuthnSvc == RPC_C_AUTHN_GSS_NEGOTIATE)
  790. {
  791. // if using snego, we need to know what sec pkg is eventually negotiated:
  792. if (gpCRpcSecurityCallbackMgr->RegisterForRpcAuthSvcCallBack(hRemoteOr))
  793. bSetSecurityCallBack = TRUE;
  794. }
  795. // Set the security info
  796. // AuthnSvc is unsigned long and 0xFFFF gets 0 extended
  797. status = RpcBindingSetAuthInfoEx(hRemoteOr,
  798. pPrincipal,
  799. RPC_C_AUTHN_LEVEL_CONNECT,
  800. wAuthnSvc != 0xFFFF ? wAuthnSvc
  801. : RPC_C_AUTHN_DEFAULT,
  802. NULL,
  803. 0,
  804. &qos);
  805. if (status != RPC_S_OK)
  806. {
  807. KdPrintEx((DPFLTR_DCOMSS_ID,
  808. DPFLTR_WARNING_LEVEL,
  809. "OR: RpcBindingSetAuthInfo to %d failed!! %d\n",
  810. wAuthnSvc,
  811. status));
  812. if (bSetSecurityCallBack)
  813. {
  814. // Get rid of our callback registration
  815. unsigned long ulIgnore = 0;
  816. unsigned char *pucIgnore = NULL;
  817. // Get rid of our callback registration
  818. gpCRpcSecurityCallbackMgr->GetSecurityContextDetailsAndTurnOffCallback(hRemoteOr, NULL,
  819. &ulIgnore, &pucIgnore);
  820. if (ulIgnore)
  821. {
  822. MIDL_user_free(pucIgnore);
  823. }
  824. }
  825. continue;
  826. }
  827. }
  828. else
  829. continue;
  830. }
  831. // Force the binding handle unsecure.
  832. else if (pMid->IsSecure())
  833. {
  834. wAuthnSvc = RPC_C_AUTHN_NONE;
  835. status = RpcBindingSetAuthInfo(hRemoteOr,
  836. 0,
  837. RPC_C_AUTHN_LEVEL_NONE,
  838. RPC_C_AUTHN_NONE,
  839. 0,
  840. 0);
  841. if (status != RPC_S_OK)
  842. {
  843. KdPrintEx((DPFLTR_DCOMSS_ID,
  844. DPFLTR_WARNING_LEVEL,
  845. "OR: RpcBindingSetAuthInfo to NONE failed!! %d\n",
  846. status));
  847. }
  848. }
  849. // try calling ResolveOxid2 first, if that fails,
  850. // try ResolveOxid.
  851. status = ResolveOxid2(hRemoteOr,
  852. poxidServer,
  853. cMyProtseqs,
  854. aMyProtseqs,
  855. &poxidInfo->psa,
  856. &poxidInfo->ipidRemUnknown,
  857. &poxidInfo->dwAuthnHint,
  858. &poxidInfo->version
  859. );
  860. if (status == RPC_S_PROCNUM_OUT_OF_RANGE)
  861. {
  862. // must be a downlevel server (COMVERSION == 5.1), try calling on
  863. // the old ResolveOXID method.
  864. // REVIEW if it's a downlevel server what does this mean wrt
  865. // bug 406902 and the snego mess? I think we're still okay.
  866. poxidInfo->version.MajorVersion = COM_MAJOR_VERSION;
  867. poxidInfo->version.MinorVersion = COM_MINOR_VERSION_1;
  868. poxidInfo->dwFlags = 0;
  869. status = ResolveOxid(hRemoteOr,
  870. poxidServer,
  871. cMyProtseqs,
  872. aMyProtseqs,
  873. &poxidInfo->psa,
  874. &poxidInfo->ipidRemUnknown,
  875. &poxidInfo->dwAuthnHint
  876. );
  877. }
  878. // At this point we are done making calls on the binding handle
  879. // Turn off the security callback no matter what the result of
  880. // the call was
  881. if (bSetSecurityCallBack)
  882. {
  883. if (status == OR_OK)
  884. {
  885. if (!gpCRpcSecurityCallbackMgr->GetSecurityContextDetailsAndTurnOffCallback(hRemoteOr,
  886. &usAuthSvcFromCallback, &ulMarshaledTargetInfoLength,
  887. &pMarshaledTargetInfo))
  888. {
  889. // something went wrong. Basically we don't trust what the callback
  890. // told us. Fall back on the original behavior
  891. bSetSecurityCallBack = FALSE;
  892. }
  893. }
  894. else
  895. {
  896. // call did not go through; just cancel the callback registration
  897. gpCRpcSecurityCallbackMgr->GetSecurityContextDetailsAndTurnOffCallback(hRemoteOr, NULL,
  898. &ulMarshaledTargetInfoLength, &pMarshaledTargetInfo);
  899. bSetSecurityCallBack = FALSE;
  900. }
  901. }
  902. if (status == OR_OK)
  903. {
  904. status = NegotiateDCOMVersion(&poxidInfo->version);
  905. }
  906. else
  907. {
  908. if (ulMarshaledTargetInfoLength)
  909. {
  910. MIDL_user_free(pMarshaledTargetInfo);
  911. }
  912. }
  913. if (status == OR_OK)
  914. {
  915. // Remember which auth.svc got used:
  916. if (bSetSecurityCallBack)
  917. {
  918. // we should not have set it unless we're using snego, and we
  919. // should have gotten something other than snego back
  920. ASSERT(wAuthnSvc == RPC_C_AUTHN_GSS_NEGOTIATE &&
  921. usAuthSvcFromCallback != RPC_C_AUTHN_GSS_NEGOTIATE);
  922. // Set the negotiated pkg; if we got back Kerberos, then cache
  923. // Snego. This will partially fix the fact that we are
  924. // hard-coding the authn svc for all future users of this mid
  925. if (usAuthSvcFromCallback == RPC_C_AUTHN_GSS_KERBEROS)
  926. pMid->SetAuthnSvc( RPC_C_AUTHN_GSS_NEGOTIATE );
  927. else
  928. pMid->SetAuthnSvc( usAuthSvcFromCallback );
  929. pMid->SetMarshaledTargetInfo(ulMarshaledTargetInfoLength, pMarshaledTargetInfo);
  930. }
  931. else
  932. {
  933. // Just use whatever was set on the call
  934. pMid->SetAuthnSvc( wAuthnSvc );
  935. if (ulMarshaledTargetInfoLength)
  936. {
  937. MIDL_user_free(pMarshaledTargetInfo);
  938. }
  939. }
  940. if (dsaValid(poxidInfo->psa))
  941. {
  942. wProtseqId = poxidInfo->psa->aStringArray[0];
  943. }
  944. else
  945. {
  946. KdPrintEx((DPFLTR_DCOMSS_ID,
  947. DPFLTR_WARNING_LEVEL,
  948. "OR: Server %s returned a bogus string array: %p\n",
  949. pMid->PrintableName(),
  950. poxidInfo->psa));
  951. ASSERT(0);
  952. if (poxidInfo->psa)
  953. {
  954. MIDL_user_free(poxidInfo->psa);
  955. poxidInfo->psa = 0;
  956. }
  957. status = OR_BADOXID;
  958. }
  959. break;
  960. }
  961. else if (status != RPC_S_ACCESS_DENIED &&
  962. status != RPC_S_UNKNOWN_AUTHN_SERVICE &&
  963. status != RPC_S_UNKNOWN_AUTHZ_SERVICE &&
  964. status != RPC_S_SEC_PKG_ERROR )
  965. {
  966. KdPrintEx((DPFLTR_DCOMSS_ID,
  967. DPFLTR_WARNING_LEVEL,
  968. "OR: Remote resolve OXID failed %d\n",
  969. status));
  970. break;
  971. }
  972. }
  973. RpcBindingFree(&hRemoteOr);
  974. delete pPrincipal;
  975. pPrincipal = NULL;
  976. }
  977. }
  978. // Else it's a remote MID, but we were given the OXID info
  979. // and protseq id from the SCM after a remote activation.
  980. else
  981. fResolved = TRUE;
  982. gpClientLock->LockExclusive();
  983. ASSERT(fReference);
  984. if ( OR_OK == status
  985. && (pMid->GetAuthnSvc() == RPC_C_AUTHN_NONE ||
  986. TRUE == fUnsecure) )
  987. {
  988. KdPrintEx((DPFLTR_DCOMSS_ID,
  989. DPFLTR_INFO_LEVEL,
  990. "OR: Machine %S, unsecure retry ok, assuming no sec\n",
  991. pMid->PrintableName()));
  992. pMid->SecurityFailed();
  993. }
  994. if (status == OR_OK)
  995. {
  996. // Lookup the oxid again to make sure it hasn't been added in the meantime.
  997. pOxid = (CClientOxid *)gpClientOxidTable->Lookup(oxidkey);
  998. if (0 == pOxid)
  999. {
  1000. ASSERT(dsaValid(poxidInfo->psa));
  1001. pOxid = new CClientOxid(*poxidServer,
  1002. pMid,
  1003. wProtseqId,
  1004. pMachineName,
  1005. fServerApartment);
  1006. if (0 != pOxid)
  1007. {
  1008. status = pOxid->UpdateInfo(poxidInfo);
  1009. if (OR_OK == status)
  1010. {
  1011. gpClientOxidTable->Add(pOxid);
  1012. }
  1013. else
  1014. {
  1015. // Will release mid, will also remove it (unnecessarily)
  1016. // from the table.
  1017. delete pOxid;
  1018. pOxid = NULL;
  1019. }
  1020. }
  1021. else
  1022. {
  1023. status = OR_NOMEM;
  1024. pMid->Release(); // May actually go away..
  1025. }
  1026. }
  1027. else
  1028. {
  1029. // Release our now extra reference on the MID
  1030. DWORD t = pMid->Release();
  1031. ASSERT(t > 0);
  1032. pOxid->Reference();
  1033. }
  1034. MIDL_user_free(poxidInfo->psa);
  1035. poxidInfo->psa = 0;
  1036. }
  1037. else
  1038. {
  1039. // Resolve failed, get rid of our extra reference.
  1040. pMid->Release();
  1041. }
  1042. }
  1043. else
  1044. {
  1045. // Found the OXID, must also have found the MID
  1046. ASSERT(fReference == FALSE);
  1047. fResolved = TRUE;
  1048. if ( poxidInfo->psa )
  1049. {
  1050. MIDL_user_free(poxidInfo->psa);
  1051. poxidInfo->psa = 0;
  1052. }
  1053. pOxid->Reference();
  1054. }
  1055. }
  1056. ASSERT( (status != OR_OK) || (pOxid && pMid) );
  1057. if ( status == OR_OK
  1058. && pOxid->IsLocal() == FALSE)
  1059. {
  1060. if (fResolved)
  1061. *poxidServer = 0;
  1062. }
  1063. if(NULL != pIsLocalOxid)
  1064. {
  1065. if((status == OR_OK) && pOxid->IsLocal())
  1066. *pIsLocalOxid = TRUE;
  1067. else
  1068. *pIsLocalOxid = FALSE;
  1069. }
  1070. if (status == OR_OK)
  1071. {
  1072. *pDestinationMid = pMid->Id();
  1073. *pusAuthnSvc = pMid->GetAuthnSvc();
  1074. if (pulMarshaledTargetInfoLength && pucMarshaledTargetInfo)
  1075. {
  1076. status = pMid->GetMarshaledTargetInfo(pulMarshaledTargetInfoLength, pucMarshaledTargetInfo);
  1077. }
  1078. // GetInfo may release the lock
  1079. status = pOxid->GetInfo(fApartment, poxidInfo);
  1080. }
  1081. if (pOxid)
  1082. {
  1083. pOxid->Release();
  1084. }
  1085. gpClientLock->UnlockExclusive();
  1086. return(status);
  1087. }
  1088. void
  1089. FreeServerOids(
  1090. CProcess *pProcess,
  1091. ULONG cServerOidsToFree,
  1092. OID aServerOidsToFree[]
  1093. )
  1094. /*++
  1095. Routine Description:
  1096. Frees the OIDs passed in.
  1097. Arguments:
  1098. phProcess - The context handle of the process.
  1099. Since this is called from SCM directly this function
  1100. CAN BE called on the same process by more then one
  1101. thread at a time.
  1102. cServerOidsToFree - Count of entries in aServerOidsToFree
  1103. aServerOidsToFree - OIDs allocated by the server process
  1104. and no longer needed.
  1105. --*/
  1106. {
  1107. // KdPrintEx((DPFLTR_DCOMSS_ID,
  1108. // DPFLTR_WARNING_LEVEL,
  1109. // "OR: FreeServerOids: pProcess:%x cOids:%x pOids:%x\n",
  1110. // pProcess,
  1111. // cServerOidsToFree,
  1112. // aServerOidsToFree));
  1113. ASSERT(gpServerLock->HeldExclusive());
  1114. if (cServerOidsToFree)
  1115. {
  1116. CServerOid *pOid;
  1117. CServerOxid *pOxid;
  1118. for (ULONG i = 0; i < cServerOidsToFree; i++)
  1119. {
  1120. CIdKey oidkey(aServerOidsToFree[i]);
  1121. pOid = (CServerOid *)gpServerOidTable->Lookup(oidkey);
  1122. if (pOid && pOid->IsRunningDown() == FALSE)
  1123. {
  1124. pOxid = pOid->GetOxid();
  1125. ASSERT(pOxid);
  1126. if (pProcess->IsOwner(pOxid))
  1127. {
  1128. if (pOid->References() == 0)
  1129. {
  1130. pOid->Remove();
  1131. pOid->SetRundown(TRUE);
  1132. delete pOid;
  1133. }
  1134. else
  1135. {
  1136. pOid->Free();
  1137. }
  1138. }
  1139. else
  1140. {
  1141. KdPrintEx((DPFLTR_DCOMSS_ID,
  1142. DPFLTR_WARNING_LEVEL,
  1143. "OR: Process %p tried to free OID %p it didn't own\n",
  1144. pProcess,
  1145. pOid));
  1146. }
  1147. }
  1148. else
  1149. {
  1150. KdPrintEx((DPFLTR_DCOMSS_ID,
  1151. DPFLTR_WARNING_LEVEL,
  1152. "OR: Process %p freed OID %p that didn't exist\n",
  1153. pProcess,
  1154. &aServerOidsToFree[i]));
  1155. }
  1156. }
  1157. }
  1158. }
  1159. error_status_t
  1160. _BulkUpdateOIDs(
  1161. IN handle_t hClient,
  1162. IN PHPROCESS phProcess,
  1163. IN ULONG cOidsToBeAdded,
  1164. IN OXID_OID_PAIR aOidsToBeAdded[],
  1165. OUT LONG aStatusOfAdds[],
  1166. IN ULONG cOidsToBeRemoved,
  1167. IN OID_MID_PAIR aOidsToBeRemoved[],
  1168. IN ULONG cServerOidsToFree,
  1169. IN OID aServerOidsToFree[],
  1170. IN ULONG cServerOidsToUnPin,
  1171. IN OID aServerOidsToUnPin[],
  1172. IN ULONG cClientOxidsToFree,
  1173. IN OXID_REF aClientOxidsToFree[]
  1174. )
  1175. /*++
  1176. Routine Description:
  1177. Updates the set of remote OIDs in use by a process.
  1178. Note:
  1179. An OID maybe removed before it is added. This means that
  1180. the client was using it and is no longer using it. In
  1181. this case a single delete from set ping is made to keep
  1182. the object alive. This is only needed if the client
  1183. has remarshalled a pointer to the object.
  1184. Arguments:
  1185. phProcess - Context handle for the process.
  1186. cOidsToBeAdded - Count of aOidsToBeAdded and aStatusOfAdds
  1187. aOidsToBeAdded - OID-OXID-MID pairs representing the
  1188. oids and the owning oxids to add.
  1189. aStatusOfAdds - Some adds may succeed when other fail.
  1190. OR_NOMEM - couldn't allocate storage
  1191. OR_BADOXID - OXID doesn't exist.
  1192. OR_OK (0) - added to set
  1193. cOidsToBeRemoved - Count of entries in aOidsToBeRemoved.
  1194. aOidsToBeRemoved - OID-MID pairs to be removed.
  1195. cServerOidsToFree - Count of entries in aServerOidsToFree
  1196. aServerOidsToFree - OIDs allocated by the client process
  1197. and no longer needed.
  1198. cServerOidsToUnPin - Count of entries in aServerOidsToUnPin
  1199. aServerOidsToUnPin - OIDs that the client process previously
  1200. told us were pinned\locked, and now no longer are.
  1201. cClientOxidsToFree - COunt of enties in aClientOxidsToFree
  1202. aClientOxidsToFree - OXIDs owned by a process (due to a direct
  1203. or indirect call to ClientResolveOxid) which are no longer
  1204. in use by the client.
  1205. Return Value:
  1206. OR_OK - All updates completed ok.
  1207. OR_PARTIAL_UPDATE - At least one entry in aStatusOfAdds is not OR_OK
  1208. --*/
  1209. {
  1210. CProcess *pProcess;
  1211. CClientOxid *pOxid;
  1212. CClientOid *pOid;
  1213. CClientSet *pSet;
  1214. CMid *pMid;
  1215. CToken *pToken;
  1216. BOOL fPartial = FALSE;
  1217. BOOL fNewSet = FALSE;
  1218. DUALSTRINGARRAY *pdsa = NULL;
  1219. ULONG i;
  1220. pProcess = CheckLocalSecurity(hClient, phProcess);
  1221. if (!pProcess)
  1222. return OR_NOACCESS;
  1223. // Parameter validation. If zero is passed for the size-of-array param
  1224. // then we don't care about the array param itself (since we never
  1225. // look at it)
  1226. if (!(cOidsToBeAdded > 0 ? (aOidsToBeAdded != NULL) : TRUE) ||
  1227. !(cOidsToBeAdded > 0 ? (aStatusOfAdds != NULL) : TRUE) ||
  1228. !(cOidsToBeRemoved > 0 ? (aOidsToBeRemoved != NULL) : TRUE) ||
  1229. !(cServerOidsToFree > 0 ? (aServerOidsToFree != NULL): TRUE) ||
  1230. !(cServerOidsToUnPin > 0 ? (aServerOidsToUnPin != NULL): TRUE) ||
  1231. !(cClientOxidsToFree > 0 ? (aClientOxidsToFree != NULL) : TRUE))
  1232. {
  1233. return OR_BADPARAM;
  1234. }
  1235. if (cOidsToBeAdded || cOidsToBeRemoved)
  1236. {
  1237. ORSTATUS status = CopyMyOrBindings(&pdsa, NULL);
  1238. if (status != RPC_S_OK)
  1239. {
  1240. return status;
  1241. }
  1242. gpClientLock->LockExclusive();
  1243. }
  1244. // /////////////////////////////////////////////////////////////////
  1245. // Process Adds.
  1246. for (i = 0; i < cOidsToBeAdded; i++)
  1247. {
  1248. fNewSet = FALSE;
  1249. // Lookup up the oxid owning this new oid.
  1250. CId2Key oxidkey(aOidsToBeAdded[i].oxid, aOidsToBeAdded[i].mid);
  1251. pOxid = (CClientOxid *)gpClientOxidTable->Lookup(oxidkey);
  1252. if (0 == pOxid)
  1253. {
  1254. OXID_INFO infoT;
  1255. ORSTATUS status;
  1256. MID mid;
  1257. gpClientLock->UnlockExclusive();
  1258. infoT.psa = 0;
  1259. USHORT usAuthnSvc;
  1260. status = _ClientResolveOXID(hClient,
  1261. phProcess,
  1262. &aOidsToBeAdded[i].oxid,
  1263. pdsa,
  1264. TRUE,
  1265. &infoT,
  1266. &mid,
  1267. NULL,
  1268. NULL,
  1269. &usAuthnSvc);
  1270. gpClientLock->LockExclusive();
  1271. if (status == OR_OK)
  1272. {
  1273. ASSERT(infoT.psa);
  1274. ASSERT(mid == gLocalMid);
  1275. MIDL_user_free(infoT.psa);
  1276. pOxid = (CClientOxid *)gpClientOxidTable->Lookup(oxidkey);
  1277. if (pOxid == 0)
  1278. {
  1279. KdPrintEx((DPFLTR_DCOMSS_ID,
  1280. DPFLTR_INFO_LEVEL,
  1281. "OR: Auto resolving oxid %p failed, wrong machine\n",
  1282. &oxidkey));
  1283. status = OR_BADOXID;
  1284. }
  1285. }
  1286. if (status != OR_OK)
  1287. {
  1288. aStatusOfAdds[i] = OR_BADOXID;
  1289. fPartial = TRUE;
  1290. continue;
  1291. }
  1292. }
  1293. // Find or create the set.
  1294. CId2Key setkey(aOidsToBeAdded[i].mid, (ID)pProcess->GetToken());
  1295. pSet = (CClientSet *)gpClientSetTable->Lookup(setkey);
  1296. if (pSet == 0)
  1297. {
  1298. pSet = new CClientSet(pOxid->GetMid(), pProcess->GetToken());
  1299. if (pSet == 0)
  1300. {
  1301. aStatusOfAdds[i] = OR_NOMEM;
  1302. fPartial = TRUE;
  1303. continue;
  1304. }
  1305. else
  1306. {
  1307. gpClientSetTable->Add(pSet);
  1308. pSet->Insert();
  1309. fNewSet = TRUE;
  1310. }
  1311. }
  1312. // Find or create the oid. If we create it, add a reference
  1313. // to the oxid for the new oid.
  1314. CId3Key oidkey(aOidsToBeAdded[i].oid, aOidsToBeAdded[i].mid, pProcess->GetToken());
  1315. pOid = (CClientOid *)gpClientOidTable->Lookup(oidkey);
  1316. if (0 == pOid)
  1317. {
  1318. pOid = new CClientOid(aOidsToBeAdded[i].oid,
  1319. aOidsToBeAdded[i].mid,
  1320. pProcess->GetToken(),
  1321. pOxid,
  1322. pSet
  1323. );
  1324. if (fNewSet)
  1325. {
  1326. if (!pOid)
  1327. {
  1328. pSet->Remove();
  1329. }
  1330. // pOid either owns a refernce now or we need to
  1331. // cleanup the set anyway.
  1332. pSet->Release();
  1333. }
  1334. if (pOid)
  1335. {
  1336. aStatusOfAdds[i] = pSet->RegisterObject(pOid);
  1337. if (aStatusOfAdds[i] == OR_OK)
  1338. {
  1339. gpClientOidTable->Add(pOid);
  1340. }
  1341. else
  1342. {
  1343. if (fNewSet)
  1344. {
  1345. pSet->Remove();
  1346. }
  1347. pOid->ClientRelease();
  1348. pOid->Release();
  1349. pOid = 0;
  1350. fPartial = TRUE;
  1351. continue;
  1352. }
  1353. }
  1354. else
  1355. {
  1356. aStatusOfAdds[i] = OR_NOMEM;
  1357. fPartial = TRUE;
  1358. continue;
  1359. }
  1360. }
  1361. else
  1362. {
  1363. ASSERT(fNewSet == FALSE);
  1364. pOid->ClientReference();
  1365. }
  1366. // If this fails it will release the oid.
  1367. aStatusOfAdds[i] = pProcess->AddOid(pOid);
  1368. if (aStatusOfAdds[i] != OR_OK)
  1369. {
  1370. fPartial = TRUE;
  1371. }
  1372. } // for oids to add
  1373. // /////////////////////////////////////////////////////////////////
  1374. // Process deletes
  1375. for (i = 0; i < cOidsToBeRemoved; i++)
  1376. {
  1377. CId3Key oidkey(aOidsToBeRemoved[i].oid,
  1378. aOidsToBeRemoved[i].mid,
  1379. pProcess->GetToken());
  1380. pOid = (CClientOid *)gpClientOidTable->Lookup(oidkey);
  1381. if (pOid)
  1382. {
  1383. CClientOid *pT = pProcess->RemoveOid(pOid);
  1384. if (pT == 0)
  1385. {
  1386. KdPrintEx((DPFLTR_DCOMSS_ID,
  1387. DPFLTR_WARNING_LEVEL,
  1388. "OR: Client process %p tried to remove oid %p which"
  1389. "it didn't own\n",
  1390. pProcess,
  1391. &aOidsToBeRemoved[i]));
  1392. }
  1393. else
  1394. ASSERT(pT == pOid);
  1395. }
  1396. else
  1397. KdPrintEx((DPFLTR_DCOMSS_ID,
  1398. DPFLTR_INFO_LEVEL,
  1399. "OR: Client %p removed an OID that doesn't exist\n",
  1400. pProcess));
  1401. } // for oids to delete
  1402. if (cOidsToBeAdded || cOidsToBeRemoved)
  1403. {
  1404. gpClientLock->UnlockExclusive();
  1405. }
  1406. ///////////////////////////////////////////////////////////////////
  1407. // Process server oid deletes
  1408. //
  1409. if (cServerOidsToFree > 0)
  1410. {
  1411. gpServerLock->LockExclusive();
  1412. FreeServerOids(pProcess, cServerOidsToFree, aServerOidsToFree);
  1413. gpServerLock->UnlockExclusive();
  1414. }
  1415. ///////////////////////////////////////////////////////////////////
  1416. //
  1417. // Process server oid unpins. We do not have an array of individual
  1418. // status update values for this operation; if the client gets back
  1419. // a success code from BulkUpdateOids, it can assume that all of the
  1420. // requested unpins were executed correctly.
  1421. //
  1422. // Also note that it is *always* safe to unpin an oid even if it should
  1423. // remain pinned; the worse that can happen is extra rundown calls.
  1424. //
  1425. if (cServerOidsToUnPin > 0)
  1426. {
  1427. gpServerLock->LockExclusive();
  1428. for (i = 0; i < cServerOidsToUnPin; i++)
  1429. {
  1430. CServerOid* pOid;
  1431. CIdKey key(aServerOidsToUnPin[i]);
  1432. pOid = (CServerOid *)gpServerOidTable->Lookup(key);
  1433. // Only unpin the oid if the calling process owns it. Don't
  1434. // assert if we didn't find it, since under stress we may
  1435. // be executing this code after the owning process\apt died.
  1436. if (pOid && pProcess->IsOwner(pOid->GetOxid()))
  1437. {
  1438. if (pOid->IsPinned())
  1439. {
  1440. pOid->SetPinned(FALSE);
  1441. }
  1442. }
  1443. }
  1444. gpServerLock->UnlockExclusive();
  1445. }
  1446. // Done
  1447. if (pdsa)
  1448. {
  1449. MIDL_user_free(pdsa);
  1450. }
  1451. if (fPartial)
  1452. {
  1453. return(OR_PARTIAL_UPDATE);
  1454. }
  1455. return(OR_OK);
  1456. }
  1457. error_status_t ServerAllocateOIDsInternal(
  1458. IN CProcess* pProcess,
  1459. IN OXID *poxidServer,
  1460. IN ULONG cOidsReturn,
  1461. IN OID aOidsReturn[],
  1462. IN ULONG cOids,
  1463. OUT OID aOids[],
  1464. OUT PULONG pOidsAllocated
  1465. )
  1466. /*++
  1467. Routine Description:
  1468. Function for registering additional OIDs on behalf of an existing
  1469. OXID.
  1470. Arguments:
  1471. pProcess - The process containing the OXID and OIDs.
  1472. poxidServer - The OXID associated with the OIDs.
  1473. cOidsReturn - Count of aOidsReturn
  1474. aOidsReturn - Array of OIDs the process is no longer using.
  1475. cOids - Count of aOids
  1476. aOids - The OIDs to register within the OXID.
  1477. pOidsAllocate - Contains the number of OIDs actually allocated
  1478. when this function returns success.
  1479. Return Value:
  1480. OR_OK - Success. At least one OID was allocated (caller should
  1481. check *pOidsAllocated for the actual number allocated, it may be
  1482. less than he requested).
  1483. OR_BADOXID - Cannot find the specified OXID
  1484. OR_NOMEM - Out of memory resource failure
  1485. --*/
  1486. {
  1487. ORSTATUS status = OR_OK;
  1488. CServerOxid *pOxid;
  1489. CServerOid *pOid;
  1490. // Parameter validation
  1491. if (!poxidServer ||
  1492. !(cOidsReturn > 0 ? (aOidsReturn != NULL) : TRUE) ||
  1493. !((cOids > 0 ? (aOids != NULL) : TRUE) ||
  1494. !pOidsAllocated))
  1495. {
  1496. return OR_BADPARAM;
  1497. }
  1498. gpServerLock->LockExclusive();
  1499. CIdKey oxidkey(*poxidServer);
  1500. pOxid = (CServerOxid *)gpServerOxidTable->Lookup(oxidkey);
  1501. if (0 == pOxid)
  1502. {
  1503. gpServerLock->UnlockExclusive();
  1504. status = OR_BADOXID;
  1505. return(status);
  1506. }
  1507. if (cOidsReturn)
  1508. {
  1509. // free the Oids returned
  1510. FreeServerOids(pProcess, cOidsReturn, aOidsReturn);
  1511. }
  1512. *pOidsAllocated = 0;
  1513. for (ULONG i = 0; i < cOids; i++)
  1514. {
  1515. ID id;
  1516. if (AllocateId(&id))
  1517. {
  1518. pOid = new CServerOid(pOxid, id);
  1519. if (NULL != pOid)
  1520. {
  1521. (*pOidsAllocated)++;
  1522. aOids[i] = id;
  1523. gpServerOidTable->Add(pOid);
  1524. // The server doesn't want to keep the OID alive.
  1525. // This will cause the OID to rundown in six minutes
  1526. // unless a set references it in the meantime...
  1527. pOid->Release();
  1528. }
  1529. else
  1530. {
  1531. // out-of-mem
  1532. break;
  1533. }
  1534. }
  1535. else
  1536. {
  1537. // failed to allocate id
  1538. break;
  1539. }
  1540. }
  1541. gpServerLock->UnlockExclusive();
  1542. // If caller asked us to allocate oids, and we were able to allocate at least
  1543. // one, return OR_OK (ole32 will handle this). If not able to allocate any
  1544. // of the requested oids, return OR_NOMEM.
  1545. //
  1546. // If caller didn't ask for any oids to be allocated, just return OR_OK.
  1547. //
  1548. if (cOids > 0)
  1549. {
  1550. return (((*pOidsAllocated) > 0) ? OR_OK : OR_NOMEM);
  1551. }
  1552. return OR_OK;
  1553. }
  1554. error_status_t _ServerAllocateOIDs(
  1555. IN handle_t hClient,
  1556. IN PHPROCESS phProcess,
  1557. IN OXID *poxidServer,
  1558. IN ULONG cOidsReturn,
  1559. IN OID aOidsReturn[],
  1560. IN ULONG cOids,
  1561. OUT OID aOids[],
  1562. OUT PULONG pOidsAllocated
  1563. )
  1564. /*++
  1565. Routine Description:
  1566. RPC entry point for registering additional OIDs on behalf of an existing
  1567. OXID. Does a security check and delegates to the internal helper function.
  1568. See ServerAllocateOIDsInternal for parameter descriptions and a more detailed
  1569. functional description.
  1570. --*/
  1571. {
  1572. CProcess* pProcess = CheckLocalSecurity(hClient, phProcess);
  1573. if (!pProcess)
  1574. return OR_NOACCESS;
  1575. return ServerAllocateOIDsInternal(
  1576. pProcess,
  1577. poxidServer,
  1578. cOidsReturn,
  1579. aOidsReturn,
  1580. cOids,
  1581. aOids,
  1582. pOidsAllocated);
  1583. }
  1584. error_status_t
  1585. _ServerAllocateOXIDAndOIDs(
  1586. IN handle_t hClient,
  1587. IN PHPROCESS phProcess,
  1588. OUT OXID *poxidServer,
  1589. IN LONG fApartment,
  1590. IN ULONG cOids,
  1591. OUT OID aOids[],
  1592. OUT PULONG pOidsAllocated,
  1593. IN OXID_INFO *poxidInfo, // No bindings
  1594. IN DUALSTRINGARRAY *pdsaStringBindings, // Expanded
  1595. IN DUALSTRINGARRAY *pdsaSecurityBindings, // Compressed
  1596. OUT DWORD64 *pdwBindingsID,
  1597. OUT DUALSTRINGARRAY **ppdsaOrBindings
  1598. )
  1599. /*++
  1600. Routine Description:
  1601. Allocates an OXID and 0 or more OIDs from the OR.
  1602. Arguments:
  1603. phProcess - The context handle of the process containing the OXID.
  1604. poxidServer - The OXID to register. May only register once.
  1605. cOids - Count of apOids
  1606. apOid - The OIDs to register within the OXID.
  1607. pcOidsAllocated - The number of OIDs actually allocated. Usually the
  1608. same as cOids unless a resource failure occures. Maybe 0.
  1609. poxidInfo - The OXID_INFO structure for the OXID without bindings.
  1610. pdsaStringBindings - Expanded string binding of the server.
  1611. pdsaSecurityBindings - The compressed security bindings of the server.
  1612. pOidsAllocated - The number of OIDs actually allocated. >= 0 and <= cOids.
  1613. pdwBindingsID -- The id of the bindings returned in ppdsaOrBindings
  1614. ppdsaOrBindings -- The current resolver bindings. Normally this is not
  1615. ever allocated, unless dynamic address tracking is enabled.
  1616. Return Value:
  1617. OR_OK - success. Returned even if some OID allocations fail. See the
  1618. pOidsAllocated parameter.
  1619. OR_NOMEM - Allocation of OXID failed.
  1620. OR_ACCESS_DENIDED - Raised if non-local client
  1621. OR_BADPARAM - if string arrays are incorrect.
  1622. --*/
  1623. {
  1624. ORSTATUS status = OR_OK;
  1625. CServerOxid *pNewOxid;
  1626. CProcess *pProcess = NULL;
  1627. pProcess = CheckLocalSecurity(hClient, phProcess);
  1628. if (!pProcess)
  1629. return OR_NOACCESS;
  1630. // Parameter validation
  1631. if (!poxidServer ||
  1632. !(cOids > 0 ? (aOids != NULL) : TRUE) ||
  1633. !pOidsAllocated || !poxidInfo ||
  1634. !pdsaStringBindings || !pdsaSecurityBindings ||
  1635. !pdwBindingsID || !ppdsaOrBindings)
  1636. {
  1637. return OR_BADPARAM;
  1638. }
  1639. gpServerLock->LockExclusive();
  1640. // Save the string bindings back to the process
  1641. if (!dsaValid(pdsaStringBindings) )
  1642. {
  1643. status = OR_BADPARAM;
  1644. }
  1645. if (!dsaValid(pdsaSecurityBindings))
  1646. {
  1647. status = OR_BADPARAM;
  1648. }
  1649. if (status == OR_OK)
  1650. {
  1651. status = pProcess->ProcessBindings(pdsaStringBindings,
  1652. pdsaSecurityBindings);
  1653. }
  1654. *pdwBindingsID = 0;
  1655. *ppdsaOrBindings = NULL;
  1656. VALIDATE((status, OR_NOMEM, OR_BADPARAM, 0));
  1657. if (status != OR_OK)
  1658. {
  1659. gpServerLock->UnlockExclusive();
  1660. return(status);
  1661. }
  1662. ID id;
  1663. if (AllocateId(&id))
  1664. {
  1665. pNewOxid = new CServerOxid(pProcess,
  1666. fApartment,
  1667. poxidInfo,
  1668. id
  1669. );
  1670. if (0 == pNewOxid)
  1671. {
  1672. gpServerLock->UnlockExclusive();
  1673. return(OR_NOMEM);
  1674. }
  1675. }
  1676. else
  1677. {
  1678. // Failed to allocate new id
  1679. gpServerLock->UnlockExclusive();
  1680. return(OR_NOMEM);
  1681. }
  1682. // Add to process and lookup table.
  1683. status = pProcess->AddOxid(pNewOxid);
  1684. VALIDATE((status, OR_NOMEM, 0));
  1685. pNewOxid->Release(); // process has a reference now or failed
  1686. gpServerLock->UnlockExclusive();
  1687. if (status == OR_OK)
  1688. {
  1689. *poxidServer = pNewOxid->Id();
  1690. status = ServerAllocateOIDsInternal(
  1691. pProcess,
  1692. poxidServer,
  1693. 0,
  1694. NULL,
  1695. cOids,
  1696. aOids,
  1697. pOidsAllocated);
  1698. }
  1699. if (status == OR_OK && gbDynamicIPChangesEnabled)
  1700. {
  1701. if (ppdsaOrBindings && pProcess->NeedsORBindings())
  1702. {
  1703. // If doing dynamic IP changes, give process the current
  1704. // OR bindings
  1705. status = CopyMyOrBindings(ppdsaOrBindings, pdwBindingsID);
  1706. if (status == OR_OK)
  1707. {
  1708. pProcess->BindingsUpdated();
  1709. }
  1710. }
  1711. }
  1712. return(status);
  1713. }
  1714. error_status_t
  1715. _ServerFreeOXIDAndOIDs(
  1716. IN handle_t hClient,
  1717. IN PHPROCESS phProcess,
  1718. IN OXID oxidServer,
  1719. IN ULONG cOids,
  1720. IN OID aOids[])
  1721. {
  1722. CServerOxid *pOxid;
  1723. CServerOid *pOid;
  1724. CProcess *pProcess = NULL;
  1725. ORSTATUS status;
  1726. UINT i;
  1727. pProcess = CheckLocalSecurity(hClient, phProcess);
  1728. if (!pProcess)
  1729. return OR_NOACCESS;
  1730. // Parameter validation
  1731. if (!(cOids > 0 ? (aOids != NULL) : TRUE))
  1732. return OR_BADPARAM;
  1733. gpServerLock->LockExclusive();
  1734. CIdKey oxidkey(oxidServer);
  1735. pOxid = (CServerOxid *)gpServerOxidTable->Lookup(oxidkey);
  1736. if (0 != pOxid)
  1737. {
  1738. if (pProcess->RemoveOxid(pOxid) == TRUE)
  1739. {
  1740. // Found the OXID and this caller owns it.
  1741. status = OR_OK;
  1742. }
  1743. else
  1744. {
  1745. // Found but not owned by this caller.
  1746. status = OR_NOACCESS;
  1747. }
  1748. }
  1749. else
  1750. {
  1751. // Oxid not found.
  1752. status = OR_BADOXID;
  1753. }
  1754. // Note pOxid maybe invalid once the last OID is removed.
  1755. if (status == OR_OK)
  1756. {
  1757. for (i = 0; i < cOids; i++)
  1758. {
  1759. CIdKey key(aOids[i]); // PERF REVIEW
  1760. pOid = (CServerOid *)gpServerOidTable->Lookup(key);
  1761. if ( (0 != pOid)
  1762. && (pOid->IsRunningDown() == FALSE)
  1763. && (pOid->GetOxid() == pOxid) )
  1764. {
  1765. if (pOid->References() == 0)
  1766. {
  1767. // Unreferenced by any sets; run it down now..
  1768. pOid->Remove();
  1769. pOid->SetRundown(TRUE);
  1770. delete pOid;
  1771. }
  1772. // else - marking it as Free() not need as Oxid is
  1773. // now marked as not running.
  1774. }
  1775. else
  1776. {
  1777. ASSERT(pOid == 0 || pOxid == pOid->GetOxid());
  1778. }
  1779. }
  1780. }
  1781. gpServerLock->UnlockExclusive();
  1782. return(status);
  1783. }
  1784. //
  1785. // Manager (server-side) calls to the remote OR interface. objex.idl
  1786. //
  1787. error_status_t
  1788. _ResolveOxid(
  1789. IN handle_t hRpc,
  1790. IN OXID *poxid,
  1791. IN USHORT cRequestedProtseqs,
  1792. IN USHORT aRequestedProtseqs[],
  1793. OUT DUALSTRINGARRAY **ppdsaOxidBindings,
  1794. OUT IPID *pipidRemUnknown,
  1795. OUT DWORD *pAuthnHint
  1796. )
  1797. {
  1798. COMVERSION ComVersion;
  1799. // just forward to the new manager routine (parameter
  1800. // validation done by callee)
  1801. return _ResolveOxid2(hRpc,
  1802. poxid,
  1803. cRequestedProtseqs,
  1804. aRequestedProtseqs,
  1805. ppdsaOxidBindings,
  1806. pipidRemUnknown,
  1807. pAuthnHint,
  1808. &ComVersion);
  1809. }
  1810. //
  1811. // Manager (server-side) calls to the remote OR interface. objex.idl
  1812. //
  1813. error_status_t
  1814. _ResolveOxid2(
  1815. IN handle_t hRpc,
  1816. IN OXID *poxid,
  1817. IN USHORT cRequestedProtseqs,
  1818. IN USHORT aRequestedProtseqs[],
  1819. OUT DUALSTRINGARRAY **ppdsaOxidBindings,
  1820. OUT IPID *pipidRemUnknown,
  1821. OUT DWORD *pAuthnHint,
  1822. OUT COMVERSION *pComVersion
  1823. )
  1824. {
  1825. ORSTATUS status;
  1826. BOOL fDidLazy;
  1827. CServerOxid *pServerOxid;
  1828. OXID_INFO oxidInfo;
  1829. // Parameter validation. Note that it would be exceedingly odd for
  1830. // a client to request zero protseqs, but we handle this anyway.
  1831. if (!poxid ||
  1832. !(cRequestedProtseqs > 0 ? (aRequestedProtseqs != NULL) : TRUE) ||
  1833. !ppdsaOxidBindings || !pipidRemUnknown ||
  1834. !pipidRemUnknown || !pAuthnHint || !pComVersion)
  1835. {
  1836. return OR_BADPARAM;
  1837. }
  1838. oxidInfo.psa = 0;
  1839. // No security check required (possible?). OXID info is not private.
  1840. #if DBG
  1841. UINT fLocal;
  1842. status = I_RpcBindingIsClientLocal(hRpc, &fLocal);
  1843. if (status != OR_OK)
  1844. {
  1845. fLocal = FALSE;
  1846. }
  1847. ASSERT(fLocal == FALSE); // Shouldn't be called locally...
  1848. #endif
  1849. fDidLazy = FALSE;
  1850. // intersect allowed protseqs with those
  1851. // requested by the client.
  1852. //
  1853. // NOTE: we are modifying memory passed in. This will not cause side
  1854. // effects because this call is always in the context of an RPC, and
  1855. // aRequestedProtseqs is an IN parameter and therefore will not change
  1856. // in the calling process.
  1857. gpClientLock->LockExclusive();
  1858. USHORT cAllowedProtseqs = 0;
  1859. for (USHORT iReqProtseq=0; iReqProtseq < cRequestedProtseqs; iReqProtseq++)
  1860. {
  1861. for (USHORT iAllowProtseq=0; iAllowProtseq < cMyProtseqs; iAllowProtseq++)
  1862. {
  1863. if (aRequestedProtseqs[iReqProtseq] == aMyProtseqs[iAllowProtseq])
  1864. {
  1865. // this protocol is in the allowed list, shift it up
  1866. // if necessary.
  1867. aRequestedProtseqs[cAllowedProtseqs] = aRequestedProtseqs[iReqProtseq];
  1868. cAllowedProtseqs++;
  1869. break;
  1870. }
  1871. }
  1872. }
  1873. cRequestedProtseqs = cAllowedProtseqs;
  1874. gpClientLock->UnlockExclusive();
  1875. gpServerLock->LockShared();
  1876. for (;;)
  1877. {
  1878. CIdKey key(*poxid);
  1879. pServerOxid = (CServerOxid *)gpServerOxidTable->Lookup(key);
  1880. if (!pServerOxid)
  1881. {
  1882. status = OR_BADOXID;
  1883. break;
  1884. }
  1885. status = pServerOxid->GetRemoteInfo(&oxidInfo,
  1886. cRequestedProtseqs,
  1887. aRequestedProtseqs);
  1888. // Work around: original intersection of clients requested protocols
  1889. // with this SCM's did'nt match. But we know that client
  1890. // does'nt send it's entire set, just one so break here
  1891. //
  1892. // Note: W2K sends all protocols on both activations and ResolveOxid
  1893. // calls; NT4 only sends one protocol on activations, and all on
  1894. // ResolveOxid calls.
  1895. //
  1896. if ((cRequestedProtseqs == 0) && (status == OR_I_NOPROTSEQ))
  1897. {
  1898. break;
  1899. }
  1900. if ( status == OR_I_NOPROTSEQ
  1901. && FALSE == fDidLazy )
  1902. {
  1903. // Ask the server to start listening, but only try this once.
  1904. fDidLazy = TRUE;
  1905. status =
  1906. pServerOxid->LazyUseProtseq(cRequestedProtseqs,
  1907. aRequestedProtseqs
  1908. );
  1909. ASSERT(gpServerLock->HeldExclusive()); // Changed during UseProtseq!
  1910. if (status == OR_OK)
  1911. {
  1912. continue;
  1913. }
  1914. }
  1915. else if (status == OR_I_NOPROTSEQ)
  1916. {
  1917. // We didn't manage to use a matching protseq.
  1918. // Since we can call on any protocol this is possible
  1919. KdPrintEx((DPFLTR_DCOMSS_ID,
  1920. DPFLTR_WARNING_LEVEL,
  1921. "OR: Failed to use a matching protseq: %p %p\n",
  1922. pServerOxid,
  1923. aRequestedProtseqs));
  1924. status = OR_NOSERVER;
  1925. }
  1926. break;
  1927. }
  1928. gpServerLock->Unlock();
  1929. if (status == OR_OK)
  1930. {
  1931. *pipidRemUnknown = oxidInfo.ipidRemUnknown;
  1932. *ppdsaOxidBindings = oxidInfo.psa;
  1933. *pAuthnHint = oxidInfo.dwAuthnHint;
  1934. *pComVersion = oxidInfo.version;
  1935. }
  1936. else
  1937. {
  1938. // Work around: original intersection of clients requested protocols
  1939. // with this SCM's did'nt match. But we know that client
  1940. // does'nt send it's entire set, just one, so send back
  1941. // an empty set but o.k activation result for bindings
  1942. //
  1943. // Note: W2K sends all protocols on both activations and ResolveOxid
  1944. // calls; NT4 only sends one protocol on activations, and all on
  1945. // ResolveOxid calls.
  1946. //
  1947. if ((cRequestedProtseqs == 0) && (status == OR_I_NOPROTSEQ))
  1948. {
  1949. *pipidRemUnknown = oxidInfo.ipidRemUnknown;
  1950. *ppdsaOxidBindings = NULL;
  1951. *pAuthnHint = oxidInfo.dwAuthnHint;
  1952. *pComVersion = oxidInfo.version;
  1953. status = OR_OK;
  1954. }
  1955. }
  1956. return(status);
  1957. }
  1958. error_status_t
  1959. _SimplePing(
  1960. IN handle_t hRpc,
  1961. IN SETID *pSetId
  1962. )
  1963. {
  1964. ORSTATUS status;
  1965. CServerSet *pServerSet;
  1966. BOOL fShared = TRUE;
  1967. // Parameter validation
  1968. if (!pSetId)
  1969. return OR_BADPARAM;
  1970. if (*pSetId == 0)
  1971. {
  1972. KdPrintEx((DPFLTR_DCOMSS_ID,
  1973. DPFLTR_WARNING_LEVEL,
  1974. "Client %p simple pinged with a setid of 0\n",
  1975. hRpc,
  1976. pSetId));
  1977. return(OR_BADSET);
  1978. }
  1979. gpServerLock->LockShared();
  1980. pServerSet = (CServerSet *)gpServerSetTable->Lookup(*pSetId);
  1981. if (pServerSet)
  1982. {
  1983. fShared = pServerSet->Ping(TRUE);
  1984. // The lock maybe exclusive now.
  1985. status = OR_OK;
  1986. }
  1987. else
  1988. {
  1989. status = OR_BADSET;
  1990. }
  1991. // See if another set in the table needs to rundown.
  1992. // PERF REVIEW - how often should I do this? 0 mod 4?
  1993. // Similar code in worker threads.
  1994. ID setid = gpServerSetTable->CheckForRundowns();
  1995. if (setid)
  1996. {
  1997. if (fShared)
  1998. {
  1999. gpServerLock->ConvertToExclusive();
  2000. fShared = FALSE;
  2001. }
  2002. gpServerSetTable->RundownSetIfNeeded(setid);
  2003. }
  2004. gpServerLock->Unlock();
  2005. return(status);
  2006. }
  2007. error_status_t
  2008. ComplexPingInternal(
  2009. IN handle_t hRpc,
  2010. IN SETID *pSetId,
  2011. IN USHORT SequenceNum,
  2012. IN ULONG cAddToSet,
  2013. IN ULONG cDelFromSet,
  2014. IN OID AddToSet[],
  2015. IN OID DelFromSet[],
  2016. OUT USHORT *pPingBackoffFactor
  2017. )
  2018. /*++
  2019. Routine Description:
  2020. Processes a complex (delta to set) ping for a given set. This call
  2021. will create the set if necessary. The call will only be processed
  2022. if the caller is in fact the creator of the set.
  2023. algorithm:
  2024. if set is not allocated
  2025. lookup security info if possible
  2026. allocate set
  2027. else
  2028. lookup set
  2029. if found or created a set
  2030. do a standard ping, updating time stamp and sequence number.
  2031. else return failure.
  2032. if oids to add, add each one.
  2033. ignore unknown OIDs
  2034. if resource allocation fails, abort.
  2035. if oids to delete, process each one.
  2036. ignore unknown OIDs
  2037. if resource failure in adds, return OR_BADOID
  2038. else return success.
  2039. Arguments:
  2040. hRpc - Handle (SCONN/SCALL) of client. Used to check security. If it is
  2041. NULL the call is local and is assumed to be secure.
  2042. REVIEW:
  2043. Since the OR _only_ uses NT system security providers it is assumed
  2044. that impersonation will work. Other security providers will not.
  2045. We need a generic way to ask for a token and compare tokens in a
  2046. security provider independent way.
  2047. pSetId - The setid to ping. If it is NULL a new set will be created,
  2048. otherwise, it is assumed to be a set previously allocated by a
  2049. call with a NULL setid to this server.
  2050. SequenceNum - A sequence number shared between the client and server
  2051. to make sure old and out-of-order pings are not processed in a
  2052. non-healthy way. Note that pings are usually datagram RPC calls
  2053. which are marked as idempotent.
  2054. cAddToSet
  2055. cDelFromSet - The count of element in AddTo/DelFromSet parameter.
  2056. AddToSet
  2057. DelFromSet - OID mostly likly belonging to servers on this machine
  2058. to Add/Remove from the set of OIDs in use by this client.
  2059. pPingBackoffFactor - Maybe set by servers which want to reduce the
  2060. ping load on the server. Serves only as a HINT for the client.
  2061. Clients do not to ping more offten then:
  2062. (1<<*pPingBackoffFactor)*BasePingInterval seconds.
  2063. Clients may choose to assume this parameter is always 0.
  2064. Return Value:
  2065. OR_OK - completed normally
  2066. OR_BADSET - non-zero and unknown setid.
  2067. OR_NOMEM - unable to allocate a resource. Note that
  2068. on the first ping a set maybe allocated (setid is non-zero
  2069. after call) but some OIDs failed to be allocated.
  2070. OR_BADOID - everything went okay, but some OIDs added where
  2071. not recognized.
  2072. --*/
  2073. {
  2074. CServerSet *pServerSet;
  2075. BOOL fProcessPing;
  2076. BOOL fBad = FALSE;
  2077. PSID psid = 0;
  2078. ORSTATUS status = OR_OK;
  2079. // Parameter validation.
  2080. if (!pSetId ||
  2081. !(cAddToSet > 0 ? (AddToSet != NULL) : TRUE) ||
  2082. !(cDelFromSet > 0 ? (DelFromSet != NULL) : TRUE) ||
  2083. !pPingBackoffFactor)
  2084. {
  2085. return OR_BADPARAM;
  2086. }
  2087. gpServerLock->LockExclusive();
  2088. // Lookup the set
  2089. if (0 != *pSetId)
  2090. {
  2091. pServerSet = (CServerSet *)gpServerSetTable->Lookup(*pSetId);
  2092. if (0 == pServerSet)
  2093. {
  2094. status = OR_BADSET;
  2095. }
  2096. if (status == OR_OK)
  2097. {
  2098. if (pServerSet->CheckSecurity(hRpc) != TRUE)
  2099. {
  2100. KdPrintEx((DPFLTR_DCOMSS_ID,
  2101. DPFLTR_WARNING_LEVEL,
  2102. "OR: Security check on set failed! (%d)\n",
  2103. GetLastError()));
  2104. status = OR_NOACCESS;
  2105. }
  2106. }
  2107. }
  2108. else if (hRpc == 0)
  2109. {
  2110. // Local client
  2111. psid = 0;
  2112. pServerSet = gpServerSetTable->Allocate(SequenceNum,
  2113. psid,
  2114. hRpc == 0,
  2115. *pSetId);
  2116. if (0 == pServerSet)
  2117. status = OR_NOMEM;
  2118. else
  2119. status = OR_OK;
  2120. }
  2121. else
  2122. {
  2123. HANDLE hT;
  2124. BOOL f;
  2125. // Unallocated set, lookup security info and allocate the set.
  2126. KdPrintEx((DPFLTR_DCOMSS_ID,
  2127. DPFLTR_INFO_LEVEL,
  2128. "OR: New client started pinging: %p\n",
  2129. hRpc));
  2130. status = RpcImpersonateClient(hRpc);
  2131. if (status == RPC_S_OK)
  2132. {
  2133. f = OpenThreadToken(GetCurrentThread(),
  2134. TOKEN_IMPERSONATE | TOKEN_QUERY,
  2135. TRUE,
  2136. &hT);
  2137. if (!f)
  2138. {
  2139. status = GetLastError();
  2140. }
  2141. else
  2142. {
  2143. status = RPC_S_OK;
  2144. }
  2145. }
  2146. if (status != RPC_S_OK)
  2147. {
  2148. KdPrintEx((DPFLTR_DCOMSS_ID,
  2149. DPFLTR_WARNING_LEVEL,
  2150. "OR: Unsecure client started pinging: %d %p\n",
  2151. status,
  2152. hRpc));
  2153. status = OR_OK;
  2154. }
  2155. else
  2156. {
  2157. ULONG needed = DEBUG_MIN(1, 24);
  2158. PTOKEN_USER ptu;
  2159. do
  2160. {
  2161. ptu = (PTOKEN_USER)alloca(needed);
  2162. ASSERT(ptu);
  2163. f = GetTokenInformation(hT,
  2164. TokenUser,
  2165. (PBYTE)ptu,
  2166. needed,
  2167. &needed);
  2168. } while ( f == FALSE && GetLastError() == ERROR_INSUFFICIENT_BUFFER);
  2169. if (f)
  2170. {
  2171. ASSERT(needed > sizeof(SID));
  2172. psid = new(needed - sizeof(SID)) SID;
  2173. if (psid)
  2174. {
  2175. f = CopySid(needed, psid, ptu->User.Sid);
  2176. ASSERT(f == TRUE);
  2177. }
  2178. else
  2179. {
  2180. status = OR_NOMEM;
  2181. }
  2182. }
  2183. else
  2184. {
  2185. KdPrintEx((DPFLTR_DCOMSS_ID,
  2186. DPFLTR_WARNING_LEVEL,
  2187. "OR: Error %d from GetTokenInformation\n",
  2188. GetLastError()));
  2189. ASSERT(0);
  2190. // Why did this happen. Either return failure to client or
  2191. // continue and make the set unsecure.
  2192. status = OR_NOMEM;
  2193. }
  2194. CloseHandle(hT);
  2195. }
  2196. // Allocate the set
  2197. if (status == OR_OK)
  2198. {
  2199. ASSERT(gpPingSetQuotaManager);
  2200. if (gpPingSetQuotaManager->IsUserQuotaExceeded(psid))
  2201. status = OR_NORESOURCE;
  2202. if (OR_OK == status)
  2203. {
  2204. if (!gpPingSetQuotaManager->ManageQuotaForUser(psid, TRUE))
  2205. {
  2206. status = OR_NOMEM;
  2207. }
  2208. else
  2209. {
  2210. pServerSet = gpServerSetTable->Allocate(SequenceNum,
  2211. psid,
  2212. hRpc == 0,
  2213. *pSetId);
  2214. if (0 == pServerSet)
  2215. {
  2216. gpPingSetQuotaManager->ManageQuotaForUser(psid, FALSE);
  2217. status = OR_NOMEM;
  2218. }
  2219. }
  2220. }
  2221. }
  2222. }
  2223. if (status != OR_OK)
  2224. {
  2225. VALIDATE((status, OR_NOMEM, OR_BADSET, OR_NOACCESS, OR_NORESOURCE, 0));
  2226. gpServerLock->UnlockExclusive();
  2227. if (psid)
  2228. delete psid;
  2229. return(status);
  2230. }
  2231. ASSERT(pServerSet);
  2232. fProcessPing = pServerSet->CheckAndUpdateSequenceNumber(SequenceNum);
  2233. if (fProcessPing)
  2234. {
  2235. // Do regular ping
  2236. pServerSet->Ping(FALSE);
  2237. *pPingBackoffFactor = 0;
  2238. // Process Add's
  2239. for (int i = cAddToSet; i ; i--)
  2240. {
  2241. status = pServerSet->AddObject(AddToSet[i - 1]);
  2242. if (status == OR_BADOID)
  2243. {
  2244. fBad = TRUE;
  2245. }
  2246. else if ( status != OR_OK )
  2247. {
  2248. break;
  2249. }
  2250. }
  2251. // Process Deletes - even some adds failed!
  2252. for (i = cDelFromSet; i; i--)
  2253. {
  2254. // Removing can't fail, no way to cleanup.
  2255. pServerSet->RemoveObject(DelFromSet[i - 1]);
  2256. }
  2257. }
  2258. gpServerLock->UnlockExclusive();
  2259. if (status == OR_OK && fBad)
  2260. {
  2261. return(OR_BADOID);
  2262. }
  2263. return(status);
  2264. }
  2265. error_status_t
  2266. _ComplexPing(
  2267. IN handle_t hRpc,
  2268. IN SETID *pSetId,
  2269. IN USHORT SequenceNum,
  2270. IN USHORT cAddToSet,
  2271. IN USHORT cDelFromSet,
  2272. IN OID AddToSet[],
  2273. IN OID DelFromSet[],
  2274. OUT USHORT *pPingBackoffFactor
  2275. )
  2276. /*--
  2277. Routine Description:
  2278. This is the exposed RPC entry point for this function. We
  2279. simply call the internal function below. See description
  2280. for ComplexPingInternal. The reason for a separate function
  2281. is because the RPC method is typed to to take USHORT's, but
  2282. internally it is more convienent to pass ULONG's.
  2283. Arguments:
  2284. See argument list for ComplexPingInternal
  2285. --*/
  2286. {
  2287. return ComplexPingInternal(hRpc,
  2288. pSetId,
  2289. SequenceNum,
  2290. cAddToSet,
  2291. cDelFromSet,
  2292. AddToSet,
  2293. DelFromSet,
  2294. pPingBackoffFactor);
  2295. }
  2296. error_status_t
  2297. _ServerAlive(
  2298. RPC_ASYNC_STATE *pAsync,
  2299. RPC_BINDING_HANDLE hServer
  2300. )
  2301. /*++
  2302. Routine Description:
  2303. Ping API for the client to validate a binding. Used when the client
  2304. is unsure of the correct binding for the server. (Ie. If the server
  2305. has multiple IP addresses).
  2306. Arguments:
  2307. hServer - RPC call binding
  2308. Return Value:
  2309. OR_OK
  2310. --*/
  2311. {
  2312. error_status_t RetVal = OR_OK;
  2313. RPC_STATUS rpcstatus;
  2314. RegisterAuthInfoIfNecessary();
  2315. rpcstatus = RpcAsyncCompleteCall(pAsync, &RetVal);
  2316. return (rpcstatus == RPC_S_OK) ? RetVal : rpcstatus;
  2317. }
  2318. error_status_t
  2319. _ServerAlive2(
  2320. RPC_ASYNC_STATE *pAsync,
  2321. RPC_BINDING_HANDLE hServer,
  2322. COMVERSION *pComVersion,
  2323. DUALSTRINGARRAY **ppdsaOrBindings,
  2324. DWORD *pReserved
  2325. )
  2326. /*++
  2327. Routine Description:
  2328. Ping API for the client to validate a binding. Used when the client
  2329. is unsure of the correct binding or authentication service for the server.
  2330. (Ie. If the server has multiple IP addresses).
  2331. Arguments:
  2332. hServer - RPC call binding
  2333. Return Value:
  2334. OR_OK
  2335. --*/
  2336. {
  2337. error_status_t RetVal = OR_OK;
  2338. RPC_STATUS rpcstatus = RPC_S_OK;
  2339. // Parameter validation
  2340. if (!pComVersion || !ppdsaOrBindings || !pReserved)
  2341. return OR_BADPARAM;
  2342. RegisterAuthInfoIfNecessary();
  2343. pComVersion->MajorVersion = COM_MAJOR_VERSION;
  2344. pComVersion->MinorVersion = COM_MINOR_VERSION;
  2345. *pReserved = 0;
  2346. RetVal = CopyMyOrBindings(ppdsaOrBindings, NULL);
  2347. if (RetVal == OR_OK)
  2348. {
  2349. rpcstatus = RpcAsyncCompleteCall(pAsync, &RetVal);
  2350. }
  2351. return (rpcstatus == RPC_S_OK) ? RetVal : rpcstatus;
  2352. }
  2353. error_status_t
  2354. _Disconnect(
  2355. handle_t hClient,
  2356. PHPROCESS *pphProcess
  2357. )
  2358. /*++
  2359. Routine Description:
  2360. Ole32 disconnect api. Used by ole32 to tell us they are being
  2361. completely uninitialized in the calling process. This lets us
  2362. cleanup the context handle in an orderly fashion w/o waiting
  2363. around for a context rundown (which would happen, eventually, but
  2364. might be much later).
  2365. Arguments:
  2366. hClient -- [in] RPC call binding handle
  2367. pphProcess -- [in,out] context handle.
  2368. Return Value:
  2369. RPC_S_OK -- context handle cleaned up
  2370. other -- error occurred
  2371. --*/
  2372. {
  2373. // Ensure this is a local client calling
  2374. CProcess* pProcess = CheckLocalSecurity(hClient, *pphProcess);
  2375. if (!pProcess)
  2376. return OR_NOACCESS;
  2377. //
  2378. // Call the rundown routine (Disconnect is effectively an
  2379. // orderly context rundown).
  2380. //
  2381. PHPROCESS_rundown(*pphProcess);
  2382. // Note: don't touch pProcess after this point, it may have
  2383. // already been freed.
  2384. pProcess = NULL;
  2385. //
  2386. // Zero out the context handle so that RPC knows that
  2387. // it has been freed.
  2388. //
  2389. *pphProcess = NULL;
  2390. return RPC_S_OK;
  2391. };
  2392. void __RPC_USER PHPROCESS_rundown(LPVOID ProcessKey)
  2393. {
  2394. CProcess *pProcess = ReferenceProcess(ProcessKey, FALSE);
  2395. KdPrintEx((DPFLTR_DCOMSS_ID,
  2396. DPFLTR_INFO_LEVEL,
  2397. "OR: Client died\n"));
  2398. ASSERT(pProcess);
  2399. pProcess->NotifyRPCRundown();
  2400. //
  2401. // This revokes OLE class registrations which were not revoked by this
  2402. // dead process. This must be done here rather then CProcess::Rundown
  2403. // because these things have references to the CProcess object.
  2404. //
  2405. pProcess->RevokeClassRegs();
  2406. pProcess->Cleanup();
  2407. ReleaseProcess(pProcess);
  2408. return;
  2409. }
  2410. void CRpcSecurityCallback::SetMarshaledTargetInfo(unsigned long ulMarshaledTargetInfoLength, unsigned char *pMarshaledTargetInfo)
  2411. {
  2412. // I don't expect any existing creds
  2413. ASSERT( (_ulMarshaledTargetInfoLength == 0) && (_pMarshaledTargetInfo == NULL));
  2414. //clear any existing creds (just in case)
  2415. if (_ulMarshaledTargetInfoLength)
  2416. {
  2417. SECURITY_STATUS status = FreeContextBuffer(_pMarshaledTargetInfo);
  2418. #if DBG == 1
  2419. if (SEC_E_OK != status)
  2420. KdPrintEx((DPFLTR_DCOMSS_ID, DPFLTR_INFO_LEVEL,"SCM: FreeContextBuffer Failed %0x%x\n"));
  2421. #endif
  2422. }
  2423. _ulMarshaledTargetInfoLength = ulMarshaledTargetInfoLength;
  2424. _pMarshaledTargetInfo = pMarshaledTargetInfo;
  2425. ASSERT(
  2426. ((_ulMarshaledTargetInfoLength == 0) && (_pMarshaledTargetInfo == NULL)) ||
  2427. ((_ulMarshaledTargetInfoLength != 0) && (_pMarshaledTargetInfo != NULL))
  2428. );
  2429. }
  2430. ORSTATUS CRpcSecurityCallback::GetMarshaledTargetInfo(unsigned long *pulMarshaledTargetInfoLength, unsigned char **pucMarshaledTargetInfo)
  2431. {
  2432. ASSERT(
  2433. ((_ulMarshaledTargetInfoLength == 0) && (_pMarshaledTargetInfo == NULL)) ||
  2434. ((_ulMarshaledTargetInfoLength != 0) && (_pMarshaledTargetInfo != NULL))
  2435. );
  2436. ORSTATUS status=OR_OK;
  2437. *pulMarshaledTargetInfoLength = 0;
  2438. *pucMarshaledTargetInfo = NULL;
  2439. if (_ulMarshaledTargetInfoLength)
  2440. {
  2441. *pucMarshaledTargetInfo = (unsigned char *) MIDL_user_allocate(_ulMarshaledTargetInfoLength * sizeof(char));
  2442. if (*pucMarshaledTargetInfo)
  2443. {
  2444. memcpy(*pucMarshaledTargetInfo, _pMarshaledTargetInfo, _ulMarshaledTargetInfoLength);
  2445. *pulMarshaledTargetInfoLength = _ulMarshaledTargetInfoLength;
  2446. SECURITY_STATUS status = FreeContextBuffer(_pMarshaledTargetInfo);
  2447. #if DBG == 1
  2448. if (SEC_E_OK != status)
  2449. KdPrintEx((DPFLTR_DCOMSS_ID, DPFLTR_INFO_LEVEL,"SCM: FreeContextBuffer Failed %0x%x\n"));
  2450. #endif
  2451. _pMarshaledTargetInfo = NULL;
  2452. _ulMarshaledTargetInfoLength = 0;
  2453. }
  2454. else
  2455. status = ERROR_NOT_ENOUGH_MEMORY;
  2456. }
  2457. return status;
  2458. }
  2459. CRpcSecurityCallback::~CRpcSecurityCallback()
  2460. {
  2461. if (_ulMarshaledTargetInfoLength)
  2462. {
  2463. SECURITY_STATUS status = FreeContextBuffer(_pMarshaledTargetInfo);
  2464. #if DBG == 1
  2465. if (SEC_E_OK != status)
  2466. KdPrintEx((DPFLTR_DCOMSS_ID, DPFLTR_INFO_LEVEL,"SCM: FreeContextBuffer Failed %0x%x\n"));
  2467. #endif
  2468. }
  2469. _ulMarshaledTargetInfoLength = 0;
  2470. _pMarshaledTargetInfo = NULL;
  2471. }
  2472. //+---------------------------------------------------------------------------
  2473. //
  2474. // Function: CRpcSecurityCallbackManager::RegisterForRpcAuthSvcCallBack
  2475. //
  2476. // Synopsis: Register the security callback with RPC. A return value of
  2477. // TRUE means the calling thread may make a call on the supplied
  2478. // binding handle, then call the the RetrieveAuthSvc method
  2479. // for the negotiated authentication svc used on the rpc call.
  2480. //
  2481. // Parameters: hRpc -- the binding handle for which the calling thread wants
  2482. // the negotiated auth. svc.
  2483. //
  2484. // Algorithm: Register the security callback with RPC. Create a new list
  2485. // element to represent this particular callback, and add to to
  2486. // the list of callbacks.
  2487. //
  2488. // Notes: There is a limitation: a thread can only be registered for one
  2489. // callback at a time. This should be ok for expected usage.
  2490. //
  2491. //----------------------------------------------------------------------------
  2492. BOOL CRpcSecurityCallbackManager::RegisterForRpcAuthSvcCallBack(handle_t hRpc)
  2493. {
  2494. RPC_STATUS status;
  2495. CRpcSecurityCallback* pNewCallback;
  2496. ASSERT(hRpc != 0 && "Callbacks are meant to be used only for remote calls!");
  2497. // Create a new list element to represent this callback
  2498. pNewCallback = new CRpcSecurityCallback(hRpc, GetCurrentThreadId());
  2499. if (!pNewCallback)
  2500. return FALSE; // out-of-memory, not much we can do
  2501. // Try to register the callback
  2502. status = RpcBindingSetOption(hRpc,
  2503. RPC_C_OPT_SECURITY_CALLBACK,
  2504. (ULONG_PTR)CRpcSecurityCallbackManager::RpcSecurityCallbackFunction);
  2505. ASSERT(status == RPC_S_OK); // this should never fail AFAIK
  2506. if (status != RPC_S_OK)
  2507. {
  2508. // again, not much we can do
  2509. delete pNewCallback;
  2510. return FALSE;
  2511. }
  2512. // Okay now we got all we need; add it to the list
  2513. _plistlock->LockExclusive();
  2514. _CallbackList.Insert(pNewCallback);
  2515. _plistlock->UnlockExclusive();
  2516. return TRUE;
  2517. };
  2518. //+---------------------------------------------------------------------------
  2519. //
  2520. // Function: CRpcSecurityCallbackManager::GetSecurityContextDetailsAndTurnOffCallback
  2521. //
  2522. // Synopsis: Tries to retrieve the negotiated authentication service for the
  2523. // call just completed on the supplied binding handle. Also
  2524. // turns off callbacks on the binding handle.
  2525. //
  2526. // Parameters: pusAuthSvc -- if the rpc call was made, this must be a valid ptr;
  2527. // if that is the case, then upon a return value of TRUE, it
  2528. // will contain the auth. svc used for the call; a value of NULL
  2529. // passed here means the caller doesn't care about the result, he
  2530. // just wants things cleaned up (typically this means either the
  2531. // call failed or was never made).
  2532. //
  2533. // Returns: TRUE -- if everything worked
  2534. // FALSE -- something is wrong or you passed a NULL pusAuthSvc
  2535. //
  2536. // Algorithm: Use the caller's thread id to search for the callback result
  2537. //
  2538. //----------------------------------------------------------------------------
  2539. BOOL CRpcSecurityCallbackManager::GetSecurityContextDetailsAndTurnOffCallback(handle_t hRpc, USHORT* pusAuthSvc,
  2540. unsigned long *pulMarshaledTargetInfoLength, unsigned char **pucMarshaledTargetInfo)
  2541. {
  2542. RPC_STATUS status;
  2543. CRpcSecurityCallback* pCallback;
  2544. DWORD dwCurrentThread = GetCurrentThreadId();
  2545. USHORT usAuthSvc;
  2546. BOOL bRet = FALSE;
  2547. _plistlock->LockExclusive();
  2548. // No matter what happens after this, we should turn off callbacks for the handle
  2549. TurnOffCallback(hRpc);
  2550. // Look for the callback result for the calling thread
  2551. for (pCallback = (CRpcSecurityCallback*)_CallbackList.First();
  2552. pCallback;
  2553. pCallback = (CRpcSecurityCallback*)pCallback->Next() )
  2554. {
  2555. if (dwCurrentThread == pCallback->GetRegisteredThreadId())
  2556. {
  2557. // found it
  2558. break;
  2559. }
  2560. };
  2561. // Given the normal usage of this stuff, we should always find a result
  2562. ASSERT(pCallback && "Didn't find rpc sec. callback result; this is unexpected");
  2563. if (!pCallback)
  2564. {
  2565. _plistlock->UnlockExclusive();
  2566. return FALSE;
  2567. };
  2568. usAuthSvc = pCallback->GetAuthSvcResult();
  2569. if (pusAuthSvc)
  2570. {
  2571. ASSERT(pCallback->WasAuthSvcSet() && "Caller is retrieving auth svc before it was set");
  2572. *pusAuthSvc = usAuthSvc;
  2573. }
  2574. status = pCallback->GetMarshaledTargetInfo(pulMarshaledTargetInfoLength, pucMarshaledTargetInfo);
  2575. // The callback's work is done, so remove it from the list and delete it
  2576. _CallbackList.Remove(pCallback);
  2577. delete pCallback;
  2578. // Check list to see if other threads also had registered callbacks on the
  2579. // same handle. We will record the result for them in case we turned off the
  2580. // callback above before they got recorded. In fact, any time two or more threads
  2581. // register for a callback on the same handle we will hit this scenario.
  2582. //
  2583. // I don't think this is 100% foolproof, but it constitutes a best-faith effort
  2584. //
  2585. for (pCallback = (CRpcSecurityCallback*)_CallbackList.First();
  2586. pCallback;
  2587. pCallback = (CRpcSecurityCallback*)pCallback->Next() )
  2588. {
  2589. if (hRpc == pCallback->RegisteredHandle())
  2590. {
  2591. // found a match
  2592. ASSERT(dwCurrentThread != pCallback->GetRegisteredThreadId());
  2593. pCallback->SetAuthSvc(usAuthSvc);
  2594. }
  2595. };
  2596. _plistlock->UnlockExclusive();
  2597. bRet = ((status == OR_OK) && (pusAuthSvc ? (*pusAuthSvc != ERROR_AUTHNSVC_VALUE) : FALSE));
  2598. if (!bRet)
  2599. {
  2600. if(*pucMarshaledTargetInfo)
  2601. {
  2602. MIDL_user_free(*pucMarshaledTargetInfo);
  2603. *pucMarshaledTargetInfo = NULL;
  2604. *pulMarshaledTargetInfoLength = 0;
  2605. }
  2606. }
  2607. return bRet;
  2608. };
  2609. //+---------------------------------------------------------------------------
  2610. //
  2611. // Function: CRpcSecurityCallbackManager::TurnOffCallback
  2612. //
  2613. // Synopsis: Function to turn off the callback on an rpc binding handle
  2614. //
  2615. // Parameters: hRpc -- the binding handle to turn off callbacks on
  2616. //
  2617. BOOL CRpcSecurityCallbackManager::TurnOffCallback(handle_t hRpc)
  2618. {
  2619. RPC_STATUS status;
  2620. status = RpcBindingSetOption(hRpc,
  2621. RPC_C_OPT_SECURITY_CALLBACK,
  2622. (ULONG_PTR) NULL );
  2623. ASSERT(status == RPC_S_OK && "RpcBindingSetOption failed when turning off security callback");
  2624. return TRUE;
  2625. };
  2626. //+---------------------------------------------------------------------------
  2627. //
  2628. // Function: CRpcSecurityCallbackManager::StoreCallbackResult
  2629. //
  2630. // Synopsis: This is a helper function for the callback function; no one
  2631. // else should use it obviously.
  2632. //
  2633. // Parameters: usAuthSvc -- the negotiated authentication service for the rpc
  2634. // call that the calling thread presumably just completed.
  2635. //
  2636. void CRpcSecurityCallbackManager::StoreCallbackResult(USHORT usAuthSvc)
  2637. {
  2638. CRpcSecurityCallback* pCallback;
  2639. DWORD dwCurrentThread = GetCurrentThreadId();
  2640. // Only need a shared lock for this
  2641. _plistlock->LockShared();
  2642. for (pCallback = (CRpcSecurityCallback*)_CallbackList.First();
  2643. pCallback;
  2644. pCallback = (CRpcSecurityCallback*)pCallback->Next() )
  2645. {
  2646. if (dwCurrentThread == pCallback->GetRegisteredThreadId())
  2647. {
  2648. // found it
  2649. break;
  2650. }
  2651. };
  2652. ASSERT(pCallback); // we should always find it
  2653. pCallback->SetAuthSvc(usAuthSvc);
  2654. _plistlock->UnlockShared();
  2655. return;
  2656. };
  2657. void CRpcSecurityCallbackManager::StoreMarshaledTargetInfo(unsigned long ulMarshaledTargetInfoLength, unsigned char *pMarshaledTargetInfo)
  2658. {
  2659. CRpcSecurityCallback* pCallback;
  2660. DWORD dwCurrentThread = GetCurrentThreadId();
  2661. // Only need a shared lock for this
  2662. _plistlock->LockShared();
  2663. for (pCallback = (CRpcSecurityCallback*)_CallbackList.First();
  2664. pCallback;
  2665. pCallback = (CRpcSecurityCallback*)pCallback->Next() )
  2666. {
  2667. if (dwCurrentThread == pCallback->GetRegisteredThreadId())
  2668. {
  2669. // found it
  2670. break;
  2671. }
  2672. };
  2673. ASSERT(pCallback); // we should always find it
  2674. pCallback->SetMarshaledTargetInfo(ulMarshaledTargetInfoLength, pMarshaledTargetInfo);
  2675. _plistlock->UnlockShared();
  2676. return;
  2677. };
  2678. //+---------------------------------------------------------------------------
  2679. //
  2680. // Function: CRpcSecurityCallbackManager::RpcSecurityCallbackFunction
  2681. //
  2682. // Synopsis: This is a callback function; we use this by setting it on a
  2683. // binding handle (using the RPC_C_OPT_SECURITY_CALLBACK option)
  2684. // so that RPC will call us back; this gives us a chance to
  2685. // determine what authentication svc was negotiated when using
  2686. // snego. Also used to obtain the credman creds used in the call
  2687. //
  2688. // Parameters: pvContext -- an opaque parameter
  2689. //
  2690. // Algorithm: call I_RpcBindingInqWireIdForSnego, I_RpcBindingInqMarshalledTargetInfo
  2691. // passing it the opaque pvContext parameter.
  2692. //
  2693. // Notes: it would be nice if we could get some info in this callback
  2694. // as to *which* handle the callback is for, but unfortunately
  2695. // kamenm was explicit on this point: pvContext is to remain
  2696. // opaque. :)
  2697. //
  2698. //----------------------------------------------------------------------------
  2699. void RPC_ENTRY CRpcSecurityCallbackManager::RpcSecurityCallbackFunction(void* pvContext)
  2700. {
  2701. RPC_STATUS status;
  2702. UCHAR ucWireId;
  2703. unsigned char *pMarshaledTargetInfo = NULL;
  2704. unsigned long ulMarshaledTargetInfoLength = 0;
  2705. // Call back to get the authsvc:
  2706. status = I_RpcBindingInqWireIdForSnego((RPC_BINDING_HANDLE)pvContext, &ucWireId);
  2707. ASSERT(status != RPC_S_SEC_PKG_ERROR); // RPC should not have called us back
  2708. // in the first place, so assert on this
  2709. ASSERT(status != RPC_S_INVALID_BINDING); // RPC folks say this can be returned for the
  2710. // following reasons: 1) unauthenticated call;
  2711. // 2) invalid context; 3) snego was not used in
  2712. // the first place. None of these should apply
  2713. // to us, so assert
  2714. if (status == RPC_S_OK)
  2715. {
  2716. ASSERT( (ucWireId != RPC_C_AUTHN_GSS_NEGOTIATE) && "We're supposed to get back the real deal not snego");
  2717. gpCRpcSecurityCallbackMgr->StoreCallbackResult(ucWireId);
  2718. }
  2719. else
  2720. {
  2721. // something went wrong (most likely in the lower level security code).
  2722. gpCRpcSecurityCallbackMgr->StoreCallbackResult(ERROR_AUTHNSVC_VALUE);
  2723. }
  2724. status = I_RpcBindingInqMarshalledTargetInfo((RPC_BINDING_HANDLE)pvContext, &ulMarshaledTargetInfoLength, &pMarshaledTargetInfo);
  2725. ASSERT(status != RPC_S_SEC_PKG_ERROR);
  2726. ASSERT(status != RPC_S_INVALID_BINDING);
  2727. if (status == RPC_S_OK)
  2728. {
  2729. gpCRpcSecurityCallbackMgr->StoreMarshaledTargetInfo(ulMarshaledTargetInfoLength, pMarshaledTargetInfo);
  2730. }
  2731. return;
  2732. };
  2733. DWORD CPingSetQuotaManager::_dwPerUserPingSetQuota = 1000;
  2734. //+---------------------------------------------------------------------------
  2735. //
  2736. // Function: CPingSetQuotaManager::ManageQuotaForUser
  2737. //
  2738. // Synopsis: This function manages the pingset quota for the user indicated by
  2739. // pSID. fAlloc = TRUE means alloc pingset quota, else deduct quota
  2740. //
  2741. BOOL CPingSetQuotaManager::ManageQuotaForUser(PSID pSid, BOOL fAlloc)
  2742. {
  2743. CUserPingSetCount *pNode = NULL;
  2744. RPC_STATUS status = OR_NOMEM;
  2745. // first see if have the user in the list
  2746. _plistlock->LockExclusive();
  2747. for (pNode = (CUserPingSetCount*)_UserPingSetCountList.First();
  2748. pNode;
  2749. pNode = (CUserPingSetCount*)pNode->Next() )
  2750. {
  2751. if (pNode->IsEqual(pSid))
  2752. {
  2753. // found it
  2754. break;
  2755. }
  2756. };
  2757. if (pNode)
  2758. {
  2759. // Have one, munge count
  2760. if (fAlloc)
  2761. {
  2762. pNode->Increment();
  2763. }
  2764. else
  2765. {
  2766. pNode->Decrement();
  2767. // last ping set for this user, delete node
  2768. if (pNode->GetCount() == 0)
  2769. {
  2770. _UserPingSetCountList.Remove(pNode);
  2771. delete pNode;
  2772. }
  2773. }
  2774. status = OR_OK;
  2775. }
  2776. else
  2777. {
  2778. // Don't have one, add.
  2779. ASSERT( fAlloc == TRUE );
  2780. pNode = new CUserPingSetCount(status, pSid);
  2781. if (pNode && (status == OR_OK) )
  2782. {
  2783. // start with 1
  2784. pNode->Increment();
  2785. _UserPingSetCountList.Insert(pNode);
  2786. }
  2787. }
  2788. _plistlock->UnlockExclusive();
  2789. return (OR_OK == status);
  2790. }
  2791. //+---------------------------------------------------------------------------
  2792. //
  2793. // Function: CPingSetQuotaManager::IsUserQuotaExceeded
  2794. //
  2795. // Synopsis: This function determines if the quota is above limit for a given user
  2796. // pSID. returns TRUE if the limit is reached, FALSE otherwise
  2797. //
  2798. BOOL CPingSetQuotaManager::IsUserQuotaExceeded(PSID pSid)
  2799. {
  2800. CUserPingSetCount *pNode = NULL;
  2801. // first see if have the user in the list
  2802. _plistlock->LockShared();
  2803. for (pNode = (CUserPingSetCount*)_UserPingSetCountList.First();
  2804. pNode;
  2805. pNode = (CUserPingSetCount*)pNode->Next() )
  2806. {
  2807. if (pNode->IsEqual(pSid))
  2808. {
  2809. // found it
  2810. break;
  2811. }
  2812. };
  2813. if (pNode)
  2814. {
  2815. DWORD dw = pNode->GetCount();
  2816. if (dw >= _dwPerUserPingSetQuota )
  2817. {
  2818. _plistlock->UnlockShared();
  2819. return TRUE;
  2820. }
  2821. }
  2822. _plistlock->UnlockShared();
  2823. return FALSE;
  2824. }
  2825. void CPingSetQuotaManager::SetPerUserPingSetQuota(DWORD dwQuota)
  2826. {
  2827. _dwPerUserPingSetQuota = dwQuota;
  2828. }