Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2136 lines
69 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1995.
  5. //
  6. // File:
  7. // remact.cxx
  8. //
  9. // Contents:
  10. //
  11. // Implementation of binding handle cache to remote activation services.
  12. //
  13. // History:
  14. //
  15. //--------------------------------------------------------------------------
  16. #include "act.hxx"
  17. #include "misc.hxx"
  18. CRemoteMachineList * gpRemoteMachineList = NULL;
  19. CSharedLock * gpRemoteMachineLock = NULL;
  20. // These globals are set to their defaults here, but can be overridden at boot
  21. // time via registry knobs. See ReadRemoteBindingHandleCacheKeys in registry.cxx.
  22. // Also note that gdwRemoteBindingHandleCacheMaxSize cannot be adjusted after boot,
  23. // but gdwRemoteBindingHandleCacheMaxLifetime and gdwRemoteBindingHandleCacheIdleTimeout can
  24. // be played with in the debugger at will for those so inclined.
  25. DWORD gdwRemoteBindingHandleCacheMaxSize = 16; // in # of cache elements
  26. DWORD gdwRemoteBindingHandleCacheMaxLifetime = 0; // in minutes
  27. DWORD gdwRemoteBindingHandleCacheIdleTimeout = 15; // in minutes
  28. class CRemActPPing : public CParallelPing
  29. {
  30. public:
  31. CRemActPPing(WCHAR *pMachine) :
  32. _ndx(0),
  33. _pMachine(pMachine)
  34. {}
  35. BOOL NextCall(PROTSEQINFO *pProtseqInfo)
  36. {
  37. RPC_STATUS status;
  38. if (_ndx < cMyProtseqs)
  39. {
  40. status = CreateRemoteBinding(_pMachine,
  41. _ndx,
  42. &pProtseqInfo->hRpc);
  43. if (status != RPC_S_OK)
  44. {
  45. pProtseqInfo->hRpc = NULL;
  46. }
  47. pProtseqInfo->dwUserInfo = _ndx;
  48. _ndx++;
  49. return TRUE;
  50. }
  51. else
  52. {
  53. return FALSE;
  54. }
  55. }
  56. void ReleaseCall(PROTSEQINFO *pProtseqInfo)
  57. {
  58. if (pProtseqInfo->hRpc)
  59. {
  60. RpcBindingFree(&pProtseqInfo->hRpc);
  61. }
  62. }
  63. private:
  64. DWORD _ndx;
  65. WCHAR *_pMachine;
  66. };
  67. //+---------------------------------------------------------------------------
  68. //
  69. // Function: RemoteActivationCall
  70. //
  71. // Synopsis: Finds or creates a machine object to cache binding handles
  72. // to the server machine and forwards the activation request
  73. // to it.
  74. //
  75. //----------------------------------------------------------------------------
  76. HRESULT
  77. RemoteActivationCall(
  78. ACTIVATION_PARAMS * pActParams,
  79. WCHAR * pwszServerName )
  80. {
  81. CRemoteMachine * pRemoteMachine;
  82. WCHAR wszPathForServer[MAX_PATH+1];
  83. WCHAR * pwszPathForServer;
  84. HRESULT hr;
  85. pActParams->activatedRemote = TRUE;
  86. Win4Assert( pwszServerName );
  87. pwszPathForServer = 0;
  88. if ( pActParams->pwszPath )
  89. {
  90. hr = GetPathForServer( pActParams->pwszPath, wszPathForServer, &pwszPathForServer );
  91. if ( hr != S_OK )
  92. return hr;
  93. }
  94. pRemoteMachine = gpRemoteMachineList->GetOrAdd( pwszServerName );
  95. if ( ! pRemoteMachine )
  96. return E_OUTOFMEMORY;
  97. Win4Assert(pActParams->pActPropsIn);
  98. BOOL fUseSystemId;
  99. pActParams->pActPropsIn->GetRemoteActivationFlags(&pActParams->fComplusOnly,
  100. &fUseSystemId);
  101. if (!fUseSystemId)
  102. {
  103. if (pActParams->pToken != NULL)
  104. pActParams->pToken->Impersonate();
  105. else
  106. {
  107. pRemoteMachine->Release();
  108. return HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED );
  109. }
  110. }
  111. IServerLocationInfo *pServerLocationInfo = NULL;
  112. ISpecialSystemProperties* pSSP = NULL;
  113. ULONG ulCurrentSessionId = 0;
  114. BOOL bUseConsole = FALSE;
  115. BOOL fRemoteThisSessionId = FALSE;
  116. pServerLocationInfo = pActParams->pActPropsIn->GetServerLocationInfo();
  117. Win4Assert(pServerLocationInfo != NULL);
  118. pServerLocationInfo->SetRemoteServerName(NULL);
  119. //
  120. // Session id's should flow off-machine only when explicitly told to; make sure
  121. // this is the case:
  122. //
  123. hr = pActParams->pActPropsIn->QueryInterface(IID_ISpecialSystemProperties, (void**)&pSSP);
  124. if (SUCCEEDED(hr))
  125. {
  126. pSSP->GetSessionId2(&ulCurrentSessionId, &bUseConsole, &fRemoteThisSessionId);
  127. if (!fRemoteThisSessionId)
  128. {
  129. hr = pSSP->SetSessionId(INVALID_SESSION_ID, FALSE, FALSE);
  130. ASSERT(SUCCEEDED(hr) && "SetSessionId failed");
  131. }
  132. }
  133. //
  134. // Try the activation:
  135. //
  136. hr = pRemoteMachine->Activate( pActParams, pwszPathForServer );
  137. //
  138. // Restore session id just in case the activation ends up being re-tried (for
  139. // whatever reason) on this machine (eg, if a load-balancing activator is loaded)
  140. //
  141. if (!fRemoteThisSessionId)
  142. {
  143. HRESULT hrLocal;
  144. hrLocal = pSSP->SetSessionId(ulCurrentSessionId, bUseConsole, FALSE);
  145. ASSERT(SUCCEEDED(hrLocal) && "SetSessionId failed");
  146. }
  147. if (pSSP)
  148. pSSP->Release();
  149. pRemoteMachine->Release();
  150. if (!fUseSystemId)
  151. pActParams->pToken->Revert();
  152. return hr;
  153. }
  154. //+---------------------------------------------------------------------------
  155. //
  156. // Function: CRemoteMachineList::GetOrAdd
  157. //
  158. // Synopsis: Scans the machine list for a matching name. Returns it if
  159. // found. Otherwise, creates a machine list entry. Returned
  160. // object is refcounted.
  161. //
  162. // Changes: jsimmons 4/6/00 Fix for bug 22803 -- cap cache size
  163. //
  164. //----------------------------------------------------------------------------
  165. CRemoteMachine *
  166. CRemoteMachineList::GetOrAdd(
  167. IN WCHAR * pwszMachine
  168. )
  169. {
  170. CRemoteMachine * pMachine;
  171. WCHAR * pwszMachineCopy;
  172. WCHAR * pwszScmSPNCopy;
  173. gpRemoteMachineLock->LockExclusive();
  174. for ( pMachine = (CRemoteMachine *) First();
  175. pMachine;
  176. pMachine = (CRemoteMachine *) pMachine->Next() )
  177. {
  178. if ( lstrcmpiW( pMachine->_pwszMachine, pwszMachine ) == 0 )
  179. {
  180. pMachine->_dwLastUsedTickCount = GetTickCount();
  181. pMachine->AddRef(); // add caller reference
  182. break;
  183. }
  184. }
  185. if ( ! pMachine )
  186. {
  187. pwszMachineCopy = (WCHAR *) PrivMemAlloc( (lstrlenW( pwszMachine ) + 1) * sizeof(WCHAR) );
  188. if (pwszMachineCopy)
  189. {
  190. pwszScmSPNCopy = (WCHAR *) PrivMemAlloc( (lstrlenW( pwszMachine ) +
  191. (sizeof(RPCSS_SPN_PREFIX) / sizeof(WCHAR))
  192. + 1) * sizeof(WCHAR) );
  193. if (pwszScmSPNCopy)
  194. {
  195. lstrcpyW( pwszMachineCopy, pwszMachine );
  196. // Form server principal name for the remote scm
  197. lstrcpyW( pwszScmSPNCopy, RPCSS_SPN_PREFIX);
  198. lstrcatW( pwszScmSPNCopy, pwszMachine);
  199. pMachine = new CRemoteMachine( pwszMachineCopy, pwszScmSPNCopy);
  200. // constructed with refcount of 1, don't addref it again
  201. if ( pMachine )
  202. {
  203. // Only attempt to save new object in cache if cache size > 0:
  204. if (_dwMaxCacheSize > 0)
  205. {
  206. ASSERT(_dwCacheSize <= _dwMaxCacheSize);
  207. if (_dwCacheSize == _dwMaxCacheSize)
  208. {
  209. // Cache has no more room. Dump the oldest one
  210. RemoveOldestCacheElement();
  211. ASSERT(_dwCacheSize < _dwMaxCacheSize);
  212. }
  213. Insert( pMachine );
  214. pMachine->AddRef();
  215. _dwCacheSize++;
  216. ASSERT(_dwCacheSize <= _dwMaxCacheSize);
  217. }
  218. }
  219. else
  220. {
  221. PrivMemFree( pwszMachineCopy );
  222. PrivMemFree( pwszScmSPNCopy );
  223. }
  224. }
  225. else
  226. {
  227. PrivMemFree(pwszMachineCopy);
  228. }
  229. }
  230. }
  231. gpRemoteMachineLock->UnlockExclusive();
  232. return pMachine;
  233. }
  234. //+---------------------------------------------------------------------------
  235. //
  236. // Function: CRemoteMachineList::CRemoteMachine
  237. //
  238. // Synopsis: Looks thru the cache for the lru element and removes it.
  239. //
  240. //----------------------------------------------------------------------------
  241. void CRemoteMachineList::RemoveOldestCacheElement()
  242. {
  243. ASSERT(_dwCacheSize > 0);
  244. ASSERT(gpRemoteMachineLock->HeldExclusive());
  245. CRemoteMachine* pLRUMachine = (CRemoteMachine*)First();
  246. CRemoteMachine* pMachine = (CRemoteMachine*)pLRUMachine->Next();
  247. while (pMachine)
  248. {
  249. if (pMachine->_dwLastUsedTickCount < pLRUMachine->_dwLastUsedTickCount)
  250. {
  251. pLRUMachine = pMachine;
  252. }
  253. pMachine = (CRemoteMachine*)pMachine->Next();
  254. }
  255. Remove(pLRUMachine);
  256. pLRUMachine->Release();
  257. _dwCacheSize--;
  258. return;
  259. }
  260. //+---------------------------------------------------------------------------
  261. //
  262. // Function: CRemoteMachineList::FlushSpecificBindings
  263. //
  264. // Synopsis: Looks thru the cache for the specified element and removes it
  265. // from the cache if found.
  266. //
  267. // Arguments: [pszMachine] -- name of the machine to flush from the cache. Can
  268. // be ""; this means all bindings should be flushed
  269. //
  270. // Returns: S_OK -- the specified bindings were found and flushed
  271. // CO_S_MACHINENAMENOTFOUND -- if "" was passed, means the cache was
  272. // empty; otherwise means that the specified machine name was not
  273. // found in the cache.
  274. //
  275. //----------------------------------------------------------------------------
  276. HRESULT CRemoteMachineList::FlushSpecificBindings(WCHAR* pszMachine)
  277. {
  278. HRESULT hr = CO_S_MACHINENAMENOTFOUND;
  279. BOOL bFlushAll = (0 == lstrcmpW(pszMachine, L""));
  280. CRemoteMachine* pMachine;
  281. CRemoteMachine* pNextMachine;
  282. gpRemoteMachineLock->LockExclusive();
  283. if (bFlushAll)
  284. {
  285. // Loop thru and release all of them
  286. while (pMachine = (CRemoteMachine*)First())
  287. {
  288. Remove(pMachine);
  289. pMachine->Release();
  290. _dwCacheSize--;
  291. hr = S_OK; // there was at least one item in the cache, so return S_OK
  292. }
  293. }
  294. else
  295. {
  296. // Loop thru looking for the specified machine name
  297. pMachine = (CRemoteMachine*)First();
  298. while (pMachine)
  299. {
  300. if (lstrcmpiW(pszMachine, pMachine->_pwszMachine) == 0)
  301. {
  302. // Found it
  303. Remove(pMachine);
  304. pMachine->Release();
  305. _dwCacheSize--;
  306. hr = S_OK; // found it so return S_OK
  307. break;
  308. }
  309. pMachine = (CRemoteMachine*)pMachine->Next();
  310. }
  311. }
  312. gpRemoteMachineLock->UnlockExclusive();
  313. return hr;
  314. }
  315. //+---------------------------------------------------------------------------
  316. //
  317. // Function: CRemoteMachineList::TryToFlushIdleOrTooOldElements
  318. //
  319. // Synopsis: Looks thru the cache for elements which have either 1) not been
  320. // used for a period than the idle timeout period; or 2) been in the cache
  321. // longer than the maximum allowable period. If any are found they are
  322. // deleted from the cache.
  323. //
  324. // Arguments: none
  325. //
  326. // Returns: void
  327. //
  328. //----------------------------------------------------------------------------
  329. void CRemoteMachineList::TryToFlushIdleOrTooOldElements()
  330. {
  331. CRemoteMachine* pMachine;
  332. CRemoteMachine* pNextMachine;
  333. DWORD dwNow = GetTickCount();
  334. DWORD dwIdleTimeout = gdwRemoteBindingHandleCacheIdleTimeout * 1000 * 60;
  335. DWORD dwLifetimeTimeout = gdwRemoteBindingHandleCacheMaxLifetime * 1000 * 60;
  336. if (!dwIdleTimeout && !dwLifetimeTimeout)
  337. return; // nothing to do
  338. gpRemoteMachineLock->LockExclusive();
  339. pMachine = (CRemoteMachine*)First();
  340. while (pMachine)
  341. {
  342. BOOL bRemoveCurrentItem;
  343. bRemoveCurrentItem = FALSE;
  344. // Check if it's been idle too long
  345. if (dwIdleTimeout > 0)
  346. {
  347. if (dwNow - pMachine->_dwLastUsedTickCount > dwIdleTimeout)
  348. {
  349. bRemoveCurrentItem = TRUE;
  350. }
  351. }
  352. // Check if it's been around too long, period
  353. if (dwLifetimeTimeout > 0)
  354. {
  355. if (dwNow - pMachine->_dwTickCountAtCreate > dwLifetimeTimeout)
  356. {
  357. bRemoveCurrentItem = TRUE;
  358. }
  359. }
  360. pNextMachine = (CRemoteMachine*)pMachine->Next();
  361. if (bRemoveCurrentItem)
  362. {
  363. Remove(pMachine);
  364. pMachine->Release();
  365. _dwCacheSize--;
  366. }
  367. pMachine = pNextMachine;
  368. }
  369. gpRemoteMachineLock->UnlockExclusive();
  370. }
  371. //+---------------------------------------------------------------------------
  372. //
  373. // Function: OLESCMBindingHandleFlush
  374. //
  375. // Synopsis: This function gets called periodically by objex's worker
  376. // thread. It gives us a chance to flush idle or too-old cache elements
  377. // in the remote binding handle cache.
  378. //
  379. //----------------------------------------------------------------------------
  380. void OLESCMBindingHandleFlush()
  381. {
  382. gpRemoteMachineList->TryToFlushIdleOrTooOldElements();
  383. }
  384. //+---------------------------------------------------------------------------
  385. //
  386. // Function: CRemoteMachine::CRemoteMachine
  387. //
  388. // Synopsis: Constructor
  389. //
  390. //----------------------------------------------------------------------------
  391. CRemoteMachine::CRemoteMachine(
  392. IN WCHAR * pwszMachine,
  393. IN WCHAR * pwszScmSPN
  394. )
  395. {
  396. _pwszMachine = pwszMachine;
  397. _pwszScmSPN = pwszScmSPN;
  398. _dsa = NULL;
  399. _ulRefCount = 1; // starts with non-zero refcount
  400. _dwLastUsedTickCount = GetTickCount();
  401. _dwTickCountAtCreate = _dwLastUsedTickCount;
  402. }
  403. //+---------------------------------------------------------------------------
  404. //
  405. // Function: CRemoteMachine::CRemoteMachine
  406. //
  407. // Synopsis: Destructor
  408. //
  409. //----------------------------------------------------------------------------
  410. CRemoteMachine::~CRemoteMachine()
  411. {
  412. ASSERT(_ulRefCount == 0);
  413. // We don't need to hold a lock to flush the bindings,
  414. // since no one else has a reference to us.
  415. FlushBindingsNoLock();
  416. if (_pwszMachine)
  417. PrivMemFree(_pwszMachine);
  418. if (_pwszScmSPN)
  419. PrivMemFree(_pwszScmSPN);
  420. if (_dsa)
  421. _dsa->Release();
  422. }
  423. // AddRef function
  424. ULONG CRemoteMachine::AddRef()
  425. {
  426. return InterlockedIncrement((PLONG)&_ulRefCount);
  427. }
  428. // Release function
  429. ULONG CRemoteMachine::Release()
  430. {
  431. ULONG ulNewRefCount = InterlockedDecrement((PLONG)&_ulRefCount);
  432. if (ulNewRefCount == 0)
  433. {
  434. delete this;
  435. }
  436. return ulNewRefCount;
  437. }
  438. //+---------------------------------------------------------------------------
  439. //
  440. // Function: CRemoteMachine::Activate
  441. //
  442. // Synopsis: Picks a protocol and authentication service to use to call
  443. // the server machine. Forwards the activation request to
  444. // CallRemoteMachine.
  445. //
  446. // Description:
  447. //
  448. // This method tries several different methods to get a binding handle.
  449. // Look for auth info match in cache
  450. // Look for any binding handle in cache
  451. // Ping server to find valid protocol sequence
  452. //
  453. // After it gets a binding handle, it tries to pick auth info.
  454. // Use client params if specified
  455. // Use cached params if they exist
  456. // Try all auth svc valid on client and server
  457. // Try unsecure
  458. //
  459. // This function maintains a cache of binding handles with the following
  460. // rules.
  461. // - All binding handles in the cache at any point in time use the same
  462. // protocol sequence.
  463. // - The best non-custom authentication info is before any other
  464. // non-custom authentication info.
  465. // - The cache is flushed if the protocol is competely invalid.
  466. // - If a cached entry gets a non security error, it is discarded
  467. // (security errors may be due to the current credentials rather then
  468. // the binding handle itself).
  469. // - Only binding handles that actually worked once are cached.
  470. //
  471. //----------------------------------------------------------------------------
  472. HRESULT
  473. CRemoteMachine::Activate(
  474. IN ACTIVATION_PARAMS * pActParams,
  475. IN WCHAR * pwszPathForServer
  476. )
  477. {
  478. CMachineBinding * pMachineBinding;
  479. handle_t hBinding = NULL;
  480. BOOL bNoEndpoint;
  481. BOOL bStatus;
  482. HRESULT hr;
  483. USHORT AuthnSvc;
  484. USHORT ProtseqId;
  485. RPC_STATUS Status = RPC_S_INTERNAL_ERROR;
  486. // Try to use a cached handle first.
  487. if (pActParams->pAuthInfo != NULL)
  488. AuthnSvc = (USHORT) pActParams->pAuthInfo->dwAuthnSvc;
  489. else
  490. AuthnSvc = AUTHN_ANY;
  491. pMachineBinding = LookupBinding( AuthnSvc, pActParams->pAuthInfo );
  492. if ( pMachineBinding )
  493. {
  494. AuthnSvc = pMachineBinding->_AuthnSvc;
  495. Status = CallRemoteMachine(
  496. pMachineBinding->_hBinding,
  497. pMachineBinding->_ProtseqId,
  498. pActParams,
  499. pwszPathForServer,
  500. _pwszMachine,
  501. &hr );
  502. if (Status == RPC_S_OK)
  503. {
  504. pActParams->AuthnSvc = AuthnSvc;
  505. pMachineBinding->Release();
  506. return hr;
  507. }
  508. // Throw away the binding if it is unlikely to work again in the
  509. // future.
  510. else if (Status != RPC_S_ACCESS_DENIED &&
  511. Status != RPC_S_SEC_PKG_ERROR)
  512. {
  513. RemoveBinding( pMachineBinding );
  514. }
  515. pMachineBinding->Release();
  516. }
  517. // Throw away all bindings if the protocol is unlikely to work
  518. // again.
  519. if (Status == RPC_S_SERVER_UNAVAILABLE ||
  520. Status == EPT_S_NOT_REGISTERED)
  521. {
  522. FlushBindings();
  523. }
  524. // Get any binding handle from the cache.
  525. else
  526. {
  527. gpRemoteMachineLock->LockShared();
  528. pMachineBinding = (CMachineBinding *) _BindingList.First();
  529. if (pMachineBinding != NULL)
  530. {
  531. Status = RpcBindingCopy( pMachineBinding->_hBinding, &hBinding );
  532. if (Status == RPC_S_OK)
  533. {
  534. ASSERT(hBinding != NULL);
  535. ProtseqId = pMachineBinding->_ProtseqId;
  536. }
  537. else
  538. hBinding = NULL;
  539. }
  540. gpRemoteMachineLock->UnlockShared();
  541. // Try to find auth info that will work.
  542. if (hBinding != NULL)
  543. {
  544. Status = PickAuthnAndActivate( pActParams, pwszPathForServer,
  545. &hBinding, AuthnSvc, ProtseqId,
  546. &hr );
  547. if (Status == RPC_S_OK)
  548. {
  549. Assert( hBinding == NULL );
  550. return hr;
  551. }
  552. else
  553. {
  554. // Stop if the activation failed but the protocol was
  555. // probably good.
  556. Assert( hBinding != NULL );
  557. RpcBindingFree( &hBinding );
  558. hBinding = NULL;
  559. if (Status != RPC_S_SERVER_UNAVAILABLE &&
  560. Status != EPT_S_NOT_REGISTERED)
  561. {
  562. if (Status == RPC_S_ACCESS_DENIED)
  563. {
  564. // Don't map security errors as this is just confusing.
  565. return HRESULT_FROM_WIN32(RPC_S_ACCESS_DENIED);
  566. }
  567. else
  568. {
  569. LogRemoteSideUnavailable( pActParams->ClsContext, _pwszMachine );
  570. return HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE);
  571. }
  572. }
  573. }
  574. }
  575. }
  576. // No cached binding handles worked. Try to ping for one.
  577. {
  578. CRemActPPing ping(_pwszMachine);
  579. // This loop only executes twice if we need to try the call without
  580. // an endpoint specified.
  581. //
  582. bNoEndpoint = FALSE;
  583. for (;;)
  584. {
  585. Status = ping.Ping();
  586. if ( RPC_S_UNKNOWN_IF == Status )
  587. {
  588. if ( ! bNoEndpoint )
  589. {
  590. for ( ULONG ProtseqIndex = 0; ProtseqIndex < ping.HandleCount(); ProtseqIndex++ )
  591. {
  592. RPC_BINDING_HANDLE tmpBinding;
  593. Status = RpcBindingCopy( ping.Info(ProtseqIndex)->hRpc, &tmpBinding);
  594. if (Status != RPC_S_OK)
  595. break;
  596. RpcBindingFree( &(ping.Info(ProtseqIndex)->hRpc));
  597. if (Status != RPC_S_OK)
  598. {
  599. RpcBindingFree(&tmpBinding);
  600. break;
  601. }
  602. RpcBindingReset(tmpBinding);
  603. if (Status != RPC_S_OK)
  604. {
  605. RpcBindingFree(&tmpBinding);
  606. break;
  607. }
  608. ping.Info(ProtseqIndex)->hRpc = tmpBinding;
  609. }
  610. if (Status == RPC_S_OK)
  611. {
  612. bNoEndpoint = TRUE;
  613. continue;
  614. }
  615. }
  616. }
  617. break;
  618. }
  619. if (Status == RPC_S_OK)
  620. {
  621. gpRemoteMachineLock->LockExclusive();
  622. if (_dsa != NULL)
  623. _dsa->Release();
  624. hBinding = ping.GetWinner()->hRpc;
  625. ping.GetWinner()->hRpc = NULL;
  626. _dsa = ping.TakeOrBindings();
  627. ProtseqId = aMyProtseqs[ping.GetWinner()->dwUserInfo];
  628. ASSERT( hBinding != NULL );
  629. gpRemoteMachineLock->UnlockExclusive();
  630. }
  631. ping.Reset();
  632. }
  633. // Try auth info with the new binding.
  634. if (hBinding != NULL)
  635. {
  636. Status = PickAuthnAndActivate( pActParams, pwszPathForServer,
  637. &hBinding, RPC_C_AUTHN_NONE, ProtseqId,
  638. &hr );
  639. if (Status == RPC_S_OK)
  640. {
  641. // asserts that in success cases binding was added to the cache
  642. Assert( hBinding == NULL );
  643. }
  644. }
  645. // If the call never worked, return a nice error code.
  646. // except for security errors.
  647. if (Status != RPC_S_OK)
  648. {
  649. if (Status == RPC_S_ACCESS_DENIED)
  650. hr = HRESULT_FROM_WIN32(RPC_S_ACCESS_DENIED);
  651. else
  652. {
  653. hr = HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE);
  654. LogRemoteSideUnavailable( pActParams->ClsContext, _pwszMachine );
  655. }
  656. }
  657. // Clean up resources.
  658. if (hBinding != NULL)
  659. RpcBindingFree( &hBinding );
  660. return hr;
  661. }
  662. //+---------------------------------------------------------------------------
  663. //
  664. // Function: CRemoteMachine::PickAuthnAndActivate
  665. //
  666. // Synopsis: Determine what authentication information to use for the
  667. // activation. The AuthnSvc parameter indicates an
  668. // authentication service that was already tried.
  669. //
  670. //----------------------------------------------------------------------------
  671. RPC_STATUS CRemoteMachine::PickAuthnAndActivate(
  672. IN ACTIVATION_PARAMS * pActParams,
  673. IN WCHAR * pwszPathForServer,
  674. IN handle_t * pBinding,
  675. IN USHORT AuthnSvc,
  676. IN USHORT ProtseqId,
  677. OUT HRESULT * phr )
  678. {
  679. RPC_SECURITY_QOS Qos;
  680. DWORD i;
  681. void *pAuthId = NULL;
  682. RPC_STATUS Status;
  683. CMachineBinding *pMachineBinding;
  684. BOOL fTry;
  685. CDualStringArray *pdsa = NULL;
  686. COAUTHIDENTITY *pAuthIdentityFinalCopy = NULL;
  687. HRESULT hr = S_OK;
  688. // If the client specified security, try exactly the settings requested.
  689. Qos.Version = RPC_C_SECURITY_QOS_VERSION;
  690. pActParams->UnsecureActivation = FALSE;
  691. if (pActParams->pAuthInfo)
  692. {
  693. // Set the requested authentication information.
  694. AuthnSvc = (USHORT) pActParams->pAuthInfo->dwAuthnSvc;
  695. pActParams->AuthnSvc = (USHORT) pActParams->pAuthInfo->dwAuthnSvc;
  696. Qos.Capabilities = pActParams->pAuthInfo->dwCapabilities;
  697. Qos.ImpersonationType = pActParams->pAuthInfo->dwImpersonationLevel;
  698. if (pActParams->pAuthInfo->pAuthIdentityData != NULL)
  699. Qos.IdentityTracking = RPC_C_QOS_IDENTITY_STATIC;
  700. else
  701. Qos.IdentityTracking = RPC_C_QOS_IDENTITY_DYNAMIC;
  702. // If using RPC_C_QOS_IDENTITY_DYNAMIC, we need to make a saveable copy of the
  703. // client's authidentity struct.
  704. if (Qos.IdentityTracking == RPC_C_QOS_IDENTITY_DYNAMIC &&
  705. pActParams->pAuthInfo->pAuthIdentityData)
  706. {
  707. hr = CopyAuthIdentity(pActParams->pAuthInfo->pAuthIdentityData, &pAuthIdentityFinalCopy);
  708. }
  709. if (SUCCEEDED(hr))
  710. {
  711. Status = RpcBindingSetAuthInfoExW(
  712. *pBinding,
  713. pActParams->pAuthInfo->pwszServerPrincName,
  714. pActParams->pAuthInfo->dwAuthnLevel,
  715. pActParams->pAuthInfo->dwAuthnSvc,
  716. (Qos.IdentityTracking == RPC_C_QOS_IDENTITY_DYNAMIC) ?
  717. pAuthIdentityFinalCopy :
  718. pActParams->pAuthInfo->pAuthIdentityData,
  719. pActParams->pAuthInfo->dwAuthzSvc,
  720. &Qos );
  721. // Try the activation.
  722. if (Status == RPC_S_OK)
  723. {
  724. Status = CallRemoteMachine(
  725. *pBinding,
  726. ProtseqId,
  727. pActParams,
  728. pwszPathForServer,
  729. _pwszMachine,
  730. phr );
  731. if (Status != RPC_S_OK)
  732. {
  733. // we won't be caching this handle, so free the COAUTHIDENTITY copy
  734. FreeAuthIdentity(pAuthIdentityFinalCopy);
  735. pAuthIdentityFinalCopy = NULL;
  736. }
  737. }
  738. }
  739. else
  740. {
  741. // couldn't get enough memory to copy the user's COAUTHIDENTITY
  742. *phr = E_OUTOFMEMORY;
  743. Status = RPC_S_OUT_OF_RESOURCES;
  744. }
  745. }
  746. // Try all authentication services and then try unsecure.
  747. else
  748. {
  749. // Get a reference to the dual string array.
  750. gpRemoteMachineLock->LockShared();
  751. pdsa = _dsa;
  752. if (pdsa) pdsa->AddRef();
  753. gpRemoteMachineLock->UnlockShared();
  754. // Initialize the QOS structure.
  755. Qos.Capabilities = RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH;
  756. Qos.ImpersonationType = RPC_C_IMP_LEVEL_IMPERSONATE;
  757. Qos.IdentityTracking = RPC_C_QOS_IDENTITY_DYNAMIC;
  758. // Loop over the authentication services.
  759. Status = RPC_S_INTERNAL_ERROR;
  760. for (i = 0; i < s_cRpcssSvc; i++)
  761. {
  762. // Skip the authentication service that was already tried.
  763. if (s_aRpcssSvc[i].wId == AuthnSvc)
  764. continue;
  765. // If there are no security bindings, only try NTLM.
  766. if (pdsa == NULL)
  767. {
  768. fTry = s_aRpcssSvc[i].wId == RPC_C_AUTHN_WINNT;
  769. }
  770. else
  771. {
  772. // If there are security bindings, try the next authentication
  773. // service if both machines use it.
  774. fTry = ValidAuthnSvc( pdsa->DSA(), s_aRpcssSvc[i].wId );
  775. }
  776. if (fTry)
  777. {
  778. BOOL bSetSecurityCallBack = FALSE;
  779. USHORT usAuthSvcFromCallback;
  780. // Set the security.
  781. Status = RPC_S_OK;
  782. if (s_aRpcssSvc[i].wId == RPC_C_AUTHN_GSS_NEGOTIATE)
  783. {
  784. // Using snego, compute list of compatible authnsvcs:
  785. ASSERT(pdsa);
  786. pAuthIdentityFinalCopy = (COAUTHIDENTITY*) ComputeSvcList( pdsa->DSA() );
  787. if (pAuthIdentityFinalCopy)
  788. {
  789. // if using snego, we need to know what sec pkg is eventually negotiated:
  790. if (gpCRpcSecurityCallbackMgr->RegisterForRpcAuthSvcCallBack(*pBinding))
  791. bSetSecurityCallBack = TRUE;
  792. }
  793. else
  794. {
  795. // Using snego, but ComputeSvcList returned NULL (out of memory)
  796. *phr = E_OUTOFMEMORY;
  797. Status = RPC_S_OUT_OF_RESOURCES;
  798. }
  799. }
  800. if (Status == RPC_S_OK)
  801. {
  802. Status = RpcBindingSetAuthInfoEx(
  803. *pBinding,
  804. _pwszScmSPN,
  805. RPC_C_AUTHN_LEVEL_CONNECT,
  806. s_aRpcssSvc[i].wId,
  807. pAuthIdentityFinalCopy,
  808. 0,
  809. &Qos );
  810. }
  811. if (Status != RPC_S_OK)
  812. {
  813. if (bSetSecurityCallBack)
  814. gpCRpcSecurityCallbackMgr->GetAuthSvcAndTurnOffCallback(*pBinding, NULL);
  815. // Free our authident copy if we have one
  816. FreeAuthIdentity(pAuthIdentityFinalCopy);
  817. pAuthIdentityFinalCopy = NULL;
  818. }
  819. // Try the activation.
  820. if (Status == RPC_S_OK)
  821. {
  822. Status = CallRemoteMachine(
  823. *pBinding,
  824. ProtseqId,
  825. pActParams,
  826. pwszPathForServer,
  827. _pwszMachine,
  828. phr );
  829. if (Status != RPC_S_OK)
  830. {
  831. // call didn't work; we definitely won't be caching this handle,
  832. // so free the authidentity copy
  833. FreeAuthIdentity(pAuthIdentityFinalCopy);
  834. pAuthIdentityFinalCopy = NULL;
  835. }
  836. if (bSetSecurityCallBack)
  837. {
  838. //
  839. // Only ask for the result of the callback if the call went through; otherwise
  840. // just cancel the registration.
  841. //
  842. if (Status == RPC_S_OK)
  843. {
  844. if (!gpCRpcSecurityCallbackMgr->GetAuthSvcAndTurnOffCallback(*pBinding,
  845. &usAuthSvcFromCallback))
  846. {
  847. // something went wrong. In this case we don't trust what the callback
  848. // told us. Fall back on the original behavior
  849. bSetSecurityCallBack = FALSE;
  850. }
  851. }
  852. else
  853. {
  854. // the call did not go through
  855. if (bSetSecurityCallBack)
  856. {
  857. // cancel the callback
  858. gpCRpcSecurityCallbackMgr->GetAuthSvcAndTurnOffCallback(*pBinding, NULL);
  859. bSetSecurityCallBack = FALSE;
  860. }
  861. }
  862. }
  863. if (Status == RPC_S_OK ||
  864. Status == RPC_S_SERVER_UNAVAILABLE ||
  865. Status == EPT_S_NOT_REGISTERED)
  866. {
  867. if (bSetSecurityCallBack)
  868. {
  869. // snego call, and we succesfully got a callback telling us
  870. // what the real authentication service was
  871. if (usAuthSvcFromCallback == RPC_C_AUTHN_GSS_KERBEROS)
  872. {
  873. // if we got back kerberos we're going to cache snego anyway; this
  874. // helps NTLM-only clients who can't use kerberos
  875. pActParams->AuthnSvc = AuthnSvc = RPC_C_AUTHN_GSS_NEGOTIATE;
  876. }
  877. else
  878. pActParams->AuthnSvc = AuthnSvc = usAuthSvcFromCallback;
  879. }
  880. else
  881. {
  882. // non-snego, or something went wrong with security callback
  883. // on a snego call
  884. pActParams->AuthnSvc = AuthnSvc = s_aRpcssSvc[i].wId;
  885. }
  886. break;
  887. }
  888. }
  889. }
  890. }
  891. if (pdsa)
  892. {
  893. pdsa->Release();
  894. pdsa = NULL;
  895. }
  896. // If no authentication services worked and the protocol doesn't
  897. // look bad, try no authentication
  898. if (Status != RPC_S_OK &&
  899. Status != RPC_S_SERVER_UNAVAILABLE &&
  900. Status != EPT_S_NOT_REGISTERED)
  901. {
  902. // remember that unsecure activation was done.
  903. // This will be used later when creating the MID
  904. // so we do unsecure pinging also.
  905. pActParams->UnsecureActivation = TRUE;
  906. // Look for a cached unsecure binding handle.
  907. pMachineBinding = LookupBinding( RPC_C_AUTHN_NONE, NULL );
  908. if ( pMachineBinding )
  909. {
  910. Status = CallRemoteMachine(
  911. pMachineBinding->_hBinding,
  912. pMachineBinding->_ProtseqId,
  913. pActParams,
  914. pwszPathForServer,
  915. _pwszMachine,
  916. phr );
  917. // Throw away the binding handle received as a parameter so
  918. // it doesn't get cached.
  919. if (Status == RPC_S_OK)
  920. {
  921. RpcBindingFree( pBinding );
  922. *pBinding = NULL;
  923. }
  924. // Throw away the binding if it is unlikely to work again in the
  925. // future.
  926. else
  927. {
  928. RemoveBinding( pMachineBinding );
  929. }
  930. pMachineBinding->Release();
  931. }
  932. // Make the current binding handle unsecure.
  933. else
  934. {
  935. // Set the authentication information.
  936. Status = RpcBindingSetAuthInfoEx(
  937. *pBinding,
  938. NULL,
  939. RPC_C_AUTHN_LEVEL_NONE,
  940. RPC_C_AUTHN_NONE,
  941. NULL,
  942. 0,
  943. &Qos );
  944. if (Status == RPC_S_OK)
  945. {
  946. AuthnSvc = RPC_C_AUTHN_NONE;
  947. Status = CallRemoteMachine(
  948. *pBinding,
  949. ProtseqId,
  950. pActParams,
  951. pwszPathForServer,
  952. _pwszMachine,
  953. phr );
  954. }
  955. }
  956. }
  957. }
  958. if (Status == RPC_S_OK && *pBinding != NULL)
  959. {
  960. //
  961. // The call completed. We now cache this binding handle.
  962. // Caching is just an optimization so we don't care if this
  963. // insert fails.
  964. //
  965. InsertBinding(
  966. *pBinding,
  967. ProtseqId,
  968. AuthnSvc,
  969. pActParams->pAuthInfo,
  970. pAuthIdentityFinalCopy);
  971. *pBinding = NULL;
  972. }
  973. // Throw away all bindings if the protocol is unlikely to work
  974. // again.
  975. else if (Status == RPC_S_SERVER_UNAVAILABLE ||
  976. Status == EPT_S_NOT_REGISTERED)
  977. {
  978. FlushBindings();
  979. }
  980. return Status;
  981. }
  982. //+---------------------------------------------------------------------------
  983. //
  984. // Function: CRemoteMachine::LookupBinding
  985. //
  986. // Synopsis: Scan the binding list for a binding with matching
  987. // authentication information
  988. //
  989. //----------------------------------------------------------------------------
  990. CMachineBinding *
  991. CRemoteMachine::LookupBinding(
  992. IN USHORT AuthnSvc,
  993. IN COAUTHINFO * pAuthInfo OPTIONAL
  994. )
  995. {
  996. CMachineBinding * pMachineBinding;
  997. gpRemoteMachineLock->LockShared();
  998. for ( pMachineBinding = (CMachineBinding *) _BindingList.First();
  999. pMachineBinding;
  1000. pMachineBinding = (CMachineBinding *) pMachineBinding->Next() )
  1001. {
  1002. if ( pMachineBinding->Equal( AuthnSvc, pAuthInfo ) )
  1003. {
  1004. pMachineBinding->Reference();
  1005. break;
  1006. }
  1007. }
  1008. gpRemoteMachineLock->UnlockShared();
  1009. return pMachineBinding;
  1010. }
  1011. //+---------------------------------------------------------------------------
  1012. //
  1013. // Function: CRemoteMachine::FlushBindings
  1014. //
  1015. // Synopsis: Release all entries under a lock
  1016. //
  1017. //----------------------------------------------------------------------------
  1018. void
  1019. CRemoteMachine::FlushBindings()
  1020. {
  1021. gpRemoteMachineLock->LockExclusive();
  1022. FlushBindingsNoLock();
  1023. gpRemoteMachineLock->UnlockExclusive();
  1024. }
  1025. //+---------------------------------------------------------------------------
  1026. //
  1027. // Function: CRemoteMachine::FlushBindingsNoLock
  1028. //
  1029. // Synopsis: Release all entries without taking a lock first.
  1030. //
  1031. //----------------------------------------------------------------------------
  1032. void CRemoteMachine::FlushBindingsNoLock()
  1033. {
  1034. CMachineBinding * pMachineBinding;
  1035. while ( pMachineBinding = (CMachineBinding *) _BindingList.First() )
  1036. {
  1037. _BindingList.Remove( pMachineBinding );
  1038. pMachineBinding->Release();
  1039. }
  1040. }
  1041. //+---------------------------------------------------------------------------
  1042. //
  1043. // Function: CRemoteMachine::InsertBinding
  1044. //
  1045. // Synopsis: Add the specified binding handle to the cache of binding
  1046. // handles for this machine. Free it if the insertion fails.
  1047. //
  1048. //----------------------------------------------------------------------------
  1049. void
  1050. CRemoteMachine::InsertBinding(
  1051. IN handle_t hBinding,
  1052. IN USHORT ProtseqId,
  1053. IN USHORT AuthnSvc,
  1054. IN COAUTHINFO * pAuthInfo OPTIONAL,
  1055. IN COAUTHIDENTITY* pAuthIdentityFinal
  1056. )
  1057. {
  1058. CMachineBinding * pMachineBinding;
  1059. CMachineBinding * pExistingBinding;
  1060. COAUTHINFO * pAuthInfoCopy;
  1061. pAuthInfoCopy = 0;
  1062. pMachineBinding = 0;
  1063. if ( ! pAuthInfo || (CopyAuthInfo( pAuthInfo, &pAuthInfoCopy ) == S_OK) )
  1064. {
  1065. pMachineBinding = new CMachineBinding(
  1066. hBinding,
  1067. ProtseqId,
  1068. AuthnSvc,
  1069. pAuthInfoCopy,
  1070. pAuthIdentityFinal);
  1071. }
  1072. if ( ! pMachineBinding )
  1073. {
  1074. FreeAuthIdentity(pAuthIdentityFinal);
  1075. RpcBindingFree( &hBinding );
  1076. return;
  1077. }
  1078. gpRemoteMachineLock->LockExclusive();
  1079. for ( pExistingBinding = (CMachineBinding *) _BindingList.First();
  1080. pExistingBinding;
  1081. pExistingBinding = (CMachineBinding *) pExistingBinding->Next() )
  1082. {
  1083. if ( pExistingBinding->Equal( AuthnSvc, pAuthInfoCopy ) )
  1084. break;
  1085. }
  1086. if ( ! pExistingBinding )
  1087. _BindingList.Insert( pMachineBinding );
  1088. gpRemoteMachineLock->UnlockExclusive();
  1089. if ( pExistingBinding )
  1090. {
  1091. // Will delete the new binding we created above.
  1092. pMachineBinding->Release();
  1093. }
  1094. }
  1095. //+---------------------------------------------------------------------------
  1096. //
  1097. // Function: CRemoteMachine::RemoveBinding
  1098. //
  1099. // Synopsis: Remove the specified binding handle from the cache for
  1100. // this machine.
  1101. //
  1102. //----------------------------------------------------------------------------
  1103. void
  1104. CRemoteMachine::RemoveBinding(
  1105. IN CMachineBinding * pMachineBinding
  1106. )
  1107. {
  1108. CMachineBinding * pBinding;
  1109. gpRemoteMachineLock->LockExclusive();
  1110. for ( pBinding = (CMachineBinding *) _BindingList.First();
  1111. pBinding;
  1112. pBinding = (CMachineBinding *) pBinding->Next() )
  1113. {
  1114. if ( pBinding == pMachineBinding )
  1115. {
  1116. _BindingList.Remove( pMachineBinding );
  1117. pMachineBinding->Release();
  1118. break;
  1119. }
  1120. }
  1121. gpRemoteMachineLock->UnlockExclusive();
  1122. }
  1123. //+---------------------------------------------------------------------------
  1124. //
  1125. // Function: CMachineBinding::CMachineBinding
  1126. //
  1127. // Synopsis: Constructor
  1128. //
  1129. //----------------------------------------------------------------------------
  1130. //
  1131. // CMachineBinding
  1132. //
  1133. CMachineBinding::CMachineBinding(
  1134. IN handle_t hBinding,
  1135. IN USHORT ProtseqId,
  1136. IN USHORT AuthnSvc,
  1137. IN COAUTHINFO * pAuthInfo OPTIONAL,
  1138. IN COAUTHIDENTITY* pAuthIdentityFinal
  1139. )
  1140. {
  1141. _hBinding = hBinding;
  1142. _ProtseqId = ProtseqId;
  1143. _AuthnSvc = AuthnSvc;
  1144. _pAuthInfo = pAuthInfo;
  1145. _pAuthIdentity = pAuthIdentityFinal; // the only reason to hold on to this
  1146. // is because in some situations it
  1147. // must not be released until the binding
  1148. // handle is gone
  1149. }
  1150. //+---------------------------------------------------------------------------
  1151. //
  1152. // Function: CMachineBinding::~CMachineBinding
  1153. //
  1154. // Synopsis: Destructor
  1155. //
  1156. //----------------------------------------------------------------------------
  1157. CMachineBinding::~CMachineBinding()
  1158. {
  1159. if ( _hBinding )
  1160. RpcBindingFree( &_hBinding );
  1161. if ( _pAuthInfo )
  1162. {
  1163. PrivMemFree( _pAuthInfo->pwszServerPrincName );
  1164. if ( _pAuthInfo->pAuthIdentityData )
  1165. {
  1166. FreeAuthIdentity(_pAuthInfo->pAuthIdentityData);
  1167. }
  1168. PrivMemFree( _pAuthInfo );
  1169. }
  1170. if (_pAuthIdentity)
  1171. FreeAuthIdentity(_pAuthIdentity);
  1172. }
  1173. //+---------------------------------------------------------------------------
  1174. //
  1175. // Function: CMachineBinding::Equal
  1176. //
  1177. // Synopsis: Return TRUE if the specified authentication information
  1178. // matches this binding handle. If the AUTHN_ANY flag is
  1179. // specified, do not check the authentication service but do
  1180. // check the authentication info.
  1181. //
  1182. //----------------------------------------------------------------------------
  1183. BOOL
  1184. CMachineBinding::Equal(
  1185. IN USHORT AuthnSvc,
  1186. IN COAUTHINFO * pAuthInfo OPTIONAL
  1187. )
  1188. {
  1189. return( (AuthnSvc == _AuthnSvc ||
  1190. (AuthnSvc == AUTHN_ANY && _AuthnSvc != RPC_C_AUTHN_NONE)) &&
  1191. EqualAuthInfo( pAuthInfo, _pAuthInfo ) );
  1192. }
  1193. //+---------------------------------------------------------------------------
  1194. //
  1195. // Function: CallRemoteMachine
  1196. //
  1197. // Synopsis: Marshal/Unmarshal the activation parameters. Call the right
  1198. // remote activation interface.
  1199. //
  1200. //----------------------------------------------------------------------------
  1201. RPC_STATUS
  1202. CallRemoteMachine(
  1203. handle_t hBinding,
  1204. USHORT ProtseqId,
  1205. ACTIVATION_PARAMS * pActParams,
  1206. WCHAR * pwszPathForServer,
  1207. WCHAR * pwszMachine,
  1208. HRESULT * phr
  1209. )
  1210. {
  1211. RPC_STATUS Status=RPC_S_OK;
  1212. // jsimmons 2/15/00 -- we explicitly don't cache the COM version of the target server; if
  1213. // we did this would allow us on subsequent calls to know in advance which RPC interface
  1214. // to use while calling. However, PM decision was to leave the current behavior alone.
  1215. // First try new interface
  1216. if (pwszPathForServer && (pwszPathForServer != pActParams->pwszPath))
  1217. {
  1218. ASSERT(pActParams->pInstanceInfo != NULL);
  1219. pActParams->pInstanceInfo->SetFile(pwszPathForServer, pActParams->Mode);
  1220. }
  1221. ASSERT(pActParams->pActPropsIn != NULL);
  1222. IScmRequestInfo *pRequestInfo;
  1223. *phr = pActParams->pActPropsIn->QueryInterface(IID_IScmRequestInfo,
  1224. (void**) &pRequestInfo);
  1225. if (*phr != S_OK)
  1226. return Status;
  1227. REMOTE_REQUEST_SCM_INFO *pRequest;
  1228. pRequest = (REMOTE_REQUEST_SCM_INFO *)
  1229. MIDL_user_allocate(sizeof(REMOTE_REQUEST_SCM_INFO));
  1230. if (pRequest == NULL)
  1231. {
  1232. pRequestInfo->Release();
  1233. *phr = E_OUTOFMEMORY;
  1234. return Status;
  1235. }
  1236. pRequest->ClientImpLevel = RPC_C_IMP_LEVEL_IDENTIFY;
  1237. pRequest->cRequestedProtseqs = cMyProtseqs;
  1238. pRequest->pRequestedProtseqs = (unsigned short*)
  1239. MIDL_user_allocate(sizeof(short)*pRequest->cRequestedProtseqs);
  1240. if (pRequest->pRequestedProtseqs==NULL)
  1241. {
  1242. *phr = E_OUTOFMEMORY;
  1243. MIDL_user_free(pRequest);
  1244. pRequestInfo->Release();
  1245. return RPC_S_OK;
  1246. }
  1247. memcpy(pRequest->pRequestedProtseqs, aMyProtseqs, sizeof(short)*cMyProtseqs);
  1248. pRequestInfo->SetRemoteRequestInfo(pRequest);
  1249. pRequestInfo->Release();
  1250. MInterfacePointer *pIFDIn, *pIFDOut=NULL;
  1251. *phr = ActPropsMarshalHelper(pActParams->pActPropsIn,
  1252. IID_IActivationPropertiesIn,
  1253. MSHCTX_DIFFERENTMACHINE,
  1254. MSHLFLAGS_NORMAL,
  1255. &pIFDIn);
  1256. if (*phr != S_OK)
  1257. {
  1258. return RPC_S_OK;
  1259. }
  1260. RpcTryExcept
  1261. {
  1262. if (pActParams->MsgType == GETCLASSOBJECT)
  1263. {
  1264. *phr = RemoteGetClassObject(
  1265. hBinding,
  1266. pActParams->ORPCthis,
  1267. pActParams->ORPCthat,
  1268. pIFDIn,
  1269. &pIFDOut);
  1270. }
  1271. else
  1272. {
  1273. *phr = RemoteCreateInstance(
  1274. hBinding,
  1275. pActParams->ORPCthis,
  1276. pActParams->ORPCthat,
  1277. NULL,
  1278. pIFDIn,
  1279. &pIFDOut);
  1280. }
  1281. }
  1282. RpcExcept(TRUE)
  1283. {
  1284. Status = RpcExceptionCode();
  1285. }
  1286. RpcEndExcept
  1287. MIDL_user_free(pIFDIn);
  1288. if ((Status == RPC_S_OK) ||
  1289. (!((Status == RPC_S_UNKNOWN_IF) ||
  1290. (Status == RPC_S_INTERFACE_NOT_FOUND) ||
  1291. (Status == RPC_S_NO_INTERFACES) ||
  1292. (Status == RPC_E_NOT_REGISTERED))))
  1293. {
  1294. if (Status != RPC_S_OK)
  1295. {
  1296. *phr = HRESULT_FROM_WIN32(Status);
  1297. return Status;
  1298. }
  1299. if (*phr != S_OK)
  1300. {
  1301. // a-sergiv (Sergei O. Ivanov), 6-17-99
  1302. // Fix for com+ 14808/nt 355212
  1303. LogRemoteSideFailure( &pActParams->Clsid, pActParams->ClsContext, pwszMachine, pwszPathForServer, *phr);
  1304. return RPC_S_OK;
  1305. }
  1306. // AWFUL HACK ALERT: This is too hacky even for the SCM
  1307. ActivationStream ActStream((InterfaceData*)
  1308. (((BYTE*)pIFDOut)+48));
  1309. pActParams->pActPropsOut = new ActivationPropertiesOut(FALSE /* fBrokenRefCount */);
  1310. if (pActParams->pActPropsOut==NULL)
  1311. {
  1312. *phr = E_OUTOFMEMORY;
  1313. return RPC_S_OK;
  1314. }
  1315. if (pActParams->pActPropsOut==NULL)
  1316. {
  1317. *phr = E_OUTOFMEMORY;
  1318. return RPC_S_OK;
  1319. }
  1320. IScmReplyInfo *pReplyInfo;
  1321. *phr = pActParams->pActPropsOut->UnmarshalInterface(&ActStream,
  1322. IID_IScmReplyInfo,
  1323. (LPVOID*)&pReplyInfo);
  1324. if (*phr != S_OK)
  1325. {
  1326. pReplyInfo->Release();
  1327. pActParams->pActPropsOut->Release();
  1328. pActParams->pActPropsOut=NULL;
  1329. MIDL_user_free(pIFDOut);
  1330. return RPC_S_OK;
  1331. }
  1332. // If in a remote LB router, just return
  1333. if (pActParams->RemoteActivation)
  1334. {
  1335. pReplyInfo->Release();
  1336. MIDL_user_free(pIFDOut);
  1337. return RPC_S_OK;
  1338. }
  1339. REMOTE_REPLY_SCM_INFO *pReply;
  1340. pReplyInfo->GetRemoteReplyInfo(&pReply);
  1341. Win4Assert(pReply!=NULL);
  1342. *pActParams->pOxidServer = pReply->Oxid;
  1343. //We will not have protocol bindings for custom marshalled objrefs
  1344. if ((pReply->pdsaOxidBindings) && (pReply->pdsaOxidBindings->wNumEntries))
  1345. {
  1346. Win4Assert(pActParams->pOxidInfo != NULL);
  1347. pActParams->pOxidInfo->psa = (DUALSTRINGARRAY *)
  1348. MIDL_user_allocate(pReply->pdsaOxidBindings->wNumEntries
  1349. * sizeof(WCHAR) +
  1350. sizeof(DUALSTRINGARRAY));
  1351. if (pActParams->pOxidInfo->psa == NULL)
  1352. {
  1353. pReplyInfo->Release();
  1354. pActParams->pActPropsOut->Release();
  1355. pActParams->pActPropsOut=NULL;
  1356. *phr = E_OUTOFMEMORY;
  1357. return RPC_S_OK;
  1358. }
  1359. dsaCopy(pActParams->pOxidInfo->psa,
  1360. pReply->pdsaOxidBindings);
  1361. }
  1362. else
  1363. pActParams->pOxidInfo->psa = NULL;
  1364. pActParams->ProtseqId = ProtseqId;
  1365. pActParams->pOxidInfo->ipidRemUnknown = pReply->ipidRemUnknown;
  1366. pActParams->pOxidInfo->dwAuthnHint = pReply->authnHint;
  1367. pActParams->pOxidInfo->version = pReply->serverVersion;
  1368. pActParams->pIIDs = 0;
  1369. pActParams->pResults = 0;
  1370. pActParams->ppIFD = 0;
  1371. MIDL_user_free(pIFDOut);
  1372. pReplyInfo->Release();
  1373. return RPC_S_OK;
  1374. }
  1375. if ( pActParams->fComplusOnly )
  1376. {
  1377. *phr = HRESULT_FROM_WIN32(Status);
  1378. return Status;
  1379. }
  1380. // Use Old Down-level interface
  1381. // all remote activations on this interface have to be made with
  1382. // minor version 1, since remote downlevel (version 5.1) servers
  1383. // refuse any other version.
  1384. pActParams->ORPCthis->version.MinorVersion = COM_MINOR_VERSION_1;
  1385. pActParams->ORPCthis->flags = ORPCF_NULL;
  1386. pActParams->ppIFD = (MInterfacePointer **)
  1387. MIDL_user_allocate(sizeof(MInterfacePointer *) *
  1388. pActParams->Interfaces);
  1389. pActParams->pResults = (HRESULT*) MIDL_user_allocate(sizeof(HRESULT) *
  1390. pActParams->Interfaces);
  1391. if ((pActParams->ppIFD == NULL) || (pActParams->pResults == NULL))
  1392. {
  1393. MIDL_user_free(pActParams->ppIFD);
  1394. MIDL_user_free(pActParams->pResults);
  1395. *phr = E_OUTOFMEMORY;
  1396. return RPC_S_OK;
  1397. }
  1398. for (DWORD i=0; i<pActParams->Interfaces;i++)
  1399. {
  1400. pActParams->ppIFD[i] = NULL;
  1401. pActParams->pResults[i] = E_FAIL;
  1402. }
  1403. Status = RemoteActivation(
  1404. hBinding,
  1405. pActParams->ORPCthis,
  1406. pActParams->ORPCthat,
  1407. &pActParams->Clsid,
  1408. pwszPathForServer,
  1409. pActParams->pIFDStorage,
  1410. RPC_C_IMP_LEVEL_IDENTIFY,
  1411. pActParams->Mode,
  1412. pActParams->Interfaces,
  1413. pActParams->pIIDs,
  1414. cMyProtseqs,
  1415. aMyProtseqs,
  1416. pActParams->pOxidServer,
  1417. &pActParams->pOxidInfo->psa,
  1418. &pActParams->pOxidInfo->ipidRemUnknown,
  1419. &pActParams->pOxidInfo->dwAuthnHint,
  1420. &pActParams->pOxidInfo->version,
  1421. phr,
  1422. pActParams->ppIFD,
  1423. pActParams->pResults );
  1424. //
  1425. // Note that this will only give us a bad status is there is a
  1426. // communication failure.
  1427. //
  1428. if ( Status != RPC_S_OK )
  1429. return Status;
  1430. // Tweak the COMVERSION to be the lower of the two.
  1431. Status = NegotiateDCOMVersion( &pActParams->pOxidInfo->version );
  1432. if ( Status != RPC_S_OK )
  1433. return Status;
  1434. if ( (RPC_S_OK == Status) && FAILED(*phr) )
  1435. LogRemoteSideFailure( &pActParams->Clsid, pActParams->ClsContext, pwszMachine, pwszPathForServer, *phr );
  1436. if ((pActParams->MsgType == GETCLASSOBJECT) && (*phr == S_OK))
  1437. {
  1438. #if 0
  1439. *phr = *pActParams->pResults;
  1440. #else
  1441. *pActParams->pResults = *phr;
  1442. #endif
  1443. }
  1444. //
  1445. // If the activation fails we return success for the communication
  1446. // status, but the overall operation has failed and the error will
  1447. // be propogated back to the client.
  1448. //
  1449. if ( FAILED(*phr) )
  1450. return RPC_S_OK;
  1451. pActParams->ProtseqId = ProtseqId;
  1452. ASSERT(pActParams->pActPropsIn != NULL);
  1453. *phr =
  1454. pActParams->pActPropsIn->GetReturnActivationProperties((ActivationPropertiesOut **)
  1455. &pActParams->pActPropsOut);
  1456. *phr = pActParams->pActPropsOut->SetMarshalledResults(pActParams->Interfaces,
  1457. pActParams->pIIDs,
  1458. pActParams->pResults,
  1459. pActParams->ppIFD);
  1460. //pActParams->pIIDs belongs to ActPropsIn
  1461. MIDL_user_free(pActParams->pResults);
  1462. for (i=0;i<pActParams->Interfaces ; i++)
  1463. MIDL_user_free(pActParams->ppIFD[i]);
  1464. MIDL_user_free(pActParams->ppIFD);
  1465. pActParams->pResults = NULL;
  1466. pActParams->ppIFD = NULL;
  1467. return RPC_S_OK;
  1468. }
  1469. //+---------------------------------------------------------------------------
  1470. //
  1471. // Function: CreateRemoteBinding
  1472. //
  1473. // Synopsis: Create a binding handle for the specified machine and protseq.
  1474. //
  1475. //----------------------------------------------------------------------------
  1476. RPC_STATUS
  1477. CreateRemoteBinding(
  1478. IN WCHAR * pwszMachine,
  1479. IN int ProtseqIndex,
  1480. OUT handle_t * phBinding
  1481. )
  1482. {
  1483. WCHAR * pwszStringBinding;
  1484. RPC_STATUS Status;
  1485. *phBinding = 0;
  1486. Status = RpcStringBindingCompose(
  1487. NULL,
  1488. gaProtseqInfo[aMyProtseqs[ProtseqIndex]].pwstrProtseq,
  1489. pwszMachine,
  1490. gaProtseqInfo[aMyProtseqs[ProtseqIndex]].pwstrEndpoint,
  1491. NULL,
  1492. &pwszStringBinding );
  1493. if ( Status != RPC_S_OK )
  1494. return Status;
  1495. Status = RpcBindingFromStringBinding( pwszStringBinding, phBinding );
  1496. RpcStringFree( &pwszStringBinding );
  1497. return Status;
  1498. }
  1499. //+---------------------------------------------------------------------------
  1500. //
  1501. // Function: CopyAuthIdentity
  1502. //
  1503. // Synopsis: Copy an auth identity structure and all its strings.
  1504. //
  1505. //----------------------------------------------------------------------------
  1506. HRESULT
  1507. CopyAuthIdentity(
  1508. IN COAUTHIDENTITY * pAuthIdentSrc,
  1509. IN COAUTHIDENTITY ** ppAuthIdentDest
  1510. )
  1511. {
  1512. ULONG ulBufSize;
  1513. COAUTHIDENTITY* pAuthIdentTemp;
  1514. ULONG ulUserLen;
  1515. ULONG ulDomainLen;
  1516. ULONG ulPwdLen;
  1517. *ppAuthIdentDest = NULL;
  1518. // Guard against both being set, although presumably this would have
  1519. // caused grief before we got to this point.
  1520. if ((pAuthIdentSrc->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) &&
  1521. (pAuthIdentSrc->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI))
  1522. {
  1523. ASSERT(0 && "Both string type flags were set!");
  1524. return E_UNEXPECTED;
  1525. }
  1526. if (pAuthIdentSrc->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE)
  1527. {
  1528. // Copy Unicode version of the struct
  1529. WCHAR* pEnd;
  1530. // Calculate size of the individual strings, with terminating nulls
  1531. ulUserLen = pAuthIdentSrc->User ? lstrlenW(pAuthIdentSrc->User) + 1 : 0;
  1532. ulDomainLen = pAuthIdentSrc->Domain ? lstrlenW(pAuthIdentSrc->Domain) + 1 : 0;
  1533. ulPwdLen = pAuthIdentSrc->Password ? lstrlenW(pAuthIdentSrc->Password) + 1 : 0;
  1534. // Calculate size of the entire buffer, in bytes
  1535. ulBufSize = sizeof(COAUTHIDENTITY) + ((ulUserLen + ulDomainLen + ulPwdLen) * sizeof(WCHAR));
  1536. // Allocate one buffer to hold struct+strings
  1537. pAuthIdentTemp = (COAUTHIDENTITY*) PrivMemAlloc(ulBufSize);
  1538. if (!pAuthIdentTemp)
  1539. return E_OUTOFMEMORY;
  1540. // Copy string lengths. These exclude the null.
  1541. pAuthIdentTemp->UserLength = (ulUserLen != 0) ? ulUserLen - 1 : 0;
  1542. pAuthIdentTemp->DomainLength = (ulDomainLen != 0) ? ulDomainLen - 1 : 0;
  1543. pAuthIdentTemp->PasswordLength = (ulPwdLen != 0) ? ulPwdLen - 1 : 0;
  1544. // Copy flags
  1545. pAuthIdentTemp->Flags = pAuthIdentSrc->Flags;
  1546. // Copy strings
  1547. pEnd = (WCHAR*)(pAuthIdentTemp + 1); // point to buffer just past end of struct
  1548. if (pAuthIdentSrc->User)
  1549. {
  1550. pAuthIdentTemp->User = pEnd;
  1551. lstrcpyW(pEnd, pAuthIdentSrc->User);
  1552. pEnd += ulUserLen;
  1553. }
  1554. else
  1555. pAuthIdentTemp->User = NULL;
  1556. if (pAuthIdentSrc->Domain)
  1557. {
  1558. pAuthIdentTemp->Domain = pEnd;
  1559. lstrcpyW(pEnd, pAuthIdentSrc->Domain);
  1560. pEnd += ulDomainLen;
  1561. }
  1562. else
  1563. pAuthIdentTemp->Domain = NULL;
  1564. if (pAuthIdentSrc->Password)
  1565. {
  1566. pAuthIdentTemp->Password = pEnd;
  1567. lstrcpyW(pEnd, pAuthIdentSrc->Password);
  1568. pEnd += ulPwdLen;
  1569. }
  1570. else
  1571. pAuthIdentTemp->Password = NULL;
  1572. }
  1573. else if (pAuthIdentSrc->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI )
  1574. {
  1575. // Copy ANSI version of the struct
  1576. CHAR* pEnd;
  1577. // Calculate size of the individual strings, with terminating nulls
  1578. ulUserLen = pAuthIdentSrc->User ? lstrlenA((LPCSTR)pAuthIdentSrc->User) + 1 : 0;
  1579. ulDomainLen = pAuthIdentSrc->Domain ? lstrlenA((LPCSTR)pAuthIdentSrc->Domain) + 1 : 0;
  1580. ulPwdLen = pAuthIdentSrc->Password ? lstrlenA((LPCSTR)pAuthIdentSrc->Password) + 1 : 0;
  1581. // Calculate size of the entire buffer, in bytes
  1582. ulBufSize = sizeof(COAUTHIDENTITY) + ((ulUserLen + ulDomainLen + ulPwdLen) * sizeof(CHAR));
  1583. // Allocate one buffer to hold struct+strings
  1584. pAuthIdentTemp = (COAUTHIDENTITY*) PrivMemAlloc(ulBufSize);
  1585. if (!pAuthIdentTemp)
  1586. return E_OUTOFMEMORY;
  1587. // Copy string lengths. These exclude the null.
  1588. pAuthIdentTemp->UserLength = (ulUserLen != 0) ? ulUserLen - 1 : 0;
  1589. pAuthIdentTemp->DomainLength = (ulDomainLen != 0) ? ulDomainLen - 1 : 0;
  1590. pAuthIdentTemp->PasswordLength = (ulPwdLen != 0) ? ulPwdLen - 1 : 0;
  1591. // Copy flags
  1592. pAuthIdentTemp->Flags = pAuthIdentSrc->Flags;
  1593. // Copy strings
  1594. pEnd = (CHAR*)(pAuthIdentTemp + 1); // point to buffer just past end of struct
  1595. if (pAuthIdentSrc->User)
  1596. {
  1597. pAuthIdentTemp->User = (USHORT*)pEnd;
  1598. lstrcpyA(pEnd, (LPCSTR)pAuthIdentSrc->User);
  1599. pEnd += ulUserLen;
  1600. }
  1601. else
  1602. pAuthIdentTemp->User = NULL;
  1603. if (pAuthIdentSrc->Domain)
  1604. {
  1605. pAuthIdentTemp->Domain = (USHORT*)pEnd;
  1606. lstrcpyA(pEnd, (LPCSTR)pAuthIdentSrc->Domain);
  1607. pEnd += ulDomainLen;
  1608. }
  1609. else
  1610. pAuthIdentTemp->Domain = NULL;
  1611. if (pAuthIdentSrc->Password)
  1612. {
  1613. pAuthIdentTemp->Password = (USHORT*)pEnd;
  1614. lstrcpyA(pEnd, (LPCSTR)pAuthIdentSrc->Password);
  1615. pEnd += ulPwdLen;
  1616. }
  1617. else
  1618. pAuthIdentTemp->Password = NULL;
  1619. }
  1620. else
  1621. {
  1622. // The user didn't specify either string bit? How did we get here?
  1623. ASSERT(0 && "String type flag was not set!");
  1624. return E_UNEXPECTED;
  1625. }
  1626. *ppAuthIdentDest = pAuthIdentTemp;
  1627. return S_OK;
  1628. }
  1629. //+---------------------------------------------------------------------------
  1630. //
  1631. // Function: FreeAuthInfo
  1632. //
  1633. // Synopsis: Free an auth info structure and all its substructures.
  1634. //
  1635. //----------------------------------------------------------------------------
  1636. void FreeAuthInfo(COAUTHINFO *pAuthInfo)
  1637. {
  1638. if (pAuthInfo)
  1639. {
  1640. if (pAuthInfo->pwszServerPrincName)
  1641. PrivMemFree(pAuthInfo->pwszServerPrincName);
  1642. if (pAuthInfo->pAuthIdentityData)
  1643. FreeAuthIdentity(pAuthInfo->pAuthIdentityData);
  1644. PrivMemFree(pAuthInfo);
  1645. }
  1646. }
  1647. //+---------------------------------------------------------------------------
  1648. //
  1649. // Function: FreeAuthIdentity
  1650. //
  1651. // Synopsis: Free an auth identity structure and all its sub strings.
  1652. //
  1653. // Note: because of the way the various activation paths work, we may be
  1654. // freeing one of two different structs here: either a COAUTHIDENTITY
  1655. // or a SEC_WINNT_AUTH_IDENTITY_EXW. COAUTHIDENTITY's are created\copied
  1656. // in CopyAuthIdentity above; SEC_WINNT_AUTH_IDENTITY_EXW's are created in
  1657. // ComputeSvcList. In both cases they are constructed as one contiguous
  1658. // buffer, so we don't have to care about the details here; just free it.
  1659. //
  1660. //----------------------------------------------------------------------------
  1661. void FreeAuthIdentity(void* pAuthIdentity)
  1662. {
  1663. if (pAuthIdentity)
  1664. {
  1665. PrivMemFree(pAuthIdentity);
  1666. }
  1667. }
  1668. //+---------------------------------------------------------------------------
  1669. //
  1670. // Function: CopyAuthInfo
  1671. //
  1672. // Synopsis: Copy an auth info structure and all its sub structures.
  1673. //
  1674. //----------------------------------------------------------------------------
  1675. HRESULT
  1676. CopyAuthInfo(
  1677. IN COAUTHINFO * pAuthInfoSrc,
  1678. IN COAUTHINFO ** ppAuthInfoDest
  1679. )
  1680. {
  1681. HRESULT hr = E_OUTOFMEMORY;
  1682. *ppAuthInfoDest = NULL;
  1683. if (pAuthInfoSrc == NULL)
  1684. {
  1685. *ppAuthInfoDest = NULL;
  1686. return S_OK;
  1687. }
  1688. if ( !(*ppAuthInfoDest = (COAUTHINFO*)PrivMemAlloc(sizeof(COAUTHINFO))) )
  1689. {
  1690. goto COPY_AUTHINFO_EXIT;
  1691. }
  1692. // only alloc space for pwszServerPrincName if its non-null
  1693. if (pAuthInfoSrc->pwszServerPrincName)
  1694. {
  1695. if ( !((*ppAuthInfoDest)->pwszServerPrincName =
  1696. (LPWSTR)PrivMemAlloc((lstrlenW(pAuthInfoSrc->pwszServerPrincName) + 1) *
  1697. sizeof(WCHAR))) )
  1698. {
  1699. goto COPY_AUTHINFO_EXIT;
  1700. }
  1701. }
  1702. else
  1703. {
  1704. (*ppAuthInfoDest)->pwszServerPrincName = NULL;
  1705. }
  1706. // copy the AuthIdentity if its non-null
  1707. if (pAuthInfoSrc->pAuthIdentityData)
  1708. {
  1709. if ( FAILED(CopyAuthIdentity(pAuthInfoSrc->pAuthIdentityData,
  1710. &((*ppAuthInfoDest)->pAuthIdentityData))) )
  1711. {
  1712. goto COPY_AUTHINFO_EXIT;
  1713. }
  1714. }
  1715. else
  1716. {
  1717. (*ppAuthInfoDest)->pAuthIdentityData = NULL;
  1718. }
  1719. (*ppAuthInfoDest)->dwAuthnSvc = pAuthInfoSrc->dwAuthnSvc;
  1720. (*ppAuthInfoDest)->dwAuthzSvc = pAuthInfoSrc->dwAuthzSvc;
  1721. (*ppAuthInfoDest)->dwAuthnLevel = pAuthInfoSrc->dwAuthnLevel;
  1722. (*ppAuthInfoDest)->dwImpersonationLevel = pAuthInfoSrc->dwImpersonationLevel;
  1723. (*ppAuthInfoDest)->dwCapabilities = pAuthInfoSrc->dwCapabilities;
  1724. if (pAuthInfoSrc->pwszServerPrincName)
  1725. {
  1726. lstrcpyW((*ppAuthInfoDest)->pwszServerPrincName,pAuthInfoSrc->pwszServerPrincName);
  1727. }
  1728. return S_OK;
  1729. COPY_AUTHINFO_EXIT:
  1730. if ( *ppAuthInfoDest )
  1731. {
  1732. if ( (*ppAuthInfoDest)->pwszServerPrincName )
  1733. {
  1734. PrivMemFree( (*ppAuthInfoDest)->pwszServerPrincName );
  1735. }
  1736. PrivMemFree( *ppAuthInfoDest );
  1737. }
  1738. return hr;
  1739. }
  1740. //+---------------------------------------------------------------------------
  1741. //
  1742. // Function: EqualAuthIdentity
  1743. //
  1744. // Synopsis: Compare two auth identity structures by member.
  1745. //
  1746. //----------------------------------------------------------------------------
  1747. BOOL
  1748. EqualAuthIdentity(
  1749. COAUTHIDENTITY* pAuthIdent,
  1750. COAUTHIDENTITY* pAuthIdentOther )
  1751. {
  1752. if ( pAuthIdent->Flags != pAuthIdentOther->Flags )
  1753. {
  1754. return FALSE;
  1755. }
  1756. ULONG cch;
  1757. if ( pAuthIdent->User && pAuthIdentOther->User )
  1758. {
  1759. if ( (cch = pAuthIdent->UserLength) != pAuthIdentOther->UserLength )
  1760. {
  1761. return FALSE;
  1762. }
  1763. if ( memcmp(pAuthIdent->User,pAuthIdentOther->User,(cch+1) * sizeof(WCHAR)) != 0 )
  1764. {
  1765. return FALSE;
  1766. }
  1767. }
  1768. else if ( pAuthIdent->User || pAuthIdentOther->User )
  1769. return FALSE;
  1770. if ( pAuthIdent->Domain && pAuthIdentOther->Domain )
  1771. {
  1772. if ( (cch = pAuthIdent->DomainLength) != pAuthIdentOther->DomainLength )
  1773. {
  1774. return FALSE;
  1775. }
  1776. if ( memcmp(pAuthIdent->Domain,pAuthIdentOther->Domain,(cch+1) * sizeof(WCHAR)) != 0 )
  1777. {
  1778. return FALSE;
  1779. }
  1780. }
  1781. else if ( pAuthIdent->Domain || pAuthIdentOther->Domain )
  1782. return FALSE;
  1783. if ( pAuthIdent->Password && pAuthIdentOther->Password )
  1784. {
  1785. if ( (cch = pAuthIdent->PasswordLength) != pAuthIdentOther->PasswordLength )
  1786. {
  1787. return FALSE;
  1788. }
  1789. if ( memcmp(pAuthIdent->Password,pAuthIdentOther->Password,(cch+1) * sizeof(WCHAR)) != 0 )
  1790. {
  1791. return FALSE;
  1792. }
  1793. }
  1794. else if ( pAuthIdent->Password || pAuthIdentOther->Password )
  1795. return FALSE;
  1796. return TRUE;
  1797. }
  1798. //+---------------------------------------------------------------------------
  1799. //
  1800. // Function: EqualAuthInfo
  1801. //
  1802. // Synopsis: Compare two auth info structures and their sub structures.
  1803. //
  1804. //----------------------------------------------------------------------------
  1805. BOOL
  1806. EqualAuthInfo(
  1807. COAUTHINFO* pAuthInfo,
  1808. COAUTHINFO* pAuthInfoOther)
  1809. {
  1810. if ( pAuthInfo && pAuthInfoOther )
  1811. {
  1812. if ( (pAuthInfo->dwAuthnSvc != pAuthInfoOther->dwAuthnSvc) ||
  1813. (pAuthInfo->dwAuthzSvc != pAuthInfoOther->dwAuthzSvc) ||
  1814. (pAuthInfo->dwAuthnLevel != pAuthInfoOther->dwAuthnLevel) ||
  1815. (pAuthInfo->dwImpersonationLevel != pAuthInfoOther->dwImpersonationLevel) ||
  1816. (pAuthInfo->dwCapabilities != pAuthInfoOther->dwCapabilities) )
  1817. {
  1818. return FALSE;
  1819. }
  1820. // only compare pwszServerPrincName's if they're both specified
  1821. if (pAuthInfo->pwszServerPrincName && pAuthInfoOther->pwszServerPrincName)
  1822. {
  1823. if ( lstrcmpW(pAuthInfo->pwszServerPrincName,
  1824. pAuthInfoOther->pwszServerPrincName) != 0 )
  1825. {
  1826. return FALSE;
  1827. }
  1828. }
  1829. else
  1830. {
  1831. // if one was NULL, both should be NULL for equality
  1832. if (pAuthInfo->pwszServerPrincName != pAuthInfoOther->pwszServerPrincName)
  1833. {
  1834. return FALSE;
  1835. }
  1836. }
  1837. if (pAuthInfo->pAuthIdentityData && pAuthInfoOther->pAuthIdentityData)
  1838. {
  1839. if (!(EqualAuthIdentity(pAuthInfo->pAuthIdentityData,
  1840. pAuthInfoOther->pAuthIdentityData)) )
  1841. {
  1842. return FALSE;
  1843. }
  1844. }
  1845. else
  1846. {
  1847. // if either authident was NULL, they should both be NULL for equality
  1848. if (pAuthInfo->pAuthIdentityData != pAuthInfoOther->pAuthIdentityData)
  1849. {
  1850. return FALSE;
  1851. }
  1852. }
  1853. }
  1854. else
  1855. {
  1856. if ( pAuthInfo != pAuthInfoOther )
  1857. {
  1858. return FALSE;
  1859. }
  1860. }
  1861. return TRUE;
  1862. }