mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 19:33:16 +00:00
- Add some hacks to Cm to allow creating registry keys that finish with a backslash (this works under NT).
- Also add a REALLY nasty hack that forces OBJ_CASE_INSENSITIVE on all Registry APIs... this is needed because we seem to completely mess up case sensitivity otherwise and any user-mode caller that doesn't specify that flag will fail. - These two fixes fix all the WINE failures for the "ntdll reg" test and should increase compatibility with some applications. - Runtime Library Registry Wrappers Fixes and Optimizations: - Use an array of registry paths instead of duplicating them - Fix implenmentation of RTL_REGISTRY_HANDLE. - Verify all Appends for failure before continuing. - Use the strict minimum key permissions isntead of KEY_ALL_ACCESS. - Don't use OBJ_OPENIF - Use CAPS for \\REGISTRY\\USER (required to match a Windows quirk exposed by a WINE test) - Use the correct length in RtlpNtQueryValueKey - Generic cleanups, formatting and commenting. svn path=/trunk/; revision=22682
This commit is contained in:
parent
96c859e6a6
commit
bbfd29210c
3 changed files with 489 additions and 507 deletions
|
@ -21,112 +21,97 @@
|
||||||
|
|
||||||
#define TAG_RTLREGISTRY TAG('R', 't', 'l', 'R')
|
#define TAG_RTLREGISTRY TAG('R', 't', 'l', 'R')
|
||||||
|
|
||||||
/* FUNCTIONS ***************************************************************/
|
/* DATA **********************************************************************/
|
||||||
|
|
||||||
static NTSTATUS
|
PCWSTR RtlpRegPaths[RTL_REGISTRY_MAXIMUM] =
|
||||||
RtlpGetRegistryHandle(ULONG RelativeTo,
|
|
||||||
PWSTR Path,
|
|
||||||
BOOLEAN Create,
|
|
||||||
PHANDLE KeyHandle)
|
|
||||||
{
|
{
|
||||||
UNICODE_STRING KeyPath;
|
NULL,
|
||||||
UNICODE_STRING KeyName;
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services",
|
||||||
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control",
|
||||||
|
L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion",
|
||||||
|
L"\\Registry\\Machine\\Hardware\\DeviceMap",
|
||||||
|
L"\\Registry\\User\\.Default",
|
||||||
|
};
|
||||||
|
|
||||||
|
/* PRIVATE FUNCTIONS *********************************************************/
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
RtlpGetRegistryHandle(IN ULONG RelativeTo,
|
||||||
|
IN PCWSTR Path,
|
||||||
|
IN BOOLEAN Create,
|
||||||
|
IN PHANDLE KeyHandle)
|
||||||
|
{
|
||||||
|
UNICODE_STRING KeyPath, KeyName;
|
||||||
WCHAR KeyBuffer[MAX_PATH];
|
WCHAR KeyBuffer[MAX_PATH];
|
||||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
|
||||||
DPRINT("RtlpGetRegistryHandle()\n");
|
/* Check if we just want the handle */
|
||||||
|
|
||||||
if (RelativeTo & RTL_REGISTRY_HANDLE)
|
if (RelativeTo & RTL_REGISTRY_HANDLE)
|
||||||
{
|
{
|
||||||
Status = ZwDuplicateObject(NtCurrentProcess(),
|
*KeyHandle = (HANDLE)Path;
|
||||||
(HANDLE)Path,
|
return STATUS_SUCCESS;
|
||||||
NtCurrentProcess(),
|
|
||||||
KeyHandle,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
DUPLICATE_SAME_ACCESS);
|
|
||||||
#ifndef NDEBUG
|
|
||||||
if(!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
DPRINT("ZwDuplicateObject() failed! Status: 0x%x\n", Status);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return(Status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for optional flag */
|
||||||
if (RelativeTo & RTL_REGISTRY_OPTIONAL)
|
if (RelativeTo & RTL_REGISTRY_OPTIONAL)
|
||||||
|
{
|
||||||
|
/* Mask it out */
|
||||||
RelativeTo &= ~RTL_REGISTRY_OPTIONAL;
|
RelativeTo &= ~RTL_REGISTRY_OPTIONAL;
|
||||||
|
|
||||||
if (RelativeTo >= RTL_REGISTRY_MAXIMUM)
|
|
||||||
{
|
|
||||||
DPRINT("Invalid relative flag, parameter invalid!\n");
|
|
||||||
return(STATUS_INVALID_PARAMETER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyName.Length = 0;
|
/* Fail on invalid parameter */
|
||||||
KeyName.MaximumLength = sizeof(KeyBuffer);
|
if (RelativeTo >= RTL_REGISTRY_MAXIMUM) return STATUS_INVALID_PARAMETER;
|
||||||
KeyName.Buffer = KeyBuffer;
|
|
||||||
KeyBuffer[0] = 0;
|
|
||||||
|
|
||||||
switch (RelativeTo)
|
/* Initialize the key name */
|
||||||
|
RtlInitEmptyUnicodeString(&KeyName, KeyBuffer, sizeof(KeyBuffer));
|
||||||
|
|
||||||
|
/* Check if we have to lookup a path to prefix */
|
||||||
|
if (RelativeTo != RTL_REGISTRY_ABSOLUTE)
|
||||||
{
|
{
|
||||||
case RTL_REGISTRY_ABSOLUTE:
|
/* Check if we need the current user key */
|
||||||
/* nothing to prefix! */
|
if (RelativeTo == RTL_REGISTRY_USER)
|
||||||
break;
|
{
|
||||||
|
/* Get the path */
|
||||||
|
Status = RtlFormatCurrentUserKeyPath(&KeyPath);
|
||||||
|
if (!NT_SUCCESS(Status)) return(Status);
|
||||||
|
|
||||||
case RTL_REGISTRY_SERVICES:
|
/* Append it */
|
||||||
RtlAppendUnicodeToString(&KeyName,
|
Status = RtlAppendUnicodeStringToString(&KeyName, &KeyPath);
|
||||||
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RTL_REGISTRY_CONTROL:
|
|
||||||
RtlAppendUnicodeToString(&KeyName,
|
|
||||||
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RTL_REGISTRY_WINDOWS_NT:
|
|
||||||
RtlAppendUnicodeToString(&KeyName,
|
|
||||||
L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RTL_REGISTRY_DEVICEMAP:
|
|
||||||
RtlAppendUnicodeToString(&KeyName,
|
|
||||||
L"\\Registry\\Machine\\Hardware\\DeviceMap\\");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RTL_REGISTRY_USER:
|
|
||||||
Status = RtlFormatCurrentUserKeyPath (&KeyPath);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
return(Status);
|
|
||||||
RtlAppendUnicodeStringToString (&KeyName,
|
|
||||||
&KeyPath);
|
|
||||||
RtlFreeUnicodeString (&KeyPath);
|
RtlFreeUnicodeString (&KeyPath);
|
||||||
RtlAppendUnicodeToString (&KeyName,
|
|
||||||
L"\\");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (Path[0] == L'\\' && RelativeTo != RTL_REGISTRY_ABSOLUTE)
|
|
||||||
{
|
{
|
||||||
Path++;
|
/* Get one of the prefixes */
|
||||||
|
Status = RtlAppendUnicodeToString(&KeyName,
|
||||||
|
RtlpRegPaths[RelativeTo]);
|
||||||
}
|
}
|
||||||
RtlAppendUnicodeToString(&KeyName,
|
|
||||||
Path);
|
|
||||||
|
|
||||||
DPRINT("KeyName %wZ\n", &KeyName);
|
/* Check for failure, otherwise, append the path separator */
|
||||||
|
if (!NT_SUCCESS(Status)) return Status;
|
||||||
|
Status = RtlAppendUnicodeToString(&KeyName, L"\\");
|
||||||
|
if (!NT_SUCCESS(Status)) return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And now append the path */
|
||||||
|
if (Path[0] == L'\\' && RelativeTo != RTL_REGISTRY_ABSOLUTE) Path++; // HACK!
|
||||||
|
Status = RtlAppendUnicodeToString(&KeyName, Path);
|
||||||
|
if (!NT_SUCCESS(Status)) return Status;
|
||||||
|
|
||||||
|
/* Initialize the object attributes */
|
||||||
InitializeObjectAttributes(&ObjectAttributes,
|
InitializeObjectAttributes(&ObjectAttributes,
|
||||||
&KeyName,
|
&KeyName,
|
||||||
OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
|
OBJ_CASE_INSENSITIVE,
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
/* Check if we want to create it */
|
||||||
if (Create)
|
if (Create)
|
||||||
{
|
{
|
||||||
|
/* Create the key with write privileges */
|
||||||
Status = ZwCreateKey(KeyHandle,
|
Status = ZwCreateKey(KeyHandle,
|
||||||
KEY_ALL_ACCESS,
|
GENERIC_WRITE,
|
||||||
&ObjectAttributes,
|
&ObjectAttributes,
|
||||||
0,
|
0,
|
||||||
NULL,
|
NULL,
|
||||||
|
@ -135,76 +120,71 @@ RtlpGetRegistryHandle(ULONG RelativeTo,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* Otherwise, just open it with read access */
|
||||||
Status = ZwOpenKey(KeyHandle,
|
Status = ZwOpenKey(KeyHandle,
|
||||||
KEY_ALL_ACCESS,
|
MAXIMUM_ALLOWED | GENERIC_READ,
|
||||||
&ObjectAttributes);
|
&ObjectAttributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
/* Return status */
|
||||||
if(!NT_SUCCESS(Status))
|
return Status;
|
||||||
{
|
|
||||||
DPRINT("%s failed! Status: 0x%x\n", (Create ? "ZwCreateKey" : "ZwOpenKey"), Status);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return(Status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* PUBLIC FUNCTIONS **********************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
NTSTATUS NTAPI
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
RtlCheckRegistryKey(IN ULONG RelativeTo,
|
RtlCheckRegistryKey(IN ULONG RelativeTo,
|
||||||
IN PWSTR Path)
|
IN PWSTR Path)
|
||||||
{
|
{
|
||||||
HANDLE KeyHandle;
|
HANDLE KeyHandle;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
|
||||||
PAGED_CODE_RTL();
|
PAGED_CODE_RTL();
|
||||||
|
|
||||||
|
/* Call the helper */
|
||||||
Status = RtlpGetRegistryHandle(RelativeTo,
|
Status = RtlpGetRegistryHandle(RelativeTo,
|
||||||
Path,
|
Path,
|
||||||
FALSE,
|
FALSE,
|
||||||
&KeyHandle);
|
&KeyHandle);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status)) return Status;
|
||||||
return(Status);
|
|
||||||
|
|
||||||
|
/* All went well, close the handle and return success */
|
||||||
ZwClose(KeyHandle);
|
ZwClose(KeyHandle);
|
||||||
|
return STATUS_SUCCESS;
|
||||||
return(STATUS_SUCCESS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
NTSTATUS NTAPI
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
RtlCreateRegistryKey(IN ULONG RelativeTo,
|
RtlCreateRegistryKey(IN ULONG RelativeTo,
|
||||||
IN PWSTR Path)
|
IN PWSTR Path)
|
||||||
{
|
{
|
||||||
HANDLE KeyHandle;
|
HANDLE KeyHandle;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
|
||||||
PAGED_CODE_RTL();
|
PAGED_CODE_RTL();
|
||||||
|
|
||||||
|
/* Call the helper */
|
||||||
Status = RtlpGetRegistryHandle(RelativeTo,
|
Status = RtlpGetRegistryHandle(RelativeTo,
|
||||||
Path,
|
Path,
|
||||||
TRUE,
|
TRUE,
|
||||||
&KeyHandle);
|
&KeyHandle);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status)) return Status;
|
||||||
return(Status);
|
|
||||||
|
|
||||||
|
/* All went well, close the handle and return success */
|
||||||
ZwClose(KeyHandle);
|
ZwClose(KeyHandle);
|
||||||
|
return STATUS_SUCCESS;
|
||||||
return(STATUS_SUCCESS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
NTSTATUS NTAPI
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
RtlDeleteRegistryValue(IN ULONG RelativeTo,
|
RtlDeleteRegistryValue(IN ULONG RelativeTo,
|
||||||
IN PCWSTR Path,
|
IN PCWSTR Path,
|
||||||
IN PCWSTR ValueName)
|
IN PCWSTR ValueName)
|
||||||
|
@ -212,33 +192,111 @@ RtlDeleteRegistryValue(IN ULONG RelativeTo,
|
||||||
HANDLE KeyHandle;
|
HANDLE KeyHandle;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
UNICODE_STRING Name;
|
UNICODE_STRING Name;
|
||||||
|
|
||||||
PAGED_CODE_RTL();
|
PAGED_CODE_RTL();
|
||||||
|
|
||||||
|
/* Call the helper */
|
||||||
Status = RtlpGetRegistryHandle(RelativeTo,
|
Status = RtlpGetRegistryHandle(RelativeTo,
|
||||||
(PWSTR)Path,
|
Path,
|
||||||
FALSE,
|
TRUE,
|
||||||
&KeyHandle);
|
&KeyHandle);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status)) return Status;
|
||||||
return(Status);
|
|
||||||
|
|
||||||
RtlInitUnicodeString(&Name,
|
/* Initialize the key name and delete it */
|
||||||
ValueName);
|
RtlInitUnicodeString(&Name, ValueName);
|
||||||
|
Status = ZwDeleteValueKey(KeyHandle, &Name);
|
||||||
Status = ZwDeleteValueKey(KeyHandle,
|
|
||||||
&Name);
|
|
||||||
|
|
||||||
|
/* All went well, close the handle and return status */
|
||||||
ZwClose(KeyHandle);
|
ZwClose(KeyHandle);
|
||||||
|
return Status;
|
||||||
return(Status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
NTSTATUS NTAPI
|
NTSTATUS
|
||||||
RtlFormatCurrentUserKeyPath (OUT PUNICODE_STRING KeyPath)
|
NTAPI
|
||||||
|
RtlWriteRegistryValue(IN ULONG RelativeTo,
|
||||||
|
IN PCWSTR Path,
|
||||||
|
IN PCWSTR ValueName,
|
||||||
|
IN ULONG ValueType,
|
||||||
|
IN PVOID ValueData,
|
||||||
|
IN ULONG ValueLength)
|
||||||
|
{
|
||||||
|
HANDLE KeyHandle;
|
||||||
|
NTSTATUS Status;
|
||||||
|
UNICODE_STRING Name;
|
||||||
|
PAGED_CODE_RTL();
|
||||||
|
|
||||||
|
/* Call the helper */
|
||||||
|
Status = RtlpGetRegistryHandle(RelativeTo,
|
||||||
|
Path,
|
||||||
|
TRUE,
|
||||||
|
&KeyHandle);
|
||||||
|
if (!NT_SUCCESS(Status)) return Status;
|
||||||
|
|
||||||
|
/* Initialize the key name and set it */
|
||||||
|
RtlInitUnicodeString(&Name, ValueName);
|
||||||
|
Status = ZwSetValueKey(KeyHandle,
|
||||||
|
&Name,
|
||||||
|
0,
|
||||||
|
ValueType,
|
||||||
|
ValueData,
|
||||||
|
ValueLength);
|
||||||
|
|
||||||
|
/* All went well, close the handle and return status */
|
||||||
|
ZwClose(KeyHandle);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
RtlOpenCurrentUser(IN ACCESS_MASK DesiredAccess,
|
||||||
|
OUT PHANDLE KeyHandle)
|
||||||
|
{
|
||||||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
UNICODE_STRING KeyPath;
|
||||||
|
NTSTATUS Status;
|
||||||
|
PAGED_CODE_RTL();
|
||||||
|
|
||||||
|
/* Get the user key */
|
||||||
|
Status = RtlFormatCurrentUserKeyPath(&KeyPath);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* Initialize the attributes and open it */
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes,
|
||||||
|
&KeyPath,
|
||||||
|
OBJ_CASE_INSENSITIVE,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
|
||||||
|
|
||||||
|
/* Free the path and return success if it worked */
|
||||||
|
RtlFreeUnicodeString(&KeyPath);
|
||||||
|
if (NT_SUCCESS(Status)) return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* It didn't work, so use the default key */
|
||||||
|
RtlInitUnicodeString(&KeyPath, RtlpRegPaths[RTL_REGISTRY_USER]);
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes,
|
||||||
|
&KeyPath,
|
||||||
|
OBJ_CASE_INSENSITIVE,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
|
||||||
|
|
||||||
|
/* Return status */
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
RtlFormatCurrentUserKeyPath(OUT PUNICODE_STRING KeyPath)
|
||||||
{
|
{
|
||||||
HANDLE TokenHandle;
|
HANDLE TokenHandle;
|
||||||
UCHAR Buffer[256];
|
UCHAR Buffer[256];
|
||||||
|
@ -246,125 +304,258 @@ RtlFormatCurrentUserKeyPath (OUT PUNICODE_STRING KeyPath)
|
||||||
ULONG Length;
|
ULONG Length;
|
||||||
UNICODE_STRING SidString;
|
UNICODE_STRING SidString;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
|
||||||
PAGED_CODE_RTL();
|
PAGED_CODE_RTL();
|
||||||
|
|
||||||
DPRINT ("RtlFormatCurrentUserKeyPath() called\n");
|
/* Open the thread token */
|
||||||
|
Status = ZwOpenThreadToken(NtCurrentThread(),
|
||||||
Status = ZwOpenThreadToken (NtCurrentThread (),
|
|
||||||
TOKEN_QUERY,
|
TOKEN_QUERY,
|
||||||
TRUE,
|
TRUE,
|
||||||
&TokenHandle);
|
&TokenHandle);
|
||||||
if (!NT_SUCCESS (Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
if (Status != STATUS_NO_TOKEN)
|
/* We failed, is it because we don't have a thread token? */
|
||||||
{
|
if (Status != STATUS_NO_TOKEN) return Status;
|
||||||
DPRINT1 ("ZwOpenThreadToken() failed (Status %lx)\n", Status);
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
Status = ZwOpenProcessToken (NtCurrentProcess (),
|
/* It is, so use the process token */
|
||||||
|
Status = ZwOpenProcessToken(NtCurrentProcess(),
|
||||||
TOKEN_QUERY,
|
TOKEN_QUERY,
|
||||||
&TokenHandle);
|
&TokenHandle);
|
||||||
if (!NT_SUCCESS (Status))
|
if (!NT_SUCCESS(Status)) return Status;
|
||||||
{
|
|
||||||
DPRINT1 ("ZwOpenProcessToken() failed (Status %lx)\n", Status);
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Now query the token information */
|
||||||
SidBuffer = (PSID_AND_ATTRIBUTES)Buffer;
|
SidBuffer = (PSID_AND_ATTRIBUTES)Buffer;
|
||||||
Status = ZwQueryInformationToken (TokenHandle,
|
Status = ZwQueryInformationToken(TokenHandle,
|
||||||
TokenUser,
|
TokenUser,
|
||||||
(PVOID)SidBuffer,
|
(PVOID)SidBuffer,
|
||||||
256,
|
sizeof(Buffer),
|
||||||
&Length);
|
&Length);
|
||||||
ZwClose (TokenHandle);
|
|
||||||
if (!NT_SUCCESS(Status))
|
/* Close the handle and handle failure */
|
||||||
|
ZwClose(TokenHandle);
|
||||||
|
if (!NT_SUCCESS(Status)) return Status;
|
||||||
|
|
||||||
|
/* Convert the SID */
|
||||||
|
Status = RtlConvertSidToUnicodeString(&SidString, SidBuffer[0].Sid, TRUE);
|
||||||
|
if (!NT_SUCCESS(Status)) return Status;
|
||||||
|
|
||||||
|
/* Add the length of the prefix */
|
||||||
|
Length = SidString.Length + sizeof(L"\\REGISTRY\\USER\\");
|
||||||
|
|
||||||
|
/* Initialize a string */
|
||||||
|
RtlInitEmptyUnicodeString(KeyPath,
|
||||||
|
RtlpAllocateStringMemory(Length, TAG_USTR),
|
||||||
|
Length);
|
||||||
|
if (!KeyPath->Buffer)
|
||||||
{
|
{
|
||||||
DPRINT1 ("ZwQueryInformationToken() failed (Status %lx)\n", Status);
|
/* Free the string and fail */
|
||||||
return Status;
|
RtlFreeUnicodeString(&SidString);
|
||||||
|
return STATUS_NO_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
Status = RtlConvertSidToUnicodeString (&SidString,
|
/* Append the prefix and SID */
|
||||||
SidBuffer[0].Sid,
|
RtlAppendUnicodeToString(KeyPath, L"\\REGISTRY\\USER\\");
|
||||||
TRUE);
|
RtlAppendUnicodeStringToString(KeyPath, &SidString);
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
DPRINT1 ("RtlConvertSidToUnicodeString() failed (Status %lx)\n", Status);
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
DPRINT ("SidString: '%wZ'\n", &SidString);
|
|
||||||
|
|
||||||
Length = SidString.Length + sizeof(L"\\Registry\\User\\");
|
|
||||||
DPRINT ("Length: %lu\n", Length);
|
|
||||||
|
|
||||||
KeyPath->Length = 0;
|
|
||||||
KeyPath->MaximumLength = Length;
|
|
||||||
KeyPath->Buffer = RtlpAllocateStringMemory(KeyPath->MaximumLength, TAG_USTR);
|
|
||||||
if (KeyPath->Buffer == NULL)
|
|
||||||
{
|
|
||||||
DPRINT1 ("RtlpAllocateMemory() failed\n");
|
|
||||||
RtlFreeUnicodeString (&SidString);
|
|
||||||
return STATUS_NO_TOKEN;
|
|
||||||
}
|
|
||||||
|
|
||||||
RtlAppendUnicodeToString (KeyPath,
|
|
||||||
L"\\Registry\\User\\");
|
|
||||||
RtlAppendUnicodeStringToString (KeyPath,
|
|
||||||
&SidString);
|
|
||||||
RtlFreeUnicodeString (&SidString);
|
|
||||||
|
|
||||||
|
/* Free the temporary string and return success */
|
||||||
|
RtlFreeUnicodeString(&SidString);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
NTSTATUS NTAPI
|
NTSTATUS
|
||||||
RtlOpenCurrentUser(IN ACCESS_MASK DesiredAccess,
|
NTAPI
|
||||||
OUT PHANDLE KeyHandle)
|
RtlpNtCreateKey(OUT HANDLE KeyHandle,
|
||||||
|
IN ACCESS_MASK DesiredAccess,
|
||||||
|
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||||||
|
IN ULONG TitleIndex,
|
||||||
|
IN PUNICODE_STRING Class,
|
||||||
|
OUT PULONG Disposition)
|
||||||
{
|
{
|
||||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
/* Check if we have object attributes */
|
||||||
UNICODE_STRING KeyPath;
|
if (ObjectAttributes)
|
||||||
|
{
|
||||||
|
/* Mask out the unsupported flags */
|
||||||
|
ObjectAttributes->Attributes &= ~(OBJ_PERMANENT | OBJ_EXCLUSIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the key */
|
||||||
|
return ZwCreateKey(KeyHandle,
|
||||||
|
DesiredAccess,
|
||||||
|
ObjectAttributes,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
Disposition);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
RtlpNtEnumerateSubKey(IN HANDLE KeyHandle,
|
||||||
|
OUT PUNICODE_STRING SubKeyName,
|
||||||
|
IN ULONG Index,
|
||||||
|
IN ULONG Unused)
|
||||||
|
{
|
||||||
|
PKEY_BASIC_INFORMATION KeyInfo = NULL;
|
||||||
|
ULONG BufferLength = 0;
|
||||||
|
ULONG ReturnedLength;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
|
||||||
PAGED_CODE_RTL();
|
/* Check if we have a name */
|
||||||
|
if (SubKeyName->MaximumLength)
|
||||||
|
{
|
||||||
|
/* Allocate a buffer for it */
|
||||||
|
BufferLength = SubKeyName->MaximumLength +
|
||||||
|
sizeof(KEY_BASIC_INFORMATION);
|
||||||
|
KeyInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength);
|
||||||
|
if (!KeyInfo) return STATUS_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
Status = RtlFormatCurrentUserKeyPath(&KeyPath);
|
/* Enumerate the key */
|
||||||
|
Status = ZwEnumerateKey(KeyHandle,
|
||||||
|
Index,
|
||||||
|
KeyBasicInformation,
|
||||||
|
KeyInfo,
|
||||||
|
BufferLength,
|
||||||
|
&ReturnedLength);
|
||||||
if (NT_SUCCESS(Status))
|
if (NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
InitializeObjectAttributes(&ObjectAttributes,
|
/* Check if the name fits */
|
||||||
&KeyPath,
|
if (KeyInfo->NameLength <= SubKeyName->MaximumLength)
|
||||||
OBJ_CASE_INSENSITIVE,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
Status = ZwOpenKey(KeyHandle,
|
|
||||||
DesiredAccess,
|
|
||||||
&ObjectAttributes);
|
|
||||||
RtlFreeUnicodeString(&KeyPath);
|
|
||||||
if (NT_SUCCESS(Status))
|
|
||||||
{
|
{
|
||||||
return STATUS_SUCCESS;
|
/* Set the length */
|
||||||
|
SubKeyName->Length = KeyInfo->NameLength;
|
||||||
|
|
||||||
|
/* Copy it */
|
||||||
|
RtlMoveMemory(SubKeyName->Buffer,
|
||||||
|
KeyInfo->Name,
|
||||||
|
SubKeyName->Length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Otherwise, we ran out of buffer space */
|
||||||
|
Status = STATUS_BUFFER_OVERFLOW;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RtlInitUnicodeString (&KeyPath,
|
/* Free the buffer and return status */
|
||||||
L"\\Registry\\User\\.Default");
|
if (KeyInfo) RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
|
||||||
InitializeObjectAttributes(&ObjectAttributes,
|
|
||||||
&KeyPath,
|
|
||||||
OBJ_CASE_INSENSITIVE,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
Status = ZwOpenKey(KeyHandle,
|
|
||||||
DesiredAccess,
|
|
||||||
&ObjectAttributes);
|
|
||||||
|
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
RtlpNtMakeTemporaryKey(IN HANDLE KeyHandle)
|
||||||
|
{
|
||||||
|
/* This just deletes the key */
|
||||||
|
return ZwDeleteKey(KeyHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
RtlpNtOpenKey(OUT HANDLE KeyHandle,
|
||||||
|
IN ACCESS_MASK DesiredAccess,
|
||||||
|
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||||||
|
IN ULONG Unused)
|
||||||
|
{
|
||||||
|
/* Check if we have object attributes */
|
||||||
|
if (ObjectAttributes)
|
||||||
|
{
|
||||||
|
/* Mask out the unsupported flags */
|
||||||
|
ObjectAttributes->Attributes &= ~(OBJ_PERMANENT | OBJ_EXCLUSIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open the key */
|
||||||
|
return ZwOpenKey(KeyHandle, DesiredAccess, ObjectAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
RtlpNtQueryValueKey(IN HANDLE KeyHandle,
|
||||||
|
OUT PULONG Type OPTIONAL,
|
||||||
|
OUT PVOID Data OPTIONAL,
|
||||||
|
IN OUT PULONG DataLength OPTIONAL,
|
||||||
|
IN ULONG Unused)
|
||||||
|
{
|
||||||
|
PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
|
||||||
|
UNICODE_STRING ValueName;
|
||||||
|
ULONG BufferLength = 0;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
/* Clear the value name */
|
||||||
|
RtlInitEmptyUnicodeString(&ValueName, NULL, 0);
|
||||||
|
|
||||||
|
/* Check if we were already given a length */
|
||||||
|
if (DataLength) BufferLength = *DataLength;
|
||||||
|
|
||||||
|
/* Add the size of the structure */
|
||||||
|
BufferLength += FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
|
||||||
|
|
||||||
|
/* Allocate memory for the value */
|
||||||
|
ValueInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength);
|
||||||
|
if (!ValueInfo) return STATUS_NO_MEMORY;
|
||||||
|
|
||||||
|
/* Query the value */
|
||||||
|
Status = ZwQueryValueKey(KeyHandle,
|
||||||
|
&ValueName,
|
||||||
|
KeyValuePartialInformation,
|
||||||
|
ValueInfo,
|
||||||
|
BufferLength,
|
||||||
|
&BufferLength);
|
||||||
|
if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
|
||||||
|
{
|
||||||
|
/* Return the length and type */
|
||||||
|
if (DataLength) *DataLength = ValueInfo->DataLength;
|
||||||
|
if (Type) *Type = ValueInfo->Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the caller wanted data back, and we got it */
|
||||||
|
if ((NT_SUCCESS(Status)) && (Data))
|
||||||
|
{
|
||||||
|
/* Copy it */
|
||||||
|
RtlMoveMemory(Data, ValueInfo->Data, ValueInfo->DataLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free the memory and return status */
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, ValueInfo);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
RtlpNtSetValueKey(IN HANDLE KeyHandle,
|
||||||
|
IN ULONG Type,
|
||||||
|
IN PVOID Data,
|
||||||
|
IN ULONG DataLength)
|
||||||
|
{
|
||||||
|
UNICODE_STRING ValueName;
|
||||||
|
|
||||||
|
/* Set the value */
|
||||||
|
RtlInitEmptyUnicodeString(&ValueName, NULL, 0);
|
||||||
|
return ZwSetValueKey(KeyHandle,
|
||||||
|
&ValueName,
|
||||||
|
0,
|
||||||
|
Type,
|
||||||
|
Data,
|
||||||
|
DataLength);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @unimplemented
|
* @unimplemented
|
||||||
|
@ -869,234 +1060,4 @@ RtlQueryRegistryValues(IN ULONG RelativeTo,
|
||||||
return(Status);
|
return(Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
NTSTATUS NTAPI
|
|
||||||
RtlWriteRegistryValue(IN ULONG RelativeTo,
|
|
||||||
IN PCWSTR Path,
|
|
||||||
IN PCWSTR ValueName,
|
|
||||||
IN ULONG ValueType,
|
|
||||||
IN PVOID ValueData,
|
|
||||||
IN ULONG ValueLength)
|
|
||||||
{
|
|
||||||
HANDLE KeyHandle;
|
|
||||||
NTSTATUS Status;
|
|
||||||
UNICODE_STRING Name;
|
|
||||||
|
|
||||||
PAGED_CODE_RTL();
|
|
||||||
|
|
||||||
Status = RtlpGetRegistryHandle(RelativeTo,
|
|
||||||
(PWSTR)Path,
|
|
||||||
TRUE,
|
|
||||||
&KeyHandle);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
DPRINT("RtlpGetRegistryHandle() failed! Status: 0x%lx\n", Status);
|
|
||||||
return(Status);
|
|
||||||
}
|
|
||||||
|
|
||||||
RtlInitUnicodeString(&Name,
|
|
||||||
ValueName);
|
|
||||||
|
|
||||||
Status = ZwSetValueKey(KeyHandle,
|
|
||||||
&Name,
|
|
||||||
0,
|
|
||||||
ValueType,
|
|
||||||
ValueData,
|
|
||||||
ValueLength);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
DPRINT1("ZwSetValueKey() failed! Status: 0x%lx\n", Status);
|
|
||||||
}
|
|
||||||
|
|
||||||
ZwClose(KeyHandle);
|
|
||||||
|
|
||||||
return(Status);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
NTSTATUS NTAPI
|
|
||||||
RtlpNtCreateKey(OUT HANDLE KeyHandle,
|
|
||||||
IN ACCESS_MASK DesiredAccess,
|
|
||||||
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|
||||||
IN ULONG Unused1,
|
|
||||||
OUT PULONG Disposition,
|
|
||||||
IN ULONG Unused2)
|
|
||||||
{
|
|
||||||
if (ObjectAttributes != NULL)
|
|
||||||
ObjectAttributes->Attributes &= ~(OBJ_PERMANENT | OBJ_EXCLUSIVE);
|
|
||||||
|
|
||||||
return(ZwCreateKey(KeyHandle,
|
|
||||||
DesiredAccess,
|
|
||||||
ObjectAttributes,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
0,
|
|
||||||
Disposition));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
NTSTATUS NTAPI
|
|
||||||
RtlpNtEnumerateSubKey(IN HANDLE KeyHandle,
|
|
||||||
OUT PUNICODE_STRING SubKeyName,
|
|
||||||
IN ULONG Index,
|
|
||||||
IN ULONG Unused)
|
|
||||||
{
|
|
||||||
PKEY_BASIC_INFORMATION KeyInfo = NULL;
|
|
||||||
ULONG BufferLength = 0;
|
|
||||||
ULONG ReturnedLength;
|
|
||||||
NTSTATUS Status;
|
|
||||||
|
|
||||||
if (SubKeyName->MaximumLength != 0)
|
|
||||||
{
|
|
||||||
BufferLength = SubKeyName->MaximumLength +
|
|
||||||
sizeof(KEY_BASIC_INFORMATION);
|
|
||||||
KeyInfo = RtlpAllocateMemory(BufferLength, TAG_RTLREGISTRY);
|
|
||||||
if (KeyInfo == NULL)
|
|
||||||
return(STATUS_NO_MEMORY);
|
|
||||||
}
|
|
||||||
|
|
||||||
Status = ZwEnumerateKey(KeyHandle,
|
|
||||||
Index,
|
|
||||||
KeyBasicInformation,
|
|
||||||
KeyInfo,
|
|
||||||
BufferLength,
|
|
||||||
&ReturnedLength);
|
|
||||||
if (NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
if (KeyInfo->NameLength + sizeof(WCHAR) <= SubKeyName->MaximumLength)
|
|
||||||
{
|
|
||||||
memmove(SubKeyName->Buffer,
|
|
||||||
KeyInfo->Name,
|
|
||||||
KeyInfo->NameLength);
|
|
||||||
SubKeyName->Buffer[KeyInfo->NameLength / sizeof(WCHAR)] = 0;
|
|
||||||
SubKeyName->Length = KeyInfo->NameLength;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Status = STATUS_BUFFER_OVERFLOW;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (KeyInfo != NULL)
|
|
||||||
{
|
|
||||||
RtlpFreeMemory(KeyInfo, TAG_RTLREGISTRY);
|
|
||||||
}
|
|
||||||
|
|
||||||
return(Status);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
NTSTATUS NTAPI
|
|
||||||
RtlpNtMakeTemporaryKey(IN HANDLE KeyHandle)
|
|
||||||
{
|
|
||||||
return(ZwDeleteKey(KeyHandle));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
NTSTATUS NTAPI
|
|
||||||
RtlpNtOpenKey(OUT HANDLE KeyHandle,
|
|
||||||
IN ACCESS_MASK DesiredAccess,
|
|
||||||
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|
||||||
IN ULONG Unused)
|
|
||||||
{
|
|
||||||
if (ObjectAttributes != NULL)
|
|
||||||
ObjectAttributes->Attributes &= ~(OBJ_PERMANENT | OBJ_EXCLUSIVE);
|
|
||||||
|
|
||||||
return(ZwOpenKey(KeyHandle,
|
|
||||||
DesiredAccess,
|
|
||||||
ObjectAttributes));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
NTSTATUS NTAPI
|
|
||||||
RtlpNtQueryValueKey(IN HANDLE KeyHandle,
|
|
||||||
OUT PULONG Type OPTIONAL,
|
|
||||||
OUT PVOID Data OPTIONAL,
|
|
||||||
IN OUT PULONG DataLength OPTIONAL,
|
|
||||||
IN ULONG Unused)
|
|
||||||
{
|
|
||||||
PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
|
|
||||||
UNICODE_STRING ValueName;
|
|
||||||
ULONG BufferLength;
|
|
||||||
ULONG ReturnedLength;
|
|
||||||
NTSTATUS Status;
|
|
||||||
|
|
||||||
RtlInitUnicodeString(&ValueName,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
BufferLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION);
|
|
||||||
if (DataLength != NULL)
|
|
||||||
BufferLength = *DataLength;
|
|
||||||
|
|
||||||
ValueInfo = RtlpAllocateMemory(BufferLength, TAG_RTLREGISTRY);
|
|
||||||
if (ValueInfo == NULL)
|
|
||||||
return(STATUS_NO_MEMORY);
|
|
||||||
|
|
||||||
Status = ZwQueryValueKey(KeyHandle,
|
|
||||||
&ValueName,
|
|
||||||
KeyValuePartialInformation,
|
|
||||||
ValueInfo,
|
|
||||||
BufferLength,
|
|
||||||
&ReturnedLength);
|
|
||||||
if (NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
if (DataLength != NULL)
|
|
||||||
*DataLength = ValueInfo->DataLength;
|
|
||||||
|
|
||||||
if (Type != NULL)
|
|
||||||
*Type = ValueInfo->Type;
|
|
||||||
|
|
||||||
if (Data != NULL)
|
|
||||||
{
|
|
||||||
memmove(Data,
|
|
||||||
ValueInfo->Data,
|
|
||||||
ValueInfo->DataLength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RtlpFreeMemory(ValueInfo, TAG_RTLREGISTRY);
|
|
||||||
|
|
||||||
return(Status);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
NTSTATUS NTAPI
|
|
||||||
RtlpNtSetValueKey(IN HANDLE KeyHandle,
|
|
||||||
IN ULONG Type,
|
|
||||||
IN PVOID Data,
|
|
||||||
IN ULONG DataLength)
|
|
||||||
{
|
|
||||||
UNICODE_STRING ValueName;
|
|
||||||
|
|
||||||
RtlInitUnicodeString(&ValueName,
|
|
||||||
NULL);
|
|
||||||
return(ZwSetValueKey(KeyHandle,
|
|
||||||
&ValueName,
|
|
||||||
0,
|
|
||||||
Type,
|
|
||||||
Data,
|
|
||||||
DataLength));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -411,13 +411,26 @@ NtCreateKey(OUT PHANDLE KeyHandle,
|
||||||
because NtCreateKey doesn't create trees */
|
because NtCreateKey doesn't create trees */
|
||||||
Start = RemainingPath.Buffer;
|
Start = RemainingPath.Buffer;
|
||||||
if (*Start == L'\\')
|
if (*Start == L'\\')
|
||||||
|
{
|
||||||
Start++;
|
Start++;
|
||||||
|
//RemainingPath.Length -= sizeof(WCHAR);
|
||||||
|
//RemainingPath.MaximumLength -= sizeof(WCHAR);
|
||||||
|
//RemainingPath.Buffer++;
|
||||||
|
//DPRINT1("String: %wZ\n", &RemainingPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RemainingPath.Buffer[(RemainingPath.Length / sizeof(WCHAR)) - 1] == '\\')
|
||||||
|
{
|
||||||
|
RemainingPath.Buffer[(RemainingPath.Length / sizeof(WCHAR)) - 1] = UNICODE_NULL;
|
||||||
|
RemainingPath.Length -= sizeof(WCHAR);
|
||||||
|
RemainingPath.MaximumLength -= sizeof(WCHAR);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 1; i < RemainingPath.Length / sizeof(WCHAR); i++)
|
for (i = 1; i < RemainingPath.Length / sizeof(WCHAR); i++)
|
||||||
{
|
{
|
||||||
if (L'\\' == RemainingPath.Buffer[i])
|
if (L'\\' == RemainingPath.Buffer[i])
|
||||||
{
|
{
|
||||||
DPRINT("NtCreateKey() doesn't create trees! (found \'\\\' in remaining path: \"%wZ\"!)\n", &RemainingPath);
|
DPRINT1("NtCreateKey() doesn't create trees! (found \'\\\' in remaining path: \"%wZ\"!)\n", &RemainingPath);
|
||||||
|
|
||||||
PostCreateKeyInfo.Object = NULL;
|
PostCreateKeyInfo.Object = NULL;
|
||||||
PostCreateKeyInfo.Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
PostCreateKeyInfo.Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
|
@ -1397,6 +1410,13 @@ NtOpenKey(OUT PHANDLE KeyHandle,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ObjectAttributes->ObjectName->Buffer[(ObjectAttributes->ObjectName->Length / sizeof(WCHAR)) - 1] == '\\')
|
||||||
|
{
|
||||||
|
ObjectAttributes->ObjectName->Buffer[(ObjectAttributes->ObjectName->Length / sizeof(WCHAR)) - 1] = UNICODE_NULL;
|
||||||
|
ObjectAttributes->ObjectName->Length -= sizeof(WCHAR);
|
||||||
|
ObjectAttributes->ObjectName->MaximumLength -= sizeof(WCHAR);
|
||||||
|
}
|
||||||
|
|
||||||
/* WINE checks for the length also */
|
/* WINE checks for the length also */
|
||||||
/*if (ObjectAttributes->ObjectName->Length > MAX_NAME_LENGTH)
|
/*if (ObjectAttributes->ObjectName->Length > MAX_NAME_LENGTH)
|
||||||
return(STATUS_BUFFER_OVERFLOW);*/
|
return(STATUS_BUFFER_OVERFLOW);*/
|
||||||
|
|
|
@ -110,6 +110,7 @@ CmFindObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo,
|
||||||
Attributes = ObjectCreateInfo->Attributes;
|
Attributes = ObjectCreateInfo->Attributes;
|
||||||
if (ObjectType == ObSymbolicLinkType)
|
if (ObjectType == ObSymbolicLinkType)
|
||||||
Attributes |= OBJ_OPENLINK;
|
Attributes |= OBJ_OPENLINK;
|
||||||
|
Attributes |= OBJ_CASE_INSENSITIVE; // hello! My name is ReactOS CM and I'm brain-dead!
|
||||||
|
|
||||||
while (TRUE)
|
while (TRUE)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue