[LSASRV]
[reactos.git] / reactos / dll / win32 / lsasrv / database.c
index d58d07b..c74604d 100644 (file)
@@ -17,6 +17,17 @@ WINE_DEFAULT_DEBUG_CHANNEL(lsasrv);
 
 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 ***************************************************************/
 
@@ -76,7 +87,7 @@ LsapIsDatabaseInstalled(VOID)
 
 
 static NTSTATUS
-LsapInstallDatabase(VOID)
+LsapCreateDatabaseKeys(VOID)
 {
     OBJECT_ATTRIBUTES ObjectAttributes;
     UNICODE_STRING KeyName;
@@ -180,7 +191,6 @@ LsapInstallDatabase(VOID)
         goto Done;
     }
 
-
 Done:
     if (SecretsKeyHandle != NULL)
         NtClose(SecretsKeyHandle);
@@ -200,6 +210,335 @@ Done:
 }
 
 
+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 AuditEventsCount;
+    ULONG AuditEventsSize;
+    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 */
+    AuditEventsCount = AuditCategoryAccountLogon - AuditCategorySystem + 1;
+    AuditEventsSize = sizeof(LSAP_POLICY_AUDIT_EVENTS_DATA) + AuditEventsCount * sizeof(DWORD);
+    AuditEventsInfo = RtlAllocateHeap(RtlGetProcessHeap(),
+                                      HEAP_ZERO_MEMORY,
+                                      AuditEventsSize);
+    if (AuditEventsInfo == NULL)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    AuditEventsInfo->AuditingMode = FALSE;
+    AuditEventsInfo->MaximumAuditEventCount = AuditEventsCount;
+    for (i = 0; i < AuditEventsCount; i++)
+        AuditEventsInfo->AuditEvents[i] = 0;
+
+    /* Initialize the DNS Domain GUID attribute */
+    memset(&DnsDomainGuid, 0, sizeof(GUID));
+
+    /* 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;
+
+    LsapSetObjectAttribute(PolicyObject,
+                           L"PolPrDmN",
+                           NULL,
+                           0);
+
+    LsapSetObjectAttribute(PolicyObject,
+                           L"PolPrDmS",
+                           NULL,
+                           0);
+
+    LsapSetObjectAttribute(PolicyObject,
+                           L"PolAcDmN",
+                           NULL,
+                           0);
+
+    LsapSetObjectAttribute(PolicyObject,
+                           L"PolAcDmS",
+                           AccountDomainSid,
+                           RtlLengthSid(AccountDomainSid));
+
+    /* Set the default quota limits attribute */
+    LsapSetObjectAttribute(PolicyObject,
+                           L"DefQuota",
+                           &QuotaInfo,
+                           sizeof(POLICY_DEFAULT_QUOTA_INFO));
+
+    /* Set the modification attribute */
+    LsapSetObjectAttribute(PolicyObject,
+                           L"PolMod",
+                           &ModificationInfo,
+                           sizeof(POLICY_MODIFICATION_INFO));
+
+    /* Set the audit full attribute */
+    LsapSetObjectAttribute(PolicyObject,
+                           L"PolAdtFl",
+                           &AuditFullInfo,
+                           sizeof(POLICY_AUDIT_FULL_QUERY_INFO));
+
+    /* Set the audit log attribute */
+    LsapSetObjectAttribute(PolicyObject,
+                           L"PolAdtLg",
+                           &AuditLogInfo,
+                           sizeof(POLICY_AUDIT_LOG_INFO));
+
+    /* Set the audit events attribute */
+    LsapSetObjectAttribute(PolicyObject,
+                           L"PolAdtEv",
+                           &AuditEventsInfo,
+                           AuditEventsSize);
+
+    /* 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(GUID));
+
+    /* Set the Sceurity 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)
 {
@@ -216,57 +555,124 @@ LsapInitDatabase(VOID)
 
     if (!LsapIsDatabaseInstalled())
     {
-        Status = LsapInstallDatabase();
+        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 install the LSA database (Status: 0x%08lx)\n", 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;
 }
 
 
-LSAPR_HANDLE
-LsapCreateDbObject(LSAPR_HANDLE ParentHandle,
-                   LPWSTR ObjectName,
-                   BOOLEAN Open,
-                   LSA_DB_OBJECT_TYPE ObjectType,
-                   ACCESS_MASK DesiredAccess)
+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 ParentObject = (PLSA_DB_OBJECT)ParentHandle;
-    PLSA_DB_OBJECT DbObject;
+    PLSA_DB_OBJECT NewObject;
     OBJECT_ATTRIBUTES ObjectAttributes;
     UNICODE_STRING KeyName;
     HANDLE ParentKeyHandle;
-    HANDLE ObjectKeyHandle;
+    HANDLE ContainerKeyHandle = NULL;
+    HANDLE ObjectKeyHandle = NULL;
     NTSTATUS Status;
 
-    if (ParentHandle != NULL)
-        ParentKeyHandle = ParentObject->KeyHandle;
-    else
+    if (DbObject == NULL)
+        return STATUS_INVALID_PARAMETER;
+
+    if (ParentObject == NULL)
         ParentKeyHandle = SecurityKeyHandle;
+    else
+        ParentKeyHandle = ParentObject->KeyHandle;
 
-    RtlInitUnicodeString(&KeyName,
-                         ObjectName);
+    if (ContainerName != NULL)
+    {
+        /* Open the container key */
+        RtlInitUnicodeString(&KeyName,
+                             ContainerName);
 
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &KeyName,
-                               OBJ_CASE_INSENSITIVE,
-                               ParentKeyHandle,
-                               NULL);
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   &KeyName,
+                                   OBJ_CASE_INSENSITIVE,
+                                   ParentKeyHandle,
+                                   NULL);
 
-    if (Open == TRUE)
-    {
-        Status = NtOpenKey(&ObjectKeyHandle,
+        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,
@@ -274,50 +680,166 @@ LsapCreateDbObject(LSAPR_HANDLE ParentHandle,
                              NULL,
                              0,
                              NULL);
+        if (!NT_SUCCESS(Status))
+        {
+            return Status;
+        }
     }
 
-    if (!NT_SUCCESS(Status))
+    NewObject = RtlAllocateHeap(RtlGetProcessHeap(),
+                                0,
+                                sizeof(LSA_DB_OBJECT));
+    if (NewObject == NULL)
     {
-        return NULL;
+        NtClose(ObjectKeyHandle);
+        return STATUS_NO_MEMORY;
     }
 
-    DbObject = (PLSA_DB_OBJECT)RtlAllocateHeap(RtlGetProcessHeap(),
-                                               0,
-                                               sizeof(LSA_DB_OBJECT));
+    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 NULL;
+        return STATUS_NO_MEMORY;
     }
 
-    DbObject->Signature = LSAP_DB_SIGNATURE;
-    DbObject->RefCount = 0;
-    DbObject->ObjectType = ObjectType;
-    DbObject->Access = DesiredAccess;
-    DbObject->KeyHandle = ObjectKeyHandle;
-    DbObject->ParentObject = ParentObject;
+    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++;
 
-    return (LSAPR_HANDLE)DbObject;
+    *DbObject = NewObject;
+
+    return STATUS_SUCCESS;
 }
 
 
 NTSTATUS
 LsapValidateDbObject(LSAPR_HANDLE Handle,
                      LSA_DB_OBJECT_TYPE ObjectType,
-                     ACCESS_MASK GrantedAccess)
+                     ACCESS_MASK DesiredAccess,
+                     PLSA_DB_OBJECT *DbObject)
 {
-    PLSA_DB_OBJECT DbObject = (PLSA_DB_OBJECT)Handle;
+    PLSA_DB_OBJECT LocalObject = (PLSA_DB_OBJECT)Handle;
     BOOLEAN bValid = FALSE;
 
     _SEH2_TRY
     {
-        if (DbObject->Signature == LSAP_DB_SIGNATURE)
+        if (LocalObject->Signature == LSAP_DB_SIGNATURE)
         {
             if ((ObjectType == LsaDbIgnoreObject) ||
-                (DbObject->ObjectType == ObjectType))
+                (LocalObject->ObjectType == ObjectType))
                 bValid = TRUE;
         }
     }
@@ -330,32 +852,112 @@ LsapValidateDbObject(LSAPR_HANDLE Handle,
     if (bValid == FALSE)
         return STATUS_INVALID_HANDLE;
 
-    if (GrantedAccess != 0)
+    if (DesiredAccess != 0)
     {
-        /* FIXME: Check for granted access rights */
+        /* 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(LSAPR_HANDLE Handle)
+LsapCloseDbObject(PLSA_DB_OBJECT DbObject)
 {
-    PLSA_DB_OBJECT DbObject = (PLSA_DB_OBJECT)Handle;
+    PLSA_DB_OBJECT ParentObject = NULL;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    DbObject->RefCount--;
 
-    if (DbObject->RefCount != 0)
-        return STATUS_UNSUCCESSFUL;
+    if (DbObject->RefCount > 0)
+        return STATUS_SUCCESS;
+
+    if (DbObject->KeyHandle != NULL)
+        NtClose(DbObject->KeyHandle);
 
     if (DbObject->ParentObject != NULL)
-        DbObject->ParentObject->RefCount--;
+        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,
+                                            64 * sizeof(WCHAR),
+                                            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);
 
-    return STATUS_SUCCESS;
+    if (ParentObject != NULL)
+    {
+        ParentObject->RefCount--;
+
+        if (ParentObject->RefCount == 0)
+            Status = LsapCloseDbObject(ParentObject);
+    }
+
+    return Status;
 }
 
 
@@ -446,13 +1048,13 @@ LsapGetObjectAttribute(PLSA_DB_OBJECT DbObject,
     if (AttributeData == NULL || *AttributeSize == 0)
     {
         *AttributeSize = ValueSize;
-        Status == STATUS_SUCCESS;
+        Status = STATUS_SUCCESS;
         goto Done;
     }
     else if (*AttributeSize < ValueSize)
     {
         *AttributeSize = ValueSize;
-        Status == STATUS_BUFFER_OVERFLOW;
+        Status = STATUS_BUFFER_OVERFLOW;
         goto Done;
     }
 
@@ -472,5 +1074,14 @@ Done:
     return Status;
 }
 
+
+NTSTATUS
+LsapDeleteObjectAttribute(PLSA_DB_OBJECT DbObject,
+                          LPWSTR AttributeName)
+{
+    return LsapRegDeleteSubKey(DbObject->KeyHandle,
+                               AttributeName);
+}
+
 /* EOF */