- Add new registry API.
- Implement LsarEnumerateAccounts.

svn path=/trunk/; revision=57764
This commit is contained in:
Eric Kohl 2012-11-24 23:19:40 +00:00
parent fad4fbd259
commit 4864e1b553
4 changed files with 667 additions and 2 deletions

View file

@ -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

View file

@ -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;
}

View file

@ -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,

View 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);
}