mirror of
https://github.com/reactos/reactos.git
synced 2024-12-30 19:14:31 +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
|
||||
policy.c
|
||||
privileges.c
|
||||
registry.c
|
||||
security.c
|
||||
lsasrv.rc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/lsasrv_stubs.c
|
||||
|
|
|
@ -642,8 +642,203 @@ NTSTATUS WINAPI LsarEnumerateAccounts(
|
|||
PLSAPR_ACCOUNT_ENUM_BUFFER EnumerationBuffer,
|
||||
DWORD PreferedMaximumLength)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
LSAPR_ACCOUNT_ENUM_BUFFER EnumBuffer = {0, NULL};
|
||||
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,
|
||||
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 */
|
||||
NTSTATUS
|
||||
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