//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996 - 1998. // // File: imprsnat.cxx // // Contents: // // Classes: // // Functions: // // History: 2-16-96 srikants Created // //---------------------------------------------------------------------------- #include #pragma hdrstop #include #include #include #include #include #include #include #include #include #include #include #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; //+--------------------------------------------------------------------------- // // 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 ); Win4Assert( 0 == _pwszPassword ); _pwszUser = AllocAndCopy( pwszUser, _ccUser ); _pwszDomain = AllocAndCopy( pwszDomain, _ccDomain ); _pwszPassword = AllocAndCopy( pwszPassword, _ccPassword ); Win4Assert( INVALID_HANDLE_VALUE == _hToken ); DWORD dwError = 0; if ( !LogonUser( _pwszUser, _pwszDomain, _pwszPassword, LOGON32_LOGON_INTERACTIVE, //LOGON32_LOGON_NETWORK 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; delete [] _pwszPassword; if ( INVALID_HANDLE_VALUE != _hToken ) CloseHandle( _hToken ); } //+--------------------------------------------------------------------------- // // 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 { ULONG ccPassword = pwszPassword ? wcslen(pwszPassword) : 0; if ( ccPassword == _ccPassword ) { return RtlEqualMemory( pwszPassword, _pwszPassword, _ccPassword*sizeof(WCHAR) ); } return FALSE; } //+--------------------------------------------------------------------------- // // Function: IpAddressFromWStr // // Synopsis: Given an ip address in the form of a.b.c.d, it is converted // into a ULONG and returned // // Arguments: [pwszAddress] - // // History: 7-12-96 srikants Created // //---------------------------------------------------------------------------- ULONG CPhyDirLogonInfo::IpAddressFromWStr( WCHAR const * pwszAddress ) { if ( 0 == pwszAddress ) return CI_DEFAULT_IP_ADDRESS; ULONG ipAddress = 0; WCHAR const * pwszStart = pwszAddress; WCHAR wszField[4]; for ( unsigned cTok = 0; (cTok < 4) && pwszStart[0]; cTok++ ) { WCHAR const * pwszEnd = wcschr( pwszStart, L'.' ); if ( 0 == pwszEnd ) pwszEnd = pwszStart + wcslen( pwszStart ); ULONG cwc = (ULONG)(pwszEnd - pwszStart); if ( cwc > 3 ) // max is 255 { ciDebugOut(( DEB_ERROR, "Bad IP Address %ws\n", pwszAddress )); return CI_DEFAULT_IP_ADDRESS; } RtlCopyMemory( wszField, pwszStart, cwc * sizeof(WCHAR) ); wszField[cwc] = 0; ULONG lField = (ULONG) _wtol( wszField ); ipAddress <<= 8; // left shift by 8 bits and or in the new ones ipAddress |= (lField & 0xFF); if ( 0 != pwszEnd[0] ) pwszStart = pwszEnd+1; else pwszStart = pwszEnd; } if ( cTok == 4 && pwszStart[0] == 0 ) return ipAddress; else return CI_DEFAULT_IP_ADDRESS; } //+--------------------------------------------------------------------------- // // 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 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 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, password %ws\n", li.GetDomain(), li.GetUser(), li.GetPassword() )); #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 ) { 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. // 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