windows-nt/Source/XPSP1/NT/ds/security/dsrole/server/ophandle.c

1426 lines
34 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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;
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;
}
//
// 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 {
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;
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() );
}
}
//
// 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.
//
fSuccess = ImpersonateLoggedOnUser(DsRolepCurrentOperationHandle.ClientToken);
// if we couldn't impersonate we continue anyway.
if (!fSuccess) {
DsRolepLogPrintRoutine(DEB_WARN, "Cannot get user locale for Format Message: %ul\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: %ul\n",
GetLastError());
}
}
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 ));
}
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();
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();
}