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.

1677 lines
49 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1998.
  5. //
  6. // File: imprsnat.cxx
  7. //
  8. // Contents:
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 2-16-96 srikants Created
  15. //
  16. //----------------------------------------------------------------------------
  17. #include <pch.cxx>
  18. #pragma hdrstop
  19. #include <wincrypt.h>
  20. #include <imprsnat.hxx>
  21. #include <pathpars.hxx>
  22. #include <smatch.hxx>
  23. #include <regacc.hxx>
  24. #include <regevent.hxx>
  25. #include <regscp.hxx>
  26. #include <ciregkey.hxx>
  27. #include <cievtmsg.h>
  28. #include <eventlog.hxx>
  29. #include <cimbmgr.hxx>
  30. #include <lcase.hxx>
  31. #include "cicat.hxx"
  32. #include "catreg.hxx"
  33. // List of logon information, shared between catalogs to help reduce
  34. // the problem of running out of logon instances.
  35. CLogonInfoList g_LogonList;
  36. //+---------------------------------------------------------------------------
  37. //
  38. // Function: EncryptMemoryPassword
  39. //
  40. // Synopsis: Encrypts a password in memory so it can be held in RAM a long
  41. // time without worrying about the password being easily
  42. // visible in crashdumps or the pagefile.
  43. //
  44. // Arguments: [pwcClearTextPassword] -- The password to encrypt
  45. // [ppbEncrypted] -- Returns a buffer allocated with
  46. // operator new with the encrypted pw.
  47. // [pcbEncrypted] -- Count of bytes allocated
  48. //
  49. // History: 4-05-02 dlee Created
  50. //
  51. //----------------------------------------------------------------------------
  52. void EncryptMemoryPassword(
  53. WCHAR const * pwcClearTextPassword,
  54. BYTE * * ppbEncrypted,
  55. DWORD * pcbEncrypted )
  56. {
  57. *ppbEncrypted = 0;
  58. *pcbEncrypted = 0;
  59. if ( 0 == pwcClearTextPassword )
  60. return;
  61. DWORD cbLen = ( wcslen( pwcClearTextPassword ) + 1 ) * sizeof( WCHAR );
  62. ULONG cBlocks = cbLen / CRYPTPROTECTMEMORY_BLOCK_SIZE;
  63. if ( 0 != ( cbLen % CRYPTPROTECTMEMORY_BLOCK_SIZE ) )
  64. cBlocks++;
  65. ULONG cbToAlloc = cBlocks * CRYPTPROTECTMEMORY_BLOCK_SIZE;
  66. XArray<BYTE> xEncrypted( cbToAlloc );
  67. ZeroMemory( xEncrypted.Get(), cbToAlloc );
  68. Win4Assert( cbToAlloc >= cbLen );
  69. RtlCopyMemory( xEncrypted.Get(), pwcClearTextPassword, cbLen );
  70. BOOL fOK = CryptProtectMemory( xEncrypted.Get(),
  71. cbToAlloc,
  72. CRYPTPROTECTMEMORY_SAME_PROCESS );
  73. if ( !fOK )
  74. {
  75. SCODE sc = HRESULT_FROM_WIN32( GetLastError() );
  76. // Don't leave the copy of the pw in memory
  77. SecureZeroMemory( xEncrypted.Get(), cbToAlloc );
  78. THROW( CException( sc ) );
  79. }
  80. *ppbEncrypted = xEncrypted.Acquire();
  81. *pcbEncrypted = cbToAlloc;
  82. } //EncryptMemoryPassword
  83. //+---------------------------------------------------------------------------
  84. //
  85. // Member: CLogonInfoList::Empty
  86. //
  87. // Synopsis: Empties the logon list
  88. //
  89. // History: 2-19-96 srikants Created
  90. //
  91. //----------------------------------------------------------------------------
  92. void CLogonInfoList::Empty()
  93. {
  94. for ( CLogonInfo * pLogonInfo = g_LogonList.Pop();
  95. 0 != pLogonInfo;
  96. pLogonInfo = g_LogonList.Pop() )
  97. {
  98. pLogonInfo->Close();
  99. delete pLogonInfo;
  100. }
  101. } //Empty
  102. //+---------------------------------------------------------------------------
  103. //
  104. // Function: AllocAndCopy
  105. //
  106. // Synopsis: A helper function to allocate and copy the source string into
  107. // a destination string.
  108. //
  109. // Arguments: [pSrc] -
  110. // [cc] -
  111. //
  112. // Returns:
  113. //
  114. // History: 4-08-96 srikants Created
  115. //
  116. //----------------------------------------------------------------------------
  117. WCHAR * CLogonInfo::AllocAndCopy( const WCHAR * pSrc, ULONG & cc )
  118. {
  119. WCHAR * pDst = 0;
  120. if ( 0 != pSrc )
  121. {
  122. cc = wcslen( pSrc );
  123. pDst = new WCHAR [cc+1];
  124. RtlCopyMemory( pDst, pSrc, (cc+1)*sizeof(WCHAR) );
  125. }
  126. else
  127. {
  128. cc = 0;
  129. }
  130. return pDst;
  131. }
  132. //+---------------------------------------------------------------------------
  133. //
  134. // Member: CLogonInfo::Logon
  135. //
  136. // Synopsis: Logon the given user with the given password.
  137. //
  138. // Arguments: [pwszUser] - User name
  139. // [pwszDomain] - Domain name
  140. // [pwszPassword] - Password (in clear text) to use.
  141. //
  142. // Returns: Status of the operation.
  143. //
  144. // History: 4-02-96 srikants Created
  145. //
  146. //----------------------------------------------------------------------------
  147. DWORD CLogonInfo::Logon( WCHAR const * pwszUser,
  148. WCHAR const * pwszDomain,
  149. WCHAR const * pwszPassword )
  150. {
  151. Win4Assert( 0 == _pwszUser );
  152. Win4Assert( 0 == _pwszDomain );
  153. _pwszUser = AllocAndCopy( pwszUser, _ccUser );
  154. _pwszDomain = AllocAndCopy( pwszDomain, _ccDomain );
  155. BYTE * pbPW = 0;
  156. DWORD cbPW = 0;
  157. EncryptMemoryPassword( pwszPassword, &pbPW, &cbPW );
  158. _xEncryptedPassword.Free();
  159. _xEncryptedPassword.Set( cbPW, pbPW );
  160. Win4Assert( INVALID_HANDLE_VALUE == _hToken );
  161. DWORD dwError = 0;
  162. if ( !LogonUser( _pwszUser, _pwszDomain, pwszPassword,
  163. LOGON32_LOGON_INTERACTIVE,
  164. LOGON32_PROVIDER_DEFAULT,
  165. &_hToken ) )
  166. {
  167. dwError = GetLastError();
  168. ciDebugOut(( DEB_ERROR, "Failure to logon user (%ws) domain (%ws). Error 0x%X\n",
  169. pwszUser, pwszDomain, dwError ));
  170. _hToken = INVALID_HANDLE_VALUE;
  171. }
  172. return dwError;
  173. } //Logon
  174. //+---------------------------------------------------------------------------
  175. //
  176. // Member: CLogonInfo::~CLogonInfo
  177. //
  178. // Synopsis: Frees up memory and closes the logon token.
  179. //
  180. // History: 4-05-96 srikants Created
  181. //
  182. //----------------------------------------------------------------------------
  183. CLogonInfo::~CLogonInfo()
  184. {
  185. Win4Assert( IsSingle() ); // must not be on the list
  186. delete [] _pwszUser;
  187. delete [] _pwszDomain;
  188. if ( INVALID_HANDLE_VALUE != _hToken )
  189. CloseHandle( _hToken );
  190. } //~CLogonInfo
  191. //+---------------------------------------------------------------------------
  192. //
  193. // Member: CLogonInfo::IsSameUser
  194. //
  195. // Synopsis: Tests if the given user and domain match what is stored in
  196. // this object.
  197. //
  198. // Arguments: [pwszUser] - Name of the user
  199. // [pwszDomain] - Name of the domain
  200. //
  201. // Returns: TRUE if same; FALSE o/w
  202. //
  203. // History: 4-05-96 srikants Created
  204. //
  205. //----------------------------------------------------------------------------
  206. BOOL CLogonInfo::IsSameUser( WCHAR const * pwszUser, WCHAR const * pwszDomain ) const
  207. {
  208. ULONG ccUser = pwszUser ? wcslen(pwszUser) : 0;
  209. ULONG ccDomain = pwszDomain ? wcslen(pwszDomain) : 0;
  210. if ( ccUser == _ccUser && ccDomain == _ccDomain )
  211. {
  212. if ( ccUser != 0 && _wcsicmp( pwszUser, _pwszUser ) != 0 )
  213. return FALSE;
  214. if ( ccDomain != 0 && _wcsicmp( pwszDomain, _pwszDomain) != 0 )
  215. return FALSE;
  216. return TRUE;
  217. }
  218. else
  219. return FALSE;
  220. }
  221. //+---------------------------------------------------------------------------
  222. //
  223. // Member: CLogonInfo::IsSamePassword
  224. //
  225. // Synopsis: Tests if the given password is same as the one stored in this.
  226. //
  227. // Arguments: [pwszPassword] - Password to compare.
  228. //
  229. // Returns: TRUE if passwords match; FALSE o/w
  230. //
  231. // History: 4-05-96 srikants Created
  232. //
  233. // Notes:
  234. //
  235. //----------------------------------------------------------------------------
  236. BOOL CLogonInfo::IsSamePassword( WCHAR const * pwszPassword ) const
  237. {
  238. BYTE * pbPW = 0;
  239. DWORD cbPW = 0;
  240. EncryptMemoryPassword( pwszPassword, &pbPW, &cbPW );
  241. XArray<BYTE> xEncryptedPassword;
  242. xEncryptedPassword.Set( cbPW, pbPW );
  243. if ( cbPW == _xEncryptedPassword.Count() )
  244. {
  245. int c = memcmp( pbPW,
  246. _xEncryptedPassword.Get(),
  247. cbPW );
  248. return ( 0 == c );
  249. }
  250. return FALSE;
  251. } //IsSamePassword
  252. //+---------------------------------------------------------------------------
  253. //
  254. // Member: CPhyDirLogonInfo::CPhyDirLogonInfo
  255. //
  256. // Synopsis: Constructor for the object that keeps logon information for a
  257. // specific physical directory
  258. //
  259. // Arguments: [pwszPhyDirName] - Name of the physical directory (remote)
  260. //
  261. // History: 4-02-96 srikants Created
  262. //
  263. //----------------------------------------------------------------------------
  264. CPhyDirLogonInfo::CPhyDirLogonInfo( CImpersonationTokenCache & cache,
  265. CImprsObjInfo const & obj,
  266. CLogonInfo * pLogonInfo )
  267. : _cache( cache ),
  268. _pwszDirName(0),
  269. _pwszVirtualRoot(0),
  270. _ccVirtual(0)
  271. {
  272. Win4Assert( 0 != obj.GetPhysicalPath() );
  273. CDoubleLink::Close();
  274. _fIsZombie = FALSE;
  275. _cRef = 0;
  276. //
  277. // Create a local copy of the physical directory, virtual root and
  278. // save the logon information.
  279. //
  280. _pwszDirName = CLogonInfo::AllocAndCopy( obj.GetPhysicalPath(), _cc );
  281. _phyScope.Init( _pwszDirName, _cc );
  282. if ( 0 != obj.GetVPath() )
  283. {
  284. _pwszVirtualRoot = CLogonInfo::AllocAndCopy( obj.GetVPath(), _ccVirtual );
  285. _virtualScope.Init( _pwszVirtualRoot, _ccVirtual );
  286. }
  287. _pLogonInfo = pLogonInfo;
  288. if ( 0 != _pLogonInfo )
  289. _pLogonInfo->Addref();
  290. }
  291. //+---------------------------------------------------------------------------
  292. //
  293. // Member: CPhyDirLogonInfo::~CPhyDirLogonInfo
  294. //
  295. // Synopsis: Free up the memory and release the logon info.
  296. //
  297. // History: 4-02-96 srikants Created
  298. //
  299. //----------------------------------------------------------------------------
  300. CPhyDirLogonInfo::~CPhyDirLogonInfo()
  301. {
  302. Win4Assert( IsSingle() ); // must not be on the list
  303. delete [] _pwszDirName;
  304. delete [] _pwszVirtualRoot;
  305. if ( 0 != _pLogonInfo )
  306. {
  307. _cache.Release( _pLogonInfo );
  308. }
  309. }
  310. //+---------------------------------------------------------------------------
  311. //
  312. // Member: CImpersonationTokenCache::CImpersonationTokenCache
  313. //
  314. // Synopsis: Constructor of the impersonation token cache.
  315. //
  316. // History: 4-02-96 srikants Created
  317. //
  318. //----------------------------------------------------------------------------
  319. CImpersonationTokenCache::CImpersonationTokenCache(
  320. WCHAR const * pwcCatName )
  321. : _fIndexW3Roots(FALSE),
  322. _fIndexNNTPRoots(FALSE),
  323. _fIndexIMAPRoots(FALSE),
  324. _W3SvcInstance(1),
  325. _NNTPSvcInstance(1),
  326. _IMAPSvcInstance(1),
  327. _fRemoteSharesPresent(FALSE),
  328. _pwszComponentName(0)
  329. {
  330. if ( 0 != pwcCatName )
  331. wcscpy( _awcCatalogName, pwcCatName );
  332. else
  333. _awcCatalogName[0] = 0;
  334. for ( unsigned i = 0; i < CI_MAX_DRIVES;i++ )
  335. _aDriveInfo[i] = eUnknown;
  336. }
  337. //+---------------------------------------------------------------------------
  338. //
  339. // Member: CImpersonationTokenCache::~CImpersonationTokenCache
  340. //
  341. // Synopsis: Release the cached information.
  342. //
  343. // History: 4-02-96 srikants Created
  344. //
  345. //----------------------------------------------------------------------------
  346. CImpersonationTokenCache::~CImpersonationTokenCache()
  347. {
  348. // Release the physical directory list elements
  349. for ( CPhyDirLogonInfo * pDirInfo = _phyDirList.Pop(); 0 != pDirInfo;
  350. pDirInfo = _phyDirList.Pop() )
  351. {
  352. pDirInfo->Close();
  353. delete pDirInfo;
  354. }
  355. delete [] _pwszComponentName;
  356. }
  357. //+---------------------------------------------------------------------------
  358. //
  359. // Member: CImpersonationTokenCache::Find
  360. //
  361. // Synopsis: Locate impersonation information for the given path.
  362. //
  363. // Arguments: [pwszPath] - Path for which impersonation information is
  364. // needed.
  365. //
  366. // Returns: A pointer to the impersonation if lookup is successful.
  367. // NULL otherwise. The returned CPhyDirLogonInfo is AddRefed().
  368. //
  369. // History: 4-02-96 srikants Created
  370. //
  371. // It is assumed that pwszPath is all Lower case.
  372. //
  373. //----------------------------------------------------------------------------
  374. CPhyDirLogonInfo *
  375. CImpersonationTokenCache::Find( WCHAR const * pwszPath, ULONG len )
  376. {
  377. CPhyDirLogonInfo * pDirInfo = 0;
  378. // ====================================================
  379. CLock lock(_mutex);
  380. //
  381. // Try to locate the path in the list
  382. //
  383. for ( CFwdPhyDirLogonIter iter(_phyDirList); !_phyDirList.AtEnd(iter);
  384. _phyDirList.Advance(iter) )
  385. {
  386. if ( iter->IsInScope( pwszPath, len ) )
  387. {
  388. pDirInfo = iter.GetEntry();
  389. break;
  390. }
  391. }
  392. if ( pDirInfo )
  393. {
  394. pDirInfo->AddRef();
  395. }
  396. // ====================================================
  397. return pDirInfo;
  398. }
  399. //+---------------------------------------------------------------------------
  400. //
  401. // Member: CImpersonationTokenCache::Find
  402. //
  403. // Synopsis: Finds a directory logon info for the given object after skipping
  404. // over the specified matched entries.
  405. //
  406. // Arguments: [info] - Information about the VPath and PhysPath and ip
  407. // address.
  408. // [cSkip] - Number of matching entries to skip
  409. //
  410. // Returns:
  411. //
  412. // Modifies:
  413. //
  414. // History: 7-12-96 srikants Created
  415. //
  416. // Notes:
  417. //
  418. //----------------------------------------------------------------------------
  419. CPhyDirLogonInfo *
  420. CImpersonationTokenCache::Find( CImprsObjInfo & info, ULONG cSkip )
  421. {
  422. CPhyDirLogonInfo * pDirInfo = 0;
  423. ULONG cSkipped = 0;
  424. // ====================================================
  425. CLock lock(_mutex);
  426. //
  427. // Try to locate the path in the list
  428. //
  429. for ( CFwdPhyDirLogonIter iter(_phyDirList); !_phyDirList.AtEnd(iter);
  430. _phyDirList.Advance(iter) )
  431. {
  432. if ( iter->IsMatch( info ) )
  433. {
  434. if ( cSkipped == cSkip )
  435. {
  436. pDirInfo = iter.GetEntry();
  437. break;
  438. }
  439. cSkipped++;
  440. }
  441. }
  442. if ( pDirInfo )
  443. {
  444. pDirInfo->AddRef();
  445. }
  446. // ====================================================
  447. return pDirInfo;
  448. }
  449. CPhyDirLogonInfo *
  450. CImpersonationTokenCache::_FindExact( CImprsObjInfo const & info )
  451. {
  452. CPhyDirLogonInfo * pDirInfo = 0;
  453. // ====================================================
  454. CLock lock(_mutex);
  455. //
  456. // Try to locate the path in the list
  457. //
  458. for ( CFwdPhyDirLogonIter iter(_phyDirList); !_phyDirList.AtEnd(iter);
  459. _phyDirList.Advance(iter) )
  460. {
  461. if ( iter->IsSame( info ) )
  462. {
  463. pDirInfo = iter.GetEntry();
  464. break;
  465. }
  466. }
  467. if ( pDirInfo )
  468. {
  469. pDirInfo->AddRef();
  470. }
  471. // ====================================================
  472. return pDirInfo;
  473. }
  474. //+---------------------------------------------------------------------------
  475. //
  476. // Member: CImpersonationTokenCache::_LokFindLogonEntry
  477. //
  478. // Synopsis: Looks up a logon entry for the given name and domain.
  479. //
  480. // Arguments: [pwszUser] -
  481. // [pwszDomain] -
  482. //
  483. // Returns:
  484. //
  485. // History: 4-05-96 srikants Created
  486. //
  487. //----------------------------------------------------------------------------
  488. CLogonInfo *
  489. CImpersonationTokenCache::_LokFindLogonEntry( WCHAR const * pwszUser,
  490. WCHAR const * pwszDomain )
  491. {
  492. for ( CFwdLogonInfoIter iter(g_LogonList); !g_LogonList.AtEnd(iter);
  493. g_LogonList.Advance(iter) )
  494. {
  495. if ( iter->IsSameUser( pwszUser, pwszDomain ) )
  496. return iter.GetEntry();
  497. }
  498. return 0;
  499. }
  500. //+---------------------------------------------------------------------------
  501. //
  502. // Class: CParseAccount
  503. //
  504. // Purpose: A class to parse account of the form domain\username
  505. //
  506. // History: 4-05-96 srikants Created
  507. //
  508. // Notes:
  509. //
  510. //----------------------------------------------------------------------------
  511. class CParseAccount
  512. {
  513. enum { MAX_USER = UNLEN, MAX_DOMAIN = 100 };
  514. public:
  515. CParseAccount( WCHAR const * pwszAccount );
  516. WCHAR const * GetUserName() const { return _wszUser; }
  517. WCHAR const * GetDomainName() const { return _wszDomain; }
  518. WCHAR * GetUserName() { return _wszUser; }
  519. WCHAR * GetDomainName() { return _wszDomain; }
  520. private:
  521. WCHAR _wszUser[MAX_USER];
  522. WCHAR _wszDomain[MAX_DOMAIN];
  523. };
  524. //+---------------------------------------------------------------------------
  525. //
  526. // Member: CParseAccount::CParseAccount
  527. //
  528. // Synopsis: Parses a string of form domain\username into domain and
  529. // username.
  530. //
  531. // Arguments: [pwszAccount] -
  532. //
  533. // History: 4-03-96 srikants Created
  534. //
  535. //----------------------------------------------------------------------------
  536. CParseAccount::CParseAccount( WCHAR const * pwszAccount )
  537. {
  538. _wszUser[0] = _wszDomain[0] = 0;
  539. if ( pwszAccount )
  540. {
  541. int len = wcslen(pwszAccount);
  542. //
  543. // Separate the domain\user into domain and user
  544. //
  545. for ( int i = len-1; i >= 0; i-- )
  546. {
  547. if ( L'\\' == pwszAccount[i] )
  548. break;
  549. }
  550. if ( i < 0 )
  551. {
  552. //
  553. // See if there is a forward slash. Some mistaken users specify the
  554. // userid like that.
  555. //
  556. for ( i = len-1; i >= 0; i-- )
  557. {
  558. if ( L'/' == pwszAccount[i] )
  559. break;
  560. }
  561. }
  562. if ( i > 0 )
  563. {
  564. //
  565. // Copy the domain name
  566. //
  567. RtlCopyMemory( _wszDomain, pwszAccount, i * sizeof(WCHAR) );
  568. _wszDomain[i] = 0;
  569. //
  570. // Copy the user name.
  571. //
  572. RtlCopyMemory( _wszUser, pwszAccount+i+1, (len-i-1)*sizeof(WCHAR) );
  573. _wszUser[len-i-1] = 0;
  574. }
  575. else
  576. {
  577. //
  578. // No backslash was specified. The entire id is the username and
  579. // domain is NULL.
  580. //
  581. RtlCopyMemory( _wszUser, pwszAccount, len*sizeof(WCHAR) );
  582. _wszUser[len] = 0;
  583. }
  584. }
  585. } //CParseAccount
  586. //+---------------------------------------------------------------------------
  587. //
  588. // Member: CImpersonationTokenCache::_LokAddDirEntry
  589. //
  590. // Synopsis: Adds a new entry to the cache for the given account name.
  591. //
  592. // Arguments: [obj] - The impersonation object info
  593. // [pwszAccount] - Name of the account to use for logging on.
  594. //
  595. // History: 4-03-96 srikants Created
  596. //
  597. //----------------------------------------------------------------------------
  598. void CImpersonationTokenCache::_LokAddDirEntry( CImprsObjInfo const & obj,
  599. WCHAR const * pwszAccount )
  600. {
  601. //
  602. // Parse the account name into username and domain.
  603. //
  604. CParseAccount parse( pwszAccount );
  605. _fRemoteSharesPresent = TRUE;
  606. //
  607. // Look up the logon entry.
  608. //
  609. CLogonInfo * pLogonInfo = _LokFindLogonEntry( parse.GetUserName(),
  610. parse.GetDomainName() );
  611. //
  612. // Create the dir entry and add it to the list of physical directories.
  613. //
  614. CPhyDirLogonInfo * pDirInfo = new CPhyDirLogonInfo( *this,
  615. obj,
  616. pLogonInfo );
  617. _phyDirList.Queue( pDirInfo );
  618. } //_LokAddDirEntry
  619. //+---------------------------------------------------------------------------
  620. //
  621. // Member: CImpersonationTokenCache::IsNetworkDrive
  622. //
  623. // Synopsis: Given a drive, check if it is a network drive.
  624. //
  625. // Arguments: [pwszPath] - Path to check.
  626. //
  627. // Returns: TRUE if it is a network drive. FALSE o/w
  628. //
  629. // History: 4-02-96 srikants Created
  630. //
  631. //----------------------------------------------------------------------------
  632. BOOL CImpersonationTokenCache::IsNetworkDrive( WCHAR const * pwszPath )
  633. {
  634. CPathParser parser( pwszPath );
  635. if ( parser.IsUNCName() )
  636. return TRUE;
  637. if ( parser.IsDrivePath() )
  638. {
  639. WCHAR wDriveLetter = pwszPath[0];
  640. unsigned iDrive = _GetDriveIndex( wDriveLetter );
  641. // ====================================================
  642. CLock lock(_mutex);
  643. if ( eUnknown == _aDriveInfo[iDrive] )
  644. {
  645. UINT uType = GetDriveType( pwszPath );
  646. if ( DRIVE_REMOTE == uType )
  647. _aDriveInfo[iDrive] = eRemote;
  648. else
  649. _aDriveInfo[iDrive] = eLocal;
  650. }
  651. return eRemote == _aDriveInfo[iDrive];
  652. // ====================================================
  653. }
  654. else
  655. {
  656. //
  657. // If it is neither a UNC nor a drive letter, it is probably
  658. // a relative name.
  659. //
  660. return FALSE;
  661. }
  662. } //IsNetworkDrive
  663. //+---------------------------------------------------------------------------
  664. //
  665. // Member: CImpersonationTokenCache::_LokValidateOrAddDirEntry
  666. //
  667. // Synopsis: Validates the given path and account. If there is no entry for
  668. // the given path, a new one is added. If the current entry does
  669. // not match the given account info, the current one is zombified
  670. // and a new entry added.
  671. //
  672. // Arguments: [pwszPhyPath] - Physical path
  673. // [pwszAccount] - Account to use for accessing the physical path.
  674. //
  675. // History: 4-05-96 srikants Created
  676. //
  677. //----------------------------------------------------------------------------
  678. void
  679. CImpersonationTokenCache::_LokValidateOrAddDirEntry( CImprsObjInfo const & obj,
  680. WCHAR const * pwszAccount )
  681. {
  682. CPhyDirLogonInfo * pDirInfo = _FindExact( obj );
  683. if ( pDirInfo )
  684. {
  685. CParseAccount account( pwszAccount );
  686. CLogonInfo * pLogonInfo = _LokFindLogonEntry( account.GetUserName(),
  687. account.GetDomainName() );
  688. if ( pLogonInfo == pDirInfo->GetLogonInfo() )
  689. {
  690. // There is no change in logon information.
  691. Win4Assert( !pLogonInfo || !pLogonInfo->IsZombie() );
  692. Release(pDirInfo);
  693. return;
  694. }
  695. //
  696. // The logon information has changed for this directory.
  697. // So, we must zombify the current entry and create a new one.
  698. //
  699. _phyDirList.RemoveFromList( pDirInfo );
  700. pDirInfo->Close();
  701. pDirInfo->Zombify();
  702. Release( pDirInfo );
  703. pDirInfo = 0;
  704. }
  705. Win4Assert( 0 == pDirInfo );
  706. _LokAddDirEntry( obj, pwszAccount );
  707. } //_LokValidateOrAddDirEntry
  708. //+---------------------------------------------------------------------------
  709. //
  710. // Member: CImpersonationTokenCache::_LokValidateOrAddLogonEntry
  711. //
  712. // Synopsis: Validate the logon entry. If there is no logon entry for
  713. // the given account, add a new one. If the current one does not
  714. // match the given one, zombify the current one and replace it
  715. // with the new information.
  716. //
  717. // Arguments: [pwszUser] - Username of the account
  718. // [pwszDomain] - Domain of the account
  719. // [pwszPassword] - Password to use for logging this account/
  720. //
  721. // History: 4-05-96 srikants Created
  722. //
  723. //----------------------------------------------------------------------------
  724. DWORD
  725. CImpersonationTokenCache::_LokValidateOrAddLogonEntry(
  726. WCHAR const * pwszUser,
  727. WCHAR const * pwszDomain,
  728. WCHAR const * pwszPassword )
  729. {
  730. CLogonInfo * pLogonInfo = _LokFindLogonEntry( pwszUser, pwszDomain );
  731. if ( pLogonInfo )
  732. {
  733. if ( pLogonInfo->IsSamePassword( pwszPassword ) )
  734. return NO_ERROR;
  735. //
  736. // Invalidate the logon information.
  737. //
  738. g_LogonList.RemoveFromList( pLogonInfo );
  739. pLogonInfo->Close();
  740. pLogonInfo->Zombify();
  741. pLogonInfo->Addref();
  742. Release( pLogonInfo );
  743. pLogonInfo = 0;
  744. }
  745. Win4Assert( 0 == pLogonInfo );
  746. //
  747. // Create a new logon entry for the user and password.
  748. //
  749. pLogonInfo = new CLogonInfo;
  750. XPtr<CLogonInfo> xLogonInfo(pLogonInfo);
  751. DWORD status = pLogonInfo->Logon( pwszUser, pwszDomain, pwszPassword );
  752. if ( 0 == status )
  753. {
  754. xLogonInfo.Acquire();
  755. g_LogonList.Push( pLogonInfo );
  756. }
  757. return status;
  758. } //_LokValidateOrAddLogonEntry
  759. //+---------------------------------------------------------------------------
  760. //
  761. // Class: CIISCallBackImp
  762. //
  763. // Purpose: Callback to parse IIS scopes and save impersonation
  764. // information for each.
  765. //
  766. // History: 30-Oct-96 dlee created
  767. //
  768. //----------------------------------------------------------------------------
  769. class CIISCallBackImp : public CMetaDataCallBack
  770. {
  771. public:
  772. CIISCallBackImp( CImpersonationTokenCache & cache ) :
  773. _cache( cache )
  774. {
  775. }
  776. SCODE CallBack( WCHAR const * pwcVPath,
  777. WCHAR const * pwcPPath,
  778. BOOL fIsIndexed,
  779. DWORD dwAccess,
  780. WCHAR const * pwcUser,
  781. WCHAR const * pwcPassword,
  782. BOOL fIsAVRoot )
  783. {
  784. ciDebugOut(( DEB_ITRACE,
  785. "CIISCallBackImp checking c '%ws', vp '%ws', pp '%ws' i %d, u '%ws' pw '%ws', isavroot: %d\n",
  786. _cache.GetCatalog(),
  787. pwcVPath,
  788. pwcPPath,
  789. fIsIndexed,
  790. pwcUser,
  791. pwcPassword,
  792. fIsAVRoot ));
  793. // If there's a vroot scope on a remote drive, a username, and a
  794. // password, save the token info.
  795. if ( ( fIsAVRoot ) &&
  796. ( fIsIndexed ) &&
  797. ( _cache.IsNetworkDrive( pwcPPath ) ) &&
  798. ( 0 != pwcUser[0] ) )
  799. {
  800. ciDebugOut(( DEB_ITRACE, "CIISCallBackImp adding\n" ));
  801. {
  802. CParseAccount parser( pwcUser );
  803. DWORD status = _cache._LokValidateOrAddLogonEntry(
  804. parser.GetUserName(),
  805. parser.GetDomainName(),
  806. pwcPassword );
  807. if ( NO_ERROR != status )
  808. _cache._WriteLogonFailure( pwcUser, status );
  809. }
  810. {
  811. // normalize both the physical and virtual paths
  812. // to lowercase
  813. CLowcaseBuf lcasePhyDir( pwcPPath );
  814. lcasePhyDir.AppendBackSlash();
  815. // vpaths in ci always have backslashes, not slashes
  816. unsigned cwc = wcslen( pwcVPath );
  817. if ( cwc >= MAX_PATH )
  818. return S_OK;
  819. WCHAR awcVPath[ MAX_PATH ];
  820. for ( unsigned x = 0; x <= cwc; x++ )
  821. {
  822. if ( L'/' == pwcVPath[x] )
  823. awcVPath[ x ] = L'\\';
  824. else
  825. awcVPath[ x ] = pwcVPath[ x ];
  826. }
  827. CLowcaseBuf lcaseVPath( awcVPath );
  828. CImprsObjInfo info( lcasePhyDir.Get(),
  829. lcaseVPath.Get() );
  830. _cache._LokValidateOrAddDirEntry( info, pwcUser );
  831. }
  832. }
  833. return S_OK;
  834. }
  835. private:
  836. CImpersonationTokenCache & _cache;
  837. };
  838. //+---------------------------------------------------------------------------
  839. //
  840. // Member: CImpersonationTokenCache::ReInitializeIISScopes
  841. //
  842. // Synopsis: ReInitialize the token cache for iis
  843. //
  844. // History: 2-Sep-97 dlee created
  845. //
  846. //----------------------------------------------------------------------------
  847. void CImpersonationTokenCache::ReInitializeIISScopes(
  848. CIISVirtualDirectories * pW3Dirs,
  849. CIISVirtualDirectories * pNNTPDirs,
  850. CIISVirtualDirectories * pIMAPDirs )
  851. {
  852. ciDebugOut(( DEB_ITRACE, "reinit iis impersonation fast\n" ));
  853. CLock lock( _mutex );
  854. Win4Assert( 0 != _pwszComponentName );
  855. CImpersonateSystem impersonate;
  856. if ( _fIndexW3Roots )
  857. {
  858. CIISCallBackImp callBack( *this );
  859. Win4Assert( 0 != pW3Dirs );
  860. pW3Dirs->Enum( callBack );
  861. }
  862. if ( _fIndexNNTPRoots )
  863. {
  864. CIISCallBackImp callBack( *this );
  865. Win4Assert( 0 != pNNTPDirs );
  866. pNNTPDirs->Enum( callBack );
  867. }
  868. if ( _fIndexIMAPRoots )
  869. {
  870. CIISCallBackImp callBack( *this );
  871. Win4Assert( 0 != pIMAPDirs );
  872. pIMAPDirs->Enum( callBack );
  873. }
  874. ciDebugOut(( DEB_ITRACE, "reinit iis impersonation fast (done)\n" ));
  875. } //ReInitializeIISScopes
  876. //+---------------------------------------------------------------------------
  877. //
  878. // Member: CImpersonationTokenCache::ReInitializeIISScopes
  879. //
  880. // Synopsis: ReInitialize the token cache for iis
  881. //
  882. // History: 4-02-96 srikants Created
  883. // 2-12-97 dlee Reimplemented for metabase
  884. //
  885. //----------------------------------------------------------------------------
  886. void CImpersonationTokenCache::ReInitializeIISScopes()
  887. {
  888. ciDebugOut(( DEB_ITRACE, "reinit iis impersonation slow\n" ));
  889. CLock lock( _mutex );
  890. Win4Assert( 0 != _pwszComponentName );
  891. CImpersonateSystem impersonate;
  892. if ( _fIndexW3Roots )
  893. {
  894. TRY
  895. {
  896. CIISVirtualDirectories dirs( W3VRoot );
  897. {
  898. CMetaDataMgr mdMgr( FALSE, W3VRoot, _W3SvcInstance );
  899. mdMgr.EnumVPaths( dirs );
  900. }
  901. CIISCallBackImp callBack( *this );
  902. dirs.Enum( callBack );
  903. }
  904. CATCH( CException, e )
  905. {
  906. ciDebugOut(( DEB_WARN,
  907. "exception getting logon info for w3\n" ));
  908. }
  909. END_CATCH
  910. }
  911. //
  912. // If the news server is enabled, we have to read the news server
  913. // virtual roots and process them.
  914. //
  915. if ( _fIndexNNTPRoots )
  916. {
  917. TRY
  918. {
  919. CIISVirtualDirectories dirs( NNTPVRoot );
  920. {
  921. CMetaDataMgr mdMgr( FALSE, NNTPVRoot, _NNTPSvcInstance );
  922. mdMgr.EnumVPaths( dirs );
  923. }
  924. CIISCallBackImp callBack( *this );
  925. dirs.Enum( callBack );
  926. }
  927. CATCH( CException, e )
  928. {
  929. ciDebugOut(( DEB_WARN,
  930. "exception getting logon info for nntp\n" ));
  931. }
  932. END_CATCH
  933. }
  934. if ( _fIndexIMAPRoots )
  935. {
  936. TRY
  937. {
  938. CIISVirtualDirectories dirs( IMAPVRoot );
  939. {
  940. CMetaDataMgr mdMgr( FALSE, IMAPVRoot, _IMAPSvcInstance );
  941. mdMgr.EnumVPaths( dirs );
  942. }
  943. CIISCallBackImp callBack( *this );
  944. dirs.Enum( callBack );
  945. }
  946. CATCH( CException, e )
  947. {
  948. ciDebugOut(( DEB_WARN,
  949. "exception getting logon info for imap\n" ));
  950. }
  951. END_CATCH
  952. }
  953. ciDebugOut(( DEB_ITRACE, "reinit iis impersonation slow (done)\n" ));
  954. } //ReInitializeIISScopes
  955. //+---------------------------------------------------------------------------
  956. //
  957. // Class: CRegistryScopesCallBackImp
  958. //
  959. // Purpose: Callback to parse registry scopes and save impersonation
  960. // information for each.
  961. //
  962. // History: 30-Oct-96 dlee created
  963. //
  964. //----------------------------------------------------------------------------
  965. class CRegistryScopesCallBackImp : public CRegCallBack
  966. {
  967. public:
  968. CRegistryScopesCallBackImp(
  969. CImpersonationTokenCache & cache ) :
  970. _cache( cache )
  971. {
  972. }
  973. NTSTATUS CallBack( WCHAR *pValueName, ULONG uValueType,
  974. VOID *pValueData, ULONG uValueLength)
  975. {
  976. TRY
  977. {
  978. CParseRegistryScope parse( pValueName,
  979. uValueType,
  980. pValueData,
  981. uValueLength );
  982. ciDebugOut(( DEB_ITRACE,
  983. "CRegistryScopesCallBackImp checking c '%ws', s '%ws' u '%ws' pw '%ws'\n",
  984. _cache.GetCatalog(),
  985. parse.GetScope(),
  986. parse.GetUsername(),
  987. parse.GetPassword( _cache.GetCatalog() ) ));
  988. // If there's a scope on a remote drive, a username, and a
  989. // password, save the token info.
  990. if ( ( 0 != parse.GetScope() ) &&
  991. ( _cache.IsNetworkDrive( parse.GetScope() ) ) &&
  992. ( 0 != parse.GetUsername() ) &&
  993. ( 0 != parse.GetPassword( _cache.GetCatalog() ) ) )
  994. {
  995. ciDebugOut(( DEB_ITRACE, "CRegistryScopesCallBackImp adding\n" ));
  996. {
  997. CParseAccount parser( parse.GetUsername() );
  998. DWORD status = _cache._LokValidateOrAddLogonEntry(
  999. parser.GetUserName(),
  1000. parser.GetDomainName(),
  1001. parse.GetPassword( _cache.GetCatalog() ) );
  1002. if ( NO_ERROR != status )
  1003. _cache._WriteLogonFailure( parse.GetUsername(), status );
  1004. }
  1005. {
  1006. CLowcaseBuf lcasePhyDir( parse.GetScope() );
  1007. lcasePhyDir.AppendBackSlash();
  1008. CImprsObjInfo info( lcasePhyDir.Get(), 0 );
  1009. _cache._LokValidateOrAddDirEntry( info, parse.GetUsername() );
  1010. }
  1011. }
  1012. }
  1013. CATCH( CException, e )
  1014. {
  1015. ciDebugOut(( DEB_ERROR,
  1016. "CRegistryScopesCallBackImp::CallBack caught error 0x%x\n",
  1017. e.GetErrorCode() ));
  1018. }
  1019. END_CATCH;
  1020. return S_OK;
  1021. }
  1022. private:
  1023. CImpersonationTokenCache & _cache;
  1024. }; //CRegistryScopesCallBackImp
  1025. //+---------------------------------------------------------------------------
  1026. //
  1027. // Member: CImpersonationTokenCache::ReInitializeScopes
  1028. //
  1029. // Synopsis: ReInitialize the token cache for remote registry scopes
  1030. //
  1031. // History: 10-24-96 dlee Created
  1032. //
  1033. //----------------------------------------------------------------------------
  1034. void CImpersonationTokenCache::ReInitializeScopes()
  1035. {
  1036. CLock lock( _mutex );
  1037. Win4Assert( 0 != _pwszComponentName );
  1038. // if the catalog isn't named, it can't have any scopes in the registry
  1039. if ( 0 == _awcCatalogName[0] )
  1040. return;
  1041. CImpersonateSystem impersonate;
  1042. TRY
  1043. {
  1044. XArray<WCHAR> xKey;
  1045. BuildRegistryScopesKey( xKey, _awcCatalogName );
  1046. ciDebugOut(( DEB_ITRACE, "Reading scope impinfo '%ws'\n", xKey.Get() ));
  1047. CRegAccess regScopes( RTL_REGISTRY_ABSOLUTE, xKey.Get() );
  1048. CRegistryScopesCallBackImp callback( *this );
  1049. regScopes.EnumerateValues( 0, callback );
  1050. }
  1051. CATCH( CException, e )
  1052. {
  1053. ciDebugOut(( DEB_WARN,
  1054. "Exception 0x%x caught groveling ci registry for impersonation info\n",
  1055. e.GetErrorCode() ));
  1056. }
  1057. END_CATCH
  1058. } //ReInitializeScopes
  1059. //+---------------------------------------------------------------------------
  1060. //
  1061. // Member: CImpersonationTokenCache::_WriteLogonFailure
  1062. //
  1063. // Synopsis: Writes an event to the event log that a logon failure
  1064. // occurred.
  1065. //
  1066. // Arguments: [pwszUser] - Id of the user
  1067. // [dwError] - Error
  1068. //
  1069. // History: 5-24-96 srikants Created
  1070. //
  1071. // Notes:
  1072. //
  1073. //----------------------------------------------------------------------------
  1074. void CImpersonationTokenCache::_WriteLogonFailure( WCHAR const * pwszUser,
  1075. DWORD dwError )
  1076. {
  1077. TRY
  1078. {
  1079. CEventLog eventLog( NULL, wcsCiEventSource );
  1080. if ( ERROR_LOGON_TYPE_NOT_GRANTED != dwError )
  1081. {
  1082. CEventItem item( EVENTLOG_ERROR_TYPE,
  1083. CI_SERVICE_CATEGORY,
  1084. MSG_CI_REMOTE_LOGON_FAILURE,
  1085. 3 );
  1086. Win4Assert( 0 != _pwszComponentName );
  1087. item.AddArg( _pwszComponentName );
  1088. item.AddArg( pwszUser );
  1089. item.AddError( dwError );
  1090. eventLog.ReportEvent( item );
  1091. }
  1092. else
  1093. {
  1094. //
  1095. // The specified user-id has no interactive logon privilege on
  1096. // this machine.
  1097. //
  1098. CEventItem item( EVENTLOG_ERROR_TYPE,
  1099. CI_SERVICE_CATEGORY,
  1100. MSG_CI_NO_INTERACTIVE_LOGON_PRIVILEGE,
  1101. 1 );
  1102. item.AddArg( pwszUser );
  1103. eventLog.ReportEvent( item );
  1104. }
  1105. }
  1106. CATCH( CException, e )
  1107. {
  1108. ciDebugOut(( DEB_ERROR, "Exception 0x%X while writing to event log\n",
  1109. e.GetErrorCode() ));
  1110. }
  1111. END_CATCH
  1112. } //_WriteLogonFailure
  1113. //+---------------------------------------------------------------------------
  1114. //
  1115. // Method: CImpersonationTokenCache::Initialize
  1116. //
  1117. // Synopsis: Initializes the token cache.
  1118. //
  1119. // History: 4-04-96 srikants Created
  1120. // 10-22-96 dlee global => member
  1121. //
  1122. //----------------------------------------------------------------------------
  1123. void CImpersonationTokenCache::Initialize(
  1124. WCHAR const * pwszComponent,
  1125. BOOL fIndexW3Roots,
  1126. BOOL fIndexNNTPRoots,
  1127. BOOL fIndexIMAPRoots,
  1128. ULONG W3SvcInstance,
  1129. ULONG NNTPSvcInstance,
  1130. ULONG IMAPSvcInstance )
  1131. {
  1132. Win4Assert( 0 == _pwszComponentName );
  1133. unsigned len = wcslen( pwszComponent );
  1134. _pwszComponentName = new WCHAR [len+1];
  1135. RtlCopyMemory( _pwszComponentName, pwszComponent, (len+1)*sizeof(WCHAR) );
  1136. _fIndexW3Roots = fIndexW3Roots;
  1137. _fIndexNNTPRoots = fIndexNNTPRoots;
  1138. _fIndexIMAPRoots = fIndexIMAPRoots;
  1139. _W3SvcInstance = W3SvcInstance;
  1140. _NNTPSvcInstance = NNTPSvcInstance;
  1141. _IMAPSvcInstance = IMAPSvcInstance;
  1142. if ( fIndexW3Roots || fIndexNNTPRoots || fIndexIMAPRoots )
  1143. ReInitializeIISScopes();
  1144. ReInitializeScopes();
  1145. } //Initialize
  1146. //+---------------------------------------------------------------------------
  1147. //
  1148. // Member: Constructor for CImpersonateRemoteAccess
  1149. //
  1150. // History: 4-03-96 srikants Created
  1151. //
  1152. //----------------------------------------------------------------------------
  1153. CImpersonateRemoteAccess::CImpersonateRemoteAccess(
  1154. CImpersonationTokenCache * pCache ) :
  1155. _pCache( pCache ),
  1156. _pTokenInfo( 0 ),
  1157. _hTokenPrev( INVALID_HANDLE_VALUE ),
  1158. _fMustRevert( FALSE )
  1159. {
  1160. }
  1161. //+---------------------------------------------------------------------------
  1162. //
  1163. // Member: CImpersonateRemoteAccess::_ImpersonateIf
  1164. //
  1165. // Synopsis: Impersonates if necessary for the given path.
  1166. //
  1167. // Arguments: [pwszPath] - Given path.
  1168. //
  1169. // History: 4-03-96 srikants Created
  1170. //
  1171. //----------------------------------------------------------------------------
  1172. BOOL CImpersonateRemoteAccess::_ImpersonateIf( WCHAR const * pwszPath,
  1173. WCHAR const * pwszVPath,
  1174. ULONG cSkip )
  1175. {
  1176. DWORD dwError = 0;
  1177. if ( _pCache->IsNetworkDrive(pwszPath) )
  1178. {
  1179. //
  1180. // If we have already impersonated for the given share, then nothing
  1181. // to do.
  1182. //
  1183. CLowcaseBuf lcasePath( pwszPath );
  1184. lcasePath.AppendBackSlash();
  1185. //
  1186. // It has been assumed that the VPath is already in lowercase and
  1187. // the forward slashes are converted to back slashes.
  1188. //
  1189. CImprsObjInfo obj( lcasePath.Get(), pwszVPath );
  1190. if ( IsImpersonated() )
  1191. {
  1192. Win4Assert( 0 != _pTokenInfo );
  1193. if ( !_pTokenInfo->IsZombie() &&
  1194. _pTokenInfo->IsMatch(obj) )
  1195. {
  1196. ciDebugOut(( DEB_ITRACE, "Already impersonated for (%ws)\n",
  1197. lcasePath.Get() ));
  1198. return TRUE;
  1199. }
  1200. else
  1201. {
  1202. Release(); // Release the current impersonation
  1203. }
  1204. }
  1205. BOOL fSuccess = OpenThreadToken( GetCurrentThread(),
  1206. TOKEN_QUERY | TOKEN_IMPERSONATE,
  1207. TRUE, // Access check against process
  1208. &_hTokenPrev );
  1209. if ( !fSuccess )
  1210. {
  1211. dwError = GetLastError();
  1212. if ( ERROR_NO_TOKEN == dwError )
  1213. {
  1214. //
  1215. // This thread is currently not impersonating anyone.
  1216. //
  1217. }
  1218. else
  1219. {
  1220. ciDebugOut(( DEB_ERROR, "Failed to open thread token. Error %d\n",
  1221. dwError ));
  1222. THROW( CException( HRESULT_FROM_WIN32(dwError)) );
  1223. }
  1224. }
  1225. //
  1226. // Get the impersonation information for the path.
  1227. //
  1228. _pTokenInfo = _pCache->Find( obj, cSkip );
  1229. if ( 0 == _pTokenInfo )
  1230. {
  1231. ciDebugOut(( DEB_WARN, "There is no %simpersonation info for (%ws)\n",
  1232. cSkip > 0 ? "more " : "",
  1233. lcasePath.Get() ));
  1234. return FALSE;
  1235. }
  1236. if ( INVALID_HANDLE_VALUE == _pTokenInfo->GetHandle() )
  1237. return FALSE;
  1238. //
  1239. // Impersonate the specified user.
  1240. //
  1241. fSuccess = ImpersonateLoggedOnUser( _pTokenInfo->GetHandle() );
  1242. if ( !fSuccess )
  1243. {
  1244. dwError = GetLastError();
  1245. ciDebugOut(( DEB_WARN, "Error (%d) while impersonating for path (%ws)\n",
  1246. dwError, pwszPath ));
  1247. return FALSE;
  1248. }
  1249. #if CIDBG == 1
  1250. ciDebugOut(( DEB_ITRACE, "Impersonated successfully for (%ws)\n",
  1251. pwszPath ));
  1252. CLogonInfo &li = *_pTokenInfo->GetLogonInfo();
  1253. ciDebugOut(( DEB_ITRACE, " using user %ws\\%ws\n",
  1254. li.GetDomain(), li.GetUser() ));
  1255. #endif
  1256. _fMustRevert = TRUE;
  1257. }
  1258. return TRUE;
  1259. } //_ImpersonateIf
  1260. //+---------------------------------------------------------------------------
  1261. //
  1262. // Member: CImpersonateRemoteAccess::Release
  1263. //
  1264. // Synopsis: Releases the resources that were used for impersonation.
  1265. //
  1266. // History: 4-04-96 srikants Created
  1267. //
  1268. //----------------------------------------------------------------------------
  1269. void CImpersonateRemoteAccess::Release()
  1270. {
  1271. DWORD dwError = 0;
  1272. if ( _fMustRevert )
  1273. {
  1274. if ( INVALID_HANDLE_VALUE != _hTokenPrev )
  1275. {
  1276. //
  1277. // This is bad -- if the impersonate fails then we're hosed.
  1278. // There are two cases where this is used, and neither case
  1279. // is bad enough to change the code.
  1280. //
  1281. // 1) webhits when it's run in a worker process
  1282. // If the IIS thread is in a bad state (with the wrong token)
  1283. // IIS will clean it up. So there is no problem here.
  1284. //
  1285. // 2) enumeration queries on remote scopes
  1286. // I don't think there is a security problem here; just a
  1287. // functionality problem. The thread is now the user issuing
  1288. // the query instead of the account used for the remote scope.
  1289. // But a RevertToSelf will happen very soon, so it'll be
  1290. // cleaned up in any case (since RevertToSelf isn't allowed to fail).
  1291. // No real work will happen until the RevertToSelf
  1292. //
  1293. BOOL fResult = ImpersonateLoggedOnUser( _hTokenPrev );
  1294. if ( !fResult )
  1295. {
  1296. dwError = GetLastError();
  1297. ciDebugOut(( DEB_WARN, "ImpersonateLoggedOnUser failed with error %d\n",
  1298. dwError ));
  1299. }
  1300. }
  1301. else
  1302. {
  1303. //
  1304. // There was no impersonation token - just revert to self.
  1305. // Note: We assume RevertToSelf can't fail. MikeHow says we have
  1306. // to assume it'll work since we don't know what to do otherwise.
  1307. //
  1308. BOOL fResult = RevertToSelf();
  1309. if ( !fResult )
  1310. {
  1311. dwError = GetLastError();
  1312. ciDebugOut(( DEB_ERROR, "RevertToSelf failed with error %d\n",
  1313. dwError ));
  1314. }
  1315. }
  1316. }
  1317. if ( _pTokenInfo )
  1318. _pCache->Release( _pTokenInfo );
  1319. if ( INVALID_HANDLE_VALUE != _hTokenPrev )
  1320. CloseHandle( _hTokenPrev );
  1321. _fMustRevert = FALSE;
  1322. _pTokenInfo = 0;
  1323. _hTokenPrev = INVALID_HANDLE_VALUE;
  1324. } //Release
  1325. //+---------------------------------------------------------------------------
  1326. //
  1327. // Member: PImpersonatedWorkItem::ImpersonateAndDoWork
  1328. //
  1329. // Synopsis: Calls the DoIt() virtual method after impersonating.
  1330. //
  1331. // Arguments: [access] - The remote access object to use for impersonation.
  1332. //
  1333. // History: 7-15-96 srikants Created
  1334. //
  1335. // Notes: Calls the DoIt() method until it either returns TRUE or there
  1336. // is an exception.
  1337. //
  1338. //----------------------------------------------------------------------------
  1339. void PImpersonatedWorkItem::ImpersonateAndDoWork( CImpersonateRemoteAccess & access )
  1340. {
  1341. ULONG cSkip = 0;
  1342. if ( _fNetPath )
  1343. {
  1344. while ( TRUE )
  1345. {
  1346. BOOL fSuccess = access.ImpersonateIf( _pwszPath, cSkip, 0 );
  1347. if ( !access.IsTokenFound() )
  1348. THROW( CException( STATUS_LOGON_FAILURE ) );
  1349. if ( fSuccess && DoIt() )
  1350. break;
  1351. cSkip++;
  1352. access.Release();
  1353. }
  1354. }
  1355. else
  1356. {
  1357. if ( access.IsImpersonated() )
  1358. {
  1359. //
  1360. // Just revert back to what it was
  1361. //
  1362. access.Release();
  1363. }
  1364. DoIt();
  1365. }
  1366. } //ImpersonateAndDoWork
  1367. //+---------------------------------------------------------------------------
  1368. //
  1369. // Member: CImpersonatedGetAttr::DoIt
  1370. //
  1371. // Synopsis: Does the actual work of getting attributes.
  1372. //
  1373. // Returns: TRUE if successful; FALSE if should be retried; THROWS
  1374. // otherwise.
  1375. //
  1376. // History: 7-18-96 srikants Created
  1377. //
  1378. //----------------------------------------------------------------------------
  1379. BOOL CImpersonatedGetAttr::DoIt()
  1380. {
  1381. if ( !GetFileAttributesEx( _funnyPath.GetPath(), GetFileExInfoStandard, &_ffData ) )
  1382. {
  1383. DWORD dwError = GetLastError();
  1384. if ( IsRetryableError( (NTSTATUS) dwError ) )
  1385. {
  1386. return FALSE;
  1387. }
  1388. else
  1389. {
  1390. ciDebugOut(( DEB_ERROR, "Error 0x%X while starting scan on path (%ws)\n",
  1391. dwError, _funnyPath.GetPath() ));
  1392. THROW( CException( HRESULT_FROM_WIN32(dwError)) );
  1393. return FALSE;
  1394. }
  1395. }
  1396. else return TRUE;
  1397. } //DoIt
  1398. //+---------------------------------------------------------------------------
  1399. //
  1400. // Member: CImpersonatedGetFileAttr::DoIt
  1401. //
  1402. // Synopsis: Does the actual work of getting attributes.
  1403. //
  1404. // Returns: TRUE if successful; FALSE if should be retried; THROWS
  1405. // otherwise.
  1406. //
  1407. // History: 12-05-01 dlee Created
  1408. //
  1409. //----------------------------------------------------------------------------
  1410. BOOL CImpersonatedGetFileAttr::DoIt()
  1411. {
  1412. ULONG ulAttr = GetFileAttributes( _funnyPath.GetPath() );
  1413. if ( INVALID_FILE_ATTRIBUTES == ulAttr )
  1414. {
  1415. DWORD dwError = GetLastError();
  1416. if ( IsRetryableError( (NTSTATUS) dwError ) )
  1417. {
  1418. return FALSE;
  1419. }
  1420. ciDebugOut(( DEB_ERROR, "Error %#x while getting file attributes (%ws)\n",
  1421. dwError, _funnyPath.GetPath() ));
  1422. THROW( CException( HRESULT_FROM_WIN32(dwError)) );
  1423. }
  1424. _ulAttr = ulAttr;
  1425. return TRUE;
  1426. } //DoIt