mirror of
https://github.com/reactos/reactos.git
synced 2024-11-18 21:13:52 +00:00
[NTDLL_APITEST]: Add tests for NtLoadKey and NtUnloadKey.
CORE-13448 svn path=/trunk/; revision=75078
This commit is contained in:
parent
3b5b6fd6f1
commit
9808e1ee19
3 changed files with 636 additions and 0 deletions
|
@ -10,6 +10,7 @@ list(APPEND SOURCE
|
|||
NtCreateThread.c
|
||||
NtDeleteKey.c
|
||||
NtFreeVirtualMemory.c
|
||||
NtLoadUnloadKey.c
|
||||
NtMapViewOfSection.c
|
||||
NtMutant.c
|
||||
NtOpenProcessToken.c
|
||||
|
|
633
rostests/apitests/ntdll/NtLoadUnloadKey.c
Normal file
633
rostests/apitests/ntdll/NtLoadUnloadKey.c
Normal file
|
@ -0,0 +1,633 @@
|
|||
/*
|
||||
* PROJECT: ReactOS API Tests
|
||||
* LICENSE: GPLv2+ - See COPYING in the top level directory
|
||||
* PURPOSE: Test for NtLoadKey and NtUnloadKey
|
||||
* PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <apitest.h>
|
||||
#include <strsafe.h>
|
||||
|
||||
#define WIN32_NO_STATUS
|
||||
#include <ndk/rtlfuncs.h>
|
||||
#include <ndk/cmfuncs.h>
|
||||
#include <ndk/cmtypes.h>
|
||||
#include <ndk/iofuncs.h>
|
||||
#include <ndk/obfuncs.h>
|
||||
#include <ndk/setypes.h>
|
||||
|
||||
/* See xdk/cmtypes.h */
|
||||
#define REG_CREATED_NEW_KEY 1
|
||||
#define REG_OPENED_EXISTING_KEY 2
|
||||
|
||||
/* Vista+ */
|
||||
#define STATUS_HIVE_UNLOADED ((NTSTATUS)0xC0000425)
|
||||
|
||||
#if 1
|
||||
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
#else
|
||||
|
||||
#define DPRINT(fmt, ...) printf("(%s:%d) " fmt, __FILE__, __LINE__, ##__VA_ARGS__);
|
||||
#define DPRINT1(fmt, ...) printf("(%s:%d) " fmt, __FILE__, __LINE__, ##__VA_ARGS__);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static BOOLEAN
|
||||
RetrieveCurrentModuleNTDirectory(
|
||||
OUT PUNICODE_STRING NtPath)
|
||||
{
|
||||
WCHAR ModulePath[MAX_PATH];
|
||||
PWSTR PathSep;
|
||||
|
||||
/* Retrieve the current path where the test is running */
|
||||
GetModuleFileNameW(NULL, ModulePath, _countof(ModulePath));
|
||||
PathSep = wcsrchr(ModulePath, L'\\');
|
||||
if (!PathSep)
|
||||
PathSep = ModulePath + wcslen(ModulePath);
|
||||
*PathSep = UNICODE_NULL;
|
||||
|
||||
/* Convert the path to NT format and work with it for now on */
|
||||
return RtlDosPathNameToNtPathName_U(ModulePath, NtPath, NULL, NULL);
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
CreateRegKey(
|
||||
OUT PHANDLE KeyHandle,
|
||||
IN HANDLE RootKey OPTIONAL,
|
||||
IN PUNICODE_STRING KeyName,
|
||||
IN ULONG CreateOptions,
|
||||
OUT PULONG Disposition OPTIONAL)
|
||||
{
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
KeyName,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
RootKey,
|
||||
NULL);
|
||||
return NtCreateKey(KeyHandle,
|
||||
KEY_ALL_ACCESS,
|
||||
&ObjectAttributes,
|
||||
0,
|
||||
NULL,
|
||||
CreateOptions,
|
||||
Disposition);
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
CreateProtoHive(
|
||||
OUT PHANDLE KeyHandle)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
UNICODE_STRING KeyName;
|
||||
|
||||
RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\SYSTEM\\$$$PROTO.HIV");
|
||||
Status = CreateRegKey(KeyHandle,
|
||||
NULL,
|
||||
&KeyName,
|
||||
REG_OPTION_NON_VOLATILE,
|
||||
NULL);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
NtFlushKey(KeyHandle);
|
||||
return Status;
|
||||
}
|
||||
|
||||
static VOID
|
||||
DestroyProtoHive(
|
||||
IN HANDLE KeyHandle)
|
||||
{
|
||||
NtDeleteKey(KeyHandle);
|
||||
NtClose(KeyHandle);
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
OpenDirectoryByHandleOrPath(
|
||||
OUT PHANDLE RootPathHandle,
|
||||
IN HANDLE RootDirectory OPTIONAL,
|
||||
IN PUNICODE_STRING RootPath OPTIONAL)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
|
||||
*RootPathHandle = NULL;
|
||||
|
||||
/*
|
||||
* RootDirectory and RootPath cannot be either both NULL
|
||||
* or both non-NULL, when being specified.
|
||||
*/
|
||||
if ((!RootDirectory && !RootPath) ||
|
||||
( RootDirectory && RootPath))
|
||||
{
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (!RootDirectory && RootPath)
|
||||
{
|
||||
/* Open the root directory path */
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
RootPath,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
NULL,
|
||||
NULL);
|
||||
Status = NtOpenFile(RootPathHandle,
|
||||
// FILE_TRAVERSE is needed to be able to use the handle as RootDirectory for future InitializeObjectAttributes calls.
|
||||
FILE_LIST_DIRECTORY | FILE_ADD_FILE /* | FILE_ADD_SUBDIRECTORY */ | FILE_TRAVERSE | SYNCHRONIZE,
|
||||
&ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE /* | FILE_OPEN_FOR_BACKUP_INTENT */);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("NtOpenFile(%wZ) failed, Status 0x%08lx\n", RootPath, Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Mark the handle as being opened locally */
|
||||
*RootPathHandle = (HANDLE)((ULONG_PTR)*RootPathHandle | 1);
|
||||
}
|
||||
else if (RootDirectory && !RootPath)
|
||||
{
|
||||
*RootPathHandle = RootDirectory;
|
||||
}
|
||||
// No other cases possible
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Should be called under privileges
|
||||
*/
|
||||
static NTSTATUS
|
||||
CreateRegistryFile(
|
||||
IN HANDLE RootDirectory OPTIONAL,
|
||||
IN PUNICODE_STRING RootPath OPTIONAL,
|
||||
IN PCWSTR RegistryKey,
|
||||
IN HANDLE ProtoKeyHandle)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
HANDLE RootPathHandle, FileHandle;
|
||||
UNICODE_STRING FileName;
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
|
||||
/* Open the root directory */
|
||||
Status = OpenDirectoryByHandleOrPath(&RootPathHandle, RootDirectory, RootPath);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("OpenDirectoryByHandleOrPath failed, Status 0x%08lx\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Create the file */
|
||||
RtlInitUnicodeString(&FileName, RegistryKey);
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
&FileName,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
(HANDLE)((ULONG_PTR)RootPathHandle & ~1), // Remove the opened-locally flag
|
||||
NULL);
|
||||
Status = NtCreateFile(&FileHandle,
|
||||
FILE_GENERIC_WRITE /* | DELETE */,
|
||||
&ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
NULL,
|
||||
FILE_ATTRIBUTE_NORMAL /* | FILE_FLAG_DELETE_ON_CLOSE */,
|
||||
0,
|
||||
FILE_OVERWRITE_IF,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE,
|
||||
NULL,
|
||||
0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("NtCreateFile(%wZ) failed, Status 0x%08lx\n", &FileName, Status);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Save the selected hive into the file */
|
||||
Status = NtSaveKeyEx(ProtoKeyHandle, FileHandle, REG_LATEST_FORMAT);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("NtSaveKeyEx(%wZ) failed, Status 0x%08lx\n", &FileName, Status);
|
||||
}
|
||||
|
||||
/* Close the file, the root directory (if opened locally), and return */
|
||||
NtClose(FileHandle);
|
||||
Cleanup:
|
||||
if ((ULONG_PTR)RootPathHandle & 1) NtClose((HANDLE)((ULONG_PTR)RootPathHandle & ~1));
|
||||
return Status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Should be called under privileges
|
||||
*/
|
||||
static NTSTATUS
|
||||
MyDeleteFile(
|
||||
IN HANDLE RootDirectory OPTIONAL,
|
||||
IN PUNICODE_STRING RootPath OPTIONAL,
|
||||
IN PCWSTR FileName,
|
||||
IN BOOLEAN ForceDelete) // ForceDelete can be used to delete read-only files
|
||||
{
|
||||
NTSTATUS Status;
|
||||
HANDLE RootPathHandle;
|
||||
UNICODE_STRING NtPath;
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
HANDLE FileHandle;
|
||||
FILE_DISPOSITION_INFORMATION FileDispInfo;
|
||||
BOOLEAN RetryOnce = FALSE;
|
||||
|
||||
/* Open the root directory */
|
||||
Status = OpenDirectoryByHandleOrPath(&RootPathHandle, RootDirectory, RootPath);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("OpenDirectoryByHandleOrPath failed, Status 0x%08lx\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Open the directory name that was passed in */
|
||||
RtlInitUnicodeString(&NtPath, FileName);
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
&NtPath,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
RootPathHandle,
|
||||
NULL);
|
||||
|
||||
Retry: /* We go back there once if RetryOnce == TRUE */
|
||||
Status = NtOpenFile(&FileHandle,
|
||||
DELETE | FILE_READ_ATTRIBUTES |
|
||||
(RetryOnce ? FILE_WRITE_ATTRIBUTES : 0),
|
||||
&ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("NtOpenFile failed with Status 0x%08lx\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (RetryOnce)
|
||||
{
|
||||
FILE_BASIC_INFORMATION FileInformation;
|
||||
|
||||
Status = NtQueryInformationFile(FileHandle,
|
||||
&IoStatusBlock,
|
||||
&FileInformation,
|
||||
sizeof(FILE_BASIC_INFORMATION),
|
||||
FileBasicInformation);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("NtQueryInformationFile failed with Status 0x%08lx\n", Status);
|
||||
NtClose(FileHandle);
|
||||
return Status;
|
||||
}
|
||||
|
||||
FileInformation.FileAttributes = FILE_ATTRIBUTE_NORMAL;
|
||||
Status = NtSetInformationFile(FileHandle,
|
||||
&IoStatusBlock,
|
||||
&FileInformation,
|
||||
sizeof(FILE_BASIC_INFORMATION),
|
||||
FileBasicInformation);
|
||||
NtClose(FileHandle);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("NtSetInformationFile failed with Status 0x%08lx\n", Status);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ask for the file to be deleted */
|
||||
FileDispInfo.DeleteFile = TRUE;
|
||||
Status = NtSetInformationFile(FileHandle,
|
||||
&IoStatusBlock,
|
||||
&FileDispInfo,
|
||||
sizeof(FILE_DISPOSITION_INFORMATION),
|
||||
FileDispositionInformation);
|
||||
NtClose(FileHandle);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
DPRINT1("Deletion of file '%S' failed, Status 0x%08lx\n", FileName, Status);
|
||||
|
||||
// FIXME: Check the precise value of Status!
|
||||
if (!NT_SUCCESS(Status) && ForceDelete && !RetryOnce)
|
||||
{
|
||||
/* Retry once */
|
||||
RetryOnce = TRUE;
|
||||
goto Retry;
|
||||
}
|
||||
|
||||
/* Return result to the caller */
|
||||
return Status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Should be called under privileges
|
||||
*/
|
||||
static NTSTATUS
|
||||
ConnectRegistry(
|
||||
IN HANDLE RootKey OPTIONAL,
|
||||
IN PCWSTR RegMountPoint,
|
||||
IN HANDLE RootDirectory OPTIONAL,
|
||||
IN PUNICODE_STRING RootPath OPTIONAL,
|
||||
IN PCWSTR RegistryKey)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
HANDLE RootPathHandle;
|
||||
UNICODE_STRING KeyName, FileName;
|
||||
OBJECT_ATTRIBUTES KeyObjectAttributes;
|
||||
OBJECT_ATTRIBUTES FileObjectAttributes;
|
||||
|
||||
/* Open the root directory */
|
||||
Status = OpenDirectoryByHandleOrPath(&RootPathHandle, RootDirectory, RootPath);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("OpenDirectoryByHandleOrPath failed, Status 0x%08lx\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
RtlInitUnicodeString(&KeyName, RegMountPoint);
|
||||
InitializeObjectAttributes(&KeyObjectAttributes,
|
||||
&KeyName,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
RootKey,
|
||||
NULL);
|
||||
|
||||
RtlInitUnicodeString(&FileName, RegistryKey);
|
||||
InitializeObjectAttributes(&FileObjectAttributes,
|
||||
&FileName,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
(HANDLE)((ULONG_PTR)RootPathHandle & ~1), // Remove the opened-locally flag
|
||||
NULL);
|
||||
|
||||
/* Mount the registry hive in the registry namespace */
|
||||
Status = NtLoadKey(&KeyObjectAttributes, &FileObjectAttributes);
|
||||
|
||||
/* Close the root directory (if opened locally), and return */
|
||||
if ((ULONG_PTR)RootPathHandle & 1) NtClose((HANDLE)((ULONG_PTR)RootPathHandle & ~1));
|
||||
return Status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Should be called under privileges
|
||||
*/
|
||||
static NTSTATUS
|
||||
DisconnectRegistry(
|
||||
IN HANDLE RootKey OPTIONAL,
|
||||
IN PCWSTR RegMountPoint,
|
||||
IN ULONG Flags)
|
||||
{
|
||||
UNICODE_STRING KeyName;
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
|
||||
RtlInitUnicodeString(&KeyName, RegMountPoint);
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
&KeyName,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
RootKey,
|
||||
NULL);
|
||||
// return NtUnloadKey(&ObjectAttributes);
|
||||
return NtUnloadKey2(&ObjectAttributes, Flags);
|
||||
}
|
||||
|
||||
|
||||
START_TEST(NtLoadUnloadKey)
|
||||
{
|
||||
typedef struct _HIVE_LIST_ENTRY
|
||||
{
|
||||
PCWSTR HiveName;
|
||||
PCWSTR RegMountPoint;
|
||||
} HIVE_LIST_ENTRY, *PHIVE_LIST_ENTRY;
|
||||
|
||||
static const HIVE_LIST_ENTRY RegistryHives[] =
|
||||
{
|
||||
{ L"TestHive1", L"\\Registry\\Machine\\TestHive1" },
|
||||
{ L"TestHive2", L"\\Registry\\Machine\\TestHive2" },
|
||||
};
|
||||
|
||||
NTSTATUS Status;
|
||||
UNICODE_STRING NtTestPath;
|
||||
UNICODE_STRING KeyName;
|
||||
HANDLE KeyHandle;
|
||||
ULONG Disposition;
|
||||
UINT i;
|
||||
BOOLEAN PrivilegeSet[2] = {FALSE, FALSE};
|
||||
WCHAR PathBuffer[MAX_PATH];
|
||||
|
||||
/* Retrieve our current directory */
|
||||
RetrieveCurrentModuleNTDirectory(&NtTestPath);
|
||||
|
||||
/* Acquire restore privilege */
|
||||
Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[0]);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
skip("RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE) failed (Status 0x%08lx)\n", Status);
|
||||
/* Exit prematurely here.... */
|
||||
// goto Cleanup;
|
||||
RtlFreeUnicodeString(&NtTestPath);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Acquire backup privilege */
|
||||
Status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[1]);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
skip("RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE) failed (Status 0x%08lx)\n", Status);
|
||||
RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]);
|
||||
/* Exit prematurely here.... */
|
||||
// goto Cleanup;
|
||||
RtlFreeUnicodeString(&NtTestPath);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create the template proto-hive */
|
||||
Status = CreateProtoHive(&KeyHandle);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
skip("CreateProtoHive() failed to create the proto-hive; Status 0x%08lx\n", Status);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Create two registry hive files from it */
|
||||
for (i = 0; i < _countof(RegistryHives); ++i)
|
||||
{
|
||||
Status = CreateRegistryFile(NULL, &NtTestPath,
|
||||
RegistryHives[i].HiveName,
|
||||
KeyHandle);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("CreateRegistryFile(%S) failed, Status 0x%08lx\n", RegistryHives[i].HiveName, Status);
|
||||
/* Exit prematurely here.... */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* That is now done, remove the proto-hive */
|
||||
DestroyProtoHive(KeyHandle);
|
||||
|
||||
/* Exit prematurely here if we failed */
|
||||
if (!NT_SUCCESS(Status))
|
||||
goto Cleanup;
|
||||
|
||||
|
||||
/***********************************************************************************************/
|
||||
|
||||
|
||||
/* Now, mount the first hive */
|
||||
Status = ConnectRegistry(NULL, RegistryHives[0].RegMountPoint,
|
||||
NULL, &NtTestPath,
|
||||
RegistryHives[0].HiveName);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("ConnectRegistry('%wZ\\%S', '%S') failed, Status 0x%08lx\n",
|
||||
&NtTestPath, RegistryHives[0].HiveName, RegistryHives[0].RegMountPoint, Status);
|
||||
}
|
||||
|
||||
/* Create or open a key inside the mounted hive */
|
||||
StringCchPrintfW(PathBuffer, _countof(PathBuffer), L"%s\\%s", RegistryHives[0].RegMountPoint, L"MyKey_1");
|
||||
RtlInitUnicodeString(&KeyName, PathBuffer);
|
||||
|
||||
KeyHandle = NULL;
|
||||
Status = CreateRegKey(&KeyHandle,
|
||||
NULL,
|
||||
&KeyName,
|
||||
REG_OPTION_NON_VOLATILE,
|
||||
&Disposition);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("CreateRegKey(%wZ) failed (Status %lx)\n", &KeyName, Status);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT1("CreateRegKey(%wZ) succeeded to %s the key (Status %lx)\n",
|
||||
&KeyName,
|
||||
Disposition == REG_CREATED_NEW_KEY ? "create" : /* REG_OPENED_EXISTING_KEY */ "open",
|
||||
Status);
|
||||
}
|
||||
|
||||
/* The key handle must be valid here */
|
||||
Status = NtFlushKey(KeyHandle);
|
||||
ok_ntstatus(Status, STATUS_SUCCESS);
|
||||
|
||||
/* Attempt to unmount the hive, with the handle key still opened */
|
||||
Status = DisconnectRegistry(NULL, RegistryHives[0].RegMountPoint, 0); // Same as NtUnloadKey(&ObjectAttributes);
|
||||
DPRINT1("Unmounting '%S' %s\n", RegistryHives[0].RegMountPoint, NT_SUCCESS(Status) ? "succeeded" : "failed");
|
||||
ok_ntstatus(Status, STATUS_CANNOT_DELETE);
|
||||
|
||||
/* The key handle should still be valid here */
|
||||
Status = NtFlushKey(KeyHandle);
|
||||
ok_ntstatus(Status, STATUS_SUCCESS);
|
||||
|
||||
/* Force-unmount the hive, with the handle key still opened */
|
||||
Status = DisconnectRegistry(NULL, RegistryHives[0].RegMountPoint, 1 /* REG_FORCE_UNLOAD */);
|
||||
DPRINT1("Force-unmounting '%S' %s\n", RegistryHives[0].RegMountPoint, NT_SUCCESS(Status) ? "succeeded" : "failed");
|
||||
ok_hex(Status, STATUS_SUCCESS);
|
||||
|
||||
/* The key handle should not be valid anymore */
|
||||
Status = NtFlushKey(KeyHandle);
|
||||
if (Status != STATUS_KEY_DELETED /* Win2k3 */ &&
|
||||
Status != STATUS_HIVE_UNLOADED /* Win7+ */)
|
||||
{
|
||||
ok_ntstatus(Status, STATUS_KEY_DELETED);
|
||||
}
|
||||
|
||||
/* The key handle should not be valid anymore */
|
||||
Status = NtDeleteKey(KeyHandle);
|
||||
ok_ntstatus(Status, STATUS_SUCCESS);
|
||||
|
||||
/* Close by principle the handle, but should this fail? */
|
||||
Status = NtClose(KeyHandle);
|
||||
ok_ntstatus(Status, STATUS_SUCCESS);
|
||||
|
||||
|
||||
/***********************************************************************************************/
|
||||
|
||||
|
||||
/* Now, mount the first hive, again */
|
||||
Status = ConnectRegistry(NULL, RegistryHives[0].RegMountPoint,
|
||||
NULL, &NtTestPath,
|
||||
RegistryHives[0].HiveName);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("ConnectRegistry('%wZ\\%S', '%S') failed, Status 0x%08lx\n",
|
||||
&NtTestPath, RegistryHives[0].HiveName, RegistryHives[0].RegMountPoint, Status);
|
||||
}
|
||||
|
||||
/* Create or open a key inside the mounted hive */
|
||||
StringCchPrintfW(PathBuffer, _countof(PathBuffer), L"%s\\%s", RegistryHives[0].RegMountPoint, L"MyKey_2");
|
||||
RtlInitUnicodeString(&KeyName, PathBuffer);
|
||||
|
||||
KeyHandle = NULL;
|
||||
Status = CreateRegKey(&KeyHandle,
|
||||
NULL,
|
||||
&KeyName,
|
||||
REG_OPTION_NON_VOLATILE,
|
||||
&Disposition);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("CreateRegKey(%wZ) failed (Status %lx)\n", &KeyName, Status);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT1("CreateRegKey(%wZ) succeeded to %s the key (Status %lx)\n",
|
||||
&KeyName,
|
||||
Disposition == REG_CREATED_NEW_KEY ? "create" : /* REG_OPENED_EXISTING_KEY */ "open",
|
||||
Status);
|
||||
}
|
||||
|
||||
/* The key handle must be valid here */
|
||||
Status = NtFlushKey(KeyHandle);
|
||||
ok_ntstatus(Status, STATUS_SUCCESS);
|
||||
|
||||
/* Delete the key, this should succeed */
|
||||
Status = NtDeleteKey(KeyHandle);
|
||||
ok_ntstatus(Status, STATUS_SUCCESS);
|
||||
|
||||
/* Close the handle, this should succeed */
|
||||
Status = NtClose(KeyHandle);
|
||||
ok_ntstatus(Status, STATUS_SUCCESS);
|
||||
|
||||
/* Attempt to unmount the hive (no forcing), this should succeed */
|
||||
Status = DisconnectRegistry(NULL, RegistryHives[0].RegMountPoint, 0); // Same as NtUnloadKey(&ObjectAttributes);
|
||||
DPRINT1("Unmounting '%S' %s\n", RegistryHives[0].RegMountPoint, NT_SUCCESS(Status) ? "succeeded" : "failed");
|
||||
ok_ntstatus(Status, STATUS_SUCCESS);
|
||||
|
||||
/* Force-unmount the hive (it is already unmounted), this should fail */
|
||||
Status = DisconnectRegistry(NULL, RegistryHives[0].RegMountPoint, 1 /* REG_FORCE_UNLOAD */);
|
||||
DPRINT1("Force-unmounting '%S' %s\n", RegistryHives[0].RegMountPoint, NT_SUCCESS(Status) ? "succeeded" : "failed");
|
||||
ok_hex(Status, STATUS_INVALID_PARAMETER);
|
||||
|
||||
#if 0
|
||||
/* Close by principle the handle, but should this fail? */
|
||||
Status = NtClose(KeyHandle);
|
||||
ok_ntstatus(Status, STATUS_SUCCESS);
|
||||
#endif
|
||||
|
||||
|
||||
/***********************************************************************************************/
|
||||
|
||||
|
||||
Cleanup:
|
||||
|
||||
/* Destroy the hive files */
|
||||
for (i = 0; i < _countof(RegistryHives); ++i)
|
||||
{
|
||||
Status = MyDeleteFile(NULL, &NtTestPath,
|
||||
RegistryHives[i].HiveName, TRUE);
|
||||
if (!NT_SUCCESS(Status))
|
||||
DPRINT1("MyDeleteFile(%S) failed, Status 0x%08lx\n", RegistryHives[i].HiveName, Status);
|
||||
}
|
||||
|
||||
/* Remove restore and backup privileges */
|
||||
RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, PrivilegeSet[1], FALSE, &PrivilegeSet[1]);
|
||||
RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]);
|
||||
|
||||
RtlFreeUnicodeString(&NtTestPath);
|
||||
}
|
|
@ -13,6 +13,7 @@ extern void func_NtCreateKey(void);
|
|||
extern void func_NtCreateThread(void);
|
||||
extern void func_NtDeleteKey(void);
|
||||
extern void func_NtFreeVirtualMemory(void);
|
||||
extern void func_NtLoadUnloadKey(void);
|
||||
extern void func_NtMapViewOfSection(void);
|
||||
extern void func_NtMutant(void);
|
||||
extern void func_NtOpenProcessToken(void);
|
||||
|
@ -68,6 +69,7 @@ const struct test winetest_testlist[] =
|
|||
{ "NtCreateThread", func_NtCreateThread },
|
||||
{ "NtDeleteKey", func_NtDeleteKey },
|
||||
{ "NtFreeVirtualMemory", func_NtFreeVirtualMemory },
|
||||
{ "NtLoadUnloadKey", func_NtLoadUnloadKey },
|
||||
{ "NtMapViewOfSection", func_NtMapViewOfSection },
|
||||
{ "NtMutant", func_NtMutant },
|
||||
{ "NtOpenProcessToken", func_NtOpenProcessToken },
|
||||
|
|
Loading…
Reference in a new issue