[SAMLIB][SAMSRV]

- Implement SamGetMembersInAlias and SamrGetMembersInAlias.
- Add registry helper routines SampRegQueryKeyInfo, SampRegEnumerateValue and SampRegSetValue.
- Remove unused SAM database code.
- Store the name and members key (only for aliases and groups) in the database object.

svn path=/trunk/; revision=56704
This commit is contained in:
Eric Kohl 2012-06-07 10:31:17 +00:00
parent d36d231899
commit c1fd93e9a2
7 changed files with 484 additions and 230 deletions

View file

@ -301,6 +301,48 @@ SamFreeMemory(IN PVOID Buffer)
}
NTSTATUS
NTAPI
SamGetMembersInAlias(IN SAM_HANDLE AliasHandle,
OUT PSID **MemberIds,
OUT PULONG MemberCount)
{
SAMPR_PSID_ARRAY_OUT SidArray;
NTSTATUS Status;
TRACE("SamGetMembersInAlias(%p %p %p)\n",
AliasHandle, MemberIds, MemberCount);
if ((MemberIds == NULL) ||
(MemberCount == NULL))
return STATUS_INVALID_PARAMETER;
*MemberIds = NULL;
*MemberCount = 0;
SidArray.Sids = NULL;
RpcTryExcept
{
Status = SamrGetMembersInAlias((SAMPR_HANDLE)AliasHandle,
&SidArray);
if (NT_SUCCESS(Status))
{
*MemberCount = SidArray.Count;
*MemberIds = (PSID *)(SidArray.Sids);
}
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
Status = I_RpcMapWin32Status(RpcExceptionCode());
}
RpcEndExcept;
return Status;
}
NTSTATUS
NTAPI
SamLookupDomainInSamServer(IN SAM_HANDLE ServerHandle,

View file

@ -23,7 +23,7 @@
@ stub SamGetCompatibilityMode
@ stub SamGetDisplayEnumerationIndex
@ stub SamGetGroupsForUser
@ stub SamGetMembersInAlias
@ stdcall SamGetMembersInAlias(ptr ptr ptr)
@ stub SamGetMembersInGroup
@ stdcall SamLookupDomainInSamServer(ptr ptr ptr)
@ stub SamLookupIdsInDomain

View file

@ -44,210 +44,6 @@ SampOpenSamKey(VOID)
return Status;
}
#if 0
static BOOLEAN
LsapIsDatabaseInstalled(VOID)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName;
HANDLE KeyHandle;
NTSTATUS Status;
RtlInitUnicodeString(&KeyName,
L"Policy");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
SecurityKeyHandle,
NULL);
Status = RtlpNtOpenKey(&KeyHandle,
KEY_READ,
&ObjectAttributes,
0);
if (!NT_SUCCESS(Status))
return FALSE;
NtClose(KeyHandle);
return TRUE;
}
static NTSTATUS
LsapCreateDatabaseKeys(VOID)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName;
HANDLE PolicyKeyHandle = NULL;
HANDLE AccountsKeyHandle = NULL;
HANDLE DomainsKeyHandle = NULL;
HANDLE SecretsKeyHandle = NULL;
NTSTATUS Status = STATUS_SUCCESS;
TRACE("LsapInstallDatabase()\n");
/* Create the 'Policy' key */
RtlInitUnicodeString(&KeyName,
L"Policy");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
SecurityKeyHandle,
NULL);
Status = NtCreateKey(&PolicyKeyHandle,
KEY_ALL_ACCESS,
&ObjectAttributes,
0,
NULL,
0,
NULL);
if (!NT_SUCCESS(Status))
{
ERR("Failed to create the 'Policy' key (Status: 0x%08lx)\n", Status);
goto Done;
}
/* Create the 'Accounts' key */
RtlInitUnicodeString(&KeyName,
L"Accounts");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
PolicyKeyHandle,
NULL);
Status = NtCreateKey(&AccountsKeyHandle,
KEY_ALL_ACCESS,
&ObjectAttributes,
0,
NULL,
0,
NULL);
if (!NT_SUCCESS(Status))
{
ERR("Failed to create the 'Accounts' key (Status: 0x%08lx)\n", Status);
goto Done;
}
/* Create the 'Domains' key */
RtlInitUnicodeString(&KeyName,
L"Domains");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
PolicyKeyHandle,
NULL);
Status = NtCreateKey(&DomainsKeyHandle,
KEY_ALL_ACCESS,
&ObjectAttributes,
0,
NULL,
0,
NULL);
if (!NT_SUCCESS(Status))
{
ERR("Failed to create the 'Domains' key (Status: 0x%08lx)\n", Status);
goto Done;
}
/* Create the 'Secrets' key */
RtlInitUnicodeString(&KeyName,
L"Secrets");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
PolicyKeyHandle,
NULL);
Status = NtCreateKey(&SecretsKeyHandle,
KEY_ALL_ACCESS,
&ObjectAttributes,
0,
NULL,
0,
NULL);
if (!NT_SUCCESS(Status))
{
ERR("Failed to create the 'Secrets' key (Status: 0x%08lx)\n", Status);
goto Done;
}
Done:
if (SecretsKeyHandle != NULL)
NtClose(SecretsKeyHandle);
if (DomainsKeyHandle != NULL)
NtClose(DomainsKeyHandle);
if (AccountsKeyHandle != NULL)
NtClose(AccountsKeyHandle);
if (PolicyKeyHandle != NULL)
NtClose(PolicyKeyHandle);
TRACE("LsapInstallDatabase() done (Status: 0x%08lx)\n", Status);
return Status;
}
static NTSTATUS
LsapCreateDatabaseObjects(VOID)
{
PLSA_DB_OBJECT PolicyObject;
NTSTATUS Status;
/* Open the 'Policy' object */
Status = LsapOpenDbObject(NULL,
L"Policy",
LsaDbPolicyObject,
0,
&PolicyObject);
if (!NT_SUCCESS(Status))
return Status;
LsapSetObjectAttribute(PolicyObject,
L"PolPrDmN",
NULL,
0);
LsapSetObjectAttribute(PolicyObject,
L"PolPrDmS",
NULL,
0);
LsapSetObjectAttribute(PolicyObject,
L"PolAcDmN",
NULL,
0);
LsapSetObjectAttribute(PolicyObject,
L"PolAcDmS",
NULL,
0);
/* Close the 'Policy' object */
LsapCloseDbObject(PolicyObject);
return STATUS_SUCCESS;
}
static NTSTATUS
LsapUpdateDatabase(VOID)
{
return STATUS_SUCCESS;
}
#endif
NTSTATUS
SampInitDatabase(VOID)
@ -310,7 +106,8 @@ SampCreateDbObject(IN PSAM_DB_OBJECT ParentObject,
UNICODE_STRING KeyName;
HANDLE ParentKeyHandle;
HANDLE ContainerKeyHandle = NULL;
HANDLE ObjectKeyHandle;
HANDLE ObjectKeyHandle = NULL;
HANDLE MembersKeyHandle = NULL;
NTSTATUS Status;
if (DbObject == NULL)
@ -359,6 +156,28 @@ SampCreateDbObject(IN PSAM_DB_OBJECT ParentObject,
0,
NULL);
if ((ObjectType == SamDbAliasObject) ||
(ObjectType == SamDbGroupObject))
{
/* Open the object key */
RtlInitUnicodeString(&KeyName,
L"Members");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
ContainerKeyHandle,
NULL);
Status = NtCreateKey(&MembersKeyHandle,
KEY_ALL_ACCESS,
&ObjectAttributes,
0,
NULL,
0,
NULL);
}
NtClose(ContainerKeyHandle);
if (!NT_SUCCESS(Status))
@ -395,15 +214,32 @@ SampCreateDbObject(IN PSAM_DB_OBJECT ParentObject,
sizeof(SAM_DB_OBJECT));
if (NewObject == NULL)
{
if (MembersKeyHandle != NULL)
NtClose(MembersKeyHandle);
NtClose(ObjectKeyHandle);
return STATUS_NO_MEMORY;
}
NewObject->Name = RtlAllocateHeap(RtlGetProcessHeap(),
0,
(wcslen(ObjectName) + 1) * sizeof(WCHAR));
if (NewObject == NULL)
{
if (MembersKeyHandle != NULL)
NtClose(MembersKeyHandle);
NtClose(ObjectKeyHandle);
RtlFreeHeap(RtlGetProcessHeap(), 0, NewObject);
return STATUS_NO_MEMORY;
}
wcscpy(NewObject->Name, ObjectName);
NewObject->Signature = SAMP_DB_SIGNATURE;
NewObject->RefCount = 1;
NewObject->ObjectType = ObjectType;
NewObject->Access = DesiredAccess;
NewObject->KeyHandle = ObjectKeyHandle;
NewObject->MembersKeyHandle = MembersKeyHandle;
NewObject->ParentObject = ParentObject;
if (ParentObject != NULL)
@ -428,7 +264,8 @@ SampOpenDbObject(IN PSAM_DB_OBJECT ParentObject,
UNICODE_STRING KeyName;
HANDLE ParentKeyHandle;
HANDLE ContainerKeyHandle = NULL;
HANDLE ObjectKeyHandle;
HANDLE ObjectKeyHandle = NULL;
HANDLE MembersKeyHandle = NULL;
NTSTATUS Status;
if (DbObject == NULL)
@ -473,6 +310,28 @@ SampOpenDbObject(IN PSAM_DB_OBJECT ParentObject,
KEY_ALL_ACCESS,
&ObjectAttributes);
if ((ObjectType == SamDbAliasObject) ||
(ObjectType == SamDbGroupObject))
{
/* Open the object key */
RtlInitUnicodeString(&KeyName,
L"Members");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
ContainerKeyHandle,
NULL);
Status = NtCreateKey(&MembersKeyHandle,
KEY_ALL_ACCESS,
&ObjectAttributes,
0,
NULL,
0,
NULL);
}
NtClose(ContainerKeyHandle);
if (!NT_SUCCESS(Status))
@ -506,15 +365,31 @@ SampOpenDbObject(IN PSAM_DB_OBJECT ParentObject,
sizeof(SAM_DB_OBJECT));
if (NewObject == NULL)
{
if (MembersKeyHandle != NULL)
NtClose(MembersKeyHandle);
NtClose(ObjectKeyHandle);
return STATUS_NO_MEMORY;
}
NewObject->Name = RtlAllocateHeap(RtlGetProcessHeap(),
0,
(wcslen(ObjectName) + 1) * sizeof(WCHAR));
if (NewObject == NULL)
{
if (MembersKeyHandle != NULL)
NtClose(MembersKeyHandle);
NtClose(ObjectKeyHandle);
RtlFreeHeap(RtlGetProcessHeap(), 0, NewObject);
return STATUS_NO_MEMORY;
}
wcscpy(NewObject->Name, ObjectName);
NewObject->Signature = SAMP_DB_SIGNATURE;
NewObject->RefCount = 1;
NewObject->ObjectType = ObjectType;
NewObject->Access = DesiredAccess;
NewObject->KeyHandle = ObjectKeyHandle;
NewObject->MembersKeyHandle = MembersKeyHandle;
NewObject->ParentObject = ParentObject;
if (ParentObject != NULL)
@ -585,9 +460,15 @@ SampCloseDbObject(PSAM_DB_OBJECT DbObject)
if (DbObject->KeyHandle != NULL)
NtClose(DbObject->KeyHandle);
if (DbObject->MembersKeyHandle != NULL)
NtClose(DbObject->MembersKeyHandle);
if (DbObject->ParentObject != NULL)
ParentObject = DbObject->ParentObject;
if (DbObject->Name != NULL)
RtlFreeHeap(RtlGetProcessHeap(), 0, DbObject->Name);
RtlFreeHeap(RtlGetProcessHeap(), 0, DbObject);
if (ParentObject != NULL)

View file

@ -15,6 +15,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(samsrv);
/* FUNCTIONS ***************************************************************/
static
BOOLEAN
IsStringType(ULONG Type)
{
return (Type == REG_SZ) || (Type == REG_EXPAND_SZ) || (Type == REG_MULTI_SZ);
}
NTSTATUS
SampRegCloseKey(IN HANDLE KeyHandle)
{
@ -132,32 +140,148 @@ SampRegOpenKey(IN HANDLE ParentKeyHandle,
NTSTATUS
SampRegSetValue(HANDLE KeyHandle,
LPWSTR ValueName,
ULONG Type,
LPVOID Data,
ULONG DataLength)
SampRegQueryKeyInfo(IN HANDLE KeyHandle,
OUT PULONG SubKeyCount,
OUT PULONG ValueCount)
{
UNICODE_STRING Name;
KEY_FULL_INFORMATION FullInfoBuffer;
ULONG Length;
NTSTATUS Status;
RtlInitUnicodeString(&Name,
ValueName);
FullInfoBuffer.ClassLength = 0;
FullInfoBuffer.ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
return ZwSetValueKey(KeyHandle,
&Name,
0,
Type,
Data,
DataLength);
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
SampRegQueryValue(HANDLE KeyHandle,
LPWSTR ValueName,
PULONG Type OPTIONAL,
LPVOID Data OPTIONAL,
PULONG DataLength OPTIONAL)
SampRegEnumerateValue(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
SampRegQueryValue(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;
@ -200,6 +324,16 @@ SampRegQueryValue(HANDLE KeyHandle,
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 */
@ -210,3 +344,24 @@ SampRegQueryValue(HANDLE KeyHandle,
return Status;
}
NTSTATUS
SampRegSetValue(HANDLE KeyHandle,
LPWSTR ValueName,
ULONG Type,
LPVOID Data,
ULONG DataLength)
{
UNICODE_STRING Name;
RtlInitUnicodeString(&Name,
ValueName);
return ZwSetValueKey(KeyHandle,
&Name,
0,
Type,
Data,
DataLength);
}

View file

@ -1186,6 +1186,8 @@ SamrAddMemberToAlias(IN SAMPR_HANDLE AliasHandle,
PSAM_DB_OBJECT AliasObject;
LPWSTR MemberIdString = NULL;
HANDLE MembersKeyHandle = NULL;
HANDLE MemberKeyHandle = NULL;
ULONG MemberIdLength;
NTSTATUS Status;
TRACE("SamrAddMemberToAlias(%p %p)\n",
@ -1205,6 +1207,8 @@ SamrAddMemberToAlias(IN SAMPR_HANDLE AliasHandle,
ConvertSidToStringSidW(MemberId, &MemberIdString);
TRACE("Member SID: %S\n", MemberIdString);
MemberIdLength = RtlLengthSid(MemberId);
Status = SampRegCreateKey(AliasObject->KeyHandle,
L"Members",
KEY_WRITE,
@ -1218,10 +1222,39 @@ SamrAddMemberToAlias(IN SAMPR_HANDLE AliasHandle,
Status = SampRegSetValue(MembersKeyHandle,
MemberIdString,
REG_BINARY,
NULL,
0);
MemberId,
MemberIdLength);
if (!NT_SUCCESS(Status))
{
TRACE("SampRegSetValue failed with status 0x%08lx\n", Status);
goto done;
}
Status = SampRegCreateKey(AliasObject->MembersKeyHandle,
MemberIdString,
KEY_WRITE,
&MemberKeyHandle);
if (!NT_SUCCESS(Status))
{
TRACE("SampRegCreateKey failed with status 0x%08lx\n", Status);
goto done;
}
Status = SampRegSetValue(MemberKeyHandle,
AliasObject->Name,
REG_BINARY,
MemberId,
MemberIdLength);
if (!NT_SUCCESS(Status))
{
TRACE("SampRegSetValue failed with status 0x%08lx\n", Status);
goto done;
}
done:
if (MemberKeyHandle != NULL)
SampRegCloseKey(MemberKeyHandle);
if (MembersKeyHandle != NULL)
SampRegCloseKey(MembersKeyHandle);
@ -1247,8 +1280,129 @@ NTAPI
SamrGetMembersInAlias(IN SAMPR_HANDLE AliasHandle,
OUT PSAMPR_PSID_ARRAY_OUT Members)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
PSAM_DB_OBJECT AliasObject;
HANDLE MembersKeyHandle = NULL;
PSAMPR_SID_INFORMATION MemberArray = NULL;
ULONG ValueCount = 0;
ULONG DataLength;
ULONG Index;
NTSTATUS Status;
TRACE("SamrGetMembersInAlias(%p %p %p)\n",
AliasHandle, Members);
/* Validate the alias handle */
Status = SampValidateDbObject(AliasHandle,
SamDbAliasObject,
ALIAS_LIST_MEMBERS,
&AliasObject);
if (!NT_SUCCESS(Status))
{
ERR("failed with status 0x%08lx\n", Status);
return Status;
}
/* Open the members key of the alias objct */
Status = SampRegOpenKey(AliasObject->KeyHandle,
L"Members",
KEY_READ,
&MembersKeyHandle);
if (!NT_SUCCESS(Status))
{
ERR("SampRegOpenKey failed with status 0x%08lx\n", Status);
return Status;
}
/* Get the number of members */
Status = SampRegQueryKeyInfo(MembersKeyHandle,
NULL,
&ValueCount);
if (!NT_SUCCESS(Status))
{
ERR("SampRegQueryKeyInfo failed with status 0x%08lx\n", Status);
goto done;
}
/* Allocate the member array */
MemberArray = midl_user_allocate(ValueCount * sizeof(SAMPR_SID_INFORMATION));
if (MemberArray == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
/* Enumerate the members */
Index = 0;
while (TRUE)
{
/* Get the size of the next SID */
DataLength = 0;
Status = SampRegEnumerateValue(MembersKeyHandle,
Index,
NULL,
NULL,
NULL,
NULL,
&DataLength);
if (!NT_SUCCESS(Status))
{
if (Status == STATUS_NO_MORE_ENTRIES)
Status = STATUS_SUCCESS;
break;
}
/* Allocate a buffer for the SID */
MemberArray[Index].SidPointer = midl_user_allocate(DataLength);
if (MemberArray[Index].SidPointer == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
/* Read the SID into the buffer */
Status = SampRegEnumerateValue(MembersKeyHandle,
Index,
NULL,
NULL,
NULL,
(PVOID)MemberArray[Index].SidPointer,
&DataLength);
if (!NT_SUCCESS(Status))
{
goto done;
}
Index++;
}
/* Return the number of members and the member array */
if (NT_SUCCESS(Status))
{
Members->Count = ValueCount;
Members->Sids = MemberArray;
}
done:
/* Clean up the members array and the SID buffers if something failed */
if (!NT_SUCCESS(Status))
{
if (MemberArray != NULL)
{
for (Index = 0; Index < ValueCount; Index++)
{
if (MemberArray[Index].SidPointer != NULL)
midl_user_free(MemberArray[Index].SidPointer);
}
midl_user_free(MemberArray);
}
}
/* Close the members key */
if (MembersKeyHandle != NULL)
SampRegCloseKey(MembersKeyHandle);
return Status;
}
/* Function 34 */

View file

@ -42,7 +42,9 @@ typedef struct _SAM_DB_OBJECT
SAM_DB_OBJECT_TYPE ObjectType;
ULONG RefCount;
ACCESS_MASK Access;
LPWSTR Name;
HANDLE KeyHandle;
HANDLE MembersKeyHandle; // only used by Aliases and Groups
struct _SAM_DB_OBJECT *ParentObject;
} SAM_DB_OBJECT, *PSAM_DB_OBJECT;
@ -126,6 +128,20 @@ SampRegOpenKey(IN HANDLE ParentKeyHandle,
IN ACCESS_MASK DesiredAccess,
OUT HANDLE KeyHandle);
NTSTATUS
SampRegQueryKeyInfo(IN HANDLE KeyHandle,
OUT PULONG SubKeyCount,
OUT PULONG ValueCount);
NTSTATUS
SampRegEnumerateValue(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
SampRegQueryValue(IN HANDLE KeyHandle,
IN LPWSTR ValueName,

View file

@ -164,6 +164,12 @@ NTSTATUS
NTAPI
SamFreeMemory(IN PVOID Buffer);
NTSTATUS
NTAPI
SamGetMembersInAlias(IN SAM_HANDLE AliasHandle,
OUT PSID **MemberIds,
OUT PULONG MemberCount);
NTSTATUS
NTAPI
SamLookupDomainInSamServer(IN SAM_HANDLE ServerHandle,