reactos/dll/win32/lsasrv/database.c

1090 lines
31 KiB
C

/*
* PROJECT: Local Security Authority Server DLL
* LICENSE: GPL - See COPYING in the top level directory
* FILE: dll/win32/lsasrv/database.c
* PURPOSE: LSA object database
* COPYRIGHT: Copyright 2011 Eric Kohl
*/
#include "lsasrv.h"
#include <pseh/pseh2.h>
/* GLOBALS *****************************************************************/
static HANDLE SecurityKeyHandle = NULL;
SID_IDENTIFIER_AUTHORITY NullSidAuthority = {SECURITY_NULL_SID_AUTHORITY};
SID_IDENTIFIER_AUTHORITY WorldSidAuthority = {SECURITY_WORLD_SID_AUTHORITY};
SID_IDENTIFIER_AUTHORITY LocalSidAuthority = {SECURITY_LOCAL_SID_AUTHORITY};
SID_IDENTIFIER_AUTHORITY CreatorSidAuthority = {SECURITY_CREATOR_SID_AUTHORITY};
SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
PSID BuiltinDomainSid = NULL;
PSID AccountDomainSid = NULL;
UNICODE_STRING BuiltinDomainName = {0, 0, NULL};
UNICODE_STRING AccountDomainName = {0, 0, NULL};
/* FUNCTIONS ***************************************************************/
static NTSTATUS
LsapOpenServiceKey(VOID)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName;
NTSTATUS Status;
RtlInitUnicodeString(&KeyName,
L"\\Registry\\Machine\\SECURITY");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = RtlpNtOpenKey(&SecurityKeyHandle,
KEY_READ | KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS,
&ObjectAttributes,
0);
return Status;
}
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
LsapCreateRandomDomainSid(OUT PSID *Sid)
{
LARGE_INTEGER SystemTime;
PULONG Seed;
NtQuerySystemTime(&SystemTime);
Seed = &SystemTime.u.LowPart;
return RtlAllocateAndInitializeSid(&NtAuthority,
4,
SECURITY_NT_NON_UNIQUE,
RtlUniform(Seed),
RtlUniform(Seed),
RtlUniform(Seed),
SECURITY_NULL_RID,
SECURITY_NULL_RID,
SECURITY_NULL_RID,
SECURITY_NULL_RID,
Sid);
}
static NTSTATUS
LsapCreateDatabaseObjects(VOID)
{
PLSAP_POLICY_AUDIT_EVENTS_DATA AuditEventsInfo = NULL;
POLICY_DEFAULT_QUOTA_INFO QuotaInfo;
POLICY_MODIFICATION_INFO ModificationInfo;
POLICY_AUDIT_FULL_QUERY_INFO AuditFullInfo = {FALSE, FALSE};
POLICY_AUDIT_LOG_INFO AuditLogInfo;
GUID DnsDomainGuid;
PLSA_DB_OBJECT PolicyObject = NULL;
PSID AccountDomainSid = NULL;
PSECURITY_DESCRIPTOR PolicySd = NULL;
ULONG PolicySdSize = 0;
ULONG i;
NTSTATUS Status;
/* Initialize the default quota limits */
QuotaInfo.QuotaLimits.PagedPoolLimit = 0x2000000;
QuotaInfo.QuotaLimits.NonPagedPoolLimit = 0x100000;
QuotaInfo.QuotaLimits.MinimumWorkingSetSize = 0x10000;
QuotaInfo.QuotaLimits.MaximumWorkingSetSize = 0xF000000;
QuotaInfo.QuotaLimits.PagefileLimit = 0;
QuotaInfo.QuotaLimits.TimeLimit.QuadPart = 0;
/* Initialize the audit log attribute */
AuditLogInfo.AuditLogPercentFull = 0;
AuditLogInfo.MaximumLogSize = 0; // DWORD
AuditLogInfo.AuditRetentionPeriod.QuadPart = 0; // LARGE_INTEGER
AuditLogInfo.AuditLogFullShutdownInProgress = 0; // BYTE
AuditLogInfo.TimeToShutdown.QuadPart = 0; // LARGE_INTEGER
AuditLogInfo.NextAuditRecordId = 0; // DWORD
/* Initialize the Audit Events attribute */
AuditEventsInfo = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(LSAP_POLICY_AUDIT_EVENTS_DATA));
if (AuditEventsInfo == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
AuditEventsInfo->AuditingMode = FALSE;
AuditEventsInfo->MaximumAuditEventCount = POLICY_AUDIT_EVENT_TYPE_COUNT;
for (i = 0; i < POLICY_AUDIT_EVENT_TYPE_COUNT; i++)
AuditEventsInfo->AuditEvents[i] = 0;
/* Initialize the DNS Domain GUID attribute */
RtlZeroMemory(&DnsDomainGuid, sizeof(DnsDomainGuid));
/* Initialize the modification attribute */
ModificationInfo.ModifiedId.QuadPart = 0;
NtQuerySystemTime(&ModificationInfo.DatabaseCreationTime);
/* Create a random domain SID */
Status = LsapCreateRandomDomainSid(&AccountDomainSid);
if (!NT_SUCCESS(Status))
goto done;
Status = LsapCreatePolicySd(&PolicySd, &PolicySdSize);
if (!NT_SUCCESS(Status))
goto done;
/* Open the 'Policy' object */
Status = LsapOpenDbObject(NULL,
NULL,
L"Policy",
LsaDbPolicyObject,
0,
TRUE,
&PolicyObject);
if (!NT_SUCCESS(Status))
goto done;
/* Set the Primary Domain Name attribute */
LsapSetObjectAttribute(PolicyObject,
L"PolPrDmN",
NULL,
0);
/* Set the Primary Domain SID attribute */
LsapSetObjectAttribute(PolicyObject,
L"PolPrDmS",
NULL,
0);
/* Set the Account Domain Name attribute */
LsapSetObjectAttribute(PolicyObject,
L"PolAcDmN",
NULL,
0);
/* Set the Account Domain SID attribute */
LsapSetObjectAttribute(PolicyObject,
L"PolAcDmS",
AccountDomainSid,
RtlLengthSid(AccountDomainSid));
/* Set the default quota limits attribute */
LsapSetObjectAttribute(PolicyObject,
L"DefQuota",
&QuotaInfo,
sizeof(QuotaInfo));
/* Set the modification attribute */
LsapSetObjectAttribute(PolicyObject,
L"PolMod",
&ModificationInfo,
sizeof(ModificationInfo));
/* Set the audit full attribute */
LsapSetObjectAttribute(PolicyObject,
L"PolAdtFl",
&AuditFullInfo,
sizeof(AuditFullInfo));
/* Set the audit log attribute */
LsapSetObjectAttribute(PolicyObject,
L"PolAdtLg",
&AuditLogInfo,
sizeof(AuditLogInfo));
/* Set the audit events attribute */
LsapSetObjectAttribute(PolicyObject,
L"PolAdtEv",
AuditEventsInfo,
sizeof(*AuditEventsInfo));
/* Set the DNS Domain Name attribute */
LsapSetObjectAttribute(PolicyObject,
L"PolDnDDN",
NULL,
0);
/* Set the DNS Forest Name attribute */
LsapSetObjectAttribute(PolicyObject,
L"PolDnTrN",
NULL,
0);
/* Set the DNS Domain GUID attribute */
LsapSetObjectAttribute(PolicyObject,
L"PolDnDmG",
&DnsDomainGuid,
sizeof(DnsDomainGuid));
/* Set the Security Descriptor */
LsapSetObjectAttribute(PolicyObject,
L"SecDesc",
PolicySd,
PolicySdSize);
done:
if (AuditEventsInfo != NULL)
RtlFreeHeap(RtlGetProcessHeap(), 0, AuditEventsInfo);
if (PolicyObject != NULL)
LsapCloseDbObject(PolicyObject);
if (AccountDomainSid != NULL)
RtlFreeSid(AccountDomainSid);
if (PolicySd != NULL)
RtlFreeHeap(RtlGetProcessHeap(), 0, PolicySd);
return Status;
}
static NTSTATUS
LsapUpdateDatabase(VOID)
{
return STATUS_SUCCESS;
}
static NTSTATUS
LsapGetDomainInfo(VOID)
{
PLSA_DB_OBJECT PolicyObject = NULL;
PUNICODE_STRING DomainName = NULL;
ULONG AttributeSize;
LPWSTR SidString = NULL;
NTSTATUS Status;
/* Get the built-in domain SID and name */
Status = RtlAllocateAndInitializeSid(&NtAuthority,
1,
SECURITY_BUILTIN_DOMAIN_RID,
0, 0, 0, 0, 0, 0, 0,
&BuiltinDomainSid);
if (!NT_SUCCESS(Status))
return Status;
/**/
RtlInitUnicodeString(&BuiltinDomainName,
L"BUILTIN");
/* Open the 'Policy' object */
Status = LsapOpenDbObject(NULL,
NULL,
L"Policy",
LsaDbPolicyObject,
0,
TRUE,
&PolicyObject);
if (!NT_SUCCESS(Status))
goto done;
/* Get the account domain SID */
AttributeSize = 0;
Status = LsapGetObjectAttribute(PolicyObject,
L"PolAcDmS",
NULL,
&AttributeSize);
if (!NT_SUCCESS(Status))
goto done;
if (AttributeSize > 0)
{
AccountDomainSid = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
AttributeSize);
if (AccountDomainSid == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
Status = LsapGetObjectAttribute(PolicyObject,
L"PolAcDmS",
AccountDomainSid,
&AttributeSize);
if (!NT_SUCCESS(Status))
goto done;
}
/* Get the account domain name */
AttributeSize = 0;
Status = LsapGetObjectAttribute(PolicyObject,
L"PolAcDmN",
NULL,
&AttributeSize);
if (!NT_SUCCESS(Status))
goto done;
if (AttributeSize > 0)
{
DomainName = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
AttributeSize);
if (DomainName == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
Status = LsapGetObjectAttribute(PolicyObject,
L"PolAcDmN",
DomainName,
&AttributeSize);
if (!NT_SUCCESS(Status))
goto done;
DomainName->Buffer = (LPWSTR)((ULONG_PTR)DomainName + (ULONG_PTR)DomainName->Buffer);
AccountDomainName.Length = DomainName->Length;
AccountDomainName.MaximumLength = DomainName->Length + sizeof(WCHAR);
AccountDomainName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
AccountDomainName.MaximumLength);
if (AccountDomainName.Buffer == NULL)
{
ERR("Failed to allocate the account domain name buffer\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
RtlCopyMemory(AccountDomainName.Buffer,
DomainName->Buffer,
DomainName->Length);
}
ConvertSidToStringSidW(BuiltinDomainSid, &SidString);
TRACE("Builtin Domain SID: %S\n", SidString);
LocalFree(SidString);
SidString = NULL;
TRACE("Builtin Domain Name: %wZ\n", &BuiltinDomainName);
ConvertSidToStringSidW(AccountDomainSid, &SidString);
TRACE("Account Domain SID: %S\n", SidString);
LocalFree(SidString);
SidString = NULL;
TRACE("Account Domain Name: %wZ\n", &AccountDomainName);
done:
if (DomainName != NULL)
RtlFreeHeap(RtlGetProcessHeap(), 0, DomainName);
if (PolicyObject != NULL)
LsapCloseDbObject(PolicyObject);
return Status;
}
NTSTATUS
LsapInitDatabase(VOID)
{
NTSTATUS Status;
TRACE("LsapInitDatabase()\n");
Status = LsapOpenServiceKey();
if (!NT_SUCCESS(Status))
{
ERR("Failed to open the service key (Status: 0x%08lx)\n", Status);
return Status;
}
if (!LsapIsDatabaseInstalled())
{
Status = LsapCreateDatabaseKeys();
if (!NT_SUCCESS(Status))
{
ERR("Failed to create the LSA database keys (Status: 0x%08lx)\n", Status);
return Status;
}
Status = LsapCreateDatabaseObjects();
if (!NT_SUCCESS(Status))
{
ERR("Failed to create the LSA database objects (Status: 0x%08lx)\n", Status);
return Status;
}
}
else
{
Status = LsapUpdateDatabase();
if (!NT_SUCCESS(Status))
{
ERR("Failed to update the LSA database (Status: 0x%08lx)\n", Status);
return Status;
}
}
Status = LsapGetDomainInfo();
if (!NT_SUCCESS(Status))
{
ERR("Failed to get the domain information (Status: 0x%08lx)\n", Status);
return Status;
}
TRACE("LsapInitDatabase() done\n");
return STATUS_SUCCESS;
}
NTSTATUS
LsapCreateDbObject(IN PLSA_DB_OBJECT ParentObject,
IN LPWSTR ContainerName,
IN LPWSTR ObjectName,
IN LSA_DB_OBJECT_TYPE ObjectType,
IN ACCESS_MASK DesiredAccess,
IN BOOLEAN Trusted,
OUT PLSA_DB_OBJECT *DbObject)
{
PLSA_DB_OBJECT NewObject;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName;
HANDLE ParentKeyHandle;
HANDLE ContainerKeyHandle = NULL;
HANDLE ObjectKeyHandle = NULL;
NTSTATUS Status;
if (DbObject == NULL)
return STATUS_INVALID_PARAMETER;
if (ParentObject == NULL)
ParentKeyHandle = SecurityKeyHandle;
else
ParentKeyHandle = ParentObject->KeyHandle;
if (ContainerName != NULL)
{
/* Open the container key */
RtlInitUnicodeString(&KeyName,
ContainerName);
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
ParentKeyHandle,
NULL);
Status = NtOpenKey(&ContainerKeyHandle,
KEY_ALL_ACCESS,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Open the object key */
RtlInitUnicodeString(&KeyName,
ObjectName);
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
ContainerKeyHandle,
NULL);
Status = NtCreateKey(&ObjectKeyHandle,
KEY_ALL_ACCESS,
&ObjectAttributes,
0,
NULL,
0,
NULL);
NtClose(ContainerKeyHandle);
if (!NT_SUCCESS(Status))
{
return Status;
}
}
else
{
RtlInitUnicodeString(&KeyName,
ObjectName);
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
ParentKeyHandle,
NULL);
Status = NtCreateKey(&ObjectKeyHandle,
KEY_ALL_ACCESS,
&ObjectAttributes,
0,
NULL,
0,
NULL);
if (!NT_SUCCESS(Status))
{
return Status;
}
}
NewObject = RtlAllocateHeap(RtlGetProcessHeap(),
0,
sizeof(LSA_DB_OBJECT));
if (NewObject == NULL)
{
NtClose(ObjectKeyHandle);
return STATUS_NO_MEMORY;
}
NewObject->Signature = LSAP_DB_SIGNATURE;
NewObject->RefCount = 1;
NewObject->ObjectType = ObjectType;
NewObject->Access = DesiredAccess;
NewObject->KeyHandle = ObjectKeyHandle;
NewObject->ParentObject = ParentObject;
NewObject->Trusted = Trusted;
if (ParentObject != NULL)
ParentObject->RefCount++;
*DbObject = NewObject;
return STATUS_SUCCESS;
}
NTSTATUS
LsapOpenDbObject(IN PLSA_DB_OBJECT ParentObject,
IN LPWSTR ContainerName,
IN LPWSTR ObjectName,
IN LSA_DB_OBJECT_TYPE ObjectType,
IN ACCESS_MASK DesiredAccess,
IN BOOLEAN Trusted,
OUT PLSA_DB_OBJECT *DbObject)
{
PLSA_DB_OBJECT NewObject;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName;
HANDLE ParentKeyHandle;
HANDLE ContainerKeyHandle = NULL;
HANDLE ObjectKeyHandle = NULL;
NTSTATUS Status;
if (DbObject == NULL)
return STATUS_INVALID_PARAMETER;
if (ParentObject == NULL)
ParentKeyHandle = SecurityKeyHandle;
else
ParentKeyHandle = ParentObject->KeyHandle;
if (ContainerName != NULL)
{
/* Open the container key */
RtlInitUnicodeString(&KeyName,
ContainerName);
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
ParentKeyHandle,
NULL);
Status = NtOpenKey(&ContainerKeyHandle,
KEY_ALL_ACCESS,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Open the object key */
RtlInitUnicodeString(&KeyName,
ObjectName);
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
ContainerKeyHandle,
NULL);
Status = NtOpenKey(&ObjectKeyHandle,
KEY_ALL_ACCESS,
&ObjectAttributes);
NtClose(ContainerKeyHandle);
if (!NT_SUCCESS(Status))
{
return Status;
}
}
else
{
/* Open the object key */
RtlInitUnicodeString(&KeyName,
ObjectName);
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
ParentKeyHandle,
NULL);
Status = NtOpenKey(&ObjectKeyHandle,
KEY_ALL_ACCESS,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
return Status;
}
}
NewObject = RtlAllocateHeap(RtlGetProcessHeap(),
0,
sizeof(LSA_DB_OBJECT));
if (NewObject == NULL)
{
NtClose(ObjectKeyHandle);
return STATUS_NO_MEMORY;
}
NewObject->Signature = LSAP_DB_SIGNATURE;
NewObject->RefCount = 1;
NewObject->ObjectType = ObjectType;
NewObject->Access = DesiredAccess;
NewObject->KeyHandle = ObjectKeyHandle;
NewObject->ParentObject = ParentObject;
NewObject->Trusted = Trusted;
if (ParentObject != NULL)
ParentObject->RefCount++;
*DbObject = NewObject;
return STATUS_SUCCESS;
}
NTSTATUS
LsapValidateDbObject(LSAPR_HANDLE Handle,
LSA_DB_OBJECT_TYPE ObjectType,
ACCESS_MASK DesiredAccess,
PLSA_DB_OBJECT *DbObject)
{
PLSA_DB_OBJECT LocalObject = (PLSA_DB_OBJECT)Handle;
BOOLEAN bValid = FALSE;
_SEH2_TRY
{
if (LocalObject->Signature == LSAP_DB_SIGNATURE)
{
if ((ObjectType == LsaDbIgnoreObject) ||
(LocalObject->ObjectType == ObjectType))
bValid = TRUE;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
bValid = FALSE;
}
_SEH2_END;
if (bValid == FALSE)
return STATUS_INVALID_HANDLE;
if (DesiredAccess != 0)
{
/* Check for granted access rights */
if ((LocalObject->Access & DesiredAccess) != DesiredAccess)
{
ERR("LsapValidateDbObject access check failed %08lx %08lx\n",
LocalObject->Access, DesiredAccess);
return STATUS_ACCESS_DENIED;
}
}
if (DbObject != NULL)
*DbObject = LocalObject;
return STATUS_SUCCESS;
}
NTSTATUS
LsapCloseDbObject(PLSA_DB_OBJECT DbObject)
{
PLSA_DB_OBJECT ParentObject = NULL;
NTSTATUS Status = STATUS_SUCCESS;
DbObject->RefCount--;
if (DbObject->RefCount > 0)
return STATUS_SUCCESS;
if (DbObject->KeyHandle != NULL)
NtClose(DbObject->KeyHandle);
if (DbObject->ParentObject != NULL)
ParentObject = DbObject->ParentObject;
RtlFreeHeap(RtlGetProcessHeap(), 0, DbObject);
if (ParentObject != NULL)
{
ParentObject->RefCount--;
if (ParentObject->RefCount == 0)
Status = LsapCloseDbObject(ParentObject);
}
return Status;
}
NTSTATUS
LsapDeleteDbObject(IN PLSA_DB_OBJECT DbObject)
{
PLSA_DB_OBJECT ParentObject = NULL;
WCHAR KeyName[64];
ULONG Index;
NTSTATUS Status = STATUS_SUCCESS;
DbObject->RefCount--;
if (DbObject->RefCount > 0)
return STATUS_SUCCESS;
if (DbObject->KeyHandle != NULL)
{
Index = 0;
while (TRUE)
{
Status = LsapRegEnumerateSubKey(DbObject->KeyHandle,
Index,
sizeof(KeyName),
KeyName);
if (!NT_SUCCESS(Status))
break;
TRACE("Index: %lu\n", Index);
TRACE("Key name: %S\n", KeyName);
Status = LsapRegDeleteSubKey(DbObject->KeyHandle,
KeyName);
if (!NT_SUCCESS(Status))
break;
}
if (Status == STATUS_NO_MORE_ENTRIES)
Status = STATUS_SUCCESS;
LsapRegDeleteKey(DbObject->KeyHandle);
NtClose(DbObject->KeyHandle);
}
if (DbObject->ParentObject != NULL)
ParentObject = DbObject->ParentObject;
RtlFreeHeap(RtlGetProcessHeap(), 0, DbObject);
if (ParentObject != NULL)
{
ParentObject->RefCount--;
if (ParentObject->RefCount == 0)
Status = LsapCloseDbObject(ParentObject);
}
return Status;
}
NTSTATUS
LsapSetObjectAttribute(PLSA_DB_OBJECT DbObject,
LPWSTR AttributeName,
LPVOID AttributeData,
ULONG AttributeSize)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName;
HANDLE AttributeKey;
NTSTATUS Status;
RtlInitUnicodeString(&KeyName,
AttributeName);
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
DbObject->KeyHandle,
NULL);
Status = NtCreateKey(&AttributeKey,
KEY_SET_VALUE,
&ObjectAttributes,
0,
NULL,
REG_OPTION_NON_VOLATILE,
NULL);
if (!NT_SUCCESS(Status))
{
ERR("NtCreateKey failed for '%S' with status 0x%lx\n",
AttributeName, Status);
return Status;
}
Status = RtlpNtSetValueKey(AttributeKey,
REG_NONE,
AttributeData,
AttributeSize);
NtClose(AttributeKey);
if (!NT_SUCCESS(Status))
{
ERR("RtlpNtSetValueKey failed for '%S' with status 0x%lx\n",
AttributeName, Status);
}
return Status;
}
NTSTATUS
LsapGetObjectAttribute(PLSA_DB_OBJECT DbObject,
LPWSTR AttributeName,
LPVOID AttributeData,
PULONG AttributeSize)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName;
HANDLE AttributeKey;
ULONG ValueSize;
NTSTATUS Status;
RtlInitUnicodeString(&KeyName,
AttributeName);
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
DbObject->KeyHandle,
NULL);
Status = NtOpenKey(&AttributeKey,
KEY_QUERY_VALUE,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
return Status;
}
ValueSize = *AttributeSize;
Status = RtlpNtQueryValueKey(AttributeKey,
NULL,
NULL,
&ValueSize,
0);
if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
{
goto Done;
}
if (AttributeData == NULL || *AttributeSize == 0)
{
*AttributeSize = ValueSize;
Status = STATUS_SUCCESS;
goto Done;
}
else if (*AttributeSize < ValueSize)
{
*AttributeSize = ValueSize;
Status = STATUS_BUFFER_OVERFLOW;
goto Done;
}
Status = RtlpNtQueryValueKey(AttributeKey,
NULL,
AttributeData,
&ValueSize,
0);
if (NT_SUCCESS(Status))
{
*AttributeSize = ValueSize;
}
Done:
NtClose(AttributeKey);
return Status;
}
NTSTATUS
LsapDeleteObjectAttribute(PLSA_DB_OBJECT DbObject,
LPWSTR AttributeName)
{
return LsapRegDeleteSubKey(DbObject->KeyHandle,
AttributeName);
}
/* EOF */