Windows-Server-2003/ds/security/azroles/azstore.cxx

2264 lines
56 KiB
C++

/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
azstore.cxx
Abstract:
Routines implementing the Authorization Store object
Author:
Cliff Van Dyke (cliffv) 11-Apr-2001
History:
Chaitanya D. Upadhyay (chaitu) 28-May-2002
Changed all references to AdminManager to AzAuthorizationStore
--*/
#include "pch.hxx"
//
// Global Data
//
//
// Global list of all AzAuthorizationStores for this process
// Access serialized by AzGlResource
//
GENERIC_OBJECT_HEAD AzGlAzStores;
SAFE_RESOURCE AzGlResource;
SAFE_RESOURCE AzGlCloseApplication;
BOOL ResourceInitialized = FALSE;
BOOL AzIsDC = FALSE;
UCHAR SidBuffer[SECURITY_MAX_SID_SIZE] = {0};
PSID AzAccountDomainSid = (PSID) SidBuffer;
BOOL AzAccountDomainSidInitialized = FALSE;
GUID AzGlZeroGuid;
//
// Well known sids
//
PSID AzGlCreatorOwnerSid;
PSID AzGlWorldSid;
PSID AzGlCreatorGroupSid;
ULONG AzGlWorldSidSize;
//
// Define the default values for all scalar attributes
//
ULONG AzGlDefDomainTimeout = AZ_AZSTORE_DEFAULT_DOMAIN_TIMEOUT;
ULONG AzGlDefScriptEngineTimeout = AZ_AZSTORE_DEFAULT_SCRIPT_ENGINE_TIMEOUT;
ULONG AzGlDefMaxScriptEngines = AZ_AZSTORE_DEFAULT_MAX_SCRIPT_ENGINES;
ULONG AzGlCurrAzRolesMajorVersion = 1;
ULONG AzGlCurrAzRolesMinorVersion = 0;
AZP_DEFAULT_VALUE AzGlAzStoreDefaultValues[] = {
{ AZ_PROP_AZSTORE_DOMAIN_TIMEOUT, AZ_DIRTY_AZSTORE_DOMAIN_TIMEOUT, &AzGlDefDomainTimeout },
{ AZ_PROP_AZSTORE_SCRIPT_ENGINE_TIMEOUT, AZ_DIRTY_AZSTORE_SCRIPT_ENGINE_TIMEOUT, &AzGlDefScriptEngineTimeout },
{ AZ_PROP_AZSTORE_MAX_SCRIPT_ENGINES, AZ_DIRTY_AZSTORE_MAX_SCRIPT_ENGINES, &AzGlDefMaxScriptEngines },
{ AZ_PROP_AZSTORE_MAJOR_VERSION, AZ_DIRTY_AZSTORE_MAJOR_VERSION, &AzGlCurrAzRolesMajorVersion},
{ AZ_PROP_AZSTORE_MINOR_VERSION, AZ_DIRTY_AZSTORE_MINOR_VERSION, &AzGlCurrAzRolesMinorVersion},
{ 0, 0, NULL }
};
AZP_STRING AzGEmptyString = {0};
#if DBG
BOOL CritSectInitialized = FALSE;
#endif // DBG
#ifdef AZROLESDBG
BOOL LogFileCritSectInitialized = FALSE;
DWORD
myatolx(
char const *psz)
{
DWORD dw = 0;
while (isxdigit(*psz))
{
char ch = *psz++;
if (isdigit(ch))
{
ch -= '0';
}
else if (isupper(ch))
{
ch += 10 - 'A';
}
else
{
ch += 10 - 'a';
}
dw = (dw << 4) | ch;
}
return(dw);
}
#endif //AZROLESDBG
DWORD
AzpInitializeAccountDomainSid( VOID )
/*++
Routine description:
This routine reads whether this machine is a DC and reads the AccountDomain
sid if it is not.
Arguments: None
Return Value:
Returns ERROR_SUCCESS on success, appropriate failure value otherwise.
--*/
{
DWORD WinStatus;
NTSTATUS Status;
PDSROLE_PRIMARY_DOMAIN_INFO_BASIC BasicInfo = NULL;
LSA_HANDLE hPolicy = NULL;
OBJECT_ATTRIBUTES obja = {0};
PPOLICY_ACCOUNT_DOMAIN_INFO pAccountInfo = NULL;
//
// Get the information about the local machine.
//
WinStatus = DsRoleGetPrimaryDomainInformation(
NULL,
DsRolePrimaryDomainInfoBasic,
(PBYTE *) &BasicInfo );
if ( WinStatus != NO_ERROR )
{
return WinStatus;
}
switch(BasicInfo->MachineRole)
{
case DsRole_RolePrimaryDomainController:
case DsRole_RoleBackupDomainController:
//
// If the local machine is a DC then the client account must be a domain
// account. The only workgroup accounts that can be authenticated are
// local machine accounts.
// Note that in this case we do not read the AccountDomainSid.
//
AzIsDC = TRUE;
DsRoleFreeMemory( BasicInfo );
return NO_ERROR;
default:
DsRoleFreeMemory( BasicInfo );
break;
}
//
// This may be a member server or a standalone machine. We need to get the
// AccountDomainSid.
//
// open LSA policy
//
Status = LsaOpenPolicy(
0,
&obja,
POLICY_VIEW_LOCAL_INFORMATION,
&hPolicy );
if (!NT_SUCCESS(Status))
{
WinStatus = LsaNtStatusToWinError(Status);
goto Cleanup;
}
//
// Read the AccountDomainOformation.
//
Status = LsaQueryInformationPolicy(
hPolicy,
PolicyAccountDomainInformation,
(PVOID*)&pAccountInfo
);
if ( !NT_SUCCESS( Status ) )
{
WinStatus = LsaNtStatusToWinError( Status );
goto Cleanup;
}
ASSERT( RtlLengthSid( pAccountInfo->DomainSid ) < SECURITY_MAX_SID_SIZE );
//
// Copy the AccountDomainSid into global buffer.
//
Status = RtlCopySid(
RtlLengthSid( pAccountInfo->DomainSid ),
AzAccountDomainSid,
pAccountInfo->DomainSid );
if ( !NT_SUCCESS( Status ) )
{
WinStatus = LsaNtStatusToWinError( Status );
goto Cleanup;
}
AzAccountDomainSidInitialized = TRUE;
Cleanup:
if ( hPolicy != NULL )
{
LsaClose( hPolicy );
}
if ( pAccountInfo != NULL )
{
LsaFreeMemory(pAccountInfo);
}
return WinStatus;
}
PSID
AzpAllocateWellKnownSid(
IN WELL_KNOWN_SID_TYPE WellKnownSidType
)
/*++
Routine Description:
This routine allocate the SID of a well known security principal
Arguments:
WellKnownSidType - the well known account sid that the caller desires
Return Values:
A pointer to the allocated SID. The caller must call AzpFreeHeap to free the sid.
NULL - buffer couldn't be allocated
--*/
{
DWORD WinStatus;
DWORD SidSize;
PSID Sid = NULL;
//
// Determine the size of the buffer
//
SidSize = 0;
if (!CreateWellKnownSid( WellKnownSidType, NULL, NULL, &SidSize)) {
WinStatus = GetLastError();
if ( WinStatus != ERROR_INSUFFICIENT_BUFFER ) {
return NULL;
}
} else {
return NULL;
}
//
// Allocate the buffer
//
Sid = AzpAllocateHeap( SidSize, "UTILWSID" );
if ( Sid == NULL ) {
return NULL;
}
//
// Fill in the SID
//
if (!CreateWellKnownSid( WellKnownSidType, NULL, Sid, &SidSize)) {
AzpFreeHeap( Sid );
Sid = NULL;
}
return Sid;
}
BOOL
AzDllInitialize(VOID)
/*++
Routine Description
This initializes global events and variables for the DLL.
Arguments
none
Return Value
Boolean: TRUE on success, FALSE on fail.
--*/
{
#ifdef DBG
NTSTATUS Status;
#endif // DBG
BOOL RetVal = TRUE;
DWORD WinStatus;
//
// Initialize global constants
//
RtlZeroMemory( &AzGlZeroGuid, sizeof(AzGlZeroGuid) );
//
// Initialize the safe lock subsystem
//
#ifdef DBG
Status = SafeLockInit( SAFE_MAX_LOCK, TRUE );
if ( !NT_SUCCESS( Status )) {
RetVal = FALSE;
KdPrint(("AzRoles.dll: SafeLockInit failed: 0x%lx\n",
Status ));
goto Cleanup;
}
#endif
//
// Initialize the resource
//
__try {
SafeInitializeResource( &AzGlCloseApplication, SAFE_CLOSE_APPLICATION );
SafeInitializeResource( &AzGlResource, SAFE_GLOBAL_LOCK );
} __except( EXCEPTION_EXECUTE_HANDLER ) {
RetVal = FALSE;
KdPrint(("AzRoles.dll: RtlInitializeResource failed: 0x%lx\n",
GetExceptionCode() ));
goto Cleanup;
}
ResourceInitialized = TRUE;
//
// Initialize the root of the tree of objects
//
AzpLockResourceExclusive( &AzGlResource );
ObInitGenericHead( &AzGlAzStores, OBJECT_TYPE_AZAUTHSTORE, NULL, NULL );
AzpUnlockResource( &AzGlResource );
//
// Initialize the stack allocator
//
SafeAllocaInitialize(
SAFEALLOCA_USE_DEFAULT,
SAFEALLOCA_USE_DEFAULT,
AzpAllocateHeapSafe,
AzpFreeHeap
);
WinStatus = AzpInitializeAccountDomainSid();
if ( WinStatus != NO_ERROR ) {
RetVal = FALSE;
KdPrint(("AzRoles.dll: AzpInitializeAccountDomainSid failed: 0x%lx\n",
WinStatus ));
goto Cleanup;
}
#if DBG
//
// Initialize the allocator
//
InitializeListHead ( &AzGlAllocatedBlocks );
Status = SafeInitializeCriticalSection( &AzGlAllocatorCritSect, SAFE_ALLOCATOR );
if ( !NT_SUCCESS( Status )) {
RetVal = FALSE;
KdPrint(("AzRoles.dll: InitializCriticalSection (AzGlAllocatorCritSect) failed: 0x%lx\n",
Status ));
goto Cleanup;
}
CritSectInitialized = TRUE;
#endif // DBG
#ifdef AZROLESDBG
//
// Initialize debugging
//
Status = SafeInitializeCriticalSection( &AzGlLogFileCritSect, SAFE_LOGFILE );
if ( !NT_SUCCESS( Status )) {
RetVal = FALSE;
KdPrint(("AzRoles.dll: InitializCriticalSection (AzGlLogFileCritSect) failed: 0x%lx\n",
Status ));
goto Cleanup;
}
LogFileCritSectInitialized = TRUE;
//
// Get debug flag from environment variable AZDBG
//
char const *pszAzDbg;
pszAzDbg = getenv("AZDBG");
if (NULL != pszAzDbg)
{
AzGlDbFlag |= myatolx(pszAzDbg);
}
#endif // AZROLESDBG
//
// Initialize Global variables
//
AzGlCreatorOwnerSid = AzpAllocateWellKnownSid( WinCreatorOwnerSid );
if ( AzGlCreatorOwnerSid == NULL ) {
RetVal = FALSE;
KdPrint(("AzRoles.dll: Cannot allocate creator owner sid\n" ));
goto Cleanup;
}
AzGlCreatorGroupSid = AzpAllocateWellKnownSid( WinCreatorGroupSid );
if ( AzGlCreatorGroupSid == NULL ) {
RetVal = FALSE;
KdPrint(("AzRoles.dll: Cannot allocate creator group sid\n" ));
goto Cleanup;
}
AzGlWorldSid = AzpAllocateWellKnownSid( WinWorldSid );
if ( AzGlWorldSid == NULL ) {
RetVal = FALSE;
KdPrint(("AzRoles.dll: Cannot allocate world sid\n" ));
goto Cleanup;
}
AzGlWorldSidSize = GetLengthSid( AzGlWorldSid );
Cleanup:
if ( !RetVal ) {
AzDllUnInitialize();
}
return RetVal;
}
BOOL
AzDllUnInitialize(VOID)
/*++
Routine Description
This uninitializes global events and variables for the DLL.
Arguments
none
Return Value
Boolean: TRUE on success, FALSE on fail.
--*/
{
BOOL RetVal = TRUE;
//
// Free any global resources
//
if ( AzGlCreatorOwnerSid != NULL ) {
AzpFreeHeap( AzGlCreatorOwnerSid );
AzGlCreatorOwnerSid = NULL;
}
if ( AzGlCreatorGroupSid != NULL ) {
AzpFreeHeap( AzGlCreatorGroupSid );
AzGlCreatorGroupSid = NULL;
}
if ( AzGlWorldSid != NULL ) {
AzpFreeHeap( AzGlWorldSid );
AzGlWorldSid = NULL;
}
//
// Delete the resource
//
if ( ResourceInitialized ) {
SafeDeleteResource( &AzGlResource );
SafeDeleteResource( &AzGlCloseApplication );
ResourceInitialized = FALSE;
}
#if DBG
//
// Done with the allocator
//
if ( CritSectInitialized ) {
ASSERT( IsListEmpty( &AzGlAllocatedBlocks ));
SafeDeleteCriticalSection ( &AzGlAllocatorCritSect );
CritSectInitialized = FALSE;
}
#endif // DBG
#ifdef AZROLESDBG
//
// Done with debugging
//
if ( LogFileCritSectInitialized ) {
SafeDeleteCriticalSection ( &AzGlLogFileCritSect );
LogFileCritSectInitialized = FALSE;
}
#endif // AZROLESDBG
return RetVal;
}
VOID
AzpAzStoreCleanupAuditSystem(
IN OUT PAZP_AZSTORE AzAuthorizationStore
)
/*++
Routine Description:
This routines deregisters the event types with Authz audit system.
Arguments:
AzAuthorizationStore - Authorization Store for which the audit handles will be deregistered.
Return Value:
NO_ERROR - The operation was successful
ERROR_NOT_ENOUGH_MEMORY - not enough memory
Other exception status codes
--*/
{
//
// Free the audit handles
//
if ( AzAuthorizationStore->hClientContextCreateAuditEventType != NULL )
{
AuthziFreeAuditEventType( AzAuthorizationStore->hClientContextCreateAuditEventType );
AzAuthorizationStore->hClientContextCreateAuditEventType = NULL;
}
if ( AzAuthorizationStore->hClientContextDeleteAuditEventType != NULL )
{
AuthziFreeAuditEventType( AzAuthorizationStore->hClientContextDeleteAuditEventType );
AzAuthorizationStore->hClientContextDeleteAuditEventType = NULL;
}
if ( AzAuthorizationStore->hAccessCheckAuditEventType != NULL )
{
AuthziFreeAuditEventType( AzAuthorizationStore->hAccessCheckAuditEventType );
AzAuthorizationStore->hAccessCheckAuditEventType = NULL;
}
if ( AzAuthorizationStore->hApplicationInitializationAuditEventType != NULL)
{
AuthziFreeAuditEventType( AzAuthorizationStore->hApplicationInitializationAuditEventType );
AzAuthorizationStore->hApplicationInitializationAuditEventType = NULL;
}
if ( AzAuthorizationStore->hClientContextCreateNameAuditEventType != NULL )
{
AuthziFreeAuditEventType( AzAuthorizationStore->hClientContextCreateNameAuditEventType );
AzAuthorizationStore->hClientContextCreateNameAuditEventType = NULL;
}
if ( AzAuthorizationStore->hClientContextDeleteNameAuditEventType != NULL )
{
AuthziFreeAuditEventType( AzAuthorizationStore->hClientContextDeleteNameAuditEventType );
AzAuthorizationStore->hClientContextDeleteNameAuditEventType = NULL;
}
if ( AzAuthorizationStore->hAccessCheckNameAuditEventType != NULL )
{
AuthziFreeAuditEventType( AzAuthorizationStore->hAccessCheckNameAuditEventType );
AzAuthorizationStore->hAccessCheckNameAuditEventType = NULL;
}
return;
}
DWORD
AzpAzStoreInitializeAuditSystem(
IN OUT PAZP_AZSTORE AzAuthorizationStore
)
/*++
Routine Description:
This routines registers the event types with Authz audit system. We need
one event handle per type of event generated.
Arguments:
AzAuthorizationStore - Authorization Store for which the audit handles will be registered.
Return Value:
NO_ERROR - The operation was successful
ERROR_NOT_ENOUGH_MEMORY - not enough memory
Other exception status codes
--*/
{
BOOL b;
HANDLE hToken = NULL;
AUTHZ_AUDIT_EVENT_TYPE_HANDLE hClientContextCreateNameAuditEventType = NULL;
AUTHZ_AUDIT_EVENT_TYPE_HANDLE hClientContextDeleteNameAuditEventType = NULL;
AUTHZ_AUDIT_EVENT_TYPE_HANDLE hAccessCheckNameAuditEventType = NULL;
AUTHZ_AUDIT_EVENT_TYPE_HANDLE hClientContextCreateAuditEventType = NULL;
AUTHZ_AUDIT_EVENT_TYPE_HANDLE hClientContextDeleteAuditEventType = NULL;
AUTHZ_AUDIT_EVENT_TYPE_HANDLE hAccessCheckAuditEventType = NULL;
AUTHZ_AUDIT_EVENT_TYPE_HANDLE hApplicationInitializationAuditEventType = NULL;
TOKEN_PRIVILEGES NewPrivilegeState = {0};
DWORD WinStatus;
TOKEN_PRIVILEGES OldPrivilegeState = {0};
BOOL PrivilegeAdjusted = FALSE;
//
// Set the values to Zero.
//
AzAuthorizationStore->hAccessCheckAuditEventType = NULL;
AzAuthorizationStore->hApplicationInitializationAuditEventType = NULL;
AzAuthorizationStore->hClientContextCreateAuditEventType = NULL;
AzAuthorizationStore->hClientContextDeleteAuditEventType = NULL;
AzAuthorizationStore->hAccessCheckNameAuditEventType = NULL;
AzAuthorizationStore->hClientContextCreateNameAuditEventType = NULL;
AzAuthorizationStore->hClientContextDeleteNameAuditEventType = NULL;
//
// Get the current token to adjust the Audit privilege.
//
WinStatus = AzpGetCurrentToken( &hToken );
if ( WinStatus != NO_ERROR ) {
return WinStatus;
}
//
// Enable the audit privilege
// If the initialize flag has the audit_is_critical bit set, then fail
// if privilege is not held. If the bit is not set, then simply return
// w/o initializing any audit handles.
//
WinStatus = AzpChangeSinglePrivilege(
SE_AUDIT_PRIVILEGE,
hToken,
&NewPrivilegeState,
&OldPrivilegeState );
if ( WinStatus != NO_ERROR ) {
CloseHandle( hToken );
if ( (AzAuthorizationStore->InitializeFlag & AZ_AZSTORE_FLAG_AUDIT_IS_CRITICAL) == 0 ) {
//
// Audit is not critical
//
WinStatus = NO_ERROR;
}
return WinStatus;
}
PrivilegeAdjusted = TRUE;
//
// Get audit handles for the event types we are interested in.
//
// Audit handle for Client context creation audit.
b = AuthziInitializeAuditEventType( 0,
SE_CATEGID_OBJECT_ACCESS,
SE_AUDITID_AZ_CLIENTCONTEXT_CREATION,
AZP_CLIENTCREATE_AUDITPARAMS_NO,
&hClientContextCreateAuditEventType );
if ( !b ) {
WinStatus = GetLastError();
goto Cleanup;
}
// Audit handle for Client context deletion audit.
b = AuthziInitializeAuditEventType( 0,
SE_CATEGID_OBJECT_ACCESS,
SE_AUDITID_AZ_CLIENTCONTEXT_DELETION,
AZP_CLIENTDELETE_AUDITPARAMS_NO,
&hClientContextDeleteAuditEventType );
if ( !b ) {
WinStatus = GetLastError();
goto Cleanup;
}
// Audit handle for access check audit.
b = AuthziInitializeAuditEventType( 0,
SE_CATEGID_OBJECT_ACCESS,
SE_AUDITID_AZ_ACCESSCHECK,
AZP_ACCESSCHECK_AUDITPARAMS_NO,
&hAccessCheckAuditEventType );
if ( !b ) {
WinStatus = GetLastError();
goto Cleanup;
}
// Audit handle for app initialization audit.
b = AuthziInitializeAuditEventType( 0,
SE_CATEGID_OBJECT_ACCESS,
SE_AUDITID_AZ_APPLICATION_INITIALIZATION,
AZP_APPINIT_AUDITPARAMS_NO,
&hApplicationInitializationAuditEventType );
if ( !b ) {
WinStatus = GetLastError();
goto Cleanup;
}
// Audit handle for Client context name creation audit.
b = AuthziInitializeAuditEventType( 0,
SE_CATEGID_OBJECT_ACCESS,
SE_AUDITID_AZ_CLIENTCONTEXT_CREATION,
AZP_CLIENTCREATE_AUDITPARAMS_NO+2,
&hClientContextCreateNameAuditEventType );
if ( !b ) {
WinStatus = GetLastError();
goto Cleanup;
}
// Audit handle for Client context name deletion audit.
b = AuthziInitializeAuditEventType( 0,
SE_CATEGID_OBJECT_ACCESS,
SE_AUDITID_AZ_CLIENTCONTEXT_DELETION,
AZP_CLIENTDELETE_AUDITPARAMS_NO+2,
&hClientContextDeleteNameAuditEventType );
if ( !b ) {
WinStatus = GetLastError();
goto Cleanup;
}
// Audit handle for access check name audit.
b = AuthziInitializeAuditEventType( 0,
SE_CATEGID_OBJECT_ACCESS,
SE_AUDITID_AZ_ACCESSCHECK,
AZP_ACCESSCHECK_AUDITPARAMS_NO+2,
&hAccessCheckNameAuditEventType );
if ( !b ) {
WinStatus = GetLastError();
goto Cleanup;
}
//
// Set the handles in the authorization store structure.
//
AzAuthorizationStore->hAccessCheckAuditEventType = hAccessCheckAuditEventType;
AzAuthorizationStore->hApplicationInitializationAuditEventType = hApplicationInitializationAuditEventType;
AzAuthorizationStore->hClientContextCreateAuditEventType =hClientContextCreateAuditEventType;
AzAuthorizationStore->hClientContextDeleteAuditEventType = hClientContextDeleteAuditEventType;
AzAuthorizationStore->hAccessCheckNameAuditEventType = hAccessCheckNameAuditEventType;
AzAuthorizationStore->hClientContextCreateNameAuditEventType = hClientContextCreateNameAuditEventType;
AzAuthorizationStore->hClientContextDeleteNameAuditEventType = hClientContextDeleteNameAuditEventType;
WinStatus = NO_ERROR;
Cleanup:
//
// In case of errors, free all the audit handles that were created.
//
if ( WinStatus != NO_ERROR ) {
if ( hClientContextCreateAuditEventType != NULL ) {
AuthziFreeAuditEventType( hClientContextCreateAuditEventType );
}
if ( hClientContextDeleteAuditEventType != NULL ) {
AuthziFreeAuditEventType( hClientContextDeleteAuditEventType );
}
if ( hAccessCheckAuditEventType != NULL ) {
AuthziFreeAuditEventType( hAccessCheckAuditEventType );
}
if ( hClientContextCreateNameAuditEventType != NULL ) {
AuthziFreeAuditEventType( hClientContextCreateNameAuditEventType );
}
if ( hClientContextDeleteNameAuditEventType != NULL ) {
AuthziFreeAuditEventType( hClientContextDeleteNameAuditEventType );
}
if ( hAccessCheckNameAuditEventType != NULL ) {
AuthziFreeAuditEventType( hAccessCheckNameAuditEventType );
}
if ( hApplicationInitializationAuditEventType != NULL) {
AuthziFreeAuditEventType( hApplicationInitializationAuditEventType );
}
}
//
// If we had adjusted the audit privilege, revert to the original state.
//
if ( PrivilegeAdjusted ) {
WinStatus = AzpChangeSinglePrivilege(
0, // This is ignored since OldState is NULL.
hToken,
&OldPrivilegeState,
NULL ); // This should be set to NULL to specify REVERT.
ASSERT( WinStatus == NO_ERROR );
}
if ( hToken != NULL ) {
CloseHandle( hToken );
}
return WinStatus;
}
DWORD
AzpAzStoreInit(
IN PGENERIC_OBJECT ParentGenericObject,
IN PGENERIC_OBJECT ChildGenericObject
)
/*++
Routine Description:
This routine is a worker routine for AzInitialize. It does any object specific
initialization that needs to be done.
On entry, AzGlResource must be locked exclusively.
Arguments:
ParentGenericObject - Specifies the parent object to add the child object onto.
The reference count has been incremented on this object.
ChildGenericObject - Specifies the newly allocated child object.
The reference count has been incremented on this object.
Return Value:
NO_ERROR - The operation was successful
ERROR_NOT_ENOUGH_MEMORY - not enough memory
Other exception status codes
--*/
{
DWORD WinStatus;
PAZP_AZSTORE AzAuthorizationStore = (PAZP_AZSTORE) ChildGenericObject;
NTSTATUS Status;
//
// Initialization
//
ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
//
// Initialize the lists of child objects
// Let the generic object manager know all of the types of children we support
//
ASSERT( ParentGenericObject == NULL );
UNREFERENCED_PARAMETER( ParentGenericObject );
ChildGenericObject->ChildGenericObjectHead = &AzAuthorizationStore->Applications;
// List of child applications
ObInitGenericHead( &AzAuthorizationStore->Applications,
OBJECT_TYPE_APPLICATION,
ChildGenericObject,
&AzAuthorizationStore->Groups );
// List of child groups
ObInitGenericHead( &AzAuthorizationStore->Groups,
OBJECT_TYPE_GROUP,
ChildGenericObject,
&ChildGenericObject->AzpSids );
// List of child AzpSids
ObInitGenericHead( &ChildGenericObject->AzpSids,
OBJECT_TYPE_SID,
ChildGenericObject,
NULL );
//
// Initialize the Domain list.
//
Status = SafeInitializeCriticalSection( &AzAuthorizationStore->DomainCritSect,
SAFE_DOMAIN_LIST );
if ( !NT_SUCCESS( Status )) {
WinStatus = RtlNtStatusToDosError( Status );
goto Cleanup;
}
AzAuthorizationStore->DomainCritSectInitialized = TRUE;
InitializeListHead( &AzAuthorizationStore->Domains );
//
// Initialize Crit sect that serializes Persist engine operations
//
Status = SafeInitializeCriticalSection( &AzAuthorizationStore->FreeScriptCritSect,
SAFE_FREE_SCRIPT_LIST );
if ( !NT_SUCCESS( Status )) {
WinStatus = RtlNtStatusToDosError( Status );
goto Cleanup;
}
AzAuthorizationStore->FreeScriptCritSectInitialized = TRUE;
InitializeListHead( &AzAuthorizationStore->LruFreeScriptHead );
//
// Initialize AzAuthStore mode
//
Status = SafeInitializeCriticalSection(
&AzAuthorizationStore->PersistCritSect,
SAFE_PERSIST_LOCK );
if ( !NT_SUCCESS( Status ))
{
WinStatus = RtlNtStatusToDosError( Status );
goto Cleanup;
}
AzAuthorizationStore->PersistCritSectInitialized = TRUE;
InitializeListHead( &AzAuthorizationStore->NewNames );
//
// Initialize the script engine timer queue
//
AzAuthorizationStore->ScriptEngineTimerQueue = CreateTimerQueue();
if ( AzAuthorizationStore->ScriptEngineTimerQueue == NULL ) {
WinStatus = GetLastError();
goto Cleanup;
}
//
// By default generate audits
//
AzAuthorizationStore->GenericObject.IsGeneratingAudits = TRUE;
WinStatus = NO_ERROR;
Cleanup:
if ( WinStatus != NO_ERROR ) {
AzpAzStoreCleanupAuditSystem( AzAuthorizationStore );
AzpAzStoreFree( ChildGenericObject );
}
return WinStatus;
}
VOID
AzpAzStoreFree(
IN PGENERIC_OBJECT GenericObject
)
/*++
Routine Description:
This routine is a worker routine for AzAuthorizationStore object free. It does any object specific
cleanup that needs to be done.
On entry, AzGlResource must be locked exclusively.
Arguments:
GenericObject - Specifies a pointer to the object to be deleted.
Return Value:
None
--*/
{
PAZP_AZSTORE AzAuthorizationStore = (PAZP_AZSTORE) GenericObject;
//
// Initialization
//
ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
//
// Close the database store
//
AzPersistClose( AzAuthorizationStore );
//
// Free any local strings
//
AzpFreeString( &AzAuthorizationStore->PolicyUrl );
//
// Free any local strings
//
AzpFreeString( &AzAuthorizationStore->TargetMachine );
//
// Free the domain list
//
if ( AzAuthorizationStore->DomainCritSectInitialized ) {
// Free the list itself
AzpUnlinkDomains( AzAuthorizationStore );
// Free the crit sect protecting the list
SafeDeleteCriticalSection( &AzAuthorizationStore->DomainCritSect );
AzAuthorizationStore->DomainCritSectInitialized = FALSE;
}
//
// Free the free script list
//
if ( AzAuthorizationStore->FreeScriptCritSectInitialized ) {
//
// The LRU FreeScriptList should have been flushed as each task object
// was freed.
// So we shouldn't be here unless the free script list is empty.
ASSERT( IsListEmpty( &AzAuthorizationStore->LruFreeScriptHead ));
ASSERT( AzAuthorizationStore->LruFreeScriptCount == 0 );
// Free the crit sect protecting the list
SafeDeleteCriticalSection( &AzAuthorizationStore->FreeScriptCritSect );
AzAuthorizationStore->FreeScriptCritSectInitialized = FALSE;
}
//
// Free the timer queue
//
if ( AzAuthorizationStore->ScriptEngineTimerQueue != NULL ) {
DeleteTimerQueueEx( AzAuthorizationStore->ScriptEngineTimerQueue,
INVALID_HANDLE_VALUE ); // Wait for operation to finish
AzAuthorizationStore->ScriptEngineTimerQueue = NULL;
}
// Free persistence engine critical section
if (AzAuthorizationStore->PersistCritSectInitialized)
{
SafeDeleteCriticalSection( &AzAuthorizationStore->PersistCritSect );
AzAuthorizationStore->PersistCritSectInitialized = FALSE;
ASSERT( IsListEmpty( &AzAuthorizationStore->NewNames ));
}
//
// Cleanup the audit system handles.
//
AzpAzStoreCleanupAuditSystem( AzAuthorizationStore );
//
// Free the provider dll
//
if ( AzAuthorizationStore->ProviderDll != NULL ) {
FreeLibrary( AzAuthorizationStore->ProviderDll );
AzAuthorizationStore->ProviderDll = NULL;
}
}
DWORD
AzpAzStoreGetProperty(
IN PGENERIC_OBJECT GenericObject,
IN ULONG Flags,
IN ULONG PropertyId,
OUT PVOID *PropertyValue
)
/*++
Routine Description:
This routine is the AzAuthorizationStore specific worker routine for AzGetProperty.
It does any object specific property gets.
On entry, AzGlResource must be locked shared.
Arguments:
GenericObject - Specifies a pointer to the object to be queried
Flags - Specifies internal flags
AZP_FLAGS_BY_GUID - name lists should be returned as GUID lists
AZP_FLAGS_PERSIST_* - Call is from the persistence provider
PropertyId - Specifies which property to return.
PropertyValue - Specifies a pointer to return the property in.
The returned pointer must be freed using AzFreeMemory.
The returned value and type depends in PropertyId. The valid values are:
AZ_PROP_AZSTORE_DOMAIN_TIMEOUT PULONG - Domain timeout (in milliseconds)
AZ_PROP_AZSTORE_SCRIPT_ENGINE_TIMEOUT PULONG - Script timeout (in milliseconds)
AZ_PROP_AZSTORE_MAX_SCRIPT_ENGINES PULONG - Max number of cached scripts
AZ_PROP_AZSTORE_MAJOR_VERSION PLONG - Major version
AZ_PROP_AZSTORE_MINOR_VERSION PLONG - Minor version
Return Value:
Status of the operation
--*/
{
DWORD WinStatus = NO_ERROR;
PAZP_AZSTORE AzAuthorizationStore = (PAZP_AZSTORE) GenericObject;
UNREFERENCED_PARAMETER( Flags );
//
// Initialization
//
ASSERT( AzpIsLockedShared( &AzGlResource ) );
//
// Return any object specific attribute
//
// Return the domain timeout to the caller
//
switch ( PropertyId ) {
case AZ_PROP_AZSTORE_DOMAIN_TIMEOUT:
*PropertyValue = AzpGetUlongProperty( AzAuthorizationStore->DomainTimeout );
if ( *PropertyValue == NULL ) {
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
}
break;
//
// Return the script engine timeout to the caller
//
case AZ_PROP_AZSTORE_SCRIPT_ENGINE_TIMEOUT:
*PropertyValue = AzpGetUlongProperty( AzAuthorizationStore->ScriptEngineTimeout );
if ( *PropertyValue == NULL ) {
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
}
break;
//
// Return max number of cached scripted engines
//
case AZ_PROP_AZSTORE_MAX_SCRIPT_ENGINES:
*PropertyValue = AzpGetUlongProperty( AzAuthorizationStore->MaxScriptEngines );
if ( *PropertyValue == NULL ) {
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
}
break;
//
// Return store's major version
//
case AZ_PROP_AZSTORE_MAJOR_VERSION:
*PropertyValue = AzpGetUlongProperty( AzAuthorizationStore->MajorVersion );
if ( *PropertyValue == NULL ) {
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
}
break;
//
// Return store's minor version
//
case AZ_PROP_AZSTORE_MINOR_VERSION:
*PropertyValue = AzpGetUlongProperty( AzAuthorizationStore->MinorVersion );
if ( *PropertyValue == NULL ) {
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
}
break;
//
// Return store's target machine for resolving accounts
//
case AZ_PROP_AZSTORE_TARGET_MACHINE:
*PropertyValue = AzpGetStringProperty( &AzAuthorizationStore->TargetMachine );
if ( *PropertyValue == NULL ) {
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
}
break;
default:
AzPrint(( AZD_INVPARM, "AzpAzStoreGetProperty: invalid prop id %ld\n", PropertyId ));
WinStatus = ERROR_INVALID_PARAMETER;
break;
}
return WinStatus;
}
DWORD
AzpAzStoreSetProperty(
IN PGENERIC_OBJECT GenericObject,
IN ULONG Flags,
IN ULONG PropertyId,
IN PVOID PropertyValue
)
/*++
Routine Description:
This routine is the AzAuthorizationStore object specific worker routine for AzSetProperty.
It does any object specific property sets.
On entry, AzGlResource must be locked exclusive.
Arguments:
GenericObject - Specifies a pointer to the object to be modified
Flags - Specifies flags controlling to operation of the routine
AZP_FLAGS_SETTING_TO_DEFAULT - Property is being set to default value
AZP_FLAGS_PERSIST_* - Call is from the persistence provider
PropertyId - Specifies which property to set.
PropertyValue - Specifies a pointer to the property.
The specified value and type depends in PropertyId. The valid values are:
AZ_PROP_AZSTORE_DOMAIN_TIMEOUT PULONG - Domain timeout (in milliseconds)
AZ_PROP_AZSTORE_SCRIPT_ENGINE_TIMEOUT PULONG - Script timeout (in milliseconds)
AZ_PROP_AZSTORE_MAX_SCRIPT_ENGINES PULONG - Max number of cached scripts
AZ_PROP_AZSTORE_MAJOR_VERSION PLONG - Major version
AZ_PROP_AZSTORE_MINOR_VERSION PLONG - Minor version
Return Value:
Status of the operation
--*/
{
DWORD WinStatus;
PAZP_AZSTORE AzAuthorizationStore = (PAZP_AZSTORE) GenericObject;
LONG TempLong;
BOOL bHasChanged = TRUE;
//
// Initialization
//
UNREFERENCED_PARAMETER( Flags );
ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
//
// Set any object specific attribute
//
// Set domain timeout
//
switch ( PropertyId ) {
case AZ_PROP_AZSTORE_DOMAIN_TIMEOUT:
BEGIN_SETPROP( &WinStatus, AzAuthorizationStore, Flags, AZ_DIRTY_AZSTORE_DOMAIN_TIMEOUT ) {
WinStatus = AzpCaptureLong( PropertyValue, &TempLong );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Do parameter validity checking
//
BEGIN_VALIDITY_CHECKING( Flags ) {
if ( TempLong < AZ_AZSTORE_MIN_DOMAIN_TIMEOUT && TempLong != -1 ) {
AzPrint(( AZD_INVPARM, "AzpAzStoreManagerSetProperty: domain timeout too small %ld\n", TempLong ));
WinStatus = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
} END_VALIDITY_CHECKING;
AzAuthorizationStore->DomainTimeout = TempLong;
} END_SETPROP(bHasChanged);
break;
//
// Set script engine timeout
//
case AZ_PROP_AZSTORE_SCRIPT_ENGINE_TIMEOUT:
BEGIN_SETPROP( &WinStatus, AzAuthorizationStore, Flags, AZ_DIRTY_AZSTORE_SCRIPT_ENGINE_TIMEOUT ) {
WinStatus = AzpCaptureLong( PropertyValue, &TempLong );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Do parameter validity checking
//
BEGIN_VALIDITY_CHECKING( Flags ) {
if ( TempLong < AZ_AZSTORE_MIN_SCRIPT_ENGINE_TIMEOUT && TempLong != -1 && TempLong != 0 ) {
AzPrint(( AZD_INVPARM, "AzpAzStoreManagerSetProperty: script engine timeout too small %ld\n", TempLong ));
WinStatus = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
} END_VALIDITY_CHECKING;
AzAuthorizationStore->ScriptEngineTimeout = TempLong;
} END_SETPROP(bHasChanged);
break;
//
// Set max number of cached scripted engines
//
case AZ_PROP_AZSTORE_MAX_SCRIPT_ENGINES:
BEGIN_SETPROP( &WinStatus, AzAuthorizationStore, Flags, AZ_DIRTY_AZSTORE_MAX_SCRIPT_ENGINES ) {
WinStatus = AzpCaptureLong( PropertyValue, &TempLong );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Do parameter validity checking
//
BEGIN_VALIDITY_CHECKING( Flags ) {
if ( TempLong < 0) {
AzPrint(( AZD_INVPARM, "AzpAzStoreManagerSetProperty: max script engines too small %ld\n", TempLong ));
WinStatus = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
} END_VALIDITY_CHECKING;
AzAuthorizationStore->MaxScriptEngines = TempLong;
} END_SETPROP(bHasChanged);
break;
//
// Major version. These are hidden from out side clients. Howeveer, in order
// for it to work with our cache model, we still have to implement this code.
//
case AZ_PROP_AZSTORE_MAJOR_VERSION:
BEGIN_SETPROP( &WinStatus, AzAuthorizationStore, Flags, AZ_DIRTY_AZSTORE_MAJOR_VERSION ) {
WinStatus = AzpCaptureLong( PropertyValue, &TempLong );
if (WinStatus != NO_ERROR)
{
goto Cleanup;
}
AzAuthorizationStore->MajorVersion = TempLong;
} END_SETPROP(bHasChanged);
break;
//
// Minor version These are hidden from out side clients. Howeveer, in order
// for it to work with our cache model, we still have to implement this code.
//
case AZ_PROP_AZSTORE_MINOR_VERSION:
BEGIN_SETPROP( &WinStatus, AzAuthorizationStore, Flags, AZ_DIRTY_AZSTORE_MINOR_VERSION ) {
WinStatus = AzpCaptureLong( PropertyValue, &TempLong );
if (WinStatus != NO_ERROR)
{
goto Cleanup;
}
AzAuthorizationStore->MinorVersion = TempLong;
} END_SETPROP(bHasChanged);
break;
default:
AzPrint(( AZD_INVPARM, "AzpAzStoreManagerSetProperty: invalid prop id %ld\n", PropertyId ));
WinStatus = ERROR_INVALID_PARAMETER;
break;
}
Cleanup:
return WinStatus;
}
DWORD
WINAPI
AzInitialize(
IN LPCWSTR PolicyUrl,
IN DWORD Flags,
IN DWORD Reserved,
OUT PAZ_HANDLE AzStoreHandle
)
/*++
Routine Description:
This routine initializes the authorization store. This routine must be called before any other
routine.
Arguments:
PolicyUrl - Specifies the location of the policy store
Flags - Specifies flags that control the behavior of AzInitialize
AZ_AZSTORE_FLAG_CREATE: Create the policy database
AZ_AZSTORE_FLAG_MANAGE_STORE_ONLY: Open the store for administrative purposes only. There
will be no runtime functions performed.
AZ_AZSTORE_FLAG_BATCH_UPDATE: When this flag is set, we will not update
the authorization store object for the purpuse of quick
discovery of store modification. For those clients who know
that they will do massive number of updates within a short
period of time on an AD store, then they should use this
flag to reduce network traffic.
AZ_AZSTORE_FLAG_AUDIT_IS_CRITICAL: If this flag is specified, the calling process needs to have
SE_AUDIT_PRIVILEGE, else error will be returned.
Reserved - Reserved. Must by zero.
AzStoreHandle - Return a handle to the AzAuthorizationStore.
The caller must close this handle by calling AzCloseHandle.
Return Value:
NO_ERROR - The operation was successful
ERROR_ALREADY_EXISTS - AZ_AZSTORE_FLAG_CREATE flag was specified and the policy already exists
ERROR_FILE_NOT_FOUND - AZ_AZSTORE_FLAG_CREATE flag was not specified and the policy does not already exist
--*/
{
DWORD WinStatus;
PGENERIC_OBJECT AzAuthorizationStore = NULL;
AZP_STRING AzStoreName;
AZP_STRING PolicyUrlString;
//
// Grab the global lock
//
AzpLockResourceExclusive( &AzGlResource );
AzpInitString( &AzStoreName, NULL );
AzpInitString( &PolicyUrlString, NULL );
//
// Initialization
//
__try {
*AzStoreHandle = NULL;
} __except( EXCEPTION_EXECUTE_HANDLER ) {
WinStatus = RtlNtStatusToDosError( GetExceptionCode());
goto Cleanup;
}
//
// Validate the input parameters
//
if ( Reserved != 0 ) {
AzPrint(( AZD_INVPARM, "AzInitialize: Reserved != 0\n" ));
WinStatus = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
if ( Flags & ~AZ_AZSTORE_FLAG_VALID ) {
AzPrint(( AZD_INVPARM, "AzInitialize: Invalid flags 0x%lx\n", Flags ));
WinStatus = ERROR_INVALID_FLAGS;
goto Cleanup;
}
//
// Capture the Policy URL
//
WinStatus = AzpCaptureString( &PolicyUrlString,
(LPWSTR) PolicyUrl,
AZ_MAX_POLICY_URL_LENGTH,
FALSE ); // NULL is not OK
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Create the object. If this succeeds, then AzAuthorizationStore is holding
// two ref count: one for global list and one for AzAuthorizationStore itself.
// Therefore, if for any reason we fail to return the requested handle,
// we must decrement one extra ref count because the global list ref
// count relies on the handle's close to go down to 0.
//
WinStatus = ObCreateObject(
NULL, // There is no parent object
&AzGlAzStores,
OBJECT_TYPE_AZAUTHSTORE,
&AzStoreName,
NULL, // Guid not known
0, // No special flags
&AzAuthorizationStore );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Set authorization store specific fields
//
AzpSwapStrings( &PolicyUrlString, &((PAZP_AZSTORE)AzAuthorizationStore)->PolicyUrl );
AzpInitString(&((PAZP_AZSTORE)AzAuthorizationStore)->TargetMachine, NULL);
((PAZP_AZSTORE)AzAuthorizationStore)->InitializeFlag = Flags;
//
// Initialize the audit system if not in manage store mode
//
if ( !AzpOpenToManageStore((PAZP_AZSTORE)AzAuthorizationStore) ) {
WinStatus = AzpAzStoreInitializeAuditSystem( (PAZP_AZSTORE)AzAuthorizationStore );
if ( WinStatus != NO_ERROR ) {
//
// Bug 591762: We will fail Initialization if SeAuditPrivilege is not held,
// or if the Audit System failed to initialize for some other reason. This is
// because the user specifically asked for Initialization with runtime audits
// being generated.
//
ObDereferenceObject( AzAuthorizationStore );
AzPrint(( AZD_CRITICAL,
"AzInitialize: Failed to Initialize Audit system: %ld\n",
WinStatus
));
goto Cleanup;
}
}
//
// Load the objects for the database store
//
WinStatus = AzPersistOpen(
(PAZP_AZSTORE)AzAuthorizationStore,
(Flags & AZ_AZSTORE_FLAG_CREATE) != 0 );
if ( WinStatus != NO_ERROR ) {
ObDereferenceObject( AzAuthorizationStore );
goto Cleanup;
}
//
// Return the handle to the caller
//
ObIncrHandleRefCount( AzAuthorizationStore );
*AzStoreHandle = AzAuthorizationStore;
WinStatus = NO_ERROR;
//
// Free locally used resources
//
Cleanup:
if ( AzAuthorizationStore != NULL ) {
ObDereferenceObject( AzAuthorizationStore );
}
AzpFreeString( &PolicyUrlString );
//
// Drop the global lock
//
AzpUnlockResource( &AzGlResource );
return WinStatus;
}
DWORD
WINAPI
AzUpdateCache(
IN AZ_HANDLE AzStoreHandle
)
/*++
Routine Description:
This routine updates the cache to match the underlying store.
Arguments:
AzStoreHandle - Specifies a handle to the AzAuthorizationStore.
Return Value:
NO_ERROR - The operation was successful
--*/
{
DWORD WinStatus;
PGENERIC_OBJECT ReferencedGenericObject = NULL;
//
// Grab the global lock
//
AzpLockResourceExclusive( &AzGlResource );
//
// Validate the passed in handle
//
WinStatus = ObReferenceObjectByHandle( (PGENERIC_OBJECT)AzStoreHandle,
FALSE, // Don't allow deleted objects
FALSE, // No need to refresh the cache here
OBJECT_TYPE_AZAUTHSTORE );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
ReferencedGenericObject = (PGENERIC_OBJECT) AzStoreHandle;
WinStatus = AzPersistUpdateCache( (PAZP_AZSTORE)ReferencedGenericObject );
//
// Free locally used resources
//
Cleanup:
if ( ReferencedGenericObject != NULL ) {
ObDereferenceObject( ReferencedGenericObject );
}
//
// Drop the global lock
//
AzpUnlockResource( &AzGlResource );
return WinStatus;
}
DWORD
WINAPI
AzGetProperty(
IN AZ_HANDLE AzHandle,
IN ULONG PropertyId,
IN DWORD Reserved,
OUT PVOID *PropertyValue
)
/*++
Routine Description:
Returns the specified property for an Authz object
Arguments:
AzHandle - Specifies a handle to the object to get the property for
PropertyId - Specifies which property to return.
Reserved - Reserved. Must by zero.
PropertyValue - Specifies a pointer to return the property in.
The returned pointer must be freed using AzFreeMemory.
The returned value and type depends in PropertyId.
The PropertyId is one of the AZ_PROP_* values.
Return Value:
NO_ERROR - The operation was successful
ERROR_INVALID_PARAMETER - PropertyId isn't valid
--*/
{
//
// Call the common routine to do most of the work
//
return ObCommonGetProperty(
(PGENERIC_OBJECT) AzHandle,
0, // No flags
PropertyId,
Reserved,
PropertyValue );
}
DWORD
WINAPI
AzSetProperty(
IN AZ_HANDLE AzHandle,
IN ULONG PropertyId,
IN DWORD Reserved,
IN PVOID PropertyValue
)
/*++
Routine Description:
Sets the specified property for an AzAuthorizationStore.
Arguments:
AzHandle - Specifies a handle to the object to set the property for
PropertyId - Specifies which property to set
Reserved - Reserved. Must by zero.
PropertyValue - Specifies a pointer to the property.
The specified value and type depends in PropertyId.
The PropertyId is one of the AZ_PROP_* values.
Return Value:
NO_ERROR - The operation was successful
ERROR_INVALID_PARAMETER - PropertyId isn't valid
--*/
{
//
// Call the common routine to do most of the work
//
return ObCommonSetProperty(
(PGENERIC_OBJECT) AzHandle,
PropertyId,
Reserved,
PropertyValue );
}
DWORD
WINAPI
AzAuthorizationStoreDelete(
IN AZ_HANDLE AzStoreHandle,
IN DWORD Reserved
)
/*++
Routine Description:
This routine deletes the authorization store object specified by the passed in handle
Also deletes any child objects of ApplicationName and the underlying store.
Arguments:
AzStoreHandle - Specifies a handle to the AzAuthorizationStore.
Reserved - Reserved. Must by zero.
Return Value:
NO_ERROR - The operation was successful
--*/
{
DWORD WinStatus;
PGENERIC_OBJECT ReferencedGenericObject = NULL;
//
// Grab the global lock
//
AzpLockResourceExclusive( &AzGlResource );
//
// Validate the input parameters
//
if ( Reserved != 0 ) {
AzPrint(( AZD_INVPARM, "AzAuthorizationStoreDelete: Reserved != 0\n" ));
WinStatus = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
//
// Validate the passed in handle
//
WinStatus = ObReferenceObjectByHandle( (PGENERIC_OBJECT)AzStoreHandle,
FALSE, // Don't allow deleted objects
FALSE, // No need to refresh the cache on a delete
OBJECT_TYPE_AZAUTHSTORE );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
ReferencedGenericObject = (PGENERIC_OBJECT) AzStoreHandle;
//
// Actually, delete the object
//
WinStatus = AzPersistSubmit( ReferencedGenericObject, TRUE );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Mark the entry (and its child objects) as deleted
// We do this since other threads may have references to the objects.
// We want to ensure those threads know the objects are deleted.
//
ObMarkObjectDeleted( ReferencedGenericObject );
//
// Return to the caller
//
WinStatus = NO_ERROR;
//
// Free locally used resources
//
Cleanup:
if ( ReferencedGenericObject != NULL ) {
ObDereferenceObject( ReferencedGenericObject );
}
//
// Drop the global lock
//
AzpUnlockResource( &AzGlResource );
return WinStatus;
}
DWORD
WINAPI
AzCloseHandle(
IN AZ_HANDLE AzHandle,
IN DWORD Reserved
)
/*++
Routine Description:
Close a handle returned from any of the Az* routines
Arguments:
AzHandle - Passes in the handle to be closed.
Reserved - Reserved. Must by zero.
Return Value:
NO_ERROR - The operation was successful.
ERROR_INVALID_HANDLE - The passed in handle was invalid
--*/
{
DWORD WinStatus;
PGENERIC_OBJECT ReferencedGenericObject = NULL;
PGENERIC_OBJECT GenericObject = (PGENERIC_OBJECT) AzHandle;
PGENERIC_OBJECT AzStoreGenericObject = NULL;
DWORD ObjectType;
//
// Grab the global lock
//
AzpLockResourceShared( &AzGlResource );
//
// Validate the input parameters
//
if ( Reserved != 0 ) {
AzPrint(( AZD_INVPARM, "AzCloseHandle: Reserved != 0\n" ));
WinStatus = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
//
// Determine the type of the object
//
WinStatus = ObGetHandleType( GenericObject,
TRUE, // Ok to close handle for deleted object
&ObjectType );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Grab the lock exclusively if we're going to change the database
//
if ( ObjectType == OBJECT_TYPE_AZAUTHSTORE ) {
AzpLockResourceSharedToExclusive( &AzGlResource );
}
//
// Validate the passed in handle
//
WinStatus = ObReferenceObjectByHandle( GenericObject,
TRUE, // Allow deleted objects
FALSE, // No need to refresh cache on a close
ObjectType );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
ReferencedGenericObject = GenericObject;
//
// Grab a reference to the root of the core cache
//
// This might be the last handle open. Closing the last handle removes
// the last reference to the object at the root of the core cache.
// We need to ensure that there are no other references to children objects.
// We do that by grabing our own reference here so that our dereference will
// be the final dereference
//
AzStoreGenericObject = &GenericObject->AzStoreObject->GenericObject;
InterlockedIncrement( &AzStoreGenericObject->ReferenceCount );
AzpDumpGoRef( "AzAuthorizationStore in AzCloseHandle ref", AzStoreGenericObject );
//
// If the object is dirty,
// and we're closing the last handle,
// abort the changes.
//
if ( GenericObject->DirtyBits != 0 &&
GenericObject->HandleReferenceCount == 1 ) {
//
// We need an exclusive lock to delete the object.
//
// If this is the AzAuthorizationStore object, the we already
// have the glock held exclusively
//
if ( ObjectType != OBJECT_TYPE_AZAUTHSTORE ) {
AzpLockResourceSharedToExclusive( &AzGlResource );
}
//
// Ensure things haven't changed
//
if ( GenericObject->DirtyBits != 0 &&
GenericObject->HandleReferenceCount == 1 ) {
AzPersistAbort( GenericObject );
}
}
//
// Handle close of AzAuthorizationStore handles
//
if ( ObjectType == OBJECT_TYPE_AZAUTHSTORE ) {
//
// If the object hasn't been deleted,
// remove the reference representing being in the global list.
//
if ( (GenericObject->Flags & GENOBJ_FLAGS_DELETED) == 0 ) {
//
// Make sure the caller doesn't re-use the handle
//
GenericObject->Flags |= GENOBJ_FLAGS_DELETED;
// No longer in the global list
ObDereferenceObject( GenericObject );
}
//
// For a client context,
// remove the link from the parent when the handle closes
//
} else if ( ObjectType == OBJECT_TYPE_CLIENT_CONTEXT ) {
ASSERT( GenericObject->HandleReferenceCount == 1 );
// One from ObReferenceObjectByHandle,
// one for being in the global list,
// one because the handle itself isn't closed yet.
//ASSERT( GenericObject->ReferenceCount == 3 );
// No longer in the global list
ObDereferenceObject( GenericObject );
}
//
// Actually close the handle
//
WinStatus = ObDecrHandleRefCount( GenericObject );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Done
//
WinStatus = NO_ERROR;
//
// Free locally used resources
//
Cleanup:
if ( ReferencedGenericObject != NULL ) {
ObDereferenceObject( ReferencedGenericObject );
}
if ( AzStoreGenericObject != NULL ) {
// This dereference might delete the entire cache
ObDereferenceObject( AzStoreGenericObject );
}
//
// Drop the global lock
//
AzpUnlockResource( &AzGlResource );
return WinStatus;
}
VOID
WINAPI
AzFreeMemory(
IN OUT PVOID Buffer
)
/*++
Routine Description
Free memory returned from AzGetProperty
Arguments
Buffer - address of buffer to free
Return Value
None
--*/
{
if ( Buffer != NULL ) {
AzpFreeHeap( Buffer);
}
}
inline BOOL
AzpAzStoreVersionAllowWrite(
IN PAZP_AZSTORE AzAuthorizationStore
)
/*++
Routine Description:
This routine tests if the current azroles.dll verion can support
writing of the store created by a potentially different version
of adroles.dll. The version of the dll that wrote the dll is captured
by the major and minor verions of the AzAuthStore object.
Arguments:
AzAuthorizationStore - the auth store object
Return Values:
TRUE if it supports the action
FALSE if not.
Note:
MajorVersion (DWORD) - Specifies the major version of the azroles.dll
that wrote this policy. An azroles.dll with an older major version
number cannot read nor write a database with a newer major version number.
The version 1 value of this DWORD is 1. We hope to never have to
change this value in future releases.
MinorVersion (DWORD) - Specifies the minor version of the azroles.dll
that wrote this policy. An azroles.dll with an older minor version
number can read but cannot write a database with a newer minor version number.
The version 1 value of this DWORD is 0.
--*/
{
return ( AzAuthorizationStore->MajorVersion == AzGlCurrAzRolesMajorVersion &&
AzAuthorizationStore->MinorVersion <= AzGlCurrAzRolesMinorVersion );
}