mirror of
https://github.com/reactos/reactos.git
synced 2025-01-02 12:32:47 +00:00
[LSASRV]
- Add new registry API. - Implement LsarEnumerateAccounts. svn path=/trunk/; revision=57764
This commit is contained in:
parent
fad4fbd259
commit
4864e1b553
4 changed files with 667 additions and 2 deletions
|
@ -18,6 +18,7 @@ list(APPEND SOURCE
|
||||||
lsasrv.c
|
lsasrv.c
|
||||||
policy.c
|
policy.c
|
||||||
privileges.c
|
privileges.c
|
||||||
|
registry.c
|
||||||
security.c
|
security.c
|
||||||
lsasrv.rc
|
lsasrv.rc
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/lsasrv_stubs.c
|
${CMAKE_CURRENT_BINARY_DIR}/lsasrv_stubs.c
|
||||||
|
|
|
@ -642,8 +642,203 @@ NTSTATUS WINAPI LsarEnumerateAccounts(
|
||||||
PLSAPR_ACCOUNT_ENUM_BUFFER EnumerationBuffer,
|
PLSAPR_ACCOUNT_ENUM_BUFFER EnumerationBuffer,
|
||||||
DWORD PreferedMaximumLength)
|
DWORD PreferedMaximumLength)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
LSAPR_ACCOUNT_ENUM_BUFFER EnumBuffer = {0, NULL};
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
PLSA_DB_OBJECT PolicyObject = NULL;
|
||||||
|
WCHAR AccountKeyName[64];
|
||||||
|
HANDLE AccountsKeyHandle = NULL;
|
||||||
|
HANDLE AccountKeyHandle;
|
||||||
|
HANDLE SidKeyHandle;
|
||||||
|
ULONG EnumIndex;
|
||||||
|
ULONG EnumCount;
|
||||||
|
ULONG RequiredLength;
|
||||||
|
ULONG DataLength;
|
||||||
|
ULONG i;
|
||||||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
TRACE("(%p %p %p %lu)\n", PolicyHandle, EnumerationContext,
|
||||||
|
EnumerationBuffer, PreferedMaximumLength);
|
||||||
|
|
||||||
|
if (EnumerationContext == NULL ||
|
||||||
|
EnumerationBuffer == NULL)
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
EnumerationBuffer->EntriesRead = 0;
|
||||||
|
EnumerationBuffer->Information = NULL;
|
||||||
|
|
||||||
|
/* Validate the PolicyHandle */
|
||||||
|
Status = LsapValidateDbObject(PolicyHandle,
|
||||||
|
LsaDbPolicyObject,
|
||||||
|
POLICY_VIEW_LOCAL_INFORMATION,
|
||||||
|
&PolicyObject);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
ERR("LsapValidateDbObject returned 0x%08lx\n", Status);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = LsapRegOpenKey(PolicyObject->KeyHandle,
|
||||||
|
L"Accounts",
|
||||||
|
KEY_READ,
|
||||||
|
&AccountsKeyHandle);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
return Status;
|
||||||
|
|
||||||
|
EnumIndex = *EnumerationContext;
|
||||||
|
EnumCount = 0;
|
||||||
|
RequiredLength = 0;
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
Status = LsapRegEnumerateSubKey(AccountsKeyHandle,
|
||||||
|
EnumIndex,
|
||||||
|
64 * sizeof(WCHAR),
|
||||||
|
AccountKeyName);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
break;
|
||||||
|
|
||||||
|
TRACE("EnumIndex: %lu\n", EnumIndex);
|
||||||
|
TRACE("Account key name: %S\n", AccountKeyName);
|
||||||
|
|
||||||
|
Status = LsapRegOpenKey(AccountsKeyHandle,
|
||||||
|
AccountKeyName,
|
||||||
|
KEY_READ,
|
||||||
|
&AccountKeyHandle);
|
||||||
|
TRACE("LsapRegOpenKey returned %08lX\n", Status);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
Status = LsapRegOpenKey(AccountKeyHandle,
|
||||||
|
L"Sid",
|
||||||
|
KEY_READ,
|
||||||
|
&SidKeyHandle);
|
||||||
|
TRACE("LsapRegOpenKey returned %08lX\n", Status);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DataLength = 0;
|
||||||
|
Status = LsapRegQueryValue(SidKeyHandle,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&DataLength);
|
||||||
|
TRACE("LsapRegQueryValue returned %08lX\n", Status);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
TRACE("Data length: %lu\n", DataLength);
|
||||||
|
|
||||||
|
if ((RequiredLength + DataLength + sizeof(LSAPR_ACCOUNT_INFORMATION)) > PreferedMaximumLength)
|
||||||
|
break;
|
||||||
|
|
||||||
|
RequiredLength += (DataLength + sizeof(LSAPR_ACCOUNT_INFORMATION));
|
||||||
|
EnumCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
LsapRegCloseKey(SidKeyHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
LsapRegCloseKey(AccountKeyHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
EnumIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("EnumCount: %lu\n", EnumCount);
|
||||||
|
TRACE("RequiredLength: %lu\n", RequiredLength);
|
||||||
|
|
||||||
|
EnumBuffer.EntriesRead = EnumCount;
|
||||||
|
EnumBuffer.Information = midl_user_allocate(EnumCount * sizeof(LSAPR_ACCOUNT_INFORMATION));
|
||||||
|
if (EnumBuffer.Information == NULL)
|
||||||
|
{
|
||||||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnumIndex = *EnumerationContext;
|
||||||
|
for (i = 0; i < EnumCount; i++, EnumIndex++)
|
||||||
|
{
|
||||||
|
Status = LsapRegEnumerateSubKey(AccountsKeyHandle,
|
||||||
|
EnumIndex,
|
||||||
|
64 * sizeof(WCHAR),
|
||||||
|
AccountKeyName);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
break;
|
||||||
|
|
||||||
|
TRACE("EnumIndex: %lu\n", EnumIndex);
|
||||||
|
TRACE("Account key name: %S\n", AccountKeyName);
|
||||||
|
|
||||||
|
Status = LsapRegOpenKey(AccountsKeyHandle,
|
||||||
|
AccountKeyName,
|
||||||
|
KEY_READ,
|
||||||
|
&AccountKeyHandle);
|
||||||
|
TRACE("LsapRegOpenKey returned %08lX\n", Status);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
Status = LsapRegOpenKey(AccountKeyHandle,
|
||||||
|
L"Sid",
|
||||||
|
KEY_READ,
|
||||||
|
&SidKeyHandle);
|
||||||
|
TRACE("LsapRegOpenKey returned %08lX\n", Status);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DataLength = 0;
|
||||||
|
Status = LsapRegQueryValue(SidKeyHandle,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&DataLength);
|
||||||
|
TRACE("LsapRegQueryValue returned %08lX\n", Status);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
EnumBuffer.Information[i].Sid = midl_user_allocate(DataLength);
|
||||||
|
if (EnumBuffer.Information[i].Sid == NULL)
|
||||||
|
{
|
||||||
|
LsapRegCloseKey(AccountKeyHandle);
|
||||||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = LsapRegQueryValue(SidKeyHandle,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
EnumBuffer.Information[i].Sid,
|
||||||
|
&DataLength);
|
||||||
|
TRACE("SampRegQueryValue returned %08lX\n", Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
LsapRegCloseKey(SidKeyHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
LsapRegCloseKey(AccountKeyHandle);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
*EnumerationContext += EnumCount;
|
||||||
|
EnumerationBuffer->EntriesRead = EnumBuffer.EntriesRead;
|
||||||
|
EnumerationBuffer->Information = EnumBuffer.Information;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
if (EnumBuffer.Information)
|
||||||
|
{
|
||||||
|
for (i = 0; i < EnumBuffer.EntriesRead; i++)
|
||||||
|
{
|
||||||
|
if (EnumBuffer.Information[i].Sid != NULL)
|
||||||
|
midl_user_free(EnumBuffer.Information[i].Sid);
|
||||||
|
}
|
||||||
|
|
||||||
|
midl_user_free(EnumBuffer.Information);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AccountsKeyHandle != NULL)
|
||||||
|
LsapRegCloseKey(AccountsKeyHandle);
|
||||||
|
|
||||||
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -263,6 +263,64 @@ LsarpEnumeratePrivileges(DWORD *EnumerationContext,
|
||||||
PLSAPR_PRIVILEGE_ENUM_BUFFER EnumerationBuffer,
|
PLSAPR_PRIVILEGE_ENUM_BUFFER EnumerationBuffer,
|
||||||
DWORD PreferedMaximumLength);
|
DWORD PreferedMaximumLength);
|
||||||
|
|
||||||
|
/* registry.h */
|
||||||
|
NTSTATUS
|
||||||
|
LsapRegCloseKey(IN HANDLE KeyHandle);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
LsapRegCreateKey(IN HANDLE ParentKeyHandle,
|
||||||
|
IN LPCWSTR KeyName,
|
||||||
|
IN ACCESS_MASK DesiredAccess,
|
||||||
|
OUT HANDLE KeyHandle);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
LsapRegDeleteKey(IN HANDLE ParentKeyHandle,
|
||||||
|
IN LPCWSTR KeyName);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
LsapRegEnumerateSubKey(IN HANDLE KeyHandle,
|
||||||
|
IN ULONG Index,
|
||||||
|
IN ULONG Length,
|
||||||
|
OUT LPWSTR Buffer);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
LsapRegOpenKey(IN HANDLE ParentKeyHandle,
|
||||||
|
IN LPCWSTR KeyName,
|
||||||
|
IN ACCESS_MASK DesiredAccess,
|
||||||
|
OUT HANDLE KeyHandle);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
LsapRegQueryKeyInfo(IN HANDLE KeyHandle,
|
||||||
|
OUT PULONG SubKeyCount,
|
||||||
|
OUT PULONG ValueCount);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
LsapRegDeleteValue(IN HANDLE KeyHandle,
|
||||||
|
IN LPWSTR ValueName);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
LsapRegEnumerateValue(IN HANDLE KeyHandle,
|
||||||
|
IN ULONG Index,
|
||||||
|
OUT LPWSTR Name,
|
||||||
|
IN OUT PULONG NameLength,
|
||||||
|
OUT PULONG Type OPTIONAL,
|
||||||
|
OUT PVOID Data OPTIONAL,
|
||||||
|
IN OUT PULONG DataLength OPTIONAL);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
LsapRegQueryValue(IN HANDLE KeyHandle,
|
||||||
|
IN LPWSTR ValueName,
|
||||||
|
OUT PULONG Type OPTIONAL,
|
||||||
|
OUT LPVOID Data OPTIONAL,
|
||||||
|
IN OUT PULONG DataLength OPTIONAL);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
LsapRegSetValue(IN HANDLE KeyHandle,
|
||||||
|
IN LPWSTR ValueName,
|
||||||
|
IN ULONG Type,
|
||||||
|
IN LPVOID Data,
|
||||||
|
IN ULONG DataLength);
|
||||||
|
|
||||||
/* security.c */
|
/* security.c */
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
LsapCreatePolicySd(PSECURITY_DESCRIPTOR *PolicySd,
|
LsapCreatePolicySd(PSECURITY_DESCRIPTOR *PolicySd,
|
||||||
|
|
411
reactos/dll/win32/lsasrv/registry.c
Normal file
411
reactos/dll/win32/lsasrv/registry.c
Normal file
|
@ -0,0 +1,411 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: Security Account Manager (SAM) Server
|
||||||
|
* FILE: reactos/dll/win32/samsrv/registry.c
|
||||||
|
* PURPOSE: Registry helper functions
|
||||||
|
*
|
||||||
|
* PROGRAMMERS: Eric Kohl
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* INCLUDES ****************************************************************/
|
||||||
|
|
||||||
|
#include "lsasrv.h"
|
||||||
|
|
||||||
|
WINE_DEFAULT_DEBUG_CHANNEL(lsasrv);
|
||||||
|
|
||||||
|
/* FUNCTIONS ***************************************************************/
|
||||||
|
|
||||||
|
static
|
||||||
|
BOOLEAN
|
||||||
|
IsStringType(ULONG Type)
|
||||||
|
{
|
||||||
|
return (Type == REG_SZ) || (Type == REG_EXPAND_SZ) || (Type == REG_MULTI_SZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
LsapRegCloseKey(IN HANDLE KeyHandle)
|
||||||
|
{
|
||||||
|
return NtClose(KeyHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
LsapRegCreateKey(IN HANDLE ParentKeyHandle,
|
||||||
|
IN LPCWSTR KeyName,
|
||||||
|
IN ACCESS_MASK DesiredAccess,
|
||||||
|
OUT HANDLE KeyHandle)
|
||||||
|
{
|
||||||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
UNICODE_STRING Name;
|
||||||
|
ULONG Disposition;
|
||||||
|
|
||||||
|
RtlInitUnicodeString(&Name, KeyName);
|
||||||
|
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes,
|
||||||
|
&Name,
|
||||||
|
OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
|
||||||
|
ParentKeyHandle,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* Create the key */
|
||||||
|
return ZwCreateKey(KeyHandle,
|
||||||
|
DesiredAccess,
|
||||||
|
&ObjectAttributes,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
&Disposition);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
LsapRegDeleteKey(IN HANDLE ParentKeyHandle,
|
||||||
|
IN LPCWSTR KeyName)
|
||||||
|
{
|
||||||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
UNICODE_STRING SubKeyName;
|
||||||
|
HANDLE TargetKey;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
RtlInitUnicodeString(&SubKeyName,
|
||||||
|
(LPWSTR)KeyName);
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes,
|
||||||
|
&SubKeyName,
|
||||||
|
OBJ_CASE_INSENSITIVE,
|
||||||
|
ParentKeyHandle,
|
||||||
|
NULL);
|
||||||
|
Status = NtOpenKey(&TargetKey,
|
||||||
|
DELETE,
|
||||||
|
&ObjectAttributes);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
return Status;
|
||||||
|
|
||||||
|
Status = NtDeleteKey(TargetKey);
|
||||||
|
|
||||||
|
NtClose(TargetKey);
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
LsapRegEnumerateSubKey(IN HANDLE KeyHandle,
|
||||||
|
IN ULONG Index,
|
||||||
|
IN ULONG Length,
|
||||||
|
OUT LPWSTR Buffer)
|
||||||
|
{
|
||||||
|
PKEY_BASIC_INFORMATION KeyInfo = NULL;
|
||||||
|
ULONG BufferLength = 0;
|
||||||
|
ULONG ReturnedLength;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
/* Check if we have a name */
|
||||||
|
if (Length)
|
||||||
|
{
|
||||||
|
/* Allocate a buffer for it */
|
||||||
|
BufferLength = sizeof(KEY_BASIC_INFORMATION) + Length * sizeof(WCHAR);
|
||||||
|
|
||||||
|
KeyInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength);
|
||||||
|
if (KeyInfo == NULL)
|
||||||
|
return STATUS_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enumerate the key */
|
||||||
|
Status = ZwEnumerateKey(KeyHandle,
|
||||||
|
Index,
|
||||||
|
KeyBasicInformation,
|
||||||
|
KeyInfo,
|
||||||
|
BufferLength,
|
||||||
|
&ReturnedLength);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* Check if the name fits */
|
||||||
|
if (KeyInfo->NameLength < (Length * sizeof(WCHAR)))
|
||||||
|
{
|
||||||
|
/* Copy it */
|
||||||
|
RtlMoveMemory(Buffer,
|
||||||
|
KeyInfo->Name,
|
||||||
|
KeyInfo->NameLength);
|
||||||
|
|
||||||
|
/* Terminate the string */
|
||||||
|
Buffer[KeyInfo->NameLength / sizeof(WCHAR)] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Otherwise, we ran out of buffer space */
|
||||||
|
Status = STATUS_BUFFER_OVERFLOW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free the buffer and return status */
|
||||||
|
if (KeyInfo)
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
LsapRegOpenKey(IN HANDLE ParentKeyHandle,
|
||||||
|
IN LPCWSTR KeyName,
|
||||||
|
IN ACCESS_MASK DesiredAccess,
|
||||||
|
OUT HANDLE KeyHandle)
|
||||||
|
{
|
||||||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
UNICODE_STRING Name;
|
||||||
|
|
||||||
|
RtlInitUnicodeString(&Name, KeyName);
|
||||||
|
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes,
|
||||||
|
&Name,
|
||||||
|
OBJ_CASE_INSENSITIVE,
|
||||||
|
ParentKeyHandle,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
return NtOpenKey(KeyHandle,
|
||||||
|
DesiredAccess,
|
||||||
|
&ObjectAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
LsapRegQueryKeyInfo(IN HANDLE KeyHandle,
|
||||||
|
OUT PULONG SubKeyCount,
|
||||||
|
OUT PULONG ValueCount)
|
||||||
|
{
|
||||||
|
KEY_FULL_INFORMATION FullInfoBuffer;
|
||||||
|
ULONG Length;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
FullInfoBuffer.ClassLength = 0;
|
||||||
|
FullInfoBuffer.ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
|
||||||
|
|
||||||
|
Status = NtQueryKey(KeyHandle,
|
||||||
|
KeyFullInformation,
|
||||||
|
&FullInfoBuffer,
|
||||||
|
sizeof(KEY_FULL_INFORMATION),
|
||||||
|
&Length);
|
||||||
|
TRACE("NtQueryKey() returned status 0x%08lX\n", Status);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
return Status;
|
||||||
|
|
||||||
|
if (SubKeyCount != NULL)
|
||||||
|
*SubKeyCount = FullInfoBuffer.SubKeys;
|
||||||
|
|
||||||
|
if (ValueCount != NULL)
|
||||||
|
*ValueCount = FullInfoBuffer.Values;
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
LsapRegDeleteValue(IN HANDLE KeyHandle,
|
||||||
|
IN LPWSTR ValueName)
|
||||||
|
{
|
||||||
|
UNICODE_STRING Name;
|
||||||
|
|
||||||
|
RtlInitUnicodeString(&Name,
|
||||||
|
ValueName);
|
||||||
|
|
||||||
|
return NtDeleteValueKey(KeyHandle,
|
||||||
|
&Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
LsapRegEnumerateValue(IN HANDLE KeyHandle,
|
||||||
|
IN ULONG Index,
|
||||||
|
OUT LPWSTR Name,
|
||||||
|
IN OUT PULONG NameLength,
|
||||||
|
OUT PULONG Type OPTIONAL,
|
||||||
|
OUT PVOID Data OPTIONAL,
|
||||||
|
IN OUT PULONG DataLength OPTIONAL)
|
||||||
|
{
|
||||||
|
PKEY_VALUE_FULL_INFORMATION ValueInfo = NULL;
|
||||||
|
ULONG BufferLength = 0;
|
||||||
|
ULONG ReturnedLength;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
TRACE("Index: %lu\n", Index);
|
||||||
|
|
||||||
|
/* Calculate the required buffer length */
|
||||||
|
BufferLength = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name);
|
||||||
|
BufferLength += (MAX_PATH + 1) * sizeof(WCHAR);
|
||||||
|
if (Data != NULL)
|
||||||
|
BufferLength += *DataLength;
|
||||||
|
|
||||||
|
/* Allocate the value buffer */
|
||||||
|
ValueInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength);
|
||||||
|
if (ValueInfo == NULL)
|
||||||
|
return STATUS_NO_MEMORY;
|
||||||
|
|
||||||
|
/* Enumerate the value*/
|
||||||
|
Status = ZwEnumerateValueKey(KeyHandle,
|
||||||
|
Index,
|
||||||
|
KeyValueFullInformation,
|
||||||
|
ValueInfo,
|
||||||
|
BufferLength,
|
||||||
|
&ReturnedLength);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
if (Name != NULL)
|
||||||
|
{
|
||||||
|
/* Check if the name fits */
|
||||||
|
if (ValueInfo->NameLength < (*NameLength * sizeof(WCHAR)))
|
||||||
|
{
|
||||||
|
/* Copy it */
|
||||||
|
RtlMoveMemory(Name,
|
||||||
|
ValueInfo->Name,
|
||||||
|
ValueInfo->NameLength);
|
||||||
|
|
||||||
|
/* Terminate the string */
|
||||||
|
Name[ValueInfo->NameLength / sizeof(WCHAR)] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Otherwise, we ran out of buffer space */
|
||||||
|
Status = STATUS_BUFFER_OVERFLOW;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Data != NULL)
|
||||||
|
{
|
||||||
|
/* Check if the data fits */
|
||||||
|
if (ValueInfo->DataLength <= *DataLength)
|
||||||
|
{
|
||||||
|
/* Copy it */
|
||||||
|
RtlMoveMemory(Data,
|
||||||
|
(PVOID)((ULONG_PTR)ValueInfo + ValueInfo->DataOffset),
|
||||||
|
ValueInfo->DataLength);
|
||||||
|
|
||||||
|
/* if the type is REG_SZ and data is not 0-terminated
|
||||||
|
* and there is enough space in the buffer NT appends a \0 */
|
||||||
|
if (IsStringType(ValueInfo->Type) &&
|
||||||
|
ValueInfo->DataLength <= *DataLength - sizeof(WCHAR))
|
||||||
|
{
|
||||||
|
WCHAR *ptr = (WCHAR *)((ULONG_PTR)Data + ValueInfo->DataLength);
|
||||||
|
if ((ptr > (WCHAR *)Data) && ptr[-1])
|
||||||
|
*ptr = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Status = STATUS_BUFFER_OVERFLOW;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
|
||||||
|
{
|
||||||
|
if (Type != NULL)
|
||||||
|
*Type = ValueInfo->Type;
|
||||||
|
|
||||||
|
if (NameLength != NULL)
|
||||||
|
*NameLength = ValueInfo->NameLength;
|
||||||
|
|
||||||
|
if (DataLength != NULL)
|
||||||
|
*DataLength = ValueInfo->DataLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free the buffer and return status */
|
||||||
|
if (ValueInfo)
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, ValueInfo);
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
LsapRegQueryValue(IN HANDLE KeyHandle,
|
||||||
|
IN LPWSTR ValueName,
|
||||||
|
OUT PULONG Type OPTIONAL,
|
||||||
|
OUT PVOID Data OPTIONAL,
|
||||||
|
IN OUT PULONG DataLength OPTIONAL)
|
||||||
|
{
|
||||||
|
PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
|
||||||
|
UNICODE_STRING Name;
|
||||||
|
ULONG BufferLength = 0;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
RtlInitUnicodeString(&Name,
|
||||||
|
ValueName);
|
||||||
|
|
||||||
|
if (DataLength != NULL)
|
||||||
|
BufferLength = *DataLength;
|
||||||
|
|
||||||
|
BufferLength += FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
|
||||||
|
|
||||||
|
/* Allocate memory for the value */
|
||||||
|
ValueInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength);
|
||||||
|
if (ValueInfo == NULL)
|
||||||
|
return STATUS_NO_MEMORY;
|
||||||
|
|
||||||
|
/* Query the value */
|
||||||
|
Status = ZwQueryValueKey(KeyHandle,
|
||||||
|
&Name,
|
||||||
|
KeyValuePartialInformation,
|
||||||
|
ValueInfo,
|
||||||
|
BufferLength,
|
||||||
|
&BufferLength);
|
||||||
|
if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
|
||||||
|
{
|
||||||
|
if (Type != NULL)
|
||||||
|
*Type = ValueInfo->Type;
|
||||||
|
|
||||||
|
if (DataLength != NULL)
|
||||||
|
*DataLength = ValueInfo->DataLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the caller wanted data back, and we got it */
|
||||||
|
if ((NT_SUCCESS(Status)) && (Data != NULL))
|
||||||
|
{
|
||||||
|
/* Copy it */
|
||||||
|
RtlMoveMemory(Data,
|
||||||
|
ValueInfo->Data,
|
||||||
|
ValueInfo->DataLength);
|
||||||
|
|
||||||
|
/* if the type is REG_SZ and data is not 0-terminated
|
||||||
|
* and there is enough space in the buffer NT appends a \0 */
|
||||||
|
if (IsStringType(ValueInfo->Type) &&
|
||||||
|
ValueInfo->DataLength <= *DataLength - sizeof(WCHAR))
|
||||||
|
{
|
||||||
|
WCHAR *ptr = (WCHAR *)((ULONG_PTR)Data + ValueInfo->DataLength);
|
||||||
|
if ((ptr > (WCHAR *)Data) && ptr[-1])
|
||||||
|
*ptr = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free the memory and return status */
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, ValueInfo);
|
||||||
|
|
||||||
|
if ((Data == NULL) && (Status == STATUS_BUFFER_OVERFLOW))
|
||||||
|
Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
LsapRegSetValue(HANDLE KeyHandle,
|
||||||
|
LPWSTR ValueName,
|
||||||
|
ULONG Type,
|
||||||
|
LPVOID Data,
|
||||||
|
ULONG DataLength)
|
||||||
|
{
|
||||||
|
UNICODE_STRING Name;
|
||||||
|
|
||||||
|
RtlInitUnicodeString(&Name,
|
||||||
|
ValueName);
|
||||||
|
|
||||||
|
return ZwSetValueKey(KeyHandle,
|
||||||
|
&Name,
|
||||||
|
0,
|
||||||
|
Type,
|
||||||
|
Data,
|
||||||
|
DataLength);
|
||||||
|
}
|
Loading…
Reference in a new issue