You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1515 lines
37 KiB
1515 lines
37 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dbadmin.c
|
|
|
|
Abstract:
|
|
|
|
Local Security Authority - Database Administration
|
|
|
|
This file contains routines that perform general Lsa Database
|
|
administration functions
|
|
|
|
Author:
|
|
|
|
Scott Birrell (ScottBi) August 27, 1991
|
|
|
|
Environment:
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <lsapch2.h>
|
|
#include "dbp.h"
|
|
#include "adtp.h"
|
|
|
|
#if DBG
|
|
LSADS_THREAD_INFO_NODE LsapDsThreadInfoList[ LSAP_THREAD_INFO_LIST_MAX ];
|
|
SAFE_RESOURCE LsapDsThreadInfoListResource;
|
|
#endif
|
|
|
|
LSADS_INIT_STATE LsaDsInitState;
|
|
|
|
|
|
|
|
NTSTATUS
|
|
LsapDbSetStates(
|
|
IN ULONG DesiredStatesSet,
|
|
IN LSAPR_HANDLE ObjectHandle,
|
|
IN LSAP_DB_OBJECT_TYPE_ID ObjectTypeId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine turns on special states in the Lsa Database. These
|
|
states can be turned off using LsapDbResetStates.
|
|
|
|
Arguments:
|
|
|
|
DesiredStatesSet - Specifies the states to be set.
|
|
|
|
LSAP_DB_LOCK - Acquire the Lsa Database lock.
|
|
|
|
LSAP_DB_LOG_QUEUE_LOCK - Acquire the Lsa Audit Log
|
|
Queue Lock.
|
|
|
|
LSAP_DB_START_TRANSACTION - Start an Lsa Database transaction. There
|
|
must not already be one in progress.
|
|
|
|
LSAP_DB_READ_ONLY_TRANSACTION - Open a transaction for read only
|
|
|
|
LSAP_DB_DS_OP_TRANSACTION - Perform a single Ds operation per transaction
|
|
|
|
ObjectHandle - Pointer to handle to be validated and referenced.
|
|
|
|
ObjectTypeId - Specifies the expected object type to which the handle
|
|
relates. An error is returned if this type does not match the
|
|
type contained in the handle.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Standard Nt Result Code
|
|
|
|
STATUS_INVALID_STATE - The Database is not in the correct state
|
|
to allow this state change.
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
NTSTATUS SecondaryStatus = STATUS_SUCCESS;
|
|
ULONG StatesSetHere = 0;
|
|
LSAP_DB_HANDLE InternalHandle = ( LSAP_DB_HANDLE )ObjectHandle;
|
|
|
|
LsapDsDebugOut(( DEB_FTRACE, "LsapDbSetStates\n" ));
|
|
|
|
//
|
|
// If we have an object type that doesn't write to the Ds, make sure we have
|
|
// the options set appropriately
|
|
//
|
|
|
|
if ( ObjectTypeId == PolicyObject ||
|
|
ObjectTypeId == AccountObject ) {
|
|
|
|
DesiredStatesSet |= LSAP_DB_NO_DS_OP_TRANSACTION;
|
|
}
|
|
|
|
if ( ObjectTypeId == TrustedDomainObject ) {
|
|
|
|
DesiredStatesSet |= LSAP_DB_READ_ONLY_TRANSACTION;
|
|
}
|
|
|
|
//
|
|
// If requested, lock the Audit Log Queue
|
|
//
|
|
|
|
if (DesiredStatesSet & LSAP_DB_LOG_QUEUE_LOCK) {
|
|
|
|
Status = LsapAdtAcquireLogFullLock();
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
goto SetStatesError;
|
|
}
|
|
|
|
StatesSetHere |= LSAP_DB_LOG_QUEUE_LOCK;
|
|
}
|
|
|
|
//
|
|
// If requested, lock the Lsa database
|
|
//
|
|
|
|
if (DesiredStatesSet & LSAP_DB_LOCK) {
|
|
|
|
LsapDbAcquireLockEx( ObjectTypeId,
|
|
DesiredStatesSet );
|
|
|
|
StatesSetHere |= LSAP_DB_LOCK;
|
|
}
|
|
|
|
//
|
|
// If requested, open a database update transaction.
|
|
//
|
|
|
|
if ( FLAG_ON( DesiredStatesSet, LSAP_DB_READ_ONLY_TRANSACTION |
|
|
LSAP_DB_NO_DS_OP_TRANSACTION |
|
|
LSAP_DB_DS_OP_TRANSACTION |
|
|
LSAP_DB_START_TRANSACTION ) ) {
|
|
|
|
|
|
Status = LsapDbOpenTransaction( DesiredStatesSet );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
goto SetStatesError;
|
|
}
|
|
|
|
StatesSetHere |= LSAP_DB_START_TRANSACTION;
|
|
}
|
|
|
|
SetStatesFinish:
|
|
|
|
LsapDsDebugOut(( DEB_FTRACE, "LsapDbSetStates: 0x%lx\n", Status ));
|
|
return( Status );
|
|
|
|
SetStatesError:
|
|
|
|
//
|
|
// If we started a transaction, abort it.
|
|
//
|
|
|
|
if (StatesSetHere & LSAP_DB_START_TRANSACTION) {
|
|
|
|
SecondaryStatus = LsapDbAbortTransaction( DesiredStatesSet );
|
|
}
|
|
|
|
//
|
|
// If we locked the database, unlock it.
|
|
//
|
|
|
|
if (StatesSetHere & LSAP_DB_LOCK) {
|
|
|
|
LsapDbReleaseLockEx( ObjectTypeId,
|
|
DesiredStatesSet );
|
|
}
|
|
|
|
//
|
|
// If we locked the Audit Log Queue, unlock it.
|
|
//
|
|
|
|
if (StatesSetHere & LSAP_DB_LOG_QUEUE_LOCK) {
|
|
|
|
LsapAdtReleaseLogFullLock();
|
|
}
|
|
|
|
goto SetStatesFinish;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
LsapDbResetStates(
|
|
IN LSAPR_HANDLE ObjectHandle,
|
|
IN ULONG Options,
|
|
IN LSAP_DB_OBJECT_TYPE_ID ObjectTypeId,
|
|
IN SECURITY_DB_DELTA_TYPE SecurityDbDeltaType,
|
|
IN NTSTATUS PreliminaryStatus
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function resets the Lsa Database states specified. It is used
|
|
to reset states set by LsapDbSetStates.
|
|
|
|
Arguments:
|
|
|
|
ObjectHandle - Handle to an LSA object. This is expected to have
|
|
already been validated.
|
|
|
|
Options - Specifies optional actions, including states to be reset
|
|
|
|
LSAP_DB_LOCK - Lsa Database lock to be released
|
|
|
|
LSAP_DB_LOG_QUEUE_LOCK - Lsa Audit Log Queue Lock to
|
|
be released.
|
|
|
|
LSAP_DB_FINISH_TRANSACTION - Lsa database transaction open.
|
|
|
|
LSAP_DB_OMIT_REPLICATOR_NOTIFICATION - Omit notification to
|
|
Replicators.
|
|
|
|
ObjectTypeId - Specifies the expected object type to which the handle
|
|
relates.
|
|
|
|
PreliminaryStatus - Indicates the preliminary result code of the
|
|
calling routine. Allows reset action to vary depending on the
|
|
result code, for example, apply or abort transaction.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Standard Nt Result Code. This is the final status to be used
|
|
by the caller and is equal to the Preliminary status except in the
|
|
case where that is as success status and this routine fails.
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
LSAP_DB_HANDLE InternalHandle = ( LSAP_DB_HANDLE )ObjectHandle;
|
|
|
|
LsapDsDebugOut(( DEB_FTRACE, "LsapDbResetStates (Prelim: 0x%lx )\n", PreliminaryStatus ));
|
|
|
|
//
|
|
// If we have an object type that doesn't write to the Ds, make sure we have
|
|
// the options set appropriately
|
|
//
|
|
if ( ObjectTypeId == PolicyObject ||
|
|
ObjectTypeId == AccountObject ) {
|
|
|
|
Options |= LSAP_DB_NO_DS_OP_TRANSACTION;
|
|
}
|
|
|
|
if ( ObjectTypeId == TrustedDomainObject ) {
|
|
|
|
Options |= LSAP_DB_READ_ONLY_TRANSACTION;
|
|
}
|
|
|
|
//
|
|
// If requested, finish a database update transaction.
|
|
//
|
|
if ( !FLAG_ON( Options, LSAP_DB_STANDALONE_REFERENCE ) &&
|
|
FLAG_ON( Options, LSAP_DB_READ_ONLY_TRANSACTION |
|
|
LSAP_DB_NO_DS_OP_TRANSACTION |
|
|
LSAP_DB_DS_OP_TRANSACTION |
|
|
LSAP_DB_FINISH_TRANSACTION ) ) {
|
|
|
|
if (NT_SUCCESS(PreliminaryStatus)) {
|
|
|
|
Status = LsapDbApplyTransaction(
|
|
ObjectHandle,
|
|
Options,
|
|
SecurityDbDeltaType
|
|
);
|
|
|
|
} else {
|
|
|
|
Status = LsapDbAbortTransaction( Options );
|
|
}
|
|
}
|
|
|
|
//
|
|
// If unlocking requested, unlock the Lsa Database.
|
|
//
|
|
|
|
if (Options & LSAP_DB_LOCK) {
|
|
|
|
LsapDbReleaseLockEx( ObjectTypeId,
|
|
Options );
|
|
}
|
|
|
|
//
|
|
// If unlocking if the Audit Log Queue requested, unlock the queue.
|
|
//
|
|
|
|
if (Options & LSAP_DB_LOG_QUEUE_LOCK) {
|
|
|
|
LsapAdtReleaseLogFullLock();
|
|
}
|
|
|
|
//
|
|
// The requested reset operations were performed successfully.
|
|
// Propagate the preliminary status back to the caller.
|
|
//
|
|
|
|
if ( NT_SUCCESS( Status ))
|
|
{
|
|
Status = PreliminaryStatus;
|
|
}
|
|
|
|
LsapDsDebugOut(( DEB_FTRACE, "LsapDbResetStates: 0x%lx\n", Status ));
|
|
return( Status );
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
LsapDbOpenTransaction(
|
|
IN ULONG Options
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function starts a transaction within the LSA Database.
|
|
|
|
WARNING: The Lsa Database must be in the locked state when this function
|
|
is called.
|
|
|
|
Arguments:
|
|
|
|
Options - Options to apply when opening the transaction. Valid values are:
|
|
LSAP_DB_READ_ONLY_TRANSACTION - Open a transaction for read only
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Standard Nt Result Code
|
|
|
|
Result codes are those returned from the Registry Transaction
|
|
Package.
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
BOOLEAN RegTransactionOpened = FALSE;
|
|
|
|
if ( !FLAG_ON( Options, LSAP_DB_READ_ONLY_TRANSACTION ) ) {
|
|
|
|
Status = LsapRegOpenTransaction();
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
RegTransactionOpened = TRUE;
|
|
}
|
|
}
|
|
|
|
if ( NT_SUCCESS( Status ) && LsapDsIsFunctionTableValid() ) {
|
|
|
|
ASSERT( LsaDsStateInfo.DsFuncTable.pOpenTransaction );
|
|
Status = (*LsaDsStateInfo.DsFuncTable.pOpenTransaction) ( Options );
|
|
if ((!NT_SUCCESS(Status)) && RegTransactionOpened)
|
|
{
|
|
NTSTATUS IgnoreStatus;
|
|
|
|
IgnoreStatus = LsapRegAbortTransaction();
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
LsapDbApplyTransaction(
|
|
IN LSAPR_HANDLE ObjectHandle,
|
|
IN ULONG Options,
|
|
IN SECURITY_DB_DELTA_TYPE SecurityDbDeltaType
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function applies a transaction within the LSA Database.
|
|
|
|
WARNING: The Lsa Database must be in the locked state when this function
|
|
is called.
|
|
|
|
Arguments:
|
|
|
|
ObjectHandle - Handle to an LSA object. This is expected to have
|
|
already been validated.
|
|
|
|
Options - Specifies optional actions to be taken. The following
|
|
options are recognized, other options relevant to calling routines
|
|
are ignored.
|
|
|
|
LSAP_DB_OMIT_REPLICATOR_NOTIFICATION - Omit notification to
|
|
Replicator.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Standard Nt Result Code
|
|
|
|
Result codes are those returned from the Registry Transaction
|
|
Package.
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
LSAP_DB_HANDLE InternalHandle = ( LSAP_DB_HANDLE )ObjectHandle;
|
|
BOOLEAN RegApplied = FALSE, Notify = FALSE;
|
|
BOOLEAN RestoreModifiedId = FALSE;
|
|
BOOLEAN RegistryLocked = FALSE;
|
|
LARGE_INTEGER Increment = {1,0},
|
|
OriginalModifiedId = { 0 };
|
|
PLSADS_PER_THREAD_INFO CurrentThreadInfo;
|
|
ULONG SavedDsOperationCount = 0;
|
|
|
|
//
|
|
// Reference the thread state so it doesn't disappear in the middle of this
|
|
// routine.
|
|
//
|
|
|
|
CurrentThreadInfo = LsapQueryThreadInfo();
|
|
|
|
if ( CurrentThreadInfo ) {
|
|
|
|
SavedDsOperationCount = CurrentThreadInfo->DsOperationCount;
|
|
LsapCreateThreadInfo();
|
|
}
|
|
|
|
//
|
|
// Verify that the LSA Database is locked
|
|
// One of many locks is locked
|
|
//
|
|
//ASSERT (LsapDbIsLocked());
|
|
|
|
//
|
|
// Apply the DS transaction before grabbing any more locks.
|
|
//
|
|
// Note that this applies the transaction before updating the modified ID.
|
|
// If we crash before updateing the modified ID, NT 4 BDCs won't be notified
|
|
// of this change.
|
|
//
|
|
|
|
if ( LsapDsIsFunctionTableValid() ) {
|
|
|
|
ASSERT( LsaDsStateInfo.DsFuncTable.pApplyTransaction );
|
|
Status = (*LsaDsStateInfo.DsFuncTable.pApplyTransaction)( Options );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Notify the replicator unless:
|
|
// We are to omit replicator (e.g. for creation of a local secret), OR
|
|
// we are installing the Policy Object,
|
|
// notification globally disabled.
|
|
//
|
|
|
|
if ((!(Options & LSAP_DB_OMIT_REPLICATOR_NOTIFICATION)) &&
|
|
(LsapDbHandle != NULL) &&
|
|
(LsapDbState.ReplicatorNotificationEnabled )) {
|
|
|
|
BOOLEAN DbChanged = FALSE;
|
|
|
|
//
|
|
// If the object is in the DS,
|
|
// determine if the DS changed.
|
|
//
|
|
|
|
if ( LsapDsIsHandleDsHandle( InternalHandle )) {
|
|
|
|
//
|
|
// Netlogon notification of DS object change is *ALWAYS* handled
|
|
// in the DS notification callback routine. That's the easiest
|
|
// way to handle things like TDO changes result in both TDO notifications
|
|
// and the corresponding global secret notification.
|
|
//
|
|
|
|
ASSERT( InternalHandle->ObjectTypeId == TrustedDomainObject ||
|
|
InternalHandle->ObjectTypeId == SecretObject );
|
|
|
|
//
|
|
// If the object is a registry object,
|
|
// determine if the registry has changed.
|
|
//
|
|
|
|
} else {
|
|
|
|
//
|
|
// Grab the registry lock.
|
|
// It serializes access to the global ModifiedId
|
|
//
|
|
|
|
LsapDbLockAcquire( &LsapDbState.RegistryLock );
|
|
RegistryLocked = TRUE;
|
|
|
|
ASSERT( SavedDsOperationCount == 0 ||
|
|
InternalHandle->ObjectTypeId == PolicyObject );
|
|
|
|
if ( LsapDbState.RegistryModificationCount > 0 ) {
|
|
DbChanged = TRUE;
|
|
|
|
//
|
|
// No one should change the database on a read only transaction.
|
|
//
|
|
|
|
ASSERT( !FLAG_ON( Options, LSAP_DB_READ_ONLY_TRANSACTION) );
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the DbChanged,
|
|
// increment the NT 4 change serial number.
|
|
//
|
|
|
|
if ( DbChanged ) {
|
|
|
|
OriginalModifiedId = LsapDbState.PolicyModificationInfo.ModifiedId;
|
|
RestoreModifiedId = TRUE;
|
|
|
|
//
|
|
// Increment Modification Count.
|
|
//
|
|
|
|
//
|
|
// we want to increment the modification count only if we
|
|
// are running on a DC
|
|
//
|
|
// see bug# 327474
|
|
//
|
|
|
|
if (LsapProductType == NtProductLanManNt)
|
|
{
|
|
LsapDbState.PolicyModificationInfo.ModifiedId.QuadPart +=
|
|
Increment.QuadPart;
|
|
}
|
|
|
|
if ( FLAG_ON( Options, LSAP_DB_READ_ONLY_TRANSACTION ) ) {
|
|
|
|
Status = LsapRegOpenTransaction();
|
|
|
|
if ( !NT_SUCCESS( Status ) ) {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
Options &= ~LSAP_DB_READ_ONLY_TRANSACTION;
|
|
}
|
|
|
|
Status = LsapDbWriteAttributeObject( LsapDbHandle,
|
|
&LsapDbNames[ PolMod ],
|
|
&LsapDbState.PolicyModificationInfo,
|
|
(ULONG) sizeof (POLICY_MODIFICATION_INFO) );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
Notify = TRUE;
|
|
|
|
//
|
|
// Invalidate the cache for the Policy Modification Information
|
|
//
|
|
|
|
LsapDbMakeInvalidInformationPolicy( PolicyModificationInformation );
|
|
}
|
|
|
|
} else {
|
|
|
|
Notify = FALSE;
|
|
}
|
|
|
|
//
|
|
// If there is a registry transaction in progress,
|
|
// apply it.
|
|
//
|
|
|
|
if ( !FLAG_ON( Options, LSAP_DB_READ_ONLY_TRANSACTION ) ) {
|
|
|
|
// Either we locked it or our caller did
|
|
ASSERT( LsapDbIsLocked( &LsapDbState.RegistryLock ));
|
|
|
|
//
|
|
// Apply the Registry Transaction.
|
|
//
|
|
|
|
Status = LsapRegApplyTransaction( );
|
|
|
|
if ( !NT_SUCCESS( Status ) ) {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
RegApplied = TRUE;
|
|
}
|
|
|
|
//
|
|
// Notify the Replicator
|
|
//
|
|
|
|
if ( Notify ) {
|
|
|
|
Status = LsapDbNotifyChangeObject( ObjectHandle, SecurityDbDeltaType );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
Cleanup:
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
|
|
//
|
|
// Transaction failed. Adjust in-memory copy of the Modification
|
|
// Count, noting that backing store copy is unaltered.
|
|
//
|
|
|
|
if ( RestoreModifiedId ) {
|
|
LsapDbState.PolicyModificationInfo.ModifiedId = OriginalModifiedId;
|
|
}
|
|
|
|
//
|
|
// Abort the registry transaction
|
|
// (Unless the isn't one or it has already been applied.)
|
|
//
|
|
|
|
if ( !FLAG_ON( Options, LSAP_DB_READ_ONLY_TRANSACTION ) && !RegApplied ) {
|
|
(VOID) LsapRegAbortTransaction( );
|
|
}
|
|
}
|
|
|
|
if ( RegistryLocked ) {
|
|
LsapDbLockRelease( &LsapDbState.RegistryLock );
|
|
}
|
|
if ( CurrentThreadInfo ) {
|
|
LsapClearThreadInfo();
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
LsapDbAbortTransaction(
|
|
IN ULONG Options
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function aborts a transaction within the LSA Database.
|
|
|
|
WARNING: The Lsa Database must be in the locked state when this function
|
|
is called.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Standard Nt Result Code
|
|
|
|
Result codes are those returned from the Registry Transaction
|
|
Package.
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
//
|
|
// Verify that the LSA Database is locked
|
|
// (One of many locks is locked.)
|
|
// ASSERT (LsapDbIsLocked());
|
|
|
|
//
|
|
// Abort the Registry Transaction
|
|
//
|
|
if ( !FLAG_ON( Options, LSAP_DB_READ_ONLY_TRANSACTION ) ) {
|
|
|
|
ASSERT( LsapDbIsLocked( &LsapDbState.RegistryLock ));
|
|
|
|
Status = LsapRegAbortTransaction( );
|
|
ASSERT( NT_SUCCESS( Status ) );
|
|
}
|
|
|
|
if ( NT_SUCCESS( Status ) && LsapDsIsFunctionTableValid() ) {
|
|
|
|
ASSERT( LsaDsStateInfo.DsFuncTable.pAbortTransaction );
|
|
Status = (*LsaDsStateInfo.DsFuncTable.pAbortTransaction)( Options );
|
|
|
|
ASSERT( NT_SUCCESS( Status ) );
|
|
}
|
|
|
|
return ( Status );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
LsapDbIsServerInitialized(
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function indicates whether the Lsa Database Server is initialized.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - TRUE if the LSA Database Server is initialized, else FALSE.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (LsapDbState.DbServerInitialized) {
|
|
|
|
return TRUE;
|
|
|
|
} else {
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
LsapDbEnableReplicatorNotification(
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function turns on Replicator Notification.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
|
|
{
|
|
LsapDbState.ReplicatorNotificationEnabled = TRUE;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
LsapDbDisableReplicatorNotification(
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function turns off Replicator Notification.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
|
|
{
|
|
LsapDbState.ReplicatorNotificationEnabled = FALSE;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
LsapDbAcquireLockEx(
|
|
IN LSAP_DB_OBJECT_TYPE_ID ObjectTypeId,
|
|
IN ULONG Options
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function manages the lock status of the LSA database for a given operation.
|
|
The LSA no longer grabs a global lock for all operations. Instead, access locking only
|
|
occurs for operations involving a write. Locks can be obtained for read or write, or
|
|
converted between the two.
|
|
|
|
Arguments:
|
|
|
|
ObjectTypeId - Specifies the expected object type to which the handle
|
|
relates. An error is returned if this type does not match the
|
|
type contained in the handle.
|
|
|
|
Options - Specifies optional additional actions including database state
|
|
changes to be made, or actions not to be performed.
|
|
|
|
LSAP_DB_READ_ONLY_TRANSACTION do not lock the registry lock
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN RegLock = FALSE;
|
|
|
|
LsapDsDebugOut(( DEB_FTRACE, "LsapDbAcquireLockEx(%x,%x)\n",
|
|
ObjectTypeId, Options ));
|
|
|
|
ASSERT( ObjectTypeId == PolicyObject ||
|
|
ObjectTypeId == TrustedDomainObject ||
|
|
ObjectTypeId == AccountObject ||
|
|
ObjectTypeId == SecretObject ||
|
|
ObjectTypeId == NullObject ||
|
|
ObjectTypeId == AllObject );
|
|
|
|
//
|
|
// Determine what lock we're talking about
|
|
//
|
|
switch ( ObjectTypeId ) {
|
|
case PolicyObject:
|
|
LsapDbLockAcquire( &LsapDbState.PolicyLock );
|
|
RegLock = TRUE;
|
|
break;
|
|
|
|
case TrustedDomainObject:
|
|
LsapDbAcquireWriteLockTrustedDomainList();
|
|
break;
|
|
|
|
case AccountObject:
|
|
LsapDbLockAcquire( &LsapDbState.AccountLock );
|
|
RegLock = TRUE;
|
|
break;
|
|
|
|
case SecretObject:
|
|
LsapDbAcquireWriteLockTrustedDomainList();
|
|
LsapDbLockAcquire( &LsapDbState.SecretLock );
|
|
RegLock = TRUE;
|
|
break;
|
|
|
|
case NullObject:
|
|
break;
|
|
|
|
case AllObject:
|
|
LsapDbLockAcquire( &LsapDbState.PolicyLock );
|
|
LsapDbAcquireWriteLockTrustedDomainList();
|
|
LsapDbLockAcquire( &LsapDbState.AccountLock );
|
|
LsapDbLockAcquire( &LsapDbState.SecretLock );
|
|
RegLock = TRUE;
|
|
break;
|
|
|
|
default:
|
|
goto AcquireLockExExit;
|
|
}
|
|
|
|
//
|
|
// See about the registry lock. Only take it after holding an object type lock.
|
|
//
|
|
if ( RegLock &&
|
|
!FLAG_ON( Options, LSAP_DB_READ_ONLY_TRANSACTION ) ) {
|
|
|
|
LsapDbLockAcquire( &LsapDbState.RegistryLock );
|
|
}
|
|
|
|
AcquireLockExExit:
|
|
|
|
LsapDsDebugOut(( DEB_FTRACE, "LsapDbAcquireLockEx\n" ));
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
LsapDbReleaseLockEx(
|
|
IN LSAP_DB_OBJECT_TYPE_ID ObjectTypeId,
|
|
IN ULONG Options
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function releases the lock obtained in the previous function. Depending on the
|
|
state of the preliminary status, the potentially opened transaction is either aborted or
|
|
applied
|
|
|
|
Arguments:
|
|
|
|
ObjectTypeId - Specifies the expected object type to which the handle
|
|
relates. An error is returned if this type does not match the
|
|
type contained in the handle.
|
|
|
|
Options - Specifies optional additional actions including database state
|
|
changes to be made, or actions not to be performed.
|
|
|
|
LSAP_DB_READ_ONLY_TRANSACTION do not release the registry lock
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN RegLock = FALSE;
|
|
|
|
LsapDsDebugOut(( DEB_FTRACE, "LsapDbReleaseLockEx(%x,%x)\n",
|
|
ObjectTypeId, Options ));
|
|
|
|
//
|
|
// Special-case check until reference count handling logic is fixed,
|
|
// then it should go away.
|
|
//
|
|
if ( FLAG_ON( Options, LSAP_DB_NO_LOCK ) && !FLAG_ON( Options, LSAP_DB_LOCK ) ) {
|
|
|
|
goto ReleaseLockExExit;
|
|
}
|
|
|
|
ASSERT( ObjectTypeId == PolicyObject ||
|
|
ObjectTypeId == TrustedDomainObject ||
|
|
ObjectTypeId == AccountObject ||
|
|
ObjectTypeId == SecretObject ||
|
|
ObjectTypeId == NullObject ||
|
|
ObjectTypeId == AllObject );
|
|
|
|
//
|
|
// Determine what lock we're talking about
|
|
//
|
|
switch ( ObjectTypeId ) {
|
|
case PolicyObject:
|
|
LsapDbLockRelease( &LsapDbState.PolicyLock );
|
|
RegLock = TRUE;
|
|
break;
|
|
|
|
case TrustedDomainObject:
|
|
LsapDbReleaseLockTrustedDomainList();
|
|
break;
|
|
|
|
case AccountObject:
|
|
LsapDbLockRelease( &LsapDbState.AccountLock );
|
|
RegLock = TRUE;
|
|
break;
|
|
|
|
case SecretObject:
|
|
LsapDbReleaseLockTrustedDomainList();
|
|
LsapDbLockRelease( &LsapDbState.SecretLock );
|
|
RegLock = TRUE;
|
|
break;
|
|
|
|
case NullObject:
|
|
break;
|
|
|
|
case AllObject:
|
|
LsapDbLockRelease( &LsapDbState.PolicyLock );
|
|
LsapDbReleaseLockTrustedDomainList();
|
|
LsapDbLockRelease( &LsapDbState.AccountLock );
|
|
LsapDbLockRelease( &LsapDbState.SecretLock );
|
|
RegLock = TRUE;
|
|
break;
|
|
|
|
default:
|
|
goto ReleaseLockExExit;
|
|
}
|
|
|
|
//
|
|
// See about the registry lock
|
|
//
|
|
if ( !FLAG_ON( Options, LSAP_DB_READ_ONLY_TRANSACTION ) && RegLock ) {
|
|
|
|
#if DBG
|
|
HANDLE CurrentThread =(HANDLE) (NtCurrentTeb())->ClientId.UniqueThread;
|
|
ASSERT( LsapDbState.RegistryLock.CriticalSection.OwningThread==CurrentThread);
|
|
ASSERT( LsapDbIsLocked(&LsapDbState.RegistryLock));
|
|
#endif
|
|
ASSERT( LsapDbState.RegistryTransactionOpen == FALSE );
|
|
LsapDbLockRelease( &LsapDbState.RegistryLock );
|
|
}
|
|
|
|
ReleaseLockExExit:
|
|
|
|
LsapDsDebugOut(( DEB_FTRACE, "LsapDbReleaseLockEx\n" ));
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
PLSADS_PER_THREAD_INFO
|
|
LsapCreateThreadInfo(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function will create a thread info structure to be used to maintain state on
|
|
the current operation while a ds/registry operation is happening
|
|
|
|
If a thread info is currently active on the thread, it's ref count is incremented
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
Created thread info on success
|
|
|
|
NULL on failure
|
|
|
|
--*/
|
|
{
|
|
PLSADS_PER_THREAD_INFO CurrentThreadInfo = NULL;
|
|
|
|
CurrentThreadInfo = TlsGetValue( LsapDsThreadState );
|
|
|
|
//
|
|
// If we have a current operation state, increment it's use count so we know how many
|
|
// times we have been called...
|
|
//
|
|
if ( CurrentThreadInfo ) {
|
|
|
|
CurrentThreadInfo->UseCount++;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Have to allocate one
|
|
//
|
|
CurrentThreadInfo = LsapAllocateLsaHeap( sizeof( LSADS_PER_THREAD_INFO ) );
|
|
|
|
if ( CurrentThreadInfo ) {
|
|
|
|
if ( TlsSetValue( LsapDsThreadState, CurrentThreadInfo ) == FALSE ) {
|
|
|
|
LsapDsDebugOut(( DEB_ERROR,
|
|
"TlsSetValue for %p on %lu failed with %lu\n",
|
|
CurrentThreadInfo,
|
|
GetCurrentThreadId(),
|
|
GetLastError() ));
|
|
|
|
LsapFreeLsaHeap( CurrentThreadInfo );
|
|
CurrentThreadInfo = NULL;
|
|
|
|
} else {
|
|
|
|
RtlZeroMemory( CurrentThreadInfo, sizeof( LSADS_PER_THREAD_INFO ) );
|
|
|
|
CurrentThreadInfo->UseCount++;
|
|
|
|
#if DBG
|
|
//
|
|
// Add ourselves to the list
|
|
//
|
|
SafeAcquireResourceExclusive( &LsapDsThreadInfoListResource, TRUE );
|
|
{
|
|
ULONG i;
|
|
BOOLEAN Inserted = FALSE;
|
|
|
|
for (i = 0; i < LSAP_THREAD_INFO_LIST_MAX; i++ ) {
|
|
|
|
ASSERT( LsapDsThreadInfoList[ i ].ThreadId != GetCurrentThreadId( ));
|
|
|
|
if ( LsapDsThreadInfoList[ i ].ThreadInfo == NULL ) {
|
|
|
|
LsapDsThreadInfoList[ i ].ThreadInfo = CurrentThreadInfo;
|
|
LsapDsThreadInfoList[ i ].ThreadId = GetCurrentThreadId( );
|
|
Inserted = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !Inserted ) {
|
|
|
|
LsapDsDebugOut(( DEB_ERROR,
|
|
"Failed to insert THREAD_INFO %p in list for %lu: "
|
|
"List full\n",
|
|
CurrentThreadInfo,
|
|
GetCurrentThreadId() ));
|
|
}
|
|
}
|
|
|
|
SafeReleaseResource( &LsapDsThreadInfoListResource );
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
return( CurrentThreadInfo );
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
LsapClearThreadInfo(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function will remove a thread info structure to be used to maintain state on
|
|
the current operation while a ds/registry operation is happening
|
|
|
|
If a thread info's ref count is greater than 1, the ref count is decremented, but the
|
|
thread info remains
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
PLSADS_PER_THREAD_INFO CurrentThreadInfo = NULL;
|
|
NTSTATUS Status;
|
|
|
|
CurrentThreadInfo = TlsGetValue( LsapDsThreadState );
|
|
|
|
//
|
|
// No thread info, nothing to do
|
|
//
|
|
if ( CurrentThreadInfo ) {
|
|
|
|
if ( CurrentThreadInfo->UseCount > 1 ) {
|
|
|
|
CurrentThreadInfo->UseCount--;
|
|
|
|
} else {
|
|
|
|
ASSERT( CurrentThreadInfo->UseCount == 1 );
|
|
|
|
if ( CurrentThreadInfo->DsTransUseCount != 0 ) {
|
|
ASSERT( CurrentThreadInfo->DsTransUseCount == 0 );
|
|
LsapDsDebugOut(( DEB_ERROR,
|
|
"Aborting transaction inside cleanup!\n" ));
|
|
LsapDsCauseTransactionToCommitOrAbort( FALSE );
|
|
}
|
|
|
|
if ( CurrentThreadInfo->DsThreadStateUseCount != 0 ) {
|
|
ASSERT( CurrentThreadInfo->DsThreadStateUseCount == 0 );
|
|
LsapDsDebugOut(( DEB_ERROR,
|
|
"Clear DS thread state inside cleanup!\n" ));
|
|
|
|
Status = LsapDsMapDsReturnToStatus( THDestroy( ) );
|
|
ASSERT( NT_SUCCESS( Status ) );
|
|
|
|
THRestore( CurrentThreadInfo->InitialThreadState );
|
|
CurrentThreadInfo->InitialThreadState = NULL;
|
|
|
|
CurrentThreadInfo->DsThreadStateUseCount = 0;
|
|
}
|
|
|
|
#if DBG
|
|
//
|
|
// Remove ourselves from the list
|
|
//
|
|
SafeAcquireResourceExclusive( &LsapDsThreadInfoListResource, TRUE );
|
|
{
|
|
ULONG i;
|
|
for (i = 0; i < LSAP_THREAD_INFO_LIST_MAX; i++ ) {
|
|
|
|
if ( LsapDsThreadInfoList[ i ].ThreadId == GetCurrentThreadId( ) ) {
|
|
|
|
ASSERT( LsapDsThreadInfoList[ i ].ThreadInfo == CurrentThreadInfo );
|
|
LsapDsThreadInfoList[ i ].ThreadInfo = NULL;
|
|
LsapDsThreadInfoList[ i ].ThreadId = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
SafeReleaseResource( &LsapDsThreadInfoListResource );
|
|
#endif
|
|
|
|
//
|
|
// Clear the entry out of the thread local storage
|
|
//
|
|
if ( TlsSetValue( LsapDsThreadState, NULL ) == FALSE ) {
|
|
|
|
LsapDsDebugOut(( DEB_ERROR,
|
|
"Failed to remove %p for thread %lu: %lu\n",
|
|
CurrentThreadInfo,
|
|
GetCurrentThreadId(),
|
|
GetLastError() ));
|
|
}
|
|
|
|
LsapFreeLsaHeap( CurrentThreadInfo );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
LsapSaveDsThreadState(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function will save off the current DS thread state that may exist at the time
|
|
the function is called. It does not distinguish between a thread state created by
|
|
an outside caller (say SAM), or one created by Lsa itself
|
|
|
|
If a thread info block does not exist at the time this function is called, nothing
|
|
is done
|
|
|
|
Calling this function refcounts the thread info
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
PLSADS_PER_THREAD_INFO CurrentThreadInfo = NULL;
|
|
|
|
CurrentThreadInfo = TlsGetValue( LsapDsThreadState );
|
|
|
|
//
|
|
// No thread info, nothing to do
|
|
//
|
|
if ( CurrentThreadInfo ) {
|
|
|
|
ASSERT( CurrentThreadInfo->UseCount > 0 );
|
|
CurrentThreadInfo->UseCount++;
|
|
|
|
ASSERT( !CurrentThreadInfo->SavedTransactionValid );
|
|
CurrentThreadInfo->SavedTransactionValid = TRUE;
|
|
CurrentThreadInfo->SavedThreadState = THSave();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
LsapRestoreDsThreadState(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function will restore a previously saved DS thread state
|
|
|
|
If a thread info block does not exist at the time this function is called or there is
|
|
no previously saved state exists, nothing is done
|
|
|
|
Calling this function refcounts the thread info
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
PLSADS_PER_THREAD_INFO CurrentThreadInfo = NULL;
|
|
|
|
CurrentThreadInfo = TlsGetValue( LsapDsThreadState );
|
|
|
|
//
|
|
// No thread info, nothing to do
|
|
//
|
|
if ( CurrentThreadInfo ) {
|
|
|
|
CurrentThreadInfo->UseCount--;
|
|
ASSERT( CurrentThreadInfo->UseCount > 0 );
|
|
|
|
if ( CurrentThreadInfo->SavedTransactionValid == TRUE ) {
|
|
|
|
CurrentThreadInfo->SavedTransactionValid = FALSE;
|
|
if ( CurrentThreadInfo->SavedThreadState ) {
|
|
|
|
THRestore( CurrentThreadInfo->SavedThreadState );
|
|
}
|
|
|
|
CurrentThreadInfo->SavedThreadState = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
LsapServerRpcThreadReturnNotify(
|
|
LPWSTR CallingFunction
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API is called when an RPC thread which has a notify routine specified in the servers
|
|
ACF file.
|
|
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Values:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
{
|
|
#if DBG
|
|
static BOOLEAN CleanAsRequired = TRUE;
|
|
PLSADS_PER_THREAD_INFO CurrentThreadInfo = NULL;
|
|
NTSTATUS Status;
|
|
HANDLE ThreadHandle = GetCurrentThread();
|
|
|
|
if ( ( LsaDsInitState == LsapDsNoDs ) ||
|
|
( LsaDsInitState == LsapDsUnknown ) )
|
|
{
|
|
return ;
|
|
}
|
|
|
|
CurrentThreadInfo = TlsGetValue( LsapDsThreadState );
|
|
|
|
ASSERT( CurrentThreadInfo == NULL );
|
|
|
|
if ( CurrentThreadInfo ) {
|
|
|
|
LsapDsDebugOut(( DEB_ERROR, "ThreadInfo left by %ws\n", CallingFunction ));
|
|
LsapClearThreadInfo();
|
|
}
|
|
|
|
ASSERT( !THQuery() );
|
|
|
|
if ( THQuery() ) {
|
|
|
|
LsapDsDebugOut(( DEB_ERROR,
|
|
"Open threadstate in cleanup. Aborting...\n" ));
|
|
|
|
if ( SampExistsDsTransaction() ) {
|
|
|
|
LsapDsDebugOut(( DEB_ERROR, "Ds transaction left by %ws\n", CallingFunction ));
|
|
LsapDsCauseTransactionToCommitOrAbort( FALSE );
|
|
THDestroy( );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Make sure we are not holding any of the locks when we exit
|
|
//
|
|
#if 0
|
|
ASSERT( ThreadHandle != LsapDbState.AccountLock.ExclusiveOwnerThread );
|
|
ASSERT( ThreadHandle != LsapDbState.PolicyLock.ExclusiveOwnerThread );
|
|
ASSERT( ThreadHandle != LsapDbState.SecretLock.ExclusiveOwnerThread );
|
|
ASSERT( ThreadHandle != LsapDbState.RegistryLock.ExclusiveOwnerThread );
|
|
#endif
|
|
|
|
#endif
|
|
|
|
UNREFERENCED_PARAMETER( CallingFunction );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsaIHealthCheck(
|
|
IN OPTIONAL LSAPR_HANDLE DomainHandle,
|
|
IN ULONG StateChange,
|
|
IN OUT PVOID StateChangeData,
|
|
IN OUT PULONG StateChangeDataLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is actually invoked by Sam to indicate that state of interest to the Lsa
|
|
has changed, and provide that state to the Lsa. Specifically, currently, it is the Sam
|
|
SessionKey
|
|
|
|
This function USED to perform sanity checks within LSA. It was invoked from
|
|
SAM on a regular basis. However, it was no longer needed. Instead, we took the
|
|
function, leaving the appropriate export from lsasrv.dll, to obsfucate the fact that
|
|
we are now using to pass the Sam encryption key back and forth...
|
|
|
|
Arguments:
|
|
|
|
DomainHandle - What domain this refers to. Null means the root domain
|
|
|
|
StateChange - What Sam/other in process client state changed that LSA cares about. Can be:
|
|
LSAI_SAM_STATE_SESS_KEY - SAM's session key has changed
|
|
|
|
StateChangeData - What data has changed. Dependent on the type of the state change. The
|
|
data format must be pre-agreed upon by the Lsa and the invoker.
|
|
|
|
|
|
Return Values:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
UNICODE_STRING CipherKey;
|
|
|
|
LsapEnterFunc( "LsaIHealthCheck" );
|
|
|
|
UNREFERENCED_PARAMETER( DomainHandle );
|
|
|
|
switch ( StateChange ) {
|
|
case LSAI_SAM_STATE_SESS_KEY:
|
|
|
|
//
|
|
// Copy the syskey into memory
|
|
//
|
|
|
|
ASSERT(LSAP_SYSKEY_SIZE==*StateChangeDataLength);
|
|
|
|
LsapDbSetSyskey(StateChangeData, LSAP_SYSKEY_SIZE);
|
|
|
|
//
|
|
// Now do a database upgrade if necessary
|
|
//
|
|
|
|
Status = LsapDbUpgradeRevision(TRUE, FALSE);
|
|
break;
|
|
|
|
case LSAI_SAM_STATE_UNROLL_SP4_ENCRYPTION:
|
|
|
|
CipherKey.Length = CipherKey.MaximumLength = (USHORT)*StateChangeDataLength;
|
|
CipherKey.Buffer = StateChangeData;
|
|
Status = LsapDbInitializeCipherKey( &CipherKey,
|
|
&LsapDbSP4SecretCipherKey );
|
|
|
|
break;
|
|
|
|
case LSAI_SAM_STATE_RETRIEVE_SESS_KEY:
|
|
|
|
//
|
|
// Return the syskey as part of state change data
|
|
//
|
|
|
|
if (NULL!=LsapDbSysKey)
|
|
{
|
|
RtlCopyMemory(StateChangeData, LsapDbSysKey, LSAP_SYSKEY_SIZE);
|
|
*StateChangeDataLength = LSAP_SYSKEY_SIZE;
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
break;
|
|
|
|
case LSAI_SAM_STATE_CLEAR_SESS_KEY:
|
|
|
|
//
|
|
// Clear the syskey in memory
|
|
//
|
|
|
|
RtlZeroMemory(LsapDbSysKey,LSAP_SYSKEY_SIZE);
|
|
LsapDbSysKey = NULL;
|
|
break;
|
|
|
|
case LSAI_SAM_GENERATE_SESS_KEY:
|
|
|
|
//
|
|
// Generate a new syskey and perform the database upgrade
|
|
//
|
|
|
|
Status = LsapDbUpgradeRevision(TRUE,TRUE);
|
|
break;
|
|
|
|
case LSAI_SAM_STATE_OLD_SESS_KEY:
|
|
|
|
//
|
|
// Return the old syskey as part of state change data
|
|
//
|
|
|
|
if (NULL!=LsapDbOldSysKey)
|
|
{
|
|
RtlCopyMemory(StateChangeData, LsapDbOldSysKey, LSAP_SYSKEY_SIZE);
|
|
*StateChangeDataLength = LSAP_SYSKEY_SIZE;
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
}
break;
default:
LsapDsDebugOut(( DEB_ERROR,
"Unhandled state change %lu\n", StateChange ));
break;
}
LsapExitFunc( "LsaIHealthCheck", Status );
return(Status);
}
|