1324 lines
28 KiB
C
1324 lines
28 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1998 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
imirror.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This is the file for the IntelliMirror conversion DLL basic To Do item processing.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Sean Selitrennikoff - 4/5/98
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "precomp.h"
|
|||
|
#pragma hdrstop
|
|||
|
|
|||
|
//
|
|||
|
// Global variables
|
|||
|
//
|
|||
|
LIST_ENTRY GlobalToDoList;
|
|||
|
IMIRROR_CALLBACK Callbacks;
|
|||
|
BYTE TmpBuffer[TMP_BUFFER_SIZE];
|
|||
|
BYTE TmpBuffer2[TMP_BUFFER_SIZE];
|
|||
|
BYTE TmpBuffer3[TMP_BUFFER_SIZE];
|
|||
|
HANDLE ghInst;
|
|||
|
BOOL fInitedFromRegistry;
|
|||
|
BOOL fCallbackPreviouslySet = FALSE;
|
|||
|
|
|||
|
#ifdef DEBUGLOG
|
|||
|
|
|||
|
HANDLE hDebugLogFile = INVALID_HANDLE_VALUE;
|
|||
|
CRITICAL_SECTION DebugFileLock;
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Definitions for this file
|
|||
|
//
|
|||
|
typedef struct _TODOITEM {
|
|||
|
IMIRROR_TODO Item;
|
|||
|
PVOID Buffer;
|
|||
|
ULONG Length;
|
|||
|
} TODOITEM, *PTODOITEM;
|
|||
|
|
|||
|
|
|||
|
typedef struct _TODOLIST {
|
|||
|
LIST_ENTRY ListEntry;
|
|||
|
ULONG ToDoNum;
|
|||
|
TODOITEM ToDoList[1];
|
|||
|
} TODOLIST, *PTODOLIST;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Main entry routine
|
|||
|
//
|
|||
|
DWORD
|
|||
|
IMirrorInitDll(
|
|||
|
HINSTANCE hInst,
|
|||
|
DWORD Reason,
|
|||
|
PVOID Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine initializes all the components for this DLL
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hInst - Instance that is calling us.
|
|||
|
|
|||
|
Reason - Why we are being invoked.
|
|||
|
|
|||
|
Context - Context passed for this init.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if successful, else FALSE
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
if (Reason == DLL_PROCESS_ATTACH) {
|
|||
|
|
|||
|
#ifdef DEBUGLOG
|
|||
|
|
|||
|
InitializeCriticalSection( &DebugFileLock );
|
|||
|
|
|||
|
hDebugLogFile = CreateFile(L"C:\\imlog",
|
|||
|
GENERIC_READ | GENERIC_WRITE,
|
|||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|||
|
NULL,
|
|||
|
CREATE_ALWAYS,
|
|||
|
0,
|
|||
|
NULL);
|
|||
|
|
|||
|
if (hDebugLogFile != INVALID_HANDLE_VALUE){
|
|||
|
|
|||
|
UCHAR FileTmpBuf[MAX_PATH ];
|
|||
|
SYSTEMTIME Time;
|
|||
|
// log the start time
|
|||
|
GetLocalTime(&Time);
|
|||
|
sprintf(FileTmpBuf,"Starting on %d-%d-%d at %d:%d:%d\n",
|
|||
|
Time.wMonth,
|
|||
|
Time.wDay,
|
|||
|
Time.wYear,
|
|||
|
Time.wHour,
|
|||
|
Time.wMinute,
|
|||
|
Time.wSecond);
|
|||
|
|
|||
|
IMLogToFile(FileTmpBuf);
|
|||
|
}
|
|||
|
#endif
|
|||
|
ghInst = hInst;
|
|||
|
|
|||
|
#ifdef DEBUGLOG
|
|||
|
} else if (Reason == DLL_PROCESS_DETACH) {
|
|||
|
|
|||
|
if (hDebugLogFile != INVALID_HANDLE_VALUE){
|
|||
|
|
|||
|
SYSTEMTIME Time;
|
|||
|
UCHAR FileTmpBuf[MAX_PATH ];
|
|||
|
|
|||
|
GetLocalTime(&Time);
|
|||
|
|
|||
|
sprintf(FileTmpBuf,"Ending on %d-%d-%d at %d:%d:%d\n",
|
|||
|
Time.wMonth, Time.wDay, Time.wYear,
|
|||
|
Time.wHour, Time.wMinute, Time.wSecond);
|
|||
|
|
|||
|
IMLogToFile(FileTmpBuf);
|
|||
|
IMFlushAndCloseLog();
|
|||
|
hDebugLogFile = INVALID_HANDLE_VALUE;
|
|||
|
DeleteCriticalSection( &DebugFileLock );
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return(TRUE);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
IMirrorInitCallback(
|
|||
|
PIMIRROR_CALLBACK pCallbacks
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine initializes the call back structure with the one supplied by the client.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pCallbacks - Client supplied information for making callbacks to the client.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
if (pCallbacks != NULL) {
|
|||
|
Callbacks = *pCallbacks;
|
|||
|
if (fInitedFromRegistry) {
|
|||
|
IMirrorReinit();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
//
|
|||
|
// Main processing loop
|
|||
|
//
|
|||
|
//
|
|||
|
//
|
|||
|
NTSTATUS
|
|||
|
ProcessToDoItems(
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is the main processing loop for To Do Items.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if it completed all to do items properly.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
IMIRROR_TODO Item;
|
|||
|
PVOID pBuffer;
|
|||
|
ULONG Length;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
Status = InitToDo();
|
|||
|
if ( Status != STATUS_SUCCESS )
|
|||
|
return Status;
|
|||
|
|
|||
|
while (1) {
|
|||
|
|
|||
|
Status = GetNextToDoItem(&Item, &pBuffer, &Length);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
IMirrorHandleError(Status, IMirrorNone);
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
switch (Item) {
|
|||
|
|
|||
|
case IMirrorNone:
|
|||
|
return STATUS_SUCCESS;
|
|||
|
|
|||
|
case VerifySystemIsNt5:
|
|||
|
Status = CheckIfNt5(pBuffer, Length);
|
|||
|
break;
|
|||
|
|
|||
|
case CheckPartitions:
|
|||
|
Status = CheckForPartitions(pBuffer, Length);
|
|||
|
break;
|
|||
|
|
|||
|
case CopyPartitions:
|
|||
|
Status = CopyCopyPartitions(pBuffer, Length);
|
|||
|
break;
|
|||
|
|
|||
|
case CopyFiles:
|
|||
|
Status = CopyCopyFiles(pBuffer, Length);
|
|||
|
break;
|
|||
|
|
|||
|
case CopyRegistry:
|
|||
|
Status = CopyCopyRegistry(pBuffer, Length);
|
|||
|
break;
|
|||
|
#if 0
|
|||
|
case PatchDSEntries:
|
|||
|
Status = ModifyDSEntries(pBuffer, Length);
|
|||
|
break;
|
|||
|
#endif
|
|||
|
case RebootSystem:
|
|||
|
Status = Callbacks.RebootFn(Callbacks.Context);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
IMirrorFreeMem(pBuffer);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
//
|
|||
|
// TO DO Item functions
|
|||
|
//
|
|||
|
//
|
|||
|
//
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
InitToDo(
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine reads from the registry all the current ToDo items and puts
|
|||
|
them in a single TODOLIST.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if it was initialized properly, else the appropriate error code.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
#if 0
|
|||
|
PTODOLIST pToDoList;
|
|||
|
PTODOLIST pNewToDoList;
|
|||
|
PTODOITEM pToDoItem;
|
|||
|
PLIST_ENTRY pListEntry;
|
|||
|
UNICODE_STRING UnicodeString;
|
|||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|||
|
PKEY_VALUE_PARTIAL_INFORMATION pKeyInfo;
|
|||
|
HANDLE Handle;
|
|||
|
ULONG ByteCount;
|
|||
|
ULONG BytesLeft;
|
|||
|
ULONG i;
|
|||
|
PBYTE pBuffer;
|
|||
|
#endif
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize global variables
|
|||
|
//
|
|||
|
InitializeListHead(&GlobalToDoList);
|
|||
|
|
|||
|
#if 0
|
|||
|
//
|
|||
|
//
|
|||
|
// Read the current ToDo list from the registry
|
|||
|
//
|
|||
|
//
|
|||
|
RtlInitUnicodeString(&UnicodeString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\RemoteBoot");
|
|||
|
|
|||
|
InitializeObjectAttributes(&ObjectAttributes,
|
|||
|
&UnicodeString,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
NULL,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
Status = NtOpenKey(&Handle,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
&ObjectAttributes
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
goto NoRegistry;
|
|||
|
}
|
|||
|
|
|||
|
RtlInitUnicodeString(&UnicodeString, L"ConversionState");
|
|||
|
|
|||
|
//
|
|||
|
// Get the size of the buffer needed
|
|||
|
//
|
|||
|
ByteCount = 0;
|
|||
|
Status = NtQueryValueKey(Handle,
|
|||
|
&UnicodeString,
|
|||
|
KeyValuePartialInformation,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
&ByteCount
|
|||
|
);
|
|||
|
|
|||
|
if (Status != STATUS_BUFFER_TOO_SMALL) {
|
|||
|
NtClose(Handle);
|
|||
|
goto NoRegistry;
|
|||
|
}
|
|||
|
|
|||
|
pKeyInfo = (PKEY_VALUE_PARTIAL_INFORMATION)IMirrorAllocMem(ByteCount);
|
|||
|
|
|||
|
if (pKeyInfo == NULL) {
|
|||
|
NtClose(Handle);
|
|||
|
return STATUS_NO_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get the buffer from the registry
|
|||
|
//
|
|||
|
Status = NtQueryValueKey(Handle,
|
|||
|
&UnicodeString,
|
|||
|
KeyValuePartialInformation,
|
|||
|
pKeyInfo,
|
|||
|
ByteCount,
|
|||
|
&ByteCount
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
IMirrorFreeMem(pKeyInfo);
|
|||
|
NtClose(Handle);
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
pBuffer = &(pKeyInfo->Data[0]);
|
|||
|
BytesLeft = pKeyInfo->DataLength;
|
|||
|
ByteCount = BytesLeft;
|
|||
|
|
|||
|
//
|
|||
|
// Now translate the buffer into our internal structures.
|
|||
|
//
|
|||
|
while (BytesLeft != 0) {
|
|||
|
|
|||
|
pToDoList = (PTODOLIST)(pBuffer + ByteCount - BytesLeft);
|
|||
|
|
|||
|
ASSERT(pToDoList->ToDoNum != 0);
|
|||
|
|
|||
|
pNewToDoList = IMirrorAllocMem(sizeof(TODOLIST) +
|
|||
|
sizeof(TODOITEM) * (pToDoList->ToDoNum - 1)
|
|||
|
);
|
|||
|
|
|||
|
if (pNewToDoList == NULL) {
|
|||
|
ClearAllToDoItems(TRUE);
|
|||
|
NtClose(Handle);
|
|||
|
return STATUS_NO_MEMORY;
|
|||
|
}
|
|||
|
BytesLeft -= (sizeof(TODOLIST) + sizeof(TODOITEM) * (pToDoList->ToDoNum - 1));
|
|||
|
|
|||
|
pToDoItem = &(pToDoList->ToDoList[0]);
|
|||
|
|
|||
|
//
|
|||
|
// Translate over one entire TODOLIST
|
|||
|
//
|
|||
|
while (pNewToDoList->ToDoNum < pToDoList->ToDoNum) {
|
|||
|
|
|||
|
i = pNewToDoList->ToDoNum;
|
|||
|
pNewToDoList->ToDoList[i] = *pToDoItem;
|
|||
|
pNewToDoList->ToDoList[i].Buffer = IMirrorAllocMem(pToDoItem->Length);
|
|||
|
BytesLeft -= pToDoItem->Length;
|
|||
|
|
|||
|
if (pNewToDoList->ToDoList[i].Buffer == NULL) {
|
|||
|
ClearAllToDoItems(TRUE);
|
|||
|
while (i > 0) {
|
|||
|
i--;
|
|||
|
IMirrorFreeMem(pNewToDoList->ToDoList[i].Buffer);
|
|||
|
}
|
|||
|
IMirrorFreeMem(pNewToDoList);
|
|||
|
NtClose(Handle);
|
|||
|
return STATUS_NO_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
RtlMoveMemory(pNewToDoList->ToDoList[i].Buffer,
|
|||
|
pToDoItem + 1,
|
|||
|
pToDoItem->Length
|
|||
|
);
|
|||
|
|
|||
|
pNewToDoList->ToDoNum++;
|
|||
|
pToDoItem = (PTODOITEM)(((PBYTE)pToDoItem) + pToDoItem->Length);
|
|||
|
pToDoItem++;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Add this list to the global To Do list
|
|||
|
//
|
|||
|
InsertTailList(&GlobalToDoList, &(pNewToDoList->ListEntry));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Remove everything from the registry so we don't accidentally restart again and again and...
|
|||
|
//
|
|||
|
RtlInitUnicodeString(&UnicodeString, L"ConversionState");
|
|||
|
|
|||
|
Status = NtDeleteValueKey(Handle, &UnicodeString);
|
|||
|
|
|||
|
NtClose(Handle);
|
|||
|
|
|||
|
if (!IsListEmpty(&GlobalToDoList)) {
|
|||
|
fInitedFromRegistry = TRUE;
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
NoRegistry:
|
|||
|
#endif
|
|||
|
fInitedFromRegistry = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// If there is nothing in the registry, presume this is a fresh start.
|
|||
|
//
|
|||
|
|
|||
|
Status = AddCheckMachineToDoItems();
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
ClearAllToDoItems(TRUE);
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
Status = AddCopyToDoItems();
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
ClearAllToDoItems(TRUE);
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
if ( Callbacks.RebootFn ) {
|
|||
|
AddToDoItem( RebootSystem, NULL, 0 );
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
GetNextToDoItem(
|
|||
|
OUT PIMIRROR_TODO Item,
|
|||
|
OUT PVOID *Buffer,
|
|||
|
OUT PULONG Length
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine gets the next thing TODO from the global list.
|
|||
|
|
|||
|
NOTE: The client is responsible for freeing Buffer.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Item - Place to store the next item to process.
|
|||
|
|
|||
|
Buffer - Any context for the item.
|
|||
|
|
|||
|
Length - Number of bytes in Buffer.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if it was able to get an item, else an appropriate error code.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PTODOLIST pToDoList;
|
|||
|
PTODOLIST pNewToDoList;
|
|||
|
PLIST_ENTRY pListEntry;
|
|||
|
|
|||
|
*Item = IMirrorNone;
|
|||
|
*Buffer = NULL;
|
|||
|
*Length = 0;
|
|||
|
|
|||
|
pToDoList = NULL;
|
|||
|
|
|||
|
while (!IsListEmpty(&GlobalToDoList)) {
|
|||
|
|
|||
|
//
|
|||
|
// Get the first list
|
|||
|
//
|
|||
|
pListEntry = RemoveHeadList(&GlobalToDoList);
|
|||
|
|
|||
|
pToDoList = CONTAINING_RECORD(pListEntry,
|
|||
|
TODOLIST,
|
|||
|
ListEntry
|
|||
|
);
|
|||
|
|
|||
|
if (pToDoList->ToDoNum != 0) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
IMirrorFreeMem(pToDoList);
|
|||
|
pToDoList = NULL;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (IsListEmpty(&GlobalToDoList) && (pToDoList == NULL)) {
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(pToDoList->ToDoNum != 0);
|
|||
|
|
|||
|
//
|
|||
|
// Found the first item.
|
|||
|
//
|
|||
|
|
|||
|
*Item = pToDoList->ToDoList[0].Item;
|
|||
|
*Buffer = pToDoList->ToDoList[0].Buffer;
|
|||
|
*Length = pToDoList->ToDoList[0].Length;
|
|||
|
|
|||
|
if (Callbacks.RemoveToDoFn != NULL) {
|
|||
|
|
|||
|
Callbacks.RemoveToDoFn( Callbacks.Context, *Item, *Buffer, *Length );
|
|||
|
}
|
|||
|
|
|||
|
pToDoList->ToDoNum--;
|
|||
|
|
|||
|
//
|
|||
|
// Now create a new ToDo list for anything that may get added by the processing of this item.
|
|||
|
// This creates an effective 'stack' of to do items, so that things get processed in the
|
|||
|
// correct order.
|
|||
|
//
|
|||
|
|
|||
|
pNewToDoList = IMirrorAllocMem(sizeof(TODOLIST));
|
|||
|
|
|||
|
if (pNewToDoList == NULL) {
|
|||
|
return STATUS_NO_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Do an effective "pop" on the current list, by moving everything else up the list
|
|||
|
//
|
|||
|
if (pToDoList->ToDoNum == 0) {
|
|||
|
IMirrorFreeMem(pToDoList);
|
|||
|
} else {
|
|||
|
RtlMoveMemory(&(pToDoList->ToDoList[0]), &(pToDoList->ToDoList[1]), sizeof(TODOITEM) * pToDoList->ToDoNum);
|
|||
|
InsertHeadList(&GlobalToDoList, pListEntry);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now push on the new space for new items.
|
|||
|
//
|
|||
|
pNewToDoList->ToDoNum = 0;
|
|||
|
InsertHeadList(&GlobalToDoList, &(pNewToDoList->ListEntry));
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AddToDoItem(
|
|||
|
IN IMIRROR_TODO Item,
|
|||
|
IN PVOID Buffer,
|
|||
|
IN ULONG Length
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine adds a TODO item to the end of the current list. It allocates
|
|||
|
new memory and copies the buffer.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Item - The item id.
|
|||
|
|
|||
|
Buffer - Buffer for any arguments, context for the item.
|
|||
|
|
|||
|
Length - Length of the buffer in bytes.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if it was able to add the item, else an appropriate error status.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PTODOLIST pNewToDoList;
|
|||
|
PLIST_ENTRY pListEntry;
|
|||
|
PBYTE pBuf;
|
|||
|
LIST_ENTRY TmpToDoList;
|
|||
|
PTODOLIST pToDoList;
|
|||
|
ULONG i;
|
|||
|
ULONG err;
|
|||
|
|
|||
|
if (Callbacks.AddToDoFn != NULL) {
|
|||
|
|
|||
|
err = Callbacks.AddToDoFn( Callbacks.Context, Item, Buffer, Length );
|
|||
|
|
|||
|
if (err != STATUS_SUCCESS) {
|
|||
|
|
|||
|
//
|
|||
|
// if the UI bounces the request, we'll treat it as success.
|
|||
|
//
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate space for the buffer
|
|||
|
//
|
|||
|
if (Length != 0) {
|
|||
|
|
|||
|
pBuf = IMirrorAllocMem(Length);
|
|||
|
|
|||
|
if (pBuf == NULL) {
|
|||
|
return STATUS_NO_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
pBuf = NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get the current TODO List
|
|||
|
//
|
|||
|
if (IsListEmpty(&GlobalToDoList)) {
|
|||
|
|
|||
|
pNewToDoList = IMirrorAllocMem(sizeof(TODOLIST));
|
|||
|
if (pNewToDoList == NULL) {
|
|||
|
IMirrorFreeMem(pBuf);
|
|||
|
return STATUS_NO_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
pNewToDoList->ToDoNum = 1;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
pListEntry = RemoveHeadList(&GlobalToDoList);
|
|||
|
|
|||
|
pToDoList = CONTAINING_RECORD(pListEntry,
|
|||
|
TODOLIST,
|
|||
|
ListEntry
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Allocate space for the new item
|
|||
|
//
|
|||
|
pNewToDoList = IMirrorReallocMem(pToDoList, sizeof(TODOLIST) + sizeof(TODOITEM) * pToDoList->ToDoNum);
|
|||
|
|
|||
|
if (pNewToDoList == NULL) {
|
|||
|
InsertHeadList(&GlobalToDoList, pListEntry);
|
|||
|
IMirrorFreeMem(pBuf);
|
|||
|
return STATUS_NO_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
pNewToDoList->ToDoNum++;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Insert the item at the end of the list
|
|||
|
//
|
|||
|
if (pBuf != NULL) {
|
|||
|
RtlMoveMemory(pBuf, Buffer, Length);
|
|||
|
}
|
|||
|
pNewToDoList->ToDoList[pNewToDoList->ToDoNum - 1].Item = Item;
|
|||
|
pNewToDoList->ToDoList[pNewToDoList->ToDoNum - 1].Buffer = pBuf;
|
|||
|
pNewToDoList->ToDoList[pNewToDoList->ToDoNum - 1].Length = Length;
|
|||
|
|
|||
|
pListEntry = &(pNewToDoList->ListEntry);
|
|||
|
InsertHeadList(&GlobalToDoList, pListEntry);
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
ClearAllToDoItems(
|
|||
|
IN BOOLEAN MemoryOnly
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine clears out all To Do items in memory and the registry
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
MemoryOnly - TRUE if to only clear the stuff in memory.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PTODOLIST pToDoList;
|
|||
|
PLIST_ENTRY pListEntry;
|
|||
|
UNICODE_STRING UnicodeString;
|
|||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|||
|
HANDLE Handle;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
//
|
|||
|
// Clear out all the items in memory
|
|||
|
//
|
|||
|
while (!IsListEmpty(&GlobalToDoList)) {
|
|||
|
|
|||
|
//
|
|||
|
// Get the first list
|
|||
|
//
|
|||
|
pListEntry = RemoveHeadList(&GlobalToDoList);
|
|||
|
|
|||
|
pToDoList = CONTAINING_RECORD(pListEntry,
|
|||
|
TODOLIST,
|
|||
|
ListEntry
|
|||
|
);
|
|||
|
|
|||
|
while (pToDoList->ToDoNum != 0) {
|
|||
|
pToDoList->ToDoNum--;
|
|||
|
|
|||
|
if (Callbacks.RemoveToDoFn != NULL) {
|
|||
|
|
|||
|
Callbacks.RemoveToDoFn( Callbacks.Context,
|
|||
|
pToDoList->ToDoList[pToDoList->ToDoNum].Item,
|
|||
|
pToDoList->ToDoList[pToDoList->ToDoNum].Buffer,
|
|||
|
pToDoList->ToDoList[pToDoList->ToDoNum].Length );
|
|||
|
}
|
|||
|
|
|||
|
if (pToDoList->ToDoList[pToDoList->ToDoNum].Length != 0) {
|
|||
|
IMirrorFreeMem(pToDoList->ToDoList[pToDoList->ToDoNum].Buffer);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
IMirrorFreeMem(pToDoList);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (MemoryOnly) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now clear out the ones in the registry
|
|||
|
//
|
|||
|
RtlInitUnicodeString(&UnicodeString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\RemoteBoot");
|
|||
|
|
|||
|
InitializeObjectAttributes(&ObjectAttributes,
|
|||
|
&UnicodeString,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
NULL,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
Status = NtOpenKey(&Handle,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
&ObjectAttributes
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
RtlInitUnicodeString(&UnicodeString, L"ConversionState");
|
|||
|
|
|||
|
Status = NtDeleteValueKey(Handle, &UnicodeString);
|
|||
|
|
|||
|
NtClose(Handle);
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SaveAllToDoItems(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine writes out all To Do items in the list to the registry so that conversion
|
|||
|
can be restarted later.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if it was able to save, else an appropriate error status.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
return STATUS_SUCCESS;
|
|||
|
#if 0
|
|||
|
PTODOLIST pToDoList;
|
|||
|
PTODOITEM pToDoItem;
|
|||
|
PLIST_ENTRY pListEntry;
|
|||
|
LIST_ENTRY TmpGlobalList;
|
|||
|
UNICODE_STRING UnicodeString;
|
|||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|||
|
HANDLE Handle;
|
|||
|
ULONG ByteCount;
|
|||
|
ULONG i;
|
|||
|
PBYTE pBuffer;
|
|||
|
PBYTE pTmp;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
//
|
|||
|
// First find the size of buffer that will be needed.
|
|||
|
//
|
|||
|
ByteCount = 0;
|
|||
|
InitializeListHead(&TmpGlobalList);
|
|||
|
while (!IsListEmpty(&GlobalToDoList)) {
|
|||
|
|
|||
|
//
|
|||
|
// Get the first list
|
|||
|
//
|
|||
|
pListEntry = RemoveHeadList(&GlobalToDoList);
|
|||
|
|
|||
|
pToDoList = CONTAINING_RECORD(pListEntry,
|
|||
|
TODOLIST,
|
|||
|
ListEntry
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Get the size of all the items
|
|||
|
//
|
|||
|
i = 0;
|
|||
|
|
|||
|
while (i < pToDoList->ToDoNum) {
|
|||
|
|
|||
|
if (i == 0) {
|
|||
|
ByteCount += sizeof(TODOLIST);
|
|||
|
} else {
|
|||
|
ByteCount += sizeof(TODOITEM);
|
|||
|
}
|
|||
|
|
|||
|
ByteCount += pToDoList->ToDoList[i].Length;
|
|||
|
|
|||
|
i++;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Save the entry away for later
|
|||
|
//
|
|||
|
InsertTailList(&TmpGlobalList, pListEntry);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (ByteCount == 0) {
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Restore global list
|
|||
|
//
|
|||
|
while (!IsListEmpty(&TmpGlobalList)) {
|
|||
|
pListEntry = RemoveHeadList(&TmpGlobalList);
|
|||
|
InsertTailList(&GlobalToDoList, pListEntry);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a buffer for everything.
|
|||
|
//
|
|||
|
pBuffer = IMirrorAllocMem(ByteCount);
|
|||
|
|
|||
|
if (pBuffer == NULL) {
|
|||
|
return STATUS_NO_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Fill the buffer
|
|||
|
//
|
|||
|
pTmp = pBuffer;
|
|||
|
|
|||
|
while (!IsListEmpty(&GlobalToDoList)) {
|
|||
|
|
|||
|
//
|
|||
|
// Get the first list
|
|||
|
//
|
|||
|
pListEntry = RemoveHeadList(&GlobalToDoList);
|
|||
|
|
|||
|
pToDoList = CONTAINING_RECORD(pListEntry,
|
|||
|
TODOLIST,
|
|||
|
ListEntry
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Copy all the items
|
|||
|
//
|
|||
|
i = 0;
|
|||
|
|
|||
|
while (i < pToDoList->ToDoNum) {
|
|||
|
|
|||
|
if (i == 0) {
|
|||
|
RtlMoveMemory(pTmp, pToDoList, sizeof(TODOLIST));
|
|||
|
pToDoItem = &(((PTODOLIST)pTmp)->ToDoList[0]);
|
|||
|
pTmp += sizeof(TODOLIST);
|
|||
|
} else {
|
|||
|
RtlMoveMemory(pTmp, &(pToDoList->ToDoList[i]), sizeof(TODOITEM));
|
|||
|
pToDoItem = (PTODOITEM)pTmp;
|
|||
|
pTmp += sizeof(TODOITEM);
|
|||
|
}
|
|||
|
|
|||
|
if (pToDoList->ToDoList[i].Length != 0) {
|
|||
|
RtlMoveMemory(pTmp, pToDoList->ToDoList[i].Buffer, pToDoList->ToDoList[i].Length);
|
|||
|
pTmp += pToDoList->ToDoList[i].Length;
|
|||
|
}
|
|||
|
|
|||
|
pToDoItem->Buffer = NULL;
|
|||
|
i++;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Save the entry away for later
|
|||
|
//
|
|||
|
InsertTailList(&TmpGlobalList, pListEntry);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Restore global list
|
|||
|
//
|
|||
|
while (!IsListEmpty(&TmpGlobalList)) {
|
|||
|
pListEntry = RemoveHeadList(&TmpGlobalList);
|
|||
|
InsertTailList(&GlobalToDoList, pListEntry);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now write the buffer to the registry
|
|||
|
//
|
|||
|
RtlInitUnicodeString(&UnicodeString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\RemoteBoot");
|
|||
|
|
|||
|
InitializeObjectAttributes(&ObjectAttributes,
|
|||
|
&UnicodeString,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
NULL,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
Status = NtCreateKey(&Handle,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
&ObjectAttributes,
|
|||
|
0,
|
|||
|
(PUNICODE_STRING)NULL,
|
|||
|
0,
|
|||
|
&i // disposition
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
IMirrorFreeMem(pBuffer);
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
RtlInitUnicodeString(&UnicodeString, L"ConversionState");
|
|||
|
|
|||
|
Status = NtSetValueKey(Handle,
|
|||
|
&UnicodeString,
|
|||
|
0,
|
|||
|
REG_BINARY,
|
|||
|
pBuffer,
|
|||
|
ByteCount
|
|||
|
);
|
|||
|
|
|||
|
NtClose(Handle);
|
|||
|
IMirrorFreeMem(pBuffer);
|
|||
|
return Status;
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ModifyToDoItem(
|
|||
|
IN IMIRROR_TODO Item,
|
|||
|
IN PVOID Buffer,
|
|||
|
IN ULONG Length
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine changes the parameters to the first TODO item that matches Item.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Item - The item id.
|
|||
|
|
|||
|
Buffer - Buffer for any arguments, context for the item.
|
|||
|
|
|||
|
Length - Length of the buffer in bytes.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if it was able to change the item, else an appropriate error status.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PLIST_ENTRY pListEntry;
|
|||
|
LIST_ENTRY TmpGlobalList;
|
|||
|
PTODOLIST pToDoList;
|
|||
|
ULONG i;
|
|||
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|||
|
|
|||
|
InitializeListHead(&TmpGlobalList);
|
|||
|
while (!IsListEmpty(&GlobalToDoList)) {
|
|||
|
|
|||
|
//
|
|||
|
// Get the first list
|
|||
|
//
|
|||
|
pListEntry = RemoveHeadList(&GlobalToDoList);
|
|||
|
|
|||
|
pToDoList = CONTAINING_RECORD(pListEntry,
|
|||
|
TODOLIST,
|
|||
|
ListEntry
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Save the entry away for later
|
|||
|
//
|
|||
|
InsertTailList(&TmpGlobalList, pListEntry);
|
|||
|
|
|||
|
//
|
|||
|
// Walk the list until we find an item that matches.
|
|||
|
//
|
|||
|
i = 0;
|
|||
|
|
|||
|
while (i < pToDoList->ToDoNum) {
|
|||
|
|
|||
|
if (pToDoList->ToDoList[i].Item == Item) {
|
|||
|
|
|||
|
if (pToDoList->ToDoList[i].Length == Length) {
|
|||
|
|
|||
|
RtlMoveMemory(pToDoList->ToDoList[i].Buffer, Buffer, Length);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
PVOID pTmp;
|
|||
|
|
|||
|
pTmp = IMirrorAllocMem(Length);
|
|||
|
|
|||
|
if (pTmp == NULL) {
|
|||
|
return STATUS_NO_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
if (pToDoList->ToDoList[i].Length != 0) {
|
|||
|
IMirrorFreeMem(pToDoList->ToDoList[i].Buffer);
|
|||
|
}
|
|||
|
|
|||
|
pToDoList->ToDoList[i].Buffer = pTmp;
|
|||
|
pToDoList->ToDoList[i].Length = Length;
|
|||
|
|
|||
|
RtlMoveMemory(pTmp, Buffer, Length);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
goto Done;
|
|||
|
}
|
|||
|
|
|||
|
i++;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
Done:
|
|||
|
|
|||
|
//
|
|||
|
// Restore global list
|
|||
|
//
|
|||
|
while (!IsListEmpty(&TmpGlobalList)) {
|
|||
|
pListEntry = RemoveTailList(&TmpGlobalList);
|
|||
|
InsertHeadList(&GlobalToDoList, pListEntry);
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
CopyToDoItemParameters(
|
|||
|
IN IMIRROR_TODO Item,
|
|||
|
OUT PVOID Buffer,
|
|||
|
IN OUT PULONG Length
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine finds the first instance of Item, and copies its current parameters into Buffer.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Item - The item id.
|
|||
|
|
|||
|
Buffer - The arguments, context for the item.
|
|||
|
|
|||
|
Length - Length of the buffer in bytes.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if it was able to change the item, else an appropriate error status.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PLIST_ENTRY pListEntry;
|
|||
|
LIST_ENTRY TmpGlobalList;
|
|||
|
PTODOLIST pToDoList;
|
|||
|
ULONG i;
|
|||
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|||
|
|
|||
|
InitializeListHead(&TmpGlobalList);
|
|||
|
while (!IsListEmpty(&GlobalToDoList)) {
|
|||
|
|
|||
|
//
|
|||
|
// Get the first list
|
|||
|
//
|
|||
|
pListEntry = RemoveHeadList(&GlobalToDoList);
|
|||
|
|
|||
|
pToDoList = CONTAINING_RECORD(pListEntry,
|
|||
|
TODOLIST,
|
|||
|
ListEntry
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Save the entry away for later
|
|||
|
//
|
|||
|
InsertTailList(&TmpGlobalList, pListEntry);
|
|||
|
|
|||
|
//
|
|||
|
// Walk the list until we find an item that matches.
|
|||
|
//
|
|||
|
i = 0;
|
|||
|
|
|||
|
while (i < pToDoList->ToDoNum) {
|
|||
|
|
|||
|
if (pToDoList->ToDoList[i].Item == Item) {
|
|||
|
|
|||
|
if (pToDoList->ToDoList[i].Length <= *Length) {
|
|||
|
|
|||
|
if (pToDoList->ToDoList[i].Length != 0) {
|
|||
|
|
|||
|
RtlMoveMemory(Buffer,
|
|||
|
pToDoList->ToDoList[i].Buffer,
|
|||
|
pToDoList->ToDoList[i].Length
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
*Length = pToDoList->ToDoList[i].Length;
|
|||
|
goto Done;
|
|||
|
}
|
|||
|
|
|||
|
i++;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
Done:
|
|||
|
|
|||
|
//
|
|||
|
// Restore global list
|
|||
|
//
|
|||
|
while (!IsListEmpty(&TmpGlobalList)) {
|
|||
|
pListEntry = RemoveTailList(&TmpGlobalList);
|
|||
|
InsertHeadList(&GlobalToDoList, pListEntry);
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
#if 0
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IMirrorDoReboot(
|
|||
|
IN PVOID pBuffer,
|
|||
|
IN ULONG Length
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine saves all the current to do items in the registry, and asks the UI if the
|
|||
|
reboot should be executed now.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pBuffer - Pointer to any arguments passed in the to do item.
|
|||
|
|
|||
|
Length - Length, in bytes of the arguments.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if it completes adding all the to do items properly.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
BOOL fRebootNow;
|
|||
|
BOOLEAN WasEnabled;
|
|||
|
DWORD Error;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Add items to reverify the machine when the reboot is complete.
|
|||
|
//
|
|||
|
#if 0
|
|||
|
Status = AddToDoItem(VerifyNetworkComponents, NULL, 0);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
IMirrorHandleError(Status, IMirrorInitialize);
|
|||
|
return Status;
|
|||
|
}
|
|||
|
#endif
|
|||
|
//
|
|||
|
// Now save everything away...
|
|||
|
//
|
|||
|
Status = SaveAllToDoItems();
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
IMirrorHandleError(Status, IMirrorReboot);
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
ClearAllToDoItems(TRUE);
|
|||
|
|
|||
|
IMirrorWarnReboot(&fRebootNow);
|
|||
|
|
|||
|
if (!fRebootNow) {
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Reboot the machine to start CSC
|
|||
|
//
|
|||
|
Status = RtlAdjustPrivilege( SE_SHUTDOWN_PRIVILEGE,
|
|||
|
(BOOLEAN)TRUE,
|
|||
|
TRUE,
|
|||
|
&WasEnabled
|
|||
|
);
|
|||
|
|
|||
|
if (Status == STATUS_NO_TOKEN) {
|
|||
|
|
|||
|
//
|
|||
|
// No thread token, use the process token
|
|||
|
//
|
|||
|
|
|||
|
Status = RtlAdjustPrivilege( SE_SHUTDOWN_PRIVILEGE,
|
|||
|
(BOOLEAN)TRUE,
|
|||
|
FALSE,
|
|||
|
&WasEnabled
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (!InitiateSystemShutdown(NULL, NULL, 0, TRUE, TRUE)) {
|
|||
|
IMirrorHandleError(ERROR_SUCCESS_REBOOT_REQUIRED, IMirrorReboot);
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
|