Author: ekohl
Date: Sat Nov 24 23:19:40 2012
New Revision: 57764
URL:
http://svn.reactos.org/svn/reactos?rev=57764&view=rev
Log:
[LSASRV]
- Add new registry API.
- Implement LsarEnumerateAccounts.
Added:
trunk/reactos/dll/win32/lsasrv/registry.c (with props)
Modified:
trunk/reactos/dll/win32/lsasrv/CMakeLists.txt
trunk/reactos/dll/win32/lsasrv/lsarpc.c
trunk/reactos/dll/win32/lsasrv/lsasrv.h
Modified: trunk/reactos/dll/win32/lsasrv/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/lsasrv/CMakeList…
==============================================================================
--- trunk/reactos/dll/win32/lsasrv/CMakeLists.txt [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/lsasrv/CMakeLists.txt [iso-8859-1] Sat Nov 24 23:19:40 2012
@@ -18,6 +18,7 @@
lsasrv.c
policy.c
privileges.c
+ registry.c
security.c
lsasrv.rc
${CMAKE_CURRENT_BINARY_DIR}/lsasrv_stubs.c
Modified: trunk/reactos/dll/win32/lsasrv/lsarpc.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/lsasrv/lsarpc.c?…
==============================================================================
--- trunk/reactos/dll/win32/lsasrv/lsarpc.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/lsasrv/lsarpc.c [iso-8859-1] Sat Nov 24 23:19:40 2012
@@ -642,8 +642,203 @@
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;
}
Modified: trunk/reactos/dll/win32/lsasrv/lsasrv.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/lsasrv/lsasrv.h?…
==============================================================================
--- trunk/reactos/dll/win32/lsasrv/lsasrv.h [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/lsasrv/lsasrv.h [iso-8859-1] Sat Nov 24 23:19:40 2012
@@ -263,6 +263,64 @@
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,
Added: trunk/reactos/dll/win32/lsasrv/registry.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/lsasrv/registry.…
==============================================================================
--- trunk/reactos/dll/win32/lsasrv/registry.c (added)
+++ trunk/reactos/dll/win32/lsasrv/registry.c [iso-8859-1] Sat Nov 24 23:19:40 2012
@@ -1,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);
+}
Propchange: trunk/reactos/dll/win32/lsasrv/registry.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: trunk/reactos/dll/win32/lsasrv/registry.c
------------------------------------------------------------------------------
svn:keywords = author date id revision