return status;
}
+static NTSTATUS
+RegistryOpenRoot(
+ IN PWCHAR Path,
+ OUT PHANDLE Parent,
+ OUT PWCHAR *ChildPath
+ )
+{
+ const WCHAR Prefix[] = L"\\Registry\\Machine\\";
+ ULONG Length;
+ UNICODE_STRING Unicode;
+ NTSTATUS status;
+
+ Length = (ULONG)wcslen(Prefix);
+
+ status = STATUS_INVALID_PARAMETER;
+ if (_wcsnicmp(Path, Prefix, Length) != 0)
+ goto fail1;
+
+ RtlInitUnicodeString(&Unicode, Prefix);
+
+ status = RegistryOpenKey(NULL, &Unicode, KEY_ALL_ACCESS, Parent);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ *ChildPath = Path + Length;
+
+ return STATUS_SUCCESS;
+
+fail2:
+fail1:
+ return status;
+}
+
NTSTATUS
RegistryCreateKey(
- IN HANDLE Parent,
+ IN HANDLE Root,
IN PUNICODE_STRING Path,
IN ULONG Options,
OUT PHANDLE Key
)
{
- OBJECT_ATTRIBUTES Attributes;
+ PWCHAR Buffer;
+ HANDLE Parent;
+ PWCHAR ChildPath;
+ PWCHAR ChildName;
+ PWCHAR Context;
+ HANDLE Child;
NTSTATUS status;
- InitializeObjectAttributes(&Attributes,
- Path,
- OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
- Parent,
- NULL);
+ //
+ // UNICODE_STRINGs are not guaranteed to have NUL terminated
+ // buffers.
+ //
- status = ZwCreateKey(Key,
- KEY_ALL_ACCESS,
- &Attributes,
- 0,
- NULL,
- Options,
- NULL
- );
- if (!NT_SUCCESS(status))
+ Buffer = __RegistryAllocate(Path->MaximumLength + sizeof (WCHAR));
+
+ status = STATUS_NO_MEMORY;
+ if (Buffer == NULL)
goto fail1;
+ RtlCopyMemory(Buffer, Path->Buffer, Path->Length);
+
+ if (Root != NULL) {
+ Parent = Root;
+ ChildPath = Buffer;
+ } else {
+ status = RegistryOpenRoot(Buffer, &Parent, &ChildPath);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+ }
+
+ ChildName = __wcstok_r(ChildPath, L"\\", &Context);
+
+ status = STATUS_INVALID_PARAMETER;
+ if (ChildName == NULL)
+ goto fail3;
+
+ Child = NULL;
+
+ while (ChildName != NULL) {
+ UNICODE_STRING Unicode;
+ OBJECT_ATTRIBUTES Attributes;
+
+ RtlInitUnicodeString(&Unicode, ChildName);
+
+ InitializeObjectAttributes(&Attributes,
+ &Unicode,
+ OBJ_CASE_INSENSITIVE |
+ OBJ_KERNEL_HANDLE |
+ OBJ_OPENIF,
+ Parent,
+ NULL);
+
+ status = ZwCreateKey(&Child,
+ KEY_ALL_ACCESS,
+ &Attributes,
+ 0,
+ NULL,
+ Options,
+ NULL
+ );
+ if (!NT_SUCCESS(status))
+ goto fail4;
+
+ ChildName = __wcstok_r(NULL, L"\\", &Context);
+
+ if (Parent != Root)
+ ZwClose(Parent);
+
+ Parent = Child;
+ }
+
+ ASSERT(Child != NULL);
+
+ *Key = Child;
+
return STATUS_SUCCESS;
+fail4:
+fail3:
+ if (Parent != Root)
+ ZwClose(Parent);
+
+fail2:
+ __RegistryFree(Buffer);
+
fail1:
return status;
}
{
ANSI_STRING Ansi;
UNICODE_STRING Unicode;
- OBJECT_ATTRIBUTES Attributes;
NTSTATUS status;
RtlInitAnsiString(&Ansi, Name);
if (!NT_SUCCESS(status))
goto fail1;
- InitializeObjectAttributes(&Attributes,
- &Unicode,
- OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
- Key,
- NULL);
-
- status = ZwCreateKey(SubKey,
- KEY_ALL_ACCESS,
- &Attributes,
- 0,
- NULL,
- Options,
- NULL
- );
+ status = RegistryCreateKey(Key, &Unicode, Options, SubKey);
if (!NT_SUCCESS(status))
goto fail2;
if (Token == NULL)
return NULL;
- while (*Token != L'\0' &&
+ while (*Token != '\0' &&
strchr(Delimiter, *Token) != NULL)
Token++;
+ if (*Token == '\0')
+ return NULL;
+
+ End = Token + 1;
+ while (*End != '\0' &&
+ strchr(Delimiter, *End) == NULL)
+ End++;
+
+ if (*End != '\0')
+ *End++ = '\0';
+
+ *Context = End;
+
+ return Token;
+}
+
+static FORCEINLINE PWCHAR
+__wcstok_r(
+ IN PWCHAR Buffer,
+ IN PWCHAR Delimiter,
+ IN OUT PWCHAR *Context
+ )
+{
+ PWCHAR Token;
+ PWCHAR End;
+
+ if (Buffer != NULL)
+ *Context = Buffer;
+
+ Token = *Context;
+
+ if (Token == NULL)
+ return NULL;
+
+ while (*Token != L'\0' &&
+ wcschr(Delimiter, *Token) != NULL)
+ Token++;
+
if (*Token == L'\0')
return NULL;
End = Token + 1;
while (*End != L'\0' &&
- strchr(Delimiter, *End) == NULL)
+ wcschr(Delimiter, *End) == NULL)
End++;
if (*End != L'\0')