/*++ 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // 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(); }