windows-nt/Source/XPSP1/NT/inetsrv/query/fsci/dll/seccache.cxx
2020-09-26 16:20:57 +08:00

268 lines
7.9 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1995 - 1998.
//
// File: seccache.cxx
//
// Contents: Security descriptor cache that maps SDIDs to granted/denied
//
// Class: CSecurityCache
//
// History: 25-Sep-95 dlee Created
// 22 Jan 96 Alanw Modified for use in user mode
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
// Local includes:
#include <seccache.hxx>
#include <catalog.hxx>
//+---------------------------------------------------------------------------
//
// Method: CSecurityCache::CSecurityCache, public
//
// Synopsis: Creates a CSecurityCache. In user mode, an
// impersonation token to use with the AccessCheck call is
// obtained.
//
// History: 22 Jan 96 Alanw Created
//
//----------------------------------------------------------------------------
CSecurityCache::CSecurityCache( PCatalog & rCat ) :
_aEntries( cDefaultSecurityDescriptorEntries ),
_hToken( INVALID_HANDLE_VALUE ),
_Cat( rCat )
{
InitToken();
}
//+---------------------------------------------------------------------------
//
// Method: CSecurityCache::InitToken, public
//
// Synopsis: Captures an impersonation token to use with the AccessCheck
// call.
//
// History: 15 Feb 96 Alanw Created
//
//----------------------------------------------------------------------------
void CSecurityCache::InitToken( )
{
DWORD ReturnLength;
NTSTATUS status;
TOKEN_STATISTICS TokenInformation;
status = NtOpenThreadToken( GetCurrentThread(),
TOKEN_QUERY | TOKEN_DUPLICATE |
TOKEN_IMPERSONATE, // Desired Access
TRUE, // OpenAsSelf
&_hToken);
if (!NT_SUCCESS(status)) {
if (status == STATUS_NO_TOKEN)
{
status = NtOpenProcessToken( GetCurrentProcess(),
TOKEN_QUERY | TOKEN_DUPLICATE |
TOKEN_IMPERSONATE, // Desired Access
&_hToken);
}
if (!NT_SUCCESS(status))
{
vqDebugOut(( DEB_ERROR,
"CSecurityCache: failed to get token handle, %x\n",
status ));
THROW(CException( status ));
}
}
status = NtQueryInformationToken ( _hToken,
TokenStatistics,
(LPVOID)&TokenInformation,
sizeof TokenInformation,
&ReturnLength);
if (!NT_SUCCESS(status))
{
vqDebugOut(( DEB_ERROR,
"CSecurityCache: failed to get token info, %x\n",
status ));
THROW(CException( status ));
}
if ( TokenInformation.TokenType != TokenImpersonation )
{
HANDLE hNewToken = INVALID_HANDLE_VALUE;
OBJECT_ATTRIBUTES ObjA;
SECURITY_QUALITY_OF_SERVICE SecurityQOS;
SecurityQOS.Length = sizeof( SECURITY_QUALITY_OF_SERVICE );
SecurityQOS.ImpersonationLevel = SecurityIdentification;
SecurityQOS.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
SecurityQOS.EffectiveOnly = FALSE;
InitializeObjectAttributes( &ObjA,
NULL,
0,
NULL,
NULL );
ObjA.SecurityQualityOfService = &SecurityQOS;
status = NtDuplicateToken( _hToken,
TOKEN_IMPERSONATE | TOKEN_QUERY,
&ObjA,
FALSE,
TokenImpersonation,
&hNewToken );
if (! NT_SUCCESS( status ) )
{
vqDebugOut(( DEB_ERROR,
"CSecurityCache: failed to duplicate token, %x\n",
status ));
THROW(CException( status ));
}
NtClose( _hToken );
_hToken = hNewToken;
}
}
CSecurityCache::~CSecurityCache()
{
if ( INVALID_HANDLE_VALUE != _hToken )
NtClose( _hToken );
}
//+---------------------------------------------------------------------------
//
// Method: CSecurityCache::_IsCached, private
//
// Synopsis: Determines whether a sdid is granted access given the
// cache's security context.
//
// Arguments: [sdidOrd] -- security descriptor ordinal to test
// [am] -- access mask of the request
// [fGranted] -- if return value is TRUE, this is either
// TRUE (if access is granted) or FALSE.
//
// Returns: TRUE if sdid was in the cache and fGranted is set
// FALSE if sdid is not cached and fGranted should be ignored
//
// History: 25-Sep-95 dlee Created
//
//----------------------------------------------------------------------------
inline BOOL CSecurityCache::_IsCached(
ULONG sdidOrd,
ACCESS_MASK am,
BOOL & fGranted ) const
{
// Look for the sdid in the cache
for ( unsigned i = 0; i < _aEntries.Count(); i++ )
{
if ( ( _aEntries[i].sdidOrd == sdidOrd ) &&
( _aEntries[i].am == am ) )
{
fGranted = _aEntries[i].fGranted;
return TRUE;
}
}
return FALSE;
} //_IsCached
//+---------------------------------------------------------------------------
//
// Method: CSecurityCache::IsGranted, public
//
// Synopsis: Determines whether a security ordinal is granted access given
// the cache's security context, and caches the result.
//
// Arguments: [sdidOrdinal] -- security descriptor ordinal to test
// [am] -- access mask of the request, one or more of
// FILE_READ_ATTRIBUTES
// FILE_READ_DATA / FILE_LIST_DIRECTORY
// FILE_TRAVERSE
//
// Returns: TRUE if sdid was granted access, FALSE otherwise
//
// History: 25-Sep-95 dlee Created
// 22 Jan 96 Alanw Modified for use in user mode
//
//----------------------------------------------------------------------------
BOOL CSecurityCache::IsGranted(
ULONG sdidOrdinal,
ACCESS_MASK am )
{
// if nothing asked for, grant
if ( 0 == am )
return TRUE;
if ( sdidNull == sdidOrdinal )
return TRUE;
if ( sdidInvalid == sdidOrdinal )
return FALSE;
BOOL fGranted;
{
CLock lock( _mutex );
if ( _IsCached( sdidOrdinal, am, fGranted ) )
return fGranted;
}
// do the security check
fGranted = FALSE;
BOOL fResult = _Cat.AccessCheck( sdidOrdinal,
GetToken(),
am,
fGranted);
if (! fResult)
{
DWORD dwError = GetLastError();
Win4Assert( fResult && dwError == NO_ERROR );
}
// Not cached yet -- do so
vqDebugOut(( DEB_ITRACE, "cacheing sdid %x, granted: %x\n",
sdidOrdinal, fGranted ));
{
CLock lock( _mutex );
// check the cache again -- it may have slipped in via a different
// thread while we weren't holding the lock.
if ( !_IsCached( sdidOrdinal, am, fGranted ) )
{
unsigned i = _aEntries.Count();
_aEntries[i].sdidOrd = sdidOrdinal;
_aEntries[i].am = am;
_aEntries[i].fGranted = fGranted;
}
}
return fGranted;
} //IsGranted