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.
1472 lines
36 KiB
1472 lines
36 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ophandle.c
|
|
|
|
Abstract:
|
|
|
|
Routines to manipulate the global operation handle
|
|
|
|
Author:
|
|
|
|
Colin Brace (ColinBr) April 5, 1999
|
|
|
|
Environment:
|
|
|
|
User Mode
|
|
|
|
Revision History:
|
|
|
|
Reorganized from
|
|
|
|
Mac McLain (MacM) Feb 10, 1997
|
|
|
|
--*/
|
|
#include <setpch.h>
|
|
#include <dssetp.h>
|
|
#include <lsarpc.h>
|
|
#include <samrpc.h>
|
|
#include <samisrv.h>
|
|
#include <db.h>
|
|
#include <confname.h>
|
|
#include <loadfn.h>
|
|
#include <ntdsa.h>
|
|
#include <dsconfig.h>
|
|
#include <attids.h>
|
|
#include <dsp.h>
|
|
#include <lsaisrv.h>
|
|
#include <malloc.h>
|
|
#include <dsgetdc.h>
|
|
#include <lmcons.h>
|
|
#include <lmaccess.h>
|
|
#include <lmapibuf.h>
|
|
#include <lmerr.h>
|
|
#include <netsetp.h>
|
|
#include <spmgr.h> // For SetupPhase definition
|
|
|
|
#include "secure.h"
|
|
#include "ophandle.h"
|
|
|
|
//
|
|
// Global data -- init'ed to an idle state in DsRoleInitialize
|
|
//
|
|
DSROLEP_OPERATION_HANDLE DsRolepCurrentOperationHandle;
|
|
DSROLEP_IFM_OPERATION_HANDLE DsRolepCurrentIfmOperationHandle = { 0 };
|
|
|
|
DWORD
|
|
DsRolepInitializeOperationHandle(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Does the initialization of the operation handle. The operation handle controls state
|
|
and actions of the ds setup apis
|
|
|
|
Arguments:
|
|
|
|
VOID
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS - Success
|
|
|
|
--*/
|
|
{
|
|
DWORD Win32Err = ERROR_SUCCESS;
|
|
OBJECT_ATTRIBUTES EventAttr;
|
|
UNICODE_STRING EventName;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Grab the lock
|
|
//
|
|
LockOpHandle();
|
|
|
|
if ( DSROLEP_IDLE != DsRolepCurrentOperationHandle.OperationState ) {
|
|
|
|
//
|
|
// Not idle? Bail
|
|
//
|
|
Win32Err = ERROR_PROMOTION_ACTIVE;
|
|
|
|
} else {
|
|
|
|
Win32Err = DsRolepGetImpersonationToken(&DsRolepCurrentOperationHandle.ClientToken);
|
|
if (ERROR_SUCCESS != Win32Err) {
|
|
DsRolepCurrentOperationHandle.ClientToken=NULL;
|
|
DsRolepLogPrintRoutine(DEB_WARN, "Cannot get user Token for Format Message: %ul\n",
|
|
Win32Err);
|
|
Win32Err = ERROR_SUCCESS;
|
|
//if Error log and continue
|
|
}
|
|
|
|
//
|
|
// We are idle, and hence ready to perform a role change
|
|
//
|
|
RtlInitUnicodeString(&EventName, DSROLEP_EVENT_NAME);
|
|
|
|
InitializeObjectAttributes(&EventAttr, &EventName, 0, NULL, NULL);
|
|
|
|
Status = NtCreateEvent( &DsRolepCurrentOperationHandle.CompletionEvent,
|
|
EVENT_ALL_ACCESS,
|
|
&EventAttr,
|
|
NotificationEvent,
|
|
FALSE);
|
|
if (Status == STATUS_OBJECT_NAME_COLLISION ) {
|
|
|
|
//
|
|
// If the event exists but the operation active flag is clear, we'll
|
|
// go ahead and use the event
|
|
//
|
|
Status = NtResetEvent( DsRolepCurrentOperationHandle.CompletionEvent, NULL );
|
|
}
|
|
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
|
|
//
|
|
// Create the cancel event
|
|
//
|
|
Status = NtCreateEvent( &DsRolepCurrentOperationHandle.CancelEvent,
|
|
EVENT_MODIFY_STATE | SYNCHRONIZE ,
|
|
NULL,
|
|
NotificationEvent,
|
|
FALSE );
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
|
|
//
|
|
// We are ready to roll!
|
|
//
|
|
|
|
DsRolepCurrentOperationHandle.OperationState = DSROLEP_RUNNING;
|
|
|
|
//
|
|
// Set the initial message
|
|
//
|
|
DsRolepCurrentOperationHandle.MsgIndex = DSROLERES_STARTING;
|
|
}
|
|
}
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
|
|
//
|
|
// Load the functions we'll need
|
|
//
|
|
Win32Err = DsRolepLoadSetupFunctions();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Release the lock
|
|
//
|
|
UnlockOpHandle();
|
|
|
|
if ( ERROR_SUCCESS != Win32Err
|
|
|| !NT_SUCCESS( Status ) ) {
|
|
|
|
if ( ERROR_SUCCESS == Win32Err ) {
|
|
|
|
Win32Err = RtlNtStatusToDosError( Status );
|
|
|
|
}
|
|
|
|
DsRolepLogPrint(( DEB_ERROR, "Internal error trying to initialize operation handle (%lu).\n", Win32Err ));
|
|
|
|
//
|
|
// Reset the handle state
|
|
//
|
|
DsRolepResetOperationHandle( DSROLEP_IDLE );
|
|
}
|
|
|
|
return( Win32Err );
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
DsRolepResetOperationHandle(
|
|
DSROLEP_OPERATION_STATE OpState
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Resets the operation handle following a failed or successful completion
|
|
of the operation
|
|
|
|
Arguments:
|
|
|
|
VOID
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS - Success
|
|
|
|
--*/
|
|
{
|
|
DWORD Win32Err = ERROR_SUCCESS;
|
|
OBJECT_ATTRIBUTES EventAttr;
|
|
UNICODE_STRING EventName;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
// These are the only two states that make sense
|
|
ASSERT( (OpState == DSROLEP_IDLE) || (OpState == DSROLEP_NEED_REBOOT) );
|
|
|
|
//
|
|
// Lock the operation handle
|
|
//
|
|
LockOpHandle();
|
|
|
|
// It should always be active
|
|
ASSERT( DSROLEP_OPERATION_ACTIVE( DsRolepCurrentOperationHandle.OperationState) );
|
|
if ( DSROLEP_OPERATION_ACTIVE( DsRolepCurrentOperationHandle.OperationState) )
|
|
{
|
|
if(DsRolepCurrentOperationHandle.ClientToken){
|
|
CloseHandle(DsRolepCurrentOperationHandle.ClientToken);
|
|
DsRolepCurrentOperationHandle.ClientToken = NULL;
|
|
}
|
|
//
|
|
// Release the resource of the operation handle
|
|
//
|
|
if ( DsRolepCurrentOperationHandle.CompletionEvent ) {
|
|
|
|
Status = NtClose( DsRolepCurrentOperationHandle.CompletionEvent );
|
|
DsRolepCurrentOperationHandle.CompletionEvent = NULL;
|
|
|
|
if ( !NT_SUCCESS( Status ) ) {
|
|
|
|
DsRoleDebugOut(( DEB_TRACE_DS,
|
|
"Failed to close event handle: 0x%lx\n", Status ));
|
|
}
|
|
}
|
|
|
|
if ( DsRolepCurrentOperationHandle.CancelEvent ) {
|
|
|
|
Status = NtClose( DsRolepCurrentOperationHandle.CancelEvent );
|
|
DsRolepCurrentOperationHandle.CancelEvent = NULL;
|
|
|
|
if ( !NT_SUCCESS( Status ) ) {
|
|
|
|
DsRoleDebugOut(( DEB_TRACE_DS,
|
|
"Failed to close event handle: 0x%lx\n", Status ));
|
|
}
|
|
}
|
|
|
|
if ( DsRolepCurrentOperationHandle.OperationThread != NULL ) {
|
|
|
|
CloseHandle( DsRolepCurrentOperationHandle.OperationThread );
|
|
DsRolepCurrentOperationHandle.OperationThread = NULL;
|
|
}
|
|
|
|
//
|
|
// Unload the global functions
|
|
//
|
|
DsRolepUnloadSetupFunctions();
|
|
|
|
//
|
|
// Clear the static variables
|
|
//
|
|
DsRolepResetOperationHandleLockHeld();
|
|
|
|
//
|
|
// Reset the operation state
|
|
//
|
|
DsRolepCurrentOperationHandle.OperationState = OpState;
|
|
|
|
//
|
|
// Reset the IFM operation
|
|
//
|
|
DsRolepCurrentIfmOperationHandle.fIfmOpHandleLock = FALSE;
|
|
}
|
|
|
|
//
|
|
// Release the lock
|
|
//
|
|
UnlockOpHandle();
|
|
|
|
if ( !NT_SUCCESS( Status ) ) {
|
|
|
|
Win32Err = RtlNtStatusToDosError( Status );
|
|
}
|
|
|
|
return( Win32Err );
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
DsRolepResetOperationHandleLockHeld(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Resets the operation handle following a failed or successful completion of the operation
|
|
|
|
Arguments:
|
|
|
|
VOID
|
|
|
|
Returns:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
|
|
ASSERT( DsRolepCurrentThreadOwnsLock() );
|
|
|
|
if ( DsRolepCurrentOperationHandle.Parameter1 ) {
|
|
LocalFree( DsRolepCurrentOperationHandle.Parameter1 );
|
|
DsRolepCurrentOperationHandle.Parameter1 = NULL;
|
|
}
|
|
if ( DsRolepCurrentOperationHandle.Parameter2 ) {
|
|
LocalFree( DsRolepCurrentOperationHandle.Parameter2 );
|
|
DsRolepCurrentOperationHandle.Parameter2 = NULL;
|
|
}
|
|
if ( DsRolepCurrentOperationHandle.Parameter3 ) {
|
|
LocalFree( DsRolepCurrentOperationHandle.Parameter3 );
|
|
DsRolepCurrentOperationHandle.Parameter3 = NULL;
|
|
}
|
|
if ( DsRolepCurrentOperationHandle.Parameter4 ) {
|
|
LocalFree( DsRolepCurrentOperationHandle.Parameter4 );
|
|
DsRolepCurrentOperationHandle.Parameter4 = NULL;
|
|
}
|
|
|
|
DsRolepCurrentOperationHandle.CompletionEvent = NULL;
|
|
DsRolepCurrentOperationHandle.OperationState = DSROLEP_IDLE;
|
|
DsRolepCurrentOperationHandle.OperationStatus = 0;
|
|
DsRolepCurrentOperationHandle.MsgIndex = 0;
|
|
DsRolepCurrentOperationHandle.DisplayStringCount = 0;
|
|
DsRolepCurrentOperationHandle.MsgModuleHandle = NULL;
|
|
DsRolepCurrentOperationHandle.UpdateStringDisplayable = NULL;
|
|
DsRolepCurrentOperationHandle.FinalResultStringDisplayable = NULL;
|
|
DsRolepCurrentOperationHandle.InstalledSiteName = NULL;
|
|
DsRolepCurrentOperationHandle.OperationResultFlags = 0;
|
|
|
|
ASSERT( DsRolepCurrentThreadOwnsLock() );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
DWORD
|
|
DsRolepSetCurrentOperationStatus(
|
|
IN ULONG MsgIndex,
|
|
IN PVOID Parameter1,
|
|
IN PVOID Parameter2,
|
|
IN PVOID Parameter3,
|
|
IN PVOID Parameter4
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Internal routine for updating the current operation handle statics
|
|
|
|
Arguments:
|
|
|
|
MsgIndex - Display message resource index
|
|
|
|
Parameter1 - First display parameter
|
|
|
|
Parameter2 - Second display parameter
|
|
|
|
Parameter3 - Third display parameter
|
|
|
|
Parameter4 - Fourth display parameter
|
|
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS - Success
|
|
|
|
--*/
|
|
{
|
|
DWORD Win32Err = ERROR_SUCCESS;
|
|
ULONG Size;
|
|
|
|
ASSERT( MsgIndex != 0 );
|
|
|
|
//
|
|
// Grab the lock
|
|
//
|
|
LockOpHandle();
|
|
|
|
DsRolepCurrentOperationHandle.MsgIndex = MsgIndex;
|
|
|
|
//
|
|
// Release previously held parameters
|
|
//
|
|
if ( DsRolepCurrentOperationHandle.Parameter1 ) {
|
|
LocalFree( DsRolepCurrentOperationHandle.Parameter1 );
|
|
DsRolepCurrentOperationHandle.Parameter1 = NULL;
|
|
}
|
|
if ( DsRolepCurrentOperationHandle.Parameter2 ) {
|
|
LocalFree( DsRolepCurrentOperationHandle.Parameter2 );
|
|
DsRolepCurrentOperationHandle.Parameter2 = NULL;
|
|
}
|
|
if ( DsRolepCurrentOperationHandle.Parameter3 ) {
|
|
LocalFree( DsRolepCurrentOperationHandle.Parameter3 );
|
|
DsRolepCurrentOperationHandle.Parameter3 = NULL;
|
|
}
|
|
if ( DsRolepCurrentOperationHandle.Parameter4 ) {
|
|
LocalFree( DsRolepCurrentOperationHandle.Parameter4 );
|
|
DsRolepCurrentOperationHandle.Parameter4 = NULL;
|
|
}
|
|
|
|
//
|
|
// Copy the new ones in
|
|
//
|
|
if ( Parameter1 ) {
|
|
Size = (wcslen( Parameter1 ) + 1) * sizeof(WCHAR);
|
|
DsRolepCurrentOperationHandle.Parameter1 = LocalAlloc( 0, Size );
|
|
if ( !DsRolepCurrentOperationHandle.Parameter1 ) {
|
|
Win32Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto ReleaseLock;
|
|
}
|
|
wcscpy( DsRolepCurrentOperationHandle.Parameter1, Parameter1 );
|
|
}
|
|
|
|
if ( Parameter2 ) {
|
|
Size = (wcslen( Parameter2 ) + 1) * sizeof(WCHAR);
|
|
DsRolepCurrentOperationHandle.Parameter2 = LocalAlloc( 0, Size );
|
|
if ( !DsRolepCurrentOperationHandle.Parameter2 ) {
|
|
Win32Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto ReleaseLock;
|
|
}
|
|
wcscpy( DsRolepCurrentOperationHandle.Parameter2, Parameter2 );
|
|
}
|
|
|
|
if ( Parameter3 ) {
|
|
Size = (wcslen( Parameter3 ) + 1) * sizeof(WCHAR);
|
|
DsRolepCurrentOperationHandle.Parameter3 = LocalAlloc( 0, Size );
|
|
if ( !DsRolepCurrentOperationHandle.Parameter3 ) {
|
|
Win32Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto ReleaseLock;
|
|
}
|
|
wcscpy( DsRolepCurrentOperationHandle.Parameter3, Parameter3 );
|
|
}
|
|
|
|
if ( Parameter4 ) {
|
|
Size = (wcslen( Parameter4 ) + 1) * sizeof(WCHAR);
|
|
DsRolepCurrentOperationHandle.Parameter4 = LocalAlloc( 0, Size );
|
|
if ( !DsRolepCurrentOperationHandle.Parameter4 ) {
|
|
Win32Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto ReleaseLock;
|
|
}
|
|
wcscpy( DsRolepCurrentOperationHandle.Parameter4, Parameter4 );
|
|
}
|
|
|
|
{
|
|
PWSTR DisplayString;
|
|
DWORD E2;
|
|
E2 = DsRolepFormatOperationString(
|
|
DsRolepCurrentOperationHandle.MsgIndex,
|
|
&DisplayString,
|
|
DsRolepCurrentOperationHandle.Parameter1,
|
|
DsRolepCurrentOperationHandle.Parameter2,
|
|
DsRolepCurrentOperationHandle.Parameter3,
|
|
DsRolepCurrentOperationHandle.Parameter4 );
|
|
|
|
if ( E2 == ERROR_SUCCESS ) {
|
|
|
|
DsRolepLogPrint(( DEB_TRACE, "%ws", DisplayString ));
|
|
MIDL_user_free( DisplayString );
|
|
}
|
|
}
|
|
|
|
ReleaseLock:
|
|
|
|
//
|
|
// Don't forget to release the lock
|
|
//
|
|
UnlockOpHandle();
|
|
|
|
|
|
return( Win32Err );
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
DsRolepSetFailureMessage(
|
|
IN DWORD FailureStatus,
|
|
IN ULONG MsgIndex,
|
|
IN PVOID Parameter1,
|
|
IN PVOID Parameter2,
|
|
IN PVOID Parameter3,
|
|
IN PVOID Parameter4
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Internal routine for updating the failure return string
|
|
|
|
Arguments:
|
|
|
|
FailureStatus - Error code for the failure
|
|
|
|
MsgIndex - Display message resource index
|
|
|
|
Parameter1 - First display parameter
|
|
|
|
Parameter2 - Second display parameter
|
|
|
|
Parameter3 - Third display parameter
|
|
|
|
Parameter4 - Fourth display parameter
|
|
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS - Success
|
|
|
|
--*/
|
|
{
|
|
DWORD Win32Err = ERROR_SUCCESS;
|
|
PWSTR DisplayString = NULL;
|
|
|
|
ASSERT( MsgIndex != 0 );
|
|
|
|
Win32Err = DsRolepFormatOperationString( MsgIndex,
|
|
&DisplayString,
|
|
Parameter1,
|
|
Parameter2,
|
|
Parameter3,
|
|
Parameter4 );
|
|
|
|
if ( Win32Err == ERROR_SUCCESS ) {
|
|
|
|
Win32Err = DsRolepStringErrorUpdateCallback( DisplayString, FailureStatus );
|
|
|
|
MIDL_user_free( DisplayString );
|
|
}
|
|
|
|
return( Win32Err );
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
DsRolepSetOperationDone(
|
|
IN DWORD Flags,
|
|
IN DWORD OperationStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Indicates that the requested operation has completed
|
|
|
|
Arguments:
|
|
|
|
Flags -- currently : DSROLEP_OP_DEMOTION
|
|
DSROLEP_OP_PROMOTION
|
|
|
|
OperationStatus - Final status of the requsted operation
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS - Success
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Grab the lock
|
|
//
|
|
LockOpHandle();
|
|
|
|
DSROLEP_CURRENT_OP0( DSROLEEVT_PROMOTION_COMPLETE );
|
|
DsRolepCurrentOperationHandle.OperationState = DSROLEP_FINISHED;
|
|
|
|
if ( DsRolepCurrentOperationHandle.OperationStatus == 0
|
|
|| (OperationStatus == ERROR_CANCELLED) ) {
|
|
|
|
DsRolepCurrentOperationHandle.OperationStatus = OperationStatus;
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == DsRolepCurrentOperationHandle.OperationStatus ) {
|
|
|
|
//
|
|
// Log an event indicating the role has changed
|
|
//
|
|
DWORD MsgId = 0;
|
|
if ( Flags & DSROLEP_OP_DEMOTION ) {
|
|
|
|
MsgId = DSROLERES_DEMOTE_SUCCESS;
|
|
|
|
} else if ( Flags & DSROLEP_OP_PROMOTION ) {
|
|
|
|
MsgId = DSROLERES_PROMOTE_SUCCESS;
|
|
|
|
} else if ( Flags & DSROLEP_OP_DEMOTION_FORCED ) {
|
|
|
|
MsgId = DSROLERES_FORCE_DEMOTE_SUCCESS;
|
|
|
|
} else {
|
|
|
|
ASSERT( FALSE && !"Bad Parameter" );
|
|
|
|
}
|
|
|
|
SpmpReportEvent( TRUE,
|
|
EVENTLOG_INFORMATION_TYPE,
|
|
MsgId,
|
|
0,
|
|
0,
|
|
NULL,
|
|
0 );
|
|
}
|
|
|
|
//
|
|
// If the operation was cancelled, give the same error message every
|
|
// time
|
|
//
|
|
if ( ERROR_CANCELLED == DsRolepCurrentOperationHandle.OperationStatus ) {
|
|
|
|
(VOID) DsRolepSetFailureMessage( ERROR_CANCELLED,
|
|
DSROLERES_OP_CANCELLED,
|
|
NULL, NULL, NULL, NULL );
|
|
}
|
|
|
|
//
|
|
// Signal the completion event
|
|
//
|
|
Status = NtSetEvent( DsRolepCurrentOperationHandle.CompletionEvent, NULL );
|
|
|
|
DsRoleDebugOut(( DEB_TRACE_DS, "DsRolepSetOperationDone[ %lu ]\n",
|
|
OperationStatus ));
|
|
|
|
|
|
//
|
|
// Release the lock
|
|
//
|
|
UnlockOpHandle();
|
|
|
|
DsRolepLogPrint(( DEB_TRACE,
|
|
"DsRolepSetOperationDone returned %lu\n",
|
|
RtlNtStatusToDosError( Status ) ));
|
|
|
|
|
|
return( RtlNtStatusToDosError( Status ) );
|
|
}
|
|
|
|
|
|
DWORD
|
|
DsRolepGetDcOperationProgress(
|
|
IN PDSROLE_SERVEROP_HANDLE DsOperationHandle,
|
|
IN OUT PDSROLER_SERVEROP_STATUS *ServerOperationStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Implementation of the RPC server for determining the current level of progress of an
|
|
operation
|
|
|
|
Arguments:
|
|
|
|
DsOperationHandle - Handle to an open operation
|
|
|
|
ServerOperationStatus - Where the status is returned.
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS - Success
|
|
|
|
ERROR_NOT_ENOUGH_MEMORY - A memory allocation failed
|
|
|
|
--*/
|
|
{
|
|
DWORD Win32Err = ERROR_SUCCESS;
|
|
|
|
//
|
|
// Grab the lock
|
|
//
|
|
LockOpHandle();
|
|
|
|
//
|
|
// Allocate the return structure
|
|
//
|
|
*ServerOperationStatus = MIDL_user_allocate( sizeof( DSROLER_SERVEROP_STATUS ) );
|
|
|
|
if ( *ServerOperationStatus == NULL ) {
|
|
|
|
Win32Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Build the return string
|
|
//
|
|
if ( DsRolepCurrentOperationHandle.MsgIndex == 0 ) {
|
|
|
|
( *ServerOperationStatus )->CurrentOperationDisplayString = MIDL_user_allocate(
|
|
( wcslen( DsRolepCurrentOperationHandle.UpdateStringDisplayable ) + 1 ) *
|
|
sizeof( WCHAR ) );
|
|
|
|
|
|
if ( ( *ServerOperationStatus )->CurrentOperationDisplayString == NULL ) {
|
|
|
|
Win32Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
} else {
|
|
|
|
wcscpy( ( *ServerOperationStatus )->CurrentOperationDisplayString,
|
|
DsRolepCurrentOperationHandle.UpdateStringDisplayable );
|
|
|
|
//
|
|
// Set the status flags if they exist
|
|
//
|
|
if ( DsRolepCurrentOperationHandle.OperationState == DSROLEP_RUNNING_NON_CRITICAL ) {
|
|
|
|
( *ServerOperationStatus )->OperationStatus =
|
|
DSROLE_CRITICAL_OPERATIONS_COMPLETED;
|
|
} else {
|
|
|
|
( *ServerOperationStatus )->OperationStatus = 0;
|
|
|
|
}
|
|
|
|
( *ServerOperationStatus )->CurrentOperationDisplayStringIndex =
|
|
DsRolepCurrentOperationHandle.DisplayStringCount == 0 ? 0 :
|
|
DsRolepCurrentOperationHandle.DisplayStringCount - 1;
|
|
}
|
|
|
|
} else {
|
|
|
|
Win32Err = DsRolepFormatOperationString(
|
|
DsRolepCurrentOperationHandle.MsgIndex,
|
|
&( *ServerOperationStatus )->CurrentOperationDisplayString,
|
|
DsRolepCurrentOperationHandle.Parameter1,
|
|
DsRolepCurrentOperationHandle.Parameter2,
|
|
DsRolepCurrentOperationHandle.Parameter3,
|
|
DsRolepCurrentOperationHandle.Parameter4 );
|
|
}
|
|
|
|
if ( Win32Err != ERROR_SUCCESS ) {
|
|
|
|
MIDL_user_free( *ServerOperationStatus );
|
|
*ServerOperationStatus = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the operation isn't completed, return that information to the caller
|
|
//
|
|
if ( Win32Err == ERROR_SUCCESS &&
|
|
DsRolepCurrentOperationHandle.OperationState != DSROLEP_FINISHED ) {
|
|
|
|
Win32Err = ERROR_IO_PENDING;
|
|
}
|
|
|
|
//
|
|
// Release the lock
|
|
//
|
|
UnlockOpHandle();
|
|
|
|
return( Win32Err );
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
DsRolepFormatOperationString(
|
|
IN ULONG MsgId,
|
|
OUT LPWSTR *FormattedString,
|
|
...
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates and formats the buffer string to be returned
|
|
|
|
Arguments:
|
|
|
|
MsgId - Which message id to format
|
|
|
|
FormattedString - Where the string is allocated. Allocation uses MIDL_user_allocate
|
|
|
|
... - va_list of arguments for the formatted string
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS - Success
|
|
|
|
ERROR_NOT_ENOUGH_MEMORY - A memory allocation failed
|
|
|
|
--*/
|
|
{
|
|
DWORD Win32Err = ERROR_SUCCESS;
|
|
WCHAR MsgBuffer[ 512 + 1];
|
|
PWSTR Msg = MsgBuffer;
|
|
ULONG MsgLength = (sizeof(MsgBuffer) / sizeof(MsgBuffer[0]) ) - 1;
|
|
ULONG Length;
|
|
BOOL fSuccess = FALSE;
|
|
BOOL fTokenCreatedLocally = FALSE;
|
|
va_list ArgList;
|
|
|
|
va_start( ArgList, FormattedString );
|
|
|
|
//
|
|
// Load the module handle for lsasrv.dll, so we can get our messages
|
|
//
|
|
if ( DsRolepCurrentOperationHandle.MsgModuleHandle == NULL ) {
|
|
|
|
DsRolepCurrentOperationHandle.MsgModuleHandle = GetModuleHandle( L"LSASRV" );
|
|
|
|
ASSERT( DsRolepCurrentOperationHandle.MsgModuleHandle );
|
|
|
|
if ( DsRolepCurrentOperationHandle.MsgModuleHandle == NULL ) {
|
|
|
|
return( GetLastError() );
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we don't have a clientToken then get one at the
|
|
//
|
|
if ( DsRolepCurrentOperationHandle.ClientToken == NULL ) {
|
|
|
|
Win32Err = DsRolepGetImpersonationToken(&DsRolepCurrentOperationHandle.ClientToken);
|
|
if (ERROR_SUCCESS != Win32Err) {
|
|
DsRolepCurrentOperationHandle.ClientToken = NULL;
|
|
DsRolepLogPrintRoutine(DEB_WARN, "Cannot get user Token for Format Message: %d\n",
|
|
Win32Err);
|
|
Win32Err = ERROR_SUCCESS;
|
|
//if error clear and continue, errors here are not fatal
|
|
} else {
|
|
|
|
fTokenCreatedLocally = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Get the required buffer size
|
|
//
|
|
|
|
//
|
|
// FormatMessage complains when given a NULL input buffer, so we'll pass in one, even though
|
|
// it won't be used because of the size being 0.
|
|
//
|
|
if (DsRolepCurrentOperationHandle.ClientToken) {
|
|
|
|
fSuccess = ImpersonateLoggedOnUser(DsRolepCurrentOperationHandle.ClientToken);
|
|
|
|
}
|
|
// if we couldn't impersonate we continue anyway.
|
|
if (!fSuccess) {
|
|
DsRolepLogPrintRoutine(DEB_WARN, "Cannot get user locale for Format Message: %d\n",
|
|
GetLastError());
|
|
}
|
|
|
|
Length = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE,
|
|
DsRolepCurrentOperationHandle.MsgModuleHandle,
|
|
MsgId, 0, Msg, MsgLength, &ArgList );
|
|
|
|
if ( Length == 0 ) {
|
|
|
|
Win32Err = GetLastError();
|
|
|
|
ASSERT( Win32Err != ERROR_MR_MID_NOT_FOUND );
|
|
|
|
if ( Win32Err == ERROR_INSUFFICIENT_BUFFER ) {
|
|
|
|
Length = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
|
DsRolepCurrentOperationHandle.MsgModuleHandle,
|
|
MsgId, 0, ( PWSTR )&Msg, 0, &ArgList );
|
|
if ( Length == 0 ) {
|
|
|
|
Win32Err = GetLastError();
|
|
|
|
} else {
|
|
|
|
Win32Err = ERROR_SUCCESS;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (fSuccess) {
|
|
fSuccess = RevertToSelf();
|
|
if (!fSuccess) {
|
|
DsRolepLogPrintRoutine(DEB_WARN, "Cannot reset to system security setting: %d\n",
|
|
GetLastError());
|
|
}
|
|
}
|
|
|
|
//if we create a token for this call then we need to clear it out.
|
|
if(DsRolepCurrentOperationHandle.ClientToken && fTokenCreatedLocally){
|
|
CloseHandle(DsRolepCurrentOperationHandle.ClientToken);
|
|
DsRolepCurrentOperationHandle.ClientToken = NULL;
|
|
}
|
|
|
|
if( Win32Err == ERROR_SUCCESS ) {
|
|
|
|
//
|
|
// Allocate a buffer
|
|
//
|
|
Length = ( wcslen( Msg ) + 1 ) * sizeof( WCHAR );
|
|
*FormattedString = MIDL_user_allocate( Length );
|
|
|
|
if ( *FormattedString == NULL ) {
|
|
|
|
Win32Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
} else {
|
|
|
|
RtlCopyMemory( *FormattedString, Msg, Length );
|
|
|
|
}
|
|
}
|
|
|
|
if ( Msg != MsgBuffer ) {
|
|
|
|
LocalFree( Msg );
|
|
}
|
|
|
|
return( Win32Err );
|
|
}
|
|
|
|
|
|
VOID
|
|
DsRolepSetCriticalOperationsDone(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Indicates to our current operation status block that the critical portion of the install
|
|
has been completed...
|
|
|
|
|
|
Arguments:
|
|
|
|
VOID
|
|
|
|
Returns:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Grab the lock
|
|
//
|
|
LockOpHandle();
|
|
|
|
DsRolepCurrentOperationHandle.OperationState = DSROLEP_RUNNING_NON_CRITICAL;
|
|
|
|
//
|
|
// Release the lock
|
|
//
|
|
UnlockOpHandle();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
DsRolepIncrementDisplayStringCount(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Increments the count of the successfully started display update strings. This is always
|
|
the index into the list of DisplayStrings PLUS ONE.
|
|
|
|
|
|
Arguments:
|
|
|
|
VOID
|
|
|
|
Returns:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Grab the lock
|
|
//
|
|
LockOpHandle();
|
|
|
|
DsRolepCurrentOperationHandle.DisplayStringCount++;
|
|
|
|
//
|
|
// Release the lock
|
|
//
|
|
UnlockOpHandle();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
DsRolepGetDcOperationResults(
|
|
IN PDSROLE_SERVEROP_HANDLE DsOperationHandle,
|
|
OUT PDSROLER_SERVEROP_RESULTS *ServerOperationResults
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets the results of the final operation. If the operation has not yet completed, this
|
|
function will block until it does
|
|
|
|
Arguments:
|
|
|
|
DsOperationHandle - Handle to an open operation
|
|
|
|
ServerOperationResults - Where the result is returned.
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS - Success
|
|
|
|
ERROR_INVALID_PARAMETER - A bad results pointer was given
|
|
|
|
--*/
|
|
{
|
|
DWORD Win32Err = ERROR_SUCCESS;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
DSROLEP_OPERATION_STATE OpState;
|
|
BOOLEAN fNeedReboot = FALSE;
|
|
|
|
|
|
//
|
|
// Parameter checking
|
|
//
|
|
if ( !ServerOperationResults ) {
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
//
|
|
// Make sure an operation is active
|
|
//
|
|
LockOpHandle();
|
|
|
|
OpState = DsRolepCurrentOperationHandle.OperationState;
|
|
|
|
UnlockOpHandle();
|
|
|
|
//
|
|
// It's an error if the operation isn't active
|
|
//
|
|
if ( !DSROLEP_OPERATION_ACTIVE( OpState ) ) {
|
|
|
|
return ERROR_NO_PROMOTION_ACTIVE;
|
|
|
|
}
|
|
|
|
//
|
|
// Wait for the operation to complete
|
|
//
|
|
Status = NtWaitForSingleObject( DsRolepCurrentOperationHandle.CompletionEvent, TRUE, NULL );
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
|
|
//
|
|
// Lock the handle
|
|
//
|
|
LockOpHandle();
|
|
|
|
//
|
|
// Allocate the return structure
|
|
//
|
|
*ServerOperationResults = MIDL_user_allocate( sizeof( DSROLER_SERVEROP_RESULTS ) );
|
|
|
|
if ( *ServerOperationResults == NULL ) {
|
|
|
|
Win32Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
} else {
|
|
|
|
( *ServerOperationResults )->OperationResultsFlags = 0;
|
|
|
|
//
|
|
// Build the return string
|
|
//
|
|
if ( DsRolepCurrentOperationHandle.OperationStatus != ERROR_SUCCESS ||
|
|
DsRolepCurrentOperationHandle.MsgIndex == 0 ) {
|
|
|
|
DSROLEP_MIDL_ALLOC_AND_COPY_STRING_ERROR(
|
|
( *ServerOperationResults )->OperationStatusDisplayString,
|
|
DsRolepCurrentOperationHandle.OperationStatus != ERROR_SUCCESS ?
|
|
DsRolepCurrentOperationHandle.FinalResultStringDisplayable :
|
|
DsRolepCurrentOperationHandle.UpdateStringDisplayable,
|
|
Win32Err );
|
|
|
|
} else {
|
|
|
|
Win32Err = DsRolepFormatOperationString(
|
|
DsRolepCurrentOperationHandle.MsgIndex,
|
|
&( *ServerOperationResults )->OperationStatusDisplayString,
|
|
DsRolepCurrentOperationHandle.Parameter1,
|
|
DsRolepCurrentOperationHandle.Parameter2,
|
|
DsRolepCurrentOperationHandle.Parameter3,
|
|
DsRolepCurrentOperationHandle.Parameter4 );
|
|
}
|
|
|
|
|
|
if ( Win32Err == ERROR_SUCCESS ) {
|
|
|
|
( *ServerOperationResults )->OperationStatus =
|
|
DsRolepCurrentOperationHandle.OperationStatus;
|
|
DsRoleDebugOut(( DEB_TRACE_DS,
|
|
"Returning status %lu\n",
|
|
DsRolepCurrentOperationHandle.OperationStatus ));
|
|
|
|
// If the operation finished successfully, we need
|
|
// a reboot
|
|
if ( ERROR_SUCCESS == DsRolepCurrentOperationHandle.OperationStatus )
|
|
{
|
|
fNeedReboot = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return the site name, if it exists
|
|
//
|
|
if ( Win32Err == ERROR_SUCCESS ) {
|
|
|
|
DSROLEP_MIDL_ALLOC_AND_COPY_STRING_ERROR(
|
|
( *ServerOperationResults)->ServerInstalledSite,
|
|
DsRolepCurrentOperationHandle.InstalledSiteName,
|
|
Win32Err );
|
|
|
|
if ( Win32Err != ERROR_SUCCESS ) {
|
|
|
|
MIDL_user_free(
|
|
( *ServerOperationResults )->OperationStatusDisplayString );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set the flags, if necessary
|
|
//
|
|
if ( Win32Err == ERROR_SUCCESS ) {
|
|
|
|
( *ServerOperationResults )->OperationResultsFlags |=
|
|
DsRolepCurrentOperationHandle.OperationResultFlags;
|
|
}
|
|
|
|
if ( Win32Err != ERROR_SUCCESS ) {
|
|
|
|
MIDL_user_free( *ServerOperationResults );
|
|
*ServerOperationResults = NULL;
|
|
}
|
|
|
|
|
|
UnlockOpHandle();
|
|
|
|
//
|
|
// Reset our current operation handle
|
|
//
|
|
DsRolepResetOperationHandle( fNeedReboot ? DSROLEP_NEED_REBOOT : DSROLEP_IDLE );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
if ( Win32Err == ERROR_SUCCESS ) {
|
|
|
|
Win32Err = RtlNtStatusToDosError( Status );
|
|
}
|
|
|
|
|
|
return( Win32Err );
|
|
}
|
|
|
|
DWORD
|
|
DsRolepOperationResultFlagsCallBack(
|
|
IN DWORD Flags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Internal routine for updating the Operation Results Flags
|
|
|
|
Arguments:
|
|
|
|
Flags - DWORD of flags to | with current flags
|
|
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS - Success
|
|
|
|
--*/
|
|
{
|
|
DWORD Win32Err = ERROR_SUCCESS;
|
|
|
|
LockOpHandle();
|
|
|
|
DsRolepCurrentOperationHandle.OperationResultFlags |= Flags;
|
|
|
|
UnlockOpHandle();
|
|
|
|
return( Win32Err );
|
|
}
|
|
|
|
DWORD
|
|
DsRolepStringUpdateCallback(
|
|
IN PWSTR StringUpdate
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Internal routine for updating the current operation handle statics
|
|
|
|
Arguments:
|
|
|
|
StringUpdate - Displayables string to set in place of the current parameters
|
|
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS - Success
|
|
|
|
--*/
|
|
{
|
|
DWORD Win32Err = ERROR_SUCCESS;
|
|
ULONG len;
|
|
|
|
//
|
|
// Grab the lock
|
|
//
|
|
LockOpHandle();
|
|
|
|
DsRolepCurrentOperationHandle.MsgIndex = 0;
|
|
DsRolepCurrentOperationHandle.Parameter1 = 0;
|
|
DsRolepCurrentOperationHandle.Parameter2 = 0;
|
|
DsRolepCurrentOperationHandle.Parameter3 = 0;
|
|
DsRolepCurrentOperationHandle.Parameter4 = 0;
|
|
|
|
if ( StringUpdate ) {
|
|
|
|
DsRolepLogPrint(( DEB_TRACE, "%ws\n", StringUpdate ));
|
|
|
|
} else {
|
|
|
|
Win32Err = ERROR_INVALID_PARAMETER;
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
DsRoleDebugOut(( DEB_TRACE_UPDATE,
|
|
"DsRolepSetCurrentOperationStatus for string %ws\n",
|
|
StringUpdate ));
|
|
|
|
if ( DsRolepCurrentOperationHandle.UpdateStringDisplayable ) {
|
|
|
|
RtlFreeHeap( RtlProcessHeap(), 0, DsRolepCurrentOperationHandle.UpdateStringDisplayable );
|
|
|
|
}
|
|
|
|
DsRolepCurrentOperationHandle.UpdateStringDisplayable =
|
|
RtlAllocateHeap( RtlProcessHeap(), 0,
|
|
( wcslen( StringUpdate ) + 1 ) * sizeof( WCHAR ) );
|
|
|
|
if ( DsRolepCurrentOperationHandle.UpdateStringDisplayable == NULL ) {
|
|
|
|
Win32Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
} else {
|
|
|
|
wcscpy( DsRolepCurrentOperationHandle.UpdateStringDisplayable, StringUpdate );
|
|
|
|
}
|
|
|
|
//
|
|
// Don't forget to release the lock
|
|
//
|
|
UnlockOpHandle();
|
|
|
|
Exit:
|
|
|
|
return( Win32Err );
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
DsRolepStringErrorUpdateCallback(
|
|
IN PWSTR String,
|
|
IN DWORD ErrorCode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Internal routine for updating the last failure operation
|
|
|
|
Arguments:
|
|
|
|
String - Displayable error string
|
|
|
|
ErrorCode - Error code associated with this failure
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS - Success
|
|
|
|
--*/
|
|
{
|
|
DWORD Win32Err = ERROR_SUCCESS;
|
|
|
|
//
|
|
// Grab the lock
|
|
//
|
|
LockOpHandle();
|
|
|
|
if ( (ERROR_SUCCESS == DsRolepCurrentOperationHandle.OperationStatus)
|
|
|| (ERROR_CANCELLED == ErrorCode) ) {
|
|
|
|
//
|
|
// Cancel overides previous error codes
|
|
//
|
|
|
|
if ( DsRolepCurrentOperationHandle.FinalResultStringDisplayable ) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, DsRolepCurrentOperationHandle.FinalResultStringDisplayable );
|
|
}
|
|
|
|
DsRolepCurrentOperationHandle.FinalResultStringDisplayable =
|
|
RtlAllocateHeap( RtlProcessHeap(), 0, ( wcslen( String ) + 1 ) * sizeof( WCHAR ) );
|
|
|
|
if ( DsRolepCurrentOperationHandle.FinalResultStringDisplayable == NULL ) {
|
|
|
|
Win32Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
} else {
|
|
|
|
wcscpy( DsRolepCurrentOperationHandle.FinalResultStringDisplayable, String );
|
|
DsRolepCurrentOperationHandle.OperationStatus = ErrorCode;
|
|
DsRoleDebugOut(( DEB_TRACE_UPDATE,
|
|
"DsRolepStringErrorUpdateCallback for error %lu and string %ws\n",
|
|
ErrorCode,
|
|
String ));
|
|
|
|
|
|
DsRolepLogPrint(( DEB_TRACE, "Error - %ws (%d)\n", String, ErrorCode ));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Release the lock
|
|
//
|
|
UnlockOpHandle();
|
|
|
|
return( Win32Err );
|
|
}
|
|
|
|
DWORD
|
|
DsRolepSetOperationHandleSiteName(
|
|
IN LPWSTR SiteName
|
|
)
|
|
{
|
|
LockOpHandle();
|
|
|
|
DsRolepCurrentOperationHandle.InstalledSiteName = SiteName;
|
|
|
|
UnlockOpHandle();
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
DsRolepCurrentThreadOwnsLock(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Tests wether the current thread owns the lock
|
|
|
|
--*/
|
|
{
|
|
ULONG_PTR ExclusiveOwnerThread = (ULONG_PTR) DsRolepCurrentOperationHandle.CurrentOpLock.ExclusiveOwnerThread;
|
|
ULONG_PTR CurrentThread = (ULONG_PTR) (NtCurrentTeb())->ClientId.UniqueThread;
|
|
|
|
if ((DsRolepCurrentOperationHandle.CurrentOpLock.NumberOfActive <0) && (ExclusiveOwnerThread==CurrentThread))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
VOID
|
|
DsRolepClearErrors(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
This routine clears the global status. The purpose of this is to
|
|
clear errors that components may have set after the demotion is
|
|
unrollable and should not return errors.
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Grab the lock
|
|
//
|
|
LockOpHandle();
|
|
|
|
if ( DsRolepCurrentOperationHandle.OperationStatus != ERROR_SUCCESS ) {
|
|
|
|
//
|
|
// Set a warning that something went wrong
|
|
//
|
|
DsRolepLogPrint(( DEB_TRACE, "Clearing a global error" ));
|
|
|
|
DSROLEP_SET_NON_FATAL_ERROR( DsRolepCurrentOperationHandle.OperationStatus );
|
|
|
|
}
|
|
|
|
if ( DsRolepCurrentOperationHandle.FinalResultStringDisplayable ) {
|
|
|
|
RtlFreeHeap( RtlProcessHeap(), 0, DsRolepCurrentOperationHandle.FinalResultStringDisplayable );
|
|
DsRolepCurrentOperationHandle.FinalResultStringDisplayable = NULL;
|
|
|
|
}
|
|
|
|
DsRolepCurrentOperationHandle.OperationStatus = ERROR_SUCCESS;
|
|
|
|
//
|
|
// Release the lock
|
|
//
|
|
UnlockOpHandle();
|
|
|
|
}
|