268 lines
7.9 KiB
C++
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
|
|
|