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
1677 lines
49 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1996 - 1998.
|
|
//
|
|
// File: imprsnat.cxx
|
|
//
|
|
// Contents:
|
|
//
|
|
// Classes:
|
|
//
|
|
// Functions:
|
|
//
|
|
// History: 2-16-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include <pch.cxx>
|
|
#pragma hdrstop
|
|
|
|
#include <wincrypt.h>
|
|
|
|
#include <imprsnat.hxx>
|
|
#include <pathpars.hxx>
|
|
#include <smatch.hxx>
|
|
#include <regacc.hxx>
|
|
#include <regevent.hxx>
|
|
#include <regscp.hxx>
|
|
#include <ciregkey.hxx>
|
|
#include <cievtmsg.h>
|
|
#include <eventlog.hxx>
|
|
#include <cimbmgr.hxx>
|
|
#include <lcase.hxx>
|
|
|
|
#include "cicat.hxx"
|
|
#include "catreg.hxx"
|
|
|
|
// List of logon information, shared between catalogs to help reduce
|
|
// the problem of running out of logon instances.
|
|
|
|
CLogonInfoList g_LogonList;
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: EncryptMemoryPassword
|
|
//
|
|
// Synopsis: Encrypts a password in memory so it can be held in RAM a long
|
|
// time without worrying about the password being easily
|
|
// visible in crashdumps or the pagefile.
|
|
//
|
|
// Arguments: [pwcClearTextPassword] -- The password to encrypt
|
|
// [ppbEncrypted] -- Returns a buffer allocated with
|
|
// operator new with the encrypted pw.
|
|
// [pcbEncrypted] -- Count of bytes allocated
|
|
//
|
|
// History: 4-05-02 dlee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void EncryptMemoryPassword(
|
|
WCHAR const * pwcClearTextPassword,
|
|
BYTE * * ppbEncrypted,
|
|
DWORD * pcbEncrypted )
|
|
{
|
|
*ppbEncrypted = 0;
|
|
*pcbEncrypted = 0;
|
|
|
|
if ( 0 == pwcClearTextPassword )
|
|
return;
|
|
|
|
DWORD cbLen = ( wcslen( pwcClearTextPassword ) + 1 ) * sizeof( WCHAR );
|
|
|
|
ULONG cBlocks = cbLen / CRYPTPROTECTMEMORY_BLOCK_SIZE;
|
|
if ( 0 != ( cbLen % CRYPTPROTECTMEMORY_BLOCK_SIZE ) )
|
|
cBlocks++;
|
|
|
|
ULONG cbToAlloc = cBlocks * CRYPTPROTECTMEMORY_BLOCK_SIZE;
|
|
XArray<BYTE> xEncrypted( cbToAlloc );
|
|
ZeroMemory( xEncrypted.Get(), cbToAlloc );
|
|
|
|
Win4Assert( cbToAlloc >= cbLen );
|
|
RtlCopyMemory( xEncrypted.Get(), pwcClearTextPassword, cbLen );
|
|
|
|
BOOL fOK = CryptProtectMemory( xEncrypted.Get(),
|
|
cbToAlloc,
|
|
CRYPTPROTECTMEMORY_SAME_PROCESS );
|
|
if ( !fOK )
|
|
{
|
|
SCODE sc = HRESULT_FROM_WIN32( GetLastError() );
|
|
|
|
// Don't leave the copy of the pw in memory
|
|
|
|
SecureZeroMemory( xEncrypted.Get(), cbToAlloc );
|
|
|
|
THROW( CException( sc ) );
|
|
}
|
|
|
|
*ppbEncrypted = xEncrypted.Acquire();
|
|
*pcbEncrypted = cbToAlloc;
|
|
} //EncryptMemoryPassword
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CLogonInfoList::Empty
|
|
//
|
|
// Synopsis: Empties the logon list
|
|
//
|
|
// History: 2-19-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CLogonInfoList::Empty()
|
|
{
|
|
for ( CLogonInfo * pLogonInfo = g_LogonList.Pop();
|
|
0 != pLogonInfo;
|
|
pLogonInfo = g_LogonList.Pop() )
|
|
{
|
|
pLogonInfo->Close();
|
|
delete pLogonInfo;
|
|
}
|
|
} //Empty
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AllocAndCopy
|
|
//
|
|
// Synopsis: A helper function to allocate and copy the source string into
|
|
// a destination string.
|
|
//
|
|
// Arguments: [pSrc] -
|
|
// [cc] -
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 4-08-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
WCHAR * CLogonInfo::AllocAndCopy( const WCHAR * pSrc, ULONG & cc )
|
|
{
|
|
WCHAR * pDst = 0;
|
|
if ( 0 != pSrc )
|
|
{
|
|
cc = wcslen( pSrc );
|
|
pDst = new WCHAR [cc+1];
|
|
RtlCopyMemory( pDst, pSrc, (cc+1)*sizeof(WCHAR) );
|
|
}
|
|
else
|
|
{
|
|
cc = 0;
|
|
}
|
|
|
|
return pDst;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CLogonInfo::Logon
|
|
//
|
|
// Synopsis: Logon the given user with the given password.
|
|
//
|
|
// Arguments: [pwszUser] - User name
|
|
// [pwszDomain] - Domain name
|
|
// [pwszPassword] - Password (in clear text) to use.
|
|
//
|
|
// Returns: Status of the operation.
|
|
//
|
|
// History: 4-02-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD CLogonInfo::Logon( WCHAR const * pwszUser,
|
|
WCHAR const * pwszDomain,
|
|
WCHAR const * pwszPassword )
|
|
{
|
|
Win4Assert( 0 == _pwszUser );
|
|
Win4Assert( 0 == _pwszDomain );
|
|
|
|
_pwszUser = AllocAndCopy( pwszUser, _ccUser );
|
|
_pwszDomain = AllocAndCopy( pwszDomain, _ccDomain );
|
|
|
|
BYTE * pbPW = 0;
|
|
DWORD cbPW = 0;
|
|
EncryptMemoryPassword( pwszPassword, &pbPW, &cbPW );
|
|
|
|
_xEncryptedPassword.Free();
|
|
_xEncryptedPassword.Set( cbPW, pbPW );
|
|
|
|
Win4Assert( INVALID_HANDLE_VALUE == _hToken );
|
|
|
|
DWORD dwError = 0;
|
|
|
|
if ( !LogonUser( _pwszUser, _pwszDomain, pwszPassword,
|
|
LOGON32_LOGON_INTERACTIVE,
|
|
LOGON32_PROVIDER_DEFAULT,
|
|
&_hToken ) )
|
|
{
|
|
dwError = GetLastError();
|
|
ciDebugOut(( DEB_ERROR, "Failure to logon user (%ws) domain (%ws). Error 0x%X\n",
|
|
pwszUser, pwszDomain, dwError ));
|
|
_hToken = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
return dwError;
|
|
} //Logon
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CLogonInfo::~CLogonInfo
|
|
//
|
|
// Synopsis: Frees up memory and closes the logon token.
|
|
//
|
|
// History: 4-05-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CLogonInfo::~CLogonInfo()
|
|
{
|
|
Win4Assert( IsSingle() ); // must not be on the list
|
|
|
|
delete [] _pwszUser;
|
|
delete [] _pwszDomain;
|
|
|
|
if ( INVALID_HANDLE_VALUE != _hToken )
|
|
CloseHandle( _hToken );
|
|
} //~CLogonInfo
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CLogonInfo::IsSameUser
|
|
//
|
|
// Synopsis: Tests if the given user and domain match what is stored in
|
|
// this object.
|
|
//
|
|
// Arguments: [pwszUser] - Name of the user
|
|
// [pwszDomain] - Name of the domain
|
|
//
|
|
// Returns: TRUE if same; FALSE o/w
|
|
//
|
|
// History: 4-05-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CLogonInfo::IsSameUser( WCHAR const * pwszUser, WCHAR const * pwszDomain ) const
|
|
{
|
|
ULONG ccUser = pwszUser ? wcslen(pwszUser) : 0;
|
|
ULONG ccDomain = pwszDomain ? wcslen(pwszDomain) : 0;
|
|
|
|
if ( ccUser == _ccUser && ccDomain == _ccDomain )
|
|
{
|
|
if ( ccUser != 0 && _wcsicmp( pwszUser, _pwszUser ) != 0 )
|
|
return FALSE;
|
|
|
|
if ( ccDomain != 0 && _wcsicmp( pwszDomain, _pwszDomain) != 0 )
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CLogonInfo::IsSamePassword
|
|
//
|
|
// Synopsis: Tests if the given password is same as the one stored in this.
|
|
//
|
|
// Arguments: [pwszPassword] - Password to compare.
|
|
//
|
|
// Returns: TRUE if passwords match; FALSE o/w
|
|
//
|
|
// History: 4-05-96 srikants Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CLogonInfo::IsSamePassword( WCHAR const * pwszPassword ) const
|
|
{
|
|
BYTE * pbPW = 0;
|
|
DWORD cbPW = 0;
|
|
EncryptMemoryPassword( pwszPassword, &pbPW, &cbPW );
|
|
XArray<BYTE> xEncryptedPassword;
|
|
xEncryptedPassword.Set( cbPW, pbPW );
|
|
|
|
if ( cbPW == _xEncryptedPassword.Count() )
|
|
{
|
|
int c = memcmp( pbPW,
|
|
_xEncryptedPassword.Get(),
|
|
cbPW );
|
|
|
|
return ( 0 == c );
|
|
}
|
|
|
|
return FALSE;
|
|
} //IsSamePassword
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CPhyDirLogonInfo::CPhyDirLogonInfo
|
|
//
|
|
// Synopsis: Constructor for the object that keeps logon information for a
|
|
// specific physical directory
|
|
//
|
|
// Arguments: [pwszPhyDirName] - Name of the physical directory (remote)
|
|
//
|
|
// History: 4-02-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CPhyDirLogonInfo::CPhyDirLogonInfo( CImpersonationTokenCache & cache,
|
|
CImprsObjInfo const & obj,
|
|
CLogonInfo * pLogonInfo )
|
|
: _cache( cache ),
|
|
_pwszDirName(0),
|
|
_pwszVirtualRoot(0),
|
|
_ccVirtual(0)
|
|
{
|
|
Win4Assert( 0 != obj.GetPhysicalPath() );
|
|
|
|
CDoubleLink::Close();
|
|
_fIsZombie = FALSE;
|
|
_cRef = 0;
|
|
|
|
//
|
|
// Create a local copy of the physical directory, virtual root and
|
|
// save the logon information.
|
|
//
|
|
_pwszDirName = CLogonInfo::AllocAndCopy( obj.GetPhysicalPath(), _cc );
|
|
_phyScope.Init( _pwszDirName, _cc );
|
|
|
|
if ( 0 != obj.GetVPath() )
|
|
{
|
|
_pwszVirtualRoot = CLogonInfo::AllocAndCopy( obj.GetVPath(), _ccVirtual );
|
|
_virtualScope.Init( _pwszVirtualRoot, _ccVirtual );
|
|
}
|
|
|
|
_pLogonInfo = pLogonInfo;
|
|
if ( 0 != _pLogonInfo )
|
|
_pLogonInfo->Addref();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CPhyDirLogonInfo::~CPhyDirLogonInfo
|
|
//
|
|
// Synopsis: Free up the memory and release the logon info.
|
|
//
|
|
// History: 4-02-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CPhyDirLogonInfo::~CPhyDirLogonInfo()
|
|
{
|
|
Win4Assert( IsSingle() ); // must not be on the list
|
|
|
|
delete [] _pwszDirName;
|
|
delete [] _pwszVirtualRoot;
|
|
|
|
if ( 0 != _pLogonInfo )
|
|
{
|
|
_cache.Release( _pLogonInfo );
|
|
}
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CImpersonationTokenCache::CImpersonationTokenCache
|
|
//
|
|
// Synopsis: Constructor of the impersonation token cache.
|
|
//
|
|
// History: 4-02-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CImpersonationTokenCache::CImpersonationTokenCache(
|
|
WCHAR const * pwcCatName )
|
|
: _fIndexW3Roots(FALSE),
|
|
_fIndexNNTPRoots(FALSE),
|
|
_fIndexIMAPRoots(FALSE),
|
|
_W3SvcInstance(1),
|
|
_NNTPSvcInstance(1),
|
|
_IMAPSvcInstance(1),
|
|
_fRemoteSharesPresent(FALSE),
|
|
_pwszComponentName(0)
|
|
{
|
|
if ( 0 != pwcCatName )
|
|
wcscpy( _awcCatalogName, pwcCatName );
|
|
else
|
|
_awcCatalogName[0] = 0;
|
|
|
|
for ( unsigned i = 0; i < CI_MAX_DRIVES;i++ )
|
|
_aDriveInfo[i] = eUnknown;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CImpersonationTokenCache::~CImpersonationTokenCache
|
|
//
|
|
// Synopsis: Release the cached information.
|
|
//
|
|
// History: 4-02-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CImpersonationTokenCache::~CImpersonationTokenCache()
|
|
{
|
|
|
|
// Release the physical directory list elements
|
|
for ( CPhyDirLogonInfo * pDirInfo = _phyDirList.Pop(); 0 != pDirInfo;
|
|
pDirInfo = _phyDirList.Pop() )
|
|
{
|
|
pDirInfo->Close();
|
|
delete pDirInfo;
|
|
}
|
|
|
|
delete [] _pwszComponentName;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CImpersonationTokenCache::Find
|
|
//
|
|
// Synopsis: Locate impersonation information for the given path.
|
|
//
|
|
// Arguments: [pwszPath] - Path for which impersonation information is
|
|
// needed.
|
|
//
|
|
// Returns: A pointer to the impersonation if lookup is successful.
|
|
// NULL otherwise. The returned CPhyDirLogonInfo is AddRefed().
|
|
//
|
|
// History: 4-02-96 srikants Created
|
|
//
|
|
// It is assumed that pwszPath is all Lower case.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CPhyDirLogonInfo *
|
|
CImpersonationTokenCache::Find( WCHAR const * pwszPath, ULONG len )
|
|
{
|
|
|
|
CPhyDirLogonInfo * pDirInfo = 0;
|
|
|
|
// ====================================================
|
|
CLock lock(_mutex);
|
|
//
|
|
// Try to locate the path in the list
|
|
//
|
|
for ( CFwdPhyDirLogonIter iter(_phyDirList); !_phyDirList.AtEnd(iter);
|
|
_phyDirList.Advance(iter) )
|
|
{
|
|
|
|
if ( iter->IsInScope( pwszPath, len ) )
|
|
{
|
|
pDirInfo = iter.GetEntry();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( pDirInfo )
|
|
{
|
|
pDirInfo->AddRef();
|
|
}
|
|
// ====================================================
|
|
|
|
return pDirInfo;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CImpersonationTokenCache::Find
|
|
//
|
|
// Synopsis: Finds a directory logon info for the given object after skipping
|
|
// over the specified matched entries.
|
|
//
|
|
// Arguments: [info] - Information about the VPath and PhysPath and ip
|
|
// address.
|
|
// [cSkip] - Number of matching entries to skip
|
|
//
|
|
// Returns:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// History: 7-12-96 srikants Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CPhyDirLogonInfo *
|
|
CImpersonationTokenCache::Find( CImprsObjInfo & info, ULONG cSkip )
|
|
{
|
|
|
|
CPhyDirLogonInfo * pDirInfo = 0;
|
|
ULONG cSkipped = 0;
|
|
|
|
// ====================================================
|
|
CLock lock(_mutex);
|
|
//
|
|
// Try to locate the path in the list
|
|
//
|
|
for ( CFwdPhyDirLogonIter iter(_phyDirList); !_phyDirList.AtEnd(iter);
|
|
_phyDirList.Advance(iter) )
|
|
{
|
|
if ( iter->IsMatch( info ) )
|
|
{
|
|
if ( cSkipped == cSkip )
|
|
{
|
|
pDirInfo = iter.GetEntry();
|
|
break;
|
|
}
|
|
cSkipped++;
|
|
}
|
|
}
|
|
|
|
if ( pDirInfo )
|
|
{
|
|
pDirInfo->AddRef();
|
|
}
|
|
// ====================================================
|
|
|
|
return pDirInfo;
|
|
}
|
|
|
|
CPhyDirLogonInfo *
|
|
CImpersonationTokenCache::_FindExact( CImprsObjInfo const & info )
|
|
{
|
|
|
|
CPhyDirLogonInfo * pDirInfo = 0;
|
|
|
|
// ====================================================
|
|
CLock lock(_mutex);
|
|
//
|
|
// Try to locate the path in the list
|
|
//
|
|
for ( CFwdPhyDirLogonIter iter(_phyDirList); !_phyDirList.AtEnd(iter);
|
|
_phyDirList.Advance(iter) )
|
|
{
|
|
|
|
if ( iter->IsSame( info ) )
|
|
{
|
|
pDirInfo = iter.GetEntry();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( pDirInfo )
|
|
{
|
|
pDirInfo->AddRef();
|
|
}
|
|
// ====================================================
|
|
|
|
return pDirInfo;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CImpersonationTokenCache::_LokFindLogonEntry
|
|
//
|
|
// Synopsis: Looks up a logon entry for the given name and domain.
|
|
//
|
|
// Arguments: [pwszUser] -
|
|
// [pwszDomain] -
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 4-05-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CLogonInfo *
|
|
CImpersonationTokenCache::_LokFindLogonEntry( WCHAR const * pwszUser,
|
|
WCHAR const * pwszDomain )
|
|
{
|
|
for ( CFwdLogonInfoIter iter(g_LogonList); !g_LogonList.AtEnd(iter);
|
|
g_LogonList.Advance(iter) )
|
|
{
|
|
if ( iter->IsSameUser( pwszUser, pwszDomain ) )
|
|
return iter.GetEntry();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Class: CParseAccount
|
|
//
|
|
// Purpose: A class to parse account of the form domain\username
|
|
//
|
|
// History: 4-05-96 srikants Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
class CParseAccount
|
|
{
|
|
enum { MAX_USER = UNLEN, MAX_DOMAIN = 100 };
|
|
|
|
public:
|
|
|
|
CParseAccount( WCHAR const * pwszAccount );
|
|
|
|
WCHAR const * GetUserName() const { return _wszUser; }
|
|
WCHAR const * GetDomainName() const { return _wszDomain; }
|
|
|
|
WCHAR * GetUserName() { return _wszUser; }
|
|
WCHAR * GetDomainName() { return _wszDomain; }
|
|
|
|
private:
|
|
|
|
WCHAR _wszUser[MAX_USER];
|
|
WCHAR _wszDomain[MAX_DOMAIN];
|
|
};
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CParseAccount::CParseAccount
|
|
//
|
|
// Synopsis: Parses a string of form domain\username into domain and
|
|
// username.
|
|
//
|
|
// Arguments: [pwszAccount] -
|
|
//
|
|
// History: 4-03-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CParseAccount::CParseAccount( WCHAR const * pwszAccount )
|
|
{
|
|
_wszUser[0] = _wszDomain[0] = 0;
|
|
|
|
if ( pwszAccount )
|
|
{
|
|
int len = wcslen(pwszAccount);
|
|
//
|
|
// Separate the domain\user into domain and user
|
|
//
|
|
for ( int i = len-1; i >= 0; i-- )
|
|
{
|
|
if ( L'\\' == pwszAccount[i] )
|
|
break;
|
|
}
|
|
|
|
if ( i < 0 )
|
|
{
|
|
//
|
|
// See if there is a forward slash. Some mistaken users specify the
|
|
// userid like that.
|
|
//
|
|
for ( i = len-1; i >= 0; i-- )
|
|
{
|
|
if ( L'/' == pwszAccount[i] )
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( i > 0 )
|
|
{
|
|
//
|
|
// Copy the domain name
|
|
//
|
|
RtlCopyMemory( _wszDomain, pwszAccount, i * sizeof(WCHAR) );
|
|
_wszDomain[i] = 0;
|
|
|
|
//
|
|
// Copy the user name.
|
|
//
|
|
RtlCopyMemory( _wszUser, pwszAccount+i+1, (len-i-1)*sizeof(WCHAR) );
|
|
_wszUser[len-i-1] = 0;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No backslash was specified. The entire id is the username and
|
|
// domain is NULL.
|
|
//
|
|
RtlCopyMemory( _wszUser, pwszAccount, len*sizeof(WCHAR) );
|
|
_wszUser[len] = 0;
|
|
}
|
|
}
|
|
} //CParseAccount
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CImpersonationTokenCache::_LokAddDirEntry
|
|
//
|
|
// Synopsis: Adds a new entry to the cache for the given account name.
|
|
//
|
|
// Arguments: [obj] - The impersonation object info
|
|
// [pwszAccount] - Name of the account to use for logging on.
|
|
//
|
|
// History: 4-03-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CImpersonationTokenCache::_LokAddDirEntry( CImprsObjInfo const & obj,
|
|
WCHAR const * pwszAccount )
|
|
{
|
|
//
|
|
// Parse the account name into username and domain.
|
|
//
|
|
|
|
CParseAccount parse( pwszAccount );
|
|
|
|
_fRemoteSharesPresent = TRUE;
|
|
|
|
//
|
|
// Look up the logon entry.
|
|
//
|
|
|
|
CLogonInfo * pLogonInfo = _LokFindLogonEntry( parse.GetUserName(),
|
|
parse.GetDomainName() );
|
|
|
|
//
|
|
// Create the dir entry and add it to the list of physical directories.
|
|
//
|
|
|
|
CPhyDirLogonInfo * pDirInfo = new CPhyDirLogonInfo( *this,
|
|
obj,
|
|
pLogonInfo );
|
|
|
|
_phyDirList.Queue( pDirInfo );
|
|
} //_LokAddDirEntry
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CImpersonationTokenCache::IsNetworkDrive
|
|
//
|
|
// Synopsis: Given a drive, check if it is a network drive.
|
|
//
|
|
// Arguments: [pwszPath] - Path to check.
|
|
//
|
|
// Returns: TRUE if it is a network drive. FALSE o/w
|
|
//
|
|
// History: 4-02-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CImpersonationTokenCache::IsNetworkDrive( WCHAR const * pwszPath )
|
|
{
|
|
CPathParser parser( pwszPath );
|
|
|
|
if ( parser.IsUNCName() )
|
|
return TRUE;
|
|
|
|
if ( parser.IsDrivePath() )
|
|
{
|
|
WCHAR wDriveLetter = pwszPath[0];
|
|
|
|
unsigned iDrive = _GetDriveIndex( wDriveLetter );
|
|
|
|
// ====================================================
|
|
CLock lock(_mutex);
|
|
|
|
if ( eUnknown == _aDriveInfo[iDrive] )
|
|
{
|
|
UINT uType = GetDriveType( pwszPath );
|
|
|
|
if ( DRIVE_REMOTE == uType )
|
|
_aDriveInfo[iDrive] = eRemote;
|
|
else
|
|
_aDriveInfo[iDrive] = eLocal;
|
|
}
|
|
|
|
return eRemote == _aDriveInfo[iDrive];
|
|
// ====================================================
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If it is neither a UNC nor a drive letter, it is probably
|
|
// a relative name.
|
|
//
|
|
return FALSE;
|
|
}
|
|
} //IsNetworkDrive
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CImpersonationTokenCache::_LokValidateOrAddDirEntry
|
|
//
|
|
// Synopsis: Validates the given path and account. If there is no entry for
|
|
// the given path, a new one is added. If the current entry does
|
|
// not match the given account info, the current one is zombified
|
|
// and a new entry added.
|
|
//
|
|
// Arguments: [pwszPhyPath] - Physical path
|
|
// [pwszAccount] - Account to use for accessing the physical path.
|
|
//
|
|
// History: 4-05-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void
|
|
CImpersonationTokenCache::_LokValidateOrAddDirEntry( CImprsObjInfo const & obj,
|
|
WCHAR const * pwszAccount )
|
|
{
|
|
CPhyDirLogonInfo * pDirInfo = _FindExact( obj );
|
|
|
|
if ( pDirInfo )
|
|
{
|
|
CParseAccount account( pwszAccount );
|
|
CLogonInfo * pLogonInfo = _LokFindLogonEntry( account.GetUserName(),
|
|
account.GetDomainName() );
|
|
|
|
if ( pLogonInfo == pDirInfo->GetLogonInfo() )
|
|
{
|
|
// There is no change in logon information.
|
|
Win4Assert( !pLogonInfo || !pLogonInfo->IsZombie() );
|
|
Release(pDirInfo);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// The logon information has changed for this directory.
|
|
// So, we must zombify the current entry and create a new one.
|
|
//
|
|
_phyDirList.RemoveFromList( pDirInfo );
|
|
pDirInfo->Close();
|
|
pDirInfo->Zombify();
|
|
Release( pDirInfo );
|
|
|
|
pDirInfo = 0;
|
|
}
|
|
|
|
Win4Assert( 0 == pDirInfo );
|
|
|
|
_LokAddDirEntry( obj, pwszAccount );
|
|
} //_LokValidateOrAddDirEntry
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CImpersonationTokenCache::_LokValidateOrAddLogonEntry
|
|
//
|
|
// Synopsis: Validate the logon entry. If there is no logon entry for
|
|
// the given account, add a new one. If the current one does not
|
|
// match the given one, zombify the current one and replace it
|
|
// with the new information.
|
|
//
|
|
// Arguments: [pwszUser] - Username of the account
|
|
// [pwszDomain] - Domain of the account
|
|
// [pwszPassword] - Password to use for logging this account/
|
|
//
|
|
// History: 4-05-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
CImpersonationTokenCache::_LokValidateOrAddLogonEntry(
|
|
WCHAR const * pwszUser,
|
|
WCHAR const * pwszDomain,
|
|
WCHAR const * pwszPassword )
|
|
{
|
|
CLogonInfo * pLogonInfo = _LokFindLogonEntry( pwszUser, pwszDomain );
|
|
if ( pLogonInfo )
|
|
{
|
|
if ( pLogonInfo->IsSamePassword( pwszPassword ) )
|
|
return NO_ERROR;
|
|
//
|
|
// Invalidate the logon information.
|
|
//
|
|
g_LogonList.RemoveFromList( pLogonInfo );
|
|
pLogonInfo->Close();
|
|
pLogonInfo->Zombify();
|
|
|
|
pLogonInfo->Addref();
|
|
Release( pLogonInfo );
|
|
|
|
pLogonInfo = 0;
|
|
}
|
|
|
|
Win4Assert( 0 == pLogonInfo );
|
|
|
|
//
|
|
// Create a new logon entry for the user and password.
|
|
//
|
|
pLogonInfo = new CLogonInfo;
|
|
XPtr<CLogonInfo> xLogonInfo(pLogonInfo);
|
|
|
|
DWORD status = pLogonInfo->Logon( pwszUser, pwszDomain, pwszPassword );
|
|
if ( 0 == status )
|
|
{
|
|
xLogonInfo.Acquire();
|
|
g_LogonList.Push( pLogonInfo );
|
|
}
|
|
|
|
return status;
|
|
} //_LokValidateOrAddLogonEntry
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Class: CIISCallBackImp
|
|
//
|
|
// Purpose: Callback to parse IIS scopes and save impersonation
|
|
// information for each.
|
|
//
|
|
// History: 30-Oct-96 dlee created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
class CIISCallBackImp : public CMetaDataCallBack
|
|
{
|
|
public:
|
|
|
|
CIISCallBackImp( CImpersonationTokenCache & cache ) :
|
|
_cache( cache )
|
|
{
|
|
}
|
|
|
|
SCODE CallBack( WCHAR const * pwcVPath,
|
|
WCHAR const * pwcPPath,
|
|
BOOL fIsIndexed,
|
|
DWORD dwAccess,
|
|
WCHAR const * pwcUser,
|
|
WCHAR const * pwcPassword,
|
|
BOOL fIsAVRoot )
|
|
{
|
|
ciDebugOut(( DEB_ITRACE,
|
|
"CIISCallBackImp checking c '%ws', vp '%ws', pp '%ws' i %d, u '%ws' pw '%ws', isavroot: %d\n",
|
|
_cache.GetCatalog(),
|
|
pwcVPath,
|
|
pwcPPath,
|
|
fIsIndexed,
|
|
pwcUser,
|
|
pwcPassword,
|
|
fIsAVRoot ));
|
|
|
|
// If there's a vroot scope on a remote drive, a username, and a
|
|
// password, save the token info.
|
|
|
|
if ( ( fIsAVRoot ) &&
|
|
( fIsIndexed ) &&
|
|
( _cache.IsNetworkDrive( pwcPPath ) ) &&
|
|
( 0 != pwcUser[0] ) )
|
|
{
|
|
ciDebugOut(( DEB_ITRACE, "CIISCallBackImp adding\n" ));
|
|
|
|
{
|
|
CParseAccount parser( pwcUser );
|
|
|
|
DWORD status = _cache._LokValidateOrAddLogonEntry(
|
|
parser.GetUserName(),
|
|
parser.GetDomainName(),
|
|
pwcPassword );
|
|
if ( NO_ERROR != status )
|
|
_cache._WriteLogonFailure( pwcUser, status );
|
|
}
|
|
|
|
{
|
|
// normalize both the physical and virtual paths
|
|
// to lowercase
|
|
|
|
CLowcaseBuf lcasePhyDir( pwcPPath );
|
|
lcasePhyDir.AppendBackSlash();
|
|
|
|
// vpaths in ci always have backslashes, not slashes
|
|
|
|
unsigned cwc = wcslen( pwcVPath );
|
|
if ( cwc >= MAX_PATH )
|
|
return S_OK;
|
|
|
|
WCHAR awcVPath[ MAX_PATH ];
|
|
for ( unsigned x = 0; x <= cwc; x++ )
|
|
{
|
|
if ( L'/' == pwcVPath[x] )
|
|
awcVPath[ x ] = L'\\';
|
|
else
|
|
awcVPath[ x ] = pwcVPath[ x ];
|
|
}
|
|
|
|
CLowcaseBuf lcaseVPath( awcVPath );
|
|
|
|
CImprsObjInfo info( lcasePhyDir.Get(),
|
|
lcaseVPath.Get() );
|
|
|
|
_cache._LokValidateOrAddDirEntry( info, pwcUser );
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
private:
|
|
CImpersonationTokenCache & _cache;
|
|
};
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CImpersonationTokenCache::ReInitializeIISScopes
|
|
//
|
|
// Synopsis: ReInitialize the token cache for iis
|
|
//
|
|
// History: 2-Sep-97 dlee created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CImpersonationTokenCache::ReInitializeIISScopes(
|
|
CIISVirtualDirectories * pW3Dirs,
|
|
CIISVirtualDirectories * pNNTPDirs,
|
|
CIISVirtualDirectories * pIMAPDirs )
|
|
{
|
|
ciDebugOut(( DEB_ITRACE, "reinit iis impersonation fast\n" ));
|
|
CLock lock( _mutex );
|
|
|
|
Win4Assert( 0 != _pwszComponentName );
|
|
|
|
CImpersonateSystem impersonate;
|
|
|
|
if ( _fIndexW3Roots )
|
|
{
|
|
CIISCallBackImp callBack( *this );
|
|
Win4Assert( 0 != pW3Dirs );
|
|
pW3Dirs->Enum( callBack );
|
|
}
|
|
|
|
if ( _fIndexNNTPRoots )
|
|
{
|
|
CIISCallBackImp callBack( *this );
|
|
Win4Assert( 0 != pNNTPDirs );
|
|
pNNTPDirs->Enum( callBack );
|
|
}
|
|
|
|
if ( _fIndexIMAPRoots )
|
|
{
|
|
CIISCallBackImp callBack( *this );
|
|
Win4Assert( 0 != pIMAPDirs );
|
|
pIMAPDirs->Enum( callBack );
|
|
}
|
|
ciDebugOut(( DEB_ITRACE, "reinit iis impersonation fast (done)\n" ));
|
|
} //ReInitializeIISScopes
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CImpersonationTokenCache::ReInitializeIISScopes
|
|
//
|
|
// Synopsis: ReInitialize the token cache for iis
|
|
//
|
|
// History: 4-02-96 srikants Created
|
|
// 2-12-97 dlee Reimplemented for metabase
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CImpersonationTokenCache::ReInitializeIISScopes()
|
|
{
|
|
ciDebugOut(( DEB_ITRACE, "reinit iis impersonation slow\n" ));
|
|
CLock lock( _mutex );
|
|
|
|
Win4Assert( 0 != _pwszComponentName );
|
|
|
|
CImpersonateSystem impersonate;
|
|
|
|
if ( _fIndexW3Roots )
|
|
{
|
|
TRY
|
|
{
|
|
CIISVirtualDirectories dirs( W3VRoot );
|
|
{
|
|
CMetaDataMgr mdMgr( FALSE, W3VRoot, _W3SvcInstance );
|
|
mdMgr.EnumVPaths( dirs );
|
|
}
|
|
|
|
CIISCallBackImp callBack( *this );
|
|
dirs.Enum( callBack );
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
ciDebugOut(( DEB_WARN,
|
|
"exception getting logon info for w3\n" ));
|
|
}
|
|
END_CATCH
|
|
}
|
|
|
|
//
|
|
// If the news server is enabled, we have to read the news server
|
|
// virtual roots and process them.
|
|
//
|
|
|
|
if ( _fIndexNNTPRoots )
|
|
{
|
|
TRY
|
|
{
|
|
CIISVirtualDirectories dirs( NNTPVRoot );
|
|
{
|
|
CMetaDataMgr mdMgr( FALSE, NNTPVRoot, _NNTPSvcInstance );
|
|
mdMgr.EnumVPaths( dirs );
|
|
}
|
|
|
|
CIISCallBackImp callBack( *this );
|
|
dirs.Enum( callBack );
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
ciDebugOut(( DEB_WARN,
|
|
"exception getting logon info for nntp\n" ));
|
|
}
|
|
END_CATCH
|
|
}
|
|
|
|
if ( _fIndexIMAPRoots )
|
|
{
|
|
TRY
|
|
{
|
|
CIISVirtualDirectories dirs( IMAPVRoot );
|
|
{
|
|
CMetaDataMgr mdMgr( FALSE, IMAPVRoot, _IMAPSvcInstance );
|
|
mdMgr.EnumVPaths( dirs );
|
|
}
|
|
|
|
CIISCallBackImp callBack( *this );
|
|
dirs.Enum( callBack );
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
ciDebugOut(( DEB_WARN,
|
|
"exception getting logon info for imap\n" ));
|
|
}
|
|
END_CATCH
|
|
}
|
|
ciDebugOut(( DEB_ITRACE, "reinit iis impersonation slow (done)\n" ));
|
|
} //ReInitializeIISScopes
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Class: CRegistryScopesCallBackImp
|
|
//
|
|
// Purpose: Callback to parse registry scopes and save impersonation
|
|
// information for each.
|
|
//
|
|
// History: 30-Oct-96 dlee created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
class CRegistryScopesCallBackImp : public CRegCallBack
|
|
{
|
|
public:
|
|
CRegistryScopesCallBackImp(
|
|
CImpersonationTokenCache & cache ) :
|
|
_cache( cache )
|
|
{
|
|
}
|
|
|
|
NTSTATUS CallBack( WCHAR *pValueName, ULONG uValueType,
|
|
VOID *pValueData, ULONG uValueLength)
|
|
{
|
|
TRY
|
|
{
|
|
CParseRegistryScope parse( pValueName,
|
|
uValueType,
|
|
pValueData,
|
|
uValueLength );
|
|
|
|
ciDebugOut(( DEB_ITRACE,
|
|
"CRegistryScopesCallBackImp checking c '%ws', s '%ws' u '%ws' pw '%ws'\n",
|
|
_cache.GetCatalog(),
|
|
parse.GetScope(),
|
|
parse.GetUsername(),
|
|
parse.GetPassword( _cache.GetCatalog() ) ));
|
|
|
|
// If there's a scope on a remote drive, a username, and a
|
|
// password, save the token info.
|
|
|
|
if ( ( 0 != parse.GetScope() ) &&
|
|
( _cache.IsNetworkDrive( parse.GetScope() ) ) &&
|
|
( 0 != parse.GetUsername() ) &&
|
|
( 0 != parse.GetPassword( _cache.GetCatalog() ) ) )
|
|
{
|
|
ciDebugOut(( DEB_ITRACE, "CRegistryScopesCallBackImp adding\n" ));
|
|
|
|
{
|
|
CParseAccount parser( parse.GetUsername() );
|
|
|
|
DWORD status = _cache._LokValidateOrAddLogonEntry(
|
|
parser.GetUserName(),
|
|
parser.GetDomainName(),
|
|
parse.GetPassword( _cache.GetCatalog() ) );
|
|
if ( NO_ERROR != status )
|
|
_cache._WriteLogonFailure( parse.GetUsername(), status );
|
|
}
|
|
|
|
{
|
|
CLowcaseBuf lcasePhyDir( parse.GetScope() );
|
|
lcasePhyDir.AppendBackSlash();
|
|
|
|
CImprsObjInfo info( lcasePhyDir.Get(), 0 );
|
|
|
|
_cache._LokValidateOrAddDirEntry( info, parse.GetUsername() );
|
|
}
|
|
}
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
ciDebugOut(( DEB_ERROR,
|
|
"CRegistryScopesCallBackImp::CallBack caught error 0x%x\n",
|
|
e.GetErrorCode() ));
|
|
}
|
|
END_CATCH;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
private:
|
|
CImpersonationTokenCache & _cache;
|
|
}; //CRegistryScopesCallBackImp
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CImpersonationTokenCache::ReInitializeScopes
|
|
//
|
|
// Synopsis: ReInitialize the token cache for remote registry scopes
|
|
//
|
|
// History: 10-24-96 dlee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CImpersonationTokenCache::ReInitializeScopes()
|
|
{
|
|
CLock lock( _mutex );
|
|
|
|
Win4Assert( 0 != _pwszComponentName );
|
|
|
|
// if the catalog isn't named, it can't have any scopes in the registry
|
|
|
|
if ( 0 == _awcCatalogName[0] )
|
|
return;
|
|
|
|
CImpersonateSystem impersonate;
|
|
|
|
TRY
|
|
{
|
|
XArray<WCHAR> xKey;
|
|
BuildRegistryScopesKey( xKey, _awcCatalogName );
|
|
ciDebugOut(( DEB_ITRACE, "Reading scope impinfo '%ws'\n", xKey.Get() ));
|
|
CRegAccess regScopes( RTL_REGISTRY_ABSOLUTE, xKey.Get() );
|
|
|
|
CRegistryScopesCallBackImp callback( *this );
|
|
regScopes.EnumerateValues( 0, callback );
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
ciDebugOut(( DEB_WARN,
|
|
"Exception 0x%x caught groveling ci registry for impersonation info\n",
|
|
e.GetErrorCode() ));
|
|
}
|
|
END_CATCH
|
|
} //ReInitializeScopes
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CImpersonationTokenCache::_WriteLogonFailure
|
|
//
|
|
// Synopsis: Writes an event to the event log that a logon failure
|
|
// occurred.
|
|
//
|
|
// Arguments: [pwszUser] - Id of the user
|
|
// [dwError] - Error
|
|
//
|
|
// History: 5-24-96 srikants Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CImpersonationTokenCache::_WriteLogonFailure( WCHAR const * pwszUser,
|
|
DWORD dwError )
|
|
{
|
|
TRY
|
|
{
|
|
CEventLog eventLog( NULL, wcsCiEventSource );
|
|
|
|
if ( ERROR_LOGON_TYPE_NOT_GRANTED != dwError )
|
|
{
|
|
CEventItem item( EVENTLOG_ERROR_TYPE,
|
|
CI_SERVICE_CATEGORY,
|
|
MSG_CI_REMOTE_LOGON_FAILURE,
|
|
3 );
|
|
|
|
Win4Assert( 0 != _pwszComponentName );
|
|
|
|
item.AddArg( _pwszComponentName );
|
|
item.AddArg( pwszUser );
|
|
item.AddError( dwError );
|
|
eventLog.ReportEvent( item );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The specified user-id has no interactive logon privilege on
|
|
// this machine.
|
|
//
|
|
CEventItem item( EVENTLOG_ERROR_TYPE,
|
|
CI_SERVICE_CATEGORY,
|
|
MSG_CI_NO_INTERACTIVE_LOGON_PRIVILEGE,
|
|
1 );
|
|
|
|
item.AddArg( pwszUser );
|
|
eventLog.ReportEvent( item );
|
|
}
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
ciDebugOut(( DEB_ERROR, "Exception 0x%X while writing to event log\n",
|
|
e.GetErrorCode() ));
|
|
}
|
|
END_CATCH
|
|
} //_WriteLogonFailure
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CImpersonationTokenCache::Initialize
|
|
//
|
|
// Synopsis: Initializes the token cache.
|
|
//
|
|
// History: 4-04-96 srikants Created
|
|
// 10-22-96 dlee global => member
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CImpersonationTokenCache::Initialize(
|
|
WCHAR const * pwszComponent,
|
|
BOOL fIndexW3Roots,
|
|
BOOL fIndexNNTPRoots,
|
|
BOOL fIndexIMAPRoots,
|
|
ULONG W3SvcInstance,
|
|
ULONG NNTPSvcInstance,
|
|
ULONG IMAPSvcInstance )
|
|
{
|
|
Win4Assert( 0 == _pwszComponentName );
|
|
unsigned len = wcslen( pwszComponent );
|
|
_pwszComponentName = new WCHAR [len+1];
|
|
RtlCopyMemory( _pwszComponentName, pwszComponent, (len+1)*sizeof(WCHAR) );
|
|
|
|
_fIndexW3Roots = fIndexW3Roots;
|
|
_fIndexNNTPRoots = fIndexNNTPRoots;
|
|
_fIndexIMAPRoots = fIndexIMAPRoots;
|
|
|
|
_W3SvcInstance = W3SvcInstance;
|
|
_NNTPSvcInstance = NNTPSvcInstance;
|
|
_IMAPSvcInstance = IMAPSvcInstance;
|
|
|
|
if ( fIndexW3Roots || fIndexNNTPRoots || fIndexIMAPRoots )
|
|
ReInitializeIISScopes();
|
|
|
|
ReInitializeScopes();
|
|
} //Initialize
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: Constructor for CImpersonateRemoteAccess
|
|
//
|
|
// History: 4-03-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CImpersonateRemoteAccess::CImpersonateRemoteAccess(
|
|
CImpersonationTokenCache * pCache ) :
|
|
_pCache( pCache ),
|
|
_pTokenInfo( 0 ),
|
|
_hTokenPrev( INVALID_HANDLE_VALUE ),
|
|
_fMustRevert( FALSE )
|
|
{
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CImpersonateRemoteAccess::_ImpersonateIf
|
|
//
|
|
// Synopsis: Impersonates if necessary for the given path.
|
|
//
|
|
// Arguments: [pwszPath] - Given path.
|
|
//
|
|
// History: 4-03-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CImpersonateRemoteAccess::_ImpersonateIf( WCHAR const * pwszPath,
|
|
WCHAR const * pwszVPath,
|
|
ULONG cSkip )
|
|
{
|
|
DWORD dwError = 0;
|
|
|
|
if ( _pCache->IsNetworkDrive(pwszPath) )
|
|
{
|
|
//
|
|
// If we have already impersonated for the given share, then nothing
|
|
// to do.
|
|
//
|
|
|
|
CLowcaseBuf lcasePath( pwszPath );
|
|
lcasePath.AppendBackSlash();
|
|
|
|
//
|
|
// It has been assumed that the VPath is already in lowercase and
|
|
// the forward slashes are converted to back slashes.
|
|
//
|
|
CImprsObjInfo obj( lcasePath.Get(), pwszVPath );
|
|
|
|
if ( IsImpersonated() )
|
|
{
|
|
Win4Assert( 0 != _pTokenInfo );
|
|
if ( !_pTokenInfo->IsZombie() &&
|
|
_pTokenInfo->IsMatch(obj) )
|
|
{
|
|
ciDebugOut(( DEB_ITRACE, "Already impersonated for (%ws)\n",
|
|
lcasePath.Get() ));
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
Release(); // Release the current impersonation
|
|
}
|
|
}
|
|
|
|
BOOL fSuccess = OpenThreadToken( GetCurrentThread(),
|
|
TOKEN_QUERY | TOKEN_IMPERSONATE,
|
|
TRUE, // Access check against process
|
|
&_hTokenPrev );
|
|
|
|
if ( !fSuccess )
|
|
{
|
|
dwError = GetLastError();
|
|
if ( ERROR_NO_TOKEN == dwError )
|
|
{
|
|
//
|
|
// This thread is currently not impersonating anyone.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
ciDebugOut(( DEB_ERROR, "Failed to open thread token. Error %d\n",
|
|
dwError ));
|
|
|
|
THROW( CException( HRESULT_FROM_WIN32(dwError)) );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get the impersonation information for the path.
|
|
//
|
|
_pTokenInfo = _pCache->Find( obj, cSkip );
|
|
if ( 0 == _pTokenInfo )
|
|
{
|
|
ciDebugOut(( DEB_WARN, "There is no %simpersonation info for (%ws)\n",
|
|
cSkip > 0 ? "more " : "",
|
|
lcasePath.Get() ));
|
|
return FALSE;
|
|
}
|
|
|
|
if ( INVALID_HANDLE_VALUE == _pTokenInfo->GetHandle() )
|
|
return FALSE;
|
|
|
|
//
|
|
// Impersonate the specified user.
|
|
//
|
|
fSuccess = ImpersonateLoggedOnUser( _pTokenInfo->GetHandle() );
|
|
if ( !fSuccess )
|
|
{
|
|
dwError = GetLastError();
|
|
ciDebugOut(( DEB_WARN, "Error (%d) while impersonating for path (%ws)\n",
|
|
dwError, pwszPath ));
|
|
return FALSE;
|
|
}
|
|
|
|
#if CIDBG == 1
|
|
|
|
ciDebugOut(( DEB_ITRACE, "Impersonated successfully for (%ws)\n",
|
|
pwszPath ));
|
|
|
|
CLogonInfo &li = *_pTokenInfo->GetLogonInfo();
|
|
|
|
ciDebugOut(( DEB_ITRACE, " using user %ws\\%ws\n",
|
|
li.GetDomain(), li.GetUser() ));
|
|
|
|
#endif
|
|
|
|
_fMustRevert = TRUE;
|
|
}
|
|
|
|
return TRUE;
|
|
} //_ImpersonateIf
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CImpersonateRemoteAccess::Release
|
|
//
|
|
// Synopsis: Releases the resources that were used for impersonation.
|
|
//
|
|
// History: 4-04-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CImpersonateRemoteAccess::Release()
|
|
{
|
|
DWORD dwError = 0;
|
|
|
|
if ( _fMustRevert )
|
|
{
|
|
if ( INVALID_HANDLE_VALUE != _hTokenPrev )
|
|
{
|
|
//
|
|
// This is bad -- if the impersonate fails then we're hosed.
|
|
// There are two cases where this is used, and neither case
|
|
// is bad enough to change the code.
|
|
//
|
|
// 1) webhits when it's run in a worker process
|
|
// If the IIS thread is in a bad state (with the wrong token)
|
|
// IIS will clean it up. So there is no problem here.
|
|
//
|
|
// 2) enumeration queries on remote scopes
|
|
// I don't think there is a security problem here; just a
|
|
// functionality problem. The thread is now the user issuing
|
|
// the query instead of the account used for the remote scope.
|
|
// But a RevertToSelf will happen very soon, so it'll be
|
|
// cleaned up in any case (since RevertToSelf isn't allowed to fail).
|
|
// No real work will happen until the RevertToSelf
|
|
//
|
|
|
|
BOOL fResult = ImpersonateLoggedOnUser( _hTokenPrev );
|
|
if ( !fResult )
|
|
{
|
|
dwError = GetLastError();
|
|
ciDebugOut(( DEB_WARN, "ImpersonateLoggedOnUser failed with error %d\n",
|
|
dwError ));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// There was no impersonation token - just revert to self.
|
|
// Note: We assume RevertToSelf can't fail. MikeHow says we have
|
|
// to assume it'll work since we don't know what to do otherwise.
|
|
//
|
|
|
|
BOOL fResult = RevertToSelf();
|
|
if ( !fResult )
|
|
{
|
|
dwError = GetLastError();
|
|
ciDebugOut(( DEB_ERROR, "RevertToSelf failed with error %d\n",
|
|
dwError ));
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( _pTokenInfo )
|
|
_pCache->Release( _pTokenInfo );
|
|
|
|
if ( INVALID_HANDLE_VALUE != _hTokenPrev )
|
|
CloseHandle( _hTokenPrev );
|
|
|
|
_fMustRevert = FALSE;
|
|
_pTokenInfo = 0;
|
|
_hTokenPrev = INVALID_HANDLE_VALUE;
|
|
} //Release
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: PImpersonatedWorkItem::ImpersonateAndDoWork
|
|
//
|
|
// Synopsis: Calls the DoIt() virtual method after impersonating.
|
|
//
|
|
// Arguments: [access] - The remote access object to use for impersonation.
|
|
//
|
|
// History: 7-15-96 srikants Created
|
|
//
|
|
// Notes: Calls the DoIt() method until it either returns TRUE or there
|
|
// is an exception.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void PImpersonatedWorkItem::ImpersonateAndDoWork( CImpersonateRemoteAccess & access )
|
|
{
|
|
ULONG cSkip = 0;
|
|
|
|
if ( _fNetPath )
|
|
{
|
|
while ( TRUE )
|
|
{
|
|
|
|
BOOL fSuccess = access.ImpersonateIf( _pwszPath, cSkip, 0 );
|
|
|
|
if ( !access.IsTokenFound() )
|
|
THROW( CException( STATUS_LOGON_FAILURE ) );
|
|
|
|
if ( fSuccess && DoIt() )
|
|
break;
|
|
|
|
cSkip++;
|
|
access.Release();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( access.IsImpersonated() )
|
|
{
|
|
//
|
|
// Just revert back to what it was
|
|
//
|
|
access.Release();
|
|
}
|
|
|
|
DoIt();
|
|
}
|
|
} //ImpersonateAndDoWork
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CImpersonatedGetAttr::DoIt
|
|
//
|
|
// Synopsis: Does the actual work of getting attributes.
|
|
//
|
|
// Returns: TRUE if successful; FALSE if should be retried; THROWS
|
|
// otherwise.
|
|
//
|
|
// History: 7-18-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CImpersonatedGetAttr::DoIt()
|
|
{
|
|
if ( !GetFileAttributesEx( _funnyPath.GetPath(), GetFileExInfoStandard, &_ffData ) )
|
|
{
|
|
DWORD dwError = GetLastError();
|
|
if ( IsRetryableError( (NTSTATUS) dwError ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
ciDebugOut(( DEB_ERROR, "Error 0x%X while starting scan on path (%ws)\n",
|
|
dwError, _funnyPath.GetPath() ));
|
|
THROW( CException( HRESULT_FROM_WIN32(dwError)) );
|
|
return FALSE;
|
|
}
|
|
}
|
|
else return TRUE;
|
|
} //DoIt
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CImpersonatedGetFileAttr::DoIt
|
|
//
|
|
// Synopsis: Does the actual work of getting attributes.
|
|
//
|
|
// Returns: TRUE if successful; FALSE if should be retried; THROWS
|
|
// otherwise.
|
|
//
|
|
// History: 12-05-01 dlee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CImpersonatedGetFileAttr::DoIt()
|
|
{
|
|
ULONG ulAttr = GetFileAttributes( _funnyPath.GetPath() );
|
|
|
|
if ( INVALID_FILE_ATTRIBUTES == ulAttr )
|
|
{
|
|
DWORD dwError = GetLastError();
|
|
|
|
if ( IsRetryableError( (NTSTATUS) dwError ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
ciDebugOut(( DEB_ERROR, "Error %#x while getting file attributes (%ws)\n",
|
|
dwError, _funnyPath.GetPath() ));
|
|
THROW( CException( HRESULT_FROM_WIN32(dwError)) );
|
|
}
|
|
|
|
_ulAttr = ulAttr;
|
|
|
|
return TRUE;
|
|
} //DoIt
|
|
|
|
|