[LSASRV][IDL] The first parameter of the Credr* functions is a PLSAPR_SERVER_NAME.
[reactos.git] / dll / win32 / lsasrv / lsarpc.c
index 7bb7714..925ca45 100644 (file)
@@ -7,36 +7,54 @@
  * PROGRAMMERS:     Eric Kohl
  */
 
-/* INCLUDES ****************************************************************/
-
 #include "lsasrv.h"
 
+/* GLOBALS *****************************************************************/
 
 static RTL_CRITICAL_SECTION PolicyHandleTableLock;
 
-WINE_DEFAULT_DEBUG_CHANNEL(lsasrv);
-
+static
+GENERIC_MAPPING
+LsapPolicyMapping = {POLICY_READ,
+                     POLICY_WRITE,
+                     POLICY_EXECUTE,
+                     POLICY_ALL_ACCESS};
+
+static
+GENERIC_MAPPING
+LsapAccountMapping = {ACCOUNT_READ,
+                      ACCOUNT_WRITE,
+                      ACCOUNT_EXECUTE,
+                      ACCOUNT_ALL_ACCESS};
+
+static
+GENERIC_MAPPING
+LsapSecretMapping = {SECRET_READ,
+                     SECRET_WRITE,
+                     SECRET_EXECUTE,
+                     SECRET_ALL_ACCESS};
 
 /* FUNCTIONS ***************************************************************/
 
-
-VOID
+NTSTATUS
 LsarStartRpcServer(VOID)
 {
     RPC_STATUS Status;
+    DWORD dwError;
+    HANDLE hEvent;
 
     RtlInitializeCriticalSection(&PolicyHandleTableLock);
 
     TRACE("LsarStartRpcServer() called\n");
 
     Status = RpcServerUseProtseqEpW(L"ncacn_np",
-                                    10,
+                                    RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
                                     L"\\pipe\\lsarpc",
                                     NULL);
     if (Status != RPC_S_OK)
     {
         WARN("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
-        return;
+        return I_RpcMapWin32Status(Status);
     }
 
     Status = RpcServerRegisterIf(lsarpc_v0_0_s_ifspec,
@@ -45,17 +63,51 @@ LsarStartRpcServer(VOID)
     if (Status != RPC_S_OK)
     {
         WARN("RpcServerRegisterIf() failed (Status %lx)\n", Status);
-        return;
+        return I_RpcMapWin32Status(Status);
     }
 
+    DsSetupInit();
+
     Status = RpcServerListen(1, 20, TRUE);
     if (Status != RPC_S_OK)
     {
         WARN("RpcServerListen() failed (Status %lx)\n", Status);
-        return;
+        return I_RpcMapWin32Status(Status);
     }
 
+    /* Notify the service manager */
+    TRACE("Creating notification event!\n");
+    hEvent = CreateEventW(NULL,
+                          TRUE,
+                          FALSE,
+                          L"LSA_RPC_SERVER_ACTIVE");
+    if (hEvent == NULL)
+    {
+        dwError = GetLastError();
+        TRACE("Failed to create or open the notification event (Error %lu)\n", dwError);
+#if 0
+        if (dwError == ERROR_ALREADY_EXISTS)
+        {
+            hEvent = OpenEventW(GENERIC_WRITE,
+                                FALSE,
+                                L"LSA_RPC_SERVER_ACTIVE");
+            if (hEvent == NULL)
+            {
+               ERR("Could not open the notification event (Error %lu)\n", GetLastError());
+               return STATUS_UNSUCCESSFUL;
+            }
+        }
+#endif
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    TRACE("Set notification event!\n");
+    SetEvent(hEvent);
+
+    /* NOTE: Do not close the event handle, as it must remain alive! */
+
     TRACE("LsarStartRpcServer() done\n");
+    return STATUS_SUCCESS;
 }
 
 
@@ -69,18 +121,20 @@ void __RPC_USER LSAPR_HANDLE_rundown(LSAPR_HANDLE hHandle)
 NTSTATUS WINAPI LsarClose(
     LSAPR_HANDLE *ObjectHandle)
 {
+    PLSA_DB_OBJECT DbObject;
     NTSTATUS Status = STATUS_SUCCESS;
 
-    TRACE("0x%p\n", ObjectHandle);
+    TRACE("LsarClose(%p)\n", ObjectHandle);
 
 //    RtlEnterCriticalSection(&PolicyHandleTableLock);
 
     Status = LsapValidateDbObject(*ObjectHandle,
                                   LsaDbIgnoreObject,
-                                  0);
+                                  0,
+                                  &DbObject);
     if (Status == STATUS_SUCCESS)
     {
-        Status = LsapCloseDbObject(*ObjectHandle);
+        Status = LsapCloseDbObject(DbObject);
         *ObjectHandle = NULL;
     }
 
@@ -94,8 +148,9 @@ NTSTATUS WINAPI LsarClose(
 NTSTATUS WINAPI LsarDelete(
     LSAPR_HANDLE ObjectHandle)
 {
-    /* Deprecated */
-    return STATUS_NOT_SUPPORTED;
+    TRACE("LsarDelete(%p)\n", ObjectHandle);
+
+    return LsarDeleteObject(&ObjectHandle);
 }
 
 
@@ -106,8 +161,26 @@ NTSTATUS WINAPI LsarEnumeratePrivileges(
     PLSAPR_PRIVILEGE_ENUM_BUFFER EnumerationBuffer,
     DWORD PreferedMaximumLength)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PLSA_DB_OBJECT PolicyObject;
+    NTSTATUS Status;
+
+    TRACE("LsarEnumeratePrivileges(%p %p %p %lu)\n",
+          PolicyHandle, EnumerationContext, EnumerationBuffer,
+          PreferedMaximumLength);
+
+    Status = LsapValidateDbObject(PolicyHandle,
+                                  LsaDbPolicyObject,
+                                  POLICY_VIEW_LOCAL_INFORMATION,
+                                  &PolicyObject);
+    if (!NT_SUCCESS(Status))
+        return Status;
+
+    if (EnumerationContext == NULL)
+        return STATUS_INVALID_PARAMETER;
+
+    return LsarpEnumeratePrivileges(EnumerationContext,
+                                    EnumerationBuffer,
+                                    PreferedMaximumLength);
 }
 
 
@@ -117,8 +190,120 @@ NTSTATUS WINAPI LsarQuerySecurityObject(
     SECURITY_INFORMATION SecurityInformation,
     PLSAPR_SR_SECURITY_DESCRIPTOR *SecurityDescriptor)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PLSA_DB_OBJECT DbObject = NULL;
+    PSECURITY_DESCRIPTOR RelativeSd = NULL;
+    PSECURITY_DESCRIPTOR ResultSd = NULL;
+    PLSAPR_SR_SECURITY_DESCRIPTOR SdData = NULL;
+    ACCESS_MASK DesiredAccess = 0;
+    ULONG RelativeSdSize = 0;
+    ULONG ResultSdSize = 0;
+    NTSTATUS Status;
+
+    TRACE("LsarQuerySecurityObject(%p %lx %p)\n",
+          ObjectHandle, SecurityInformation, SecurityDescriptor);
+
+    if (SecurityDescriptor == NULL)
+        return STATUS_INVALID_PARAMETER;
+
+    *SecurityDescriptor = NULL;
+
+    if ((SecurityInformation & OWNER_SECURITY_INFORMATION) ||
+        (SecurityInformation & GROUP_SECURITY_INFORMATION) ||
+        (SecurityInformation & DACL_SECURITY_INFORMATION))
+        DesiredAccess |= READ_CONTROL;
+
+    if (SecurityInformation & SACL_SECURITY_INFORMATION)
+        DesiredAccess |= ACCESS_SYSTEM_SECURITY;
+
+    /* Validate the ObjectHandle */
+    Status = LsapValidateDbObject(ObjectHandle,
+                                  LsaDbIgnoreObject,
+                                  DesiredAccess,
+                                  &DbObject);
+    if (!NT_SUCCESS(Status))
+        return Status;
+
+    /* Get the size of the SD */
+    Status = LsapGetObjectAttribute(DbObject,
+                                    L"SecDesc",
+                                    NULL,
+                                    &RelativeSdSize);
+    if (!NT_SUCCESS(Status))
+        return Status;
+
+    /* Allocate a buffer for the SD */
+    RelativeSd = MIDL_user_allocate(RelativeSdSize);
+    if (RelativeSd == NULL)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    /* Get the SD */
+    Status = LsapGetObjectAttribute(DbObject,
+                                    L"SecDesc",
+                                    RelativeSd,
+                                    &RelativeSdSize);
+    if (!NT_SUCCESS(Status))
+        goto done;
+
+    /* Invalidate the SD information that was not requested */
+    if (!(SecurityInformation & OWNER_SECURITY_INFORMATION))
+        ((PISECURITY_DESCRIPTOR)RelativeSd)->Owner = NULL;
+
+    if (!(SecurityInformation & GROUP_SECURITY_INFORMATION))
+        ((PISECURITY_DESCRIPTOR)RelativeSd)->Group = NULL;
+
+    if (!(SecurityInformation & DACL_SECURITY_INFORMATION))
+        ((PISECURITY_DESCRIPTOR)RelativeSd)->Control &= ~SE_DACL_PRESENT;
+
+    if (!(SecurityInformation & SACL_SECURITY_INFORMATION))
+        ((PISECURITY_DESCRIPTOR)RelativeSd)->Control &= ~SE_SACL_PRESENT;
+
+    /* Calculate the required SD size */
+    Status = RtlMakeSelfRelativeSD(RelativeSd,
+                                   NULL,
+                                   &ResultSdSize);
+    if (Status != STATUS_BUFFER_TOO_SMALL)
+        goto done;
+
+    /* Allocate a buffer for the new SD */
+    ResultSd = MIDL_user_allocate(ResultSdSize);
+    if (ResultSd == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto done;
+    }
+
+    /* Build the new SD */
+    Status = RtlMakeSelfRelativeSD(RelativeSd,
+                                   ResultSd,
+                                   &ResultSdSize);
+    if (!NT_SUCCESS(Status))
+        goto done;
+
+    /* Allocate the SD data buffer */
+    SdData = MIDL_user_allocate(sizeof(LSAPR_SR_SECURITY_DESCRIPTOR));
+    if (SdData == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto done;
+    }
+
+    /* Fill the SD data buffer and return it to the caller */
+    SdData->Length = RelativeSdSize;
+    SdData->SecurityDescriptor = (PBYTE)ResultSd;
+
+    *SecurityDescriptor = SdData;
+
+done:
+    if (!NT_SUCCESS(Status))
+    {
+        if (ResultSd != NULL)
+            MIDL_user_free(ResultSd);
+    }
+
+    if (RelativeSd != NULL)
+        MIDL_user_free(RelativeSd);
+
+    return Status;
 }
 
 
@@ -128,8 +313,151 @@ NTSTATUS WINAPI LsarSetSecurityObject(
     SECURITY_INFORMATION SecurityInformation,
     PLSAPR_SR_SECURITY_DESCRIPTOR SecurityDescriptor)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PLSA_DB_OBJECT DbObject = NULL;
+    ACCESS_MASK DesiredAccess = 0;
+    PSECURITY_DESCRIPTOR RelativeSd = NULL;
+    ULONG RelativeSdSize = 0;
+    HANDLE TokenHandle = NULL;
+    PGENERIC_MAPPING Mapping;
+    NTSTATUS Status;
+
+    TRACE("LsarSetSecurityObject(%p %lx %p)\n",
+          ObjectHandle, SecurityInformation, SecurityDescriptor);
+
+    if ((SecurityDescriptor == NULL) ||
+        (SecurityDescriptor->SecurityDescriptor == NULL) ||
+        !RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)SecurityDescriptor->SecurityDescriptor))
+        return ERROR_INVALID_PARAMETER;
+
+    if (SecurityInformation == 0 ||
+        SecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
+        | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))
+        return ERROR_INVALID_PARAMETER;
+
+    if (SecurityInformation & SACL_SECURITY_INFORMATION)
+        DesiredAccess |= ACCESS_SYSTEM_SECURITY;
+
+    if (SecurityInformation & DACL_SECURITY_INFORMATION)
+        DesiredAccess |= WRITE_DAC;
+
+    if (SecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
+        DesiredAccess |= WRITE_OWNER;
+
+    if ((SecurityInformation & OWNER_SECURITY_INFORMATION) &&
+        (((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Owner == NULL))
+        return ERROR_INVALID_PARAMETER;
+
+    if ((SecurityInformation & GROUP_SECURITY_INFORMATION) &&
+        (((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Group == NULL))
+        return ERROR_INVALID_PARAMETER;
+
+    /* Validate the ObjectHandle */
+    Status = LsapValidateDbObject(ObjectHandle,
+                                  LsaDbIgnoreObject,
+                                  DesiredAccess,
+                                  &DbObject);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapValidateDbObject failed (Status 0x%08lx)\n", Status);
+        return Status;
+    }
+
+    /* Get the mapping for the object type */
+    switch (DbObject->ObjectType)
+    {
+        case LsaDbPolicyObject:
+            Mapping = &LsapPolicyMapping;
+            break;
+
+        case LsaDbAccountObject:
+            Mapping = &LsapAccountMapping;
+            break;
+
+//        case LsaDbDomainObject:
+//            Mapping = &LsapDomainMapping;
+//            break;
+
+        case LsaDbSecretObject:
+            Mapping = &LsapSecretMapping;
+            break;
+
+        default:
+            return STATUS_INVALID_HANDLE;
+    }
+
+    /* Get the size of the SD */
+    Status = LsapGetObjectAttribute(DbObject,
+                                    L"SecDesc",
+                                    NULL,
+                                    &RelativeSdSize);
+    if (!NT_SUCCESS(Status))
+        return Status;
+
+    /* Allocate a buffer for the SD */
+    RelativeSd = RtlAllocateHeap(RtlGetProcessHeap(), 0, RelativeSdSize);
+    if (RelativeSd == NULL)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    /* Get the SD */
+    Status = LsapGetObjectAttribute(DbObject,
+                                    L"SecDesc",
+                                    RelativeSd,
+                                    &RelativeSdSize);
+    if (!NT_SUCCESS(Status))
+        goto done;
+
+    /* Get the clients token if we try to set the owner */
+    if (SecurityInformation & OWNER_SECURITY_INFORMATION)
+    {
+        Status = I_RpcMapWin32Status(RpcImpersonateClient(NULL));
+        if (!NT_SUCCESS(Status))
+        {
+            ERR("RpcImpersonateClient returns 0x%08lx\n", Status);
+            goto done;
+        }
+
+        Status = NtOpenThreadToken(NtCurrentThread(),
+                                   TOKEN_QUERY,
+                                   TRUE,
+                                   &TokenHandle);
+        RpcRevertToSelf();
+        if (!NT_SUCCESS(Status))
+        {
+            ERR("NtOpenThreadToken returns 0x%08lx\n", Status);
+            goto done;
+        }
+    }
+
+    /* Build the new security descriptor */
+    Status = RtlSetSecurityObject(SecurityInformation,
+                                  (PSECURITY_DESCRIPTOR)SecurityDescriptor->SecurityDescriptor,
+                                  &RelativeSd,
+                                  Mapping,
+                                  TokenHandle);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("RtlSetSecurityObject failed (Status 0x%08lx)\n", Status);
+        goto done;
+    }
+
+    /* Set the modified SD */
+    Status = LsapSetObjectAttribute(DbObject,
+                                    L"SecDesc",
+                                    RelativeSd,
+                                    RtlLengthSecurityDescriptor(RelativeSd));
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapSetObjectAttribute failed (Status 0x%08lx)\n", Status);
+    }
+
+done:
+    if (TokenHandle != NULL)
+        NtClose(TokenHandle);
+
+    if (RelativeSd != NULL)
+        RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSd);
+
+    return Status;
 }
 
 
@@ -154,22 +482,27 @@ NTSTATUS WINAPI LsarOpenPolicy(
     ACCESS_MASK DesiredAccess,
     LSAPR_HANDLE *PolicyHandle)
 {
-    NTSTATUS Status = STATUS_SUCCESS;
+    PLSA_DB_OBJECT PolicyObject;
+    NTSTATUS Status;
 
-    TRACE("LsarOpenPolicy called!\n");
+    TRACE("LsarOpenPolicy(%S %p %lx %p)\n",
+          SystemName, ObjectAttributes, DesiredAccess, PolicyHandle);
 
     RtlEnterCriticalSection(&PolicyHandleTableLock);
 
-    *PolicyHandle = LsapCreateDbObject(NULL,
-                                       L"Policy",
-                                       TRUE,
-                                       LsaDbPolicyObject,
-                                       DesiredAccess);
-    if (*PolicyHandle == NULL)
-        Status = STATUS_INSUFFICIENT_RESOURCES;
+    Status = LsapOpenDbObject(NULL,
+                              NULL,
+                              L"Policy",
+                              LsaDbPolicyObject,
+                              DesiredAccess,
+                              FALSE,
+                              &PolicyObject);
 
     RtlLeaveCriticalSection(&PolicyHandleTableLock);
 
+    if (NT_SUCCESS(Status))
+        *PolicyHandle = (LSAPR_HANDLE)PolicyObject;
+
     TRACE("LsarOpenPolicy done!\n");
 
     return Status;
@@ -182,6 +515,8 @@ NTSTATUS WINAPI LsarQueryInformationPolicy(
     POLICY_INFORMATION_CLASS InformationClass,
     PLSAPR_POLICY_INFORMATION *PolicyInformation)
 {
+    PLSA_DB_OBJECT PolicyObject;
+    ACCESS_MASK DesiredAccess = 0;
     NTSTATUS Status;
 
     TRACE("LsarQueryInformationPolicy(%p,0x%08x,%p)\n",
@@ -192,46 +527,112 @@ NTSTATUS WINAPI LsarQueryInformationPolicy(
         TRACE("*PolicyInformation %p\n", *PolicyInformation);
     }
 
+    switch (InformationClass)
+    {
+        case PolicyAuditLogInformation:
+        case PolicyAuditEventsInformation:
+        case PolicyAuditFullQueryInformation:
+            DesiredAccess = POLICY_VIEW_AUDIT_INFORMATION;
+            break;
+
+        case PolicyPrimaryDomainInformation:
+        case PolicyAccountDomainInformation:
+        case PolicyLsaServerRoleInformation:
+        case PolicyReplicaSourceInformation:
+        case PolicyDefaultQuotaInformation:
+        case PolicyModificationInformation:
+        case PolicyDnsDomainInformation:
+        case PolicyDnsDomainInformationInt:
+        case PolicyLocalAccountDomainInformation:
+            DesiredAccess = POLICY_VIEW_LOCAL_INFORMATION;
+            break;
+
+        case PolicyPdAccountInformation:
+            DesiredAccess = POLICY_GET_PRIVATE_INFORMATION;
+            break;
+
+        default:
+            ERR("Invalid InformationClass!\n");
+            return STATUS_INVALID_PARAMETER;
+    }
+
     Status = LsapValidateDbObject(PolicyHandle,
                                   LsaDbPolicyObject,
-                                  0); /* FIXME */
+                                  DesiredAccess,
+                                  &PolicyObject);
     if (!NT_SUCCESS(Status))
         return Status;
 
     switch (InformationClass)
     {
+        case PolicyAuditLogInformation:      /* 1 */
+            Status = LsarQueryAuditLog(PolicyObject,
+                                       PolicyInformation);
+            break;
+
         case PolicyAuditEventsInformation:   /* 2 */
-            Status = LsarQueryAuditEvents(PolicyHandle,
+            Status = LsarQueryAuditEvents(PolicyObject,
                                           PolicyInformation);
             break;
 
         case PolicyPrimaryDomainInformation: /* 3 */
-            Status = LsarQueryPrimaryDomain(PolicyHandle,
+            Status = LsarQueryPrimaryDomain(PolicyObject,
                                             PolicyInformation);
             break;
 
+        case PolicyPdAccountInformation:     /* 4 */
+            Status = LsarQueryPdAccount(PolicyObject,
+                                        PolicyInformation);
+            break;
+
         case PolicyAccountDomainInformation: /* 5 */
-            Status = LsarQueryAccountDomain(PolicyHandle,
+            Status = LsarQueryAccountDomain(PolicyObject,
+                                            PolicyInformation);
+            break;
+
+        case PolicyLsaServerRoleInformation: /* 6 */
+            Status = LsarQueryServerRole(PolicyObject,
+                                         PolicyInformation);
+            break;
+
+        case PolicyReplicaSourceInformation: /* 7 */
+            Status = LsarQueryReplicaSource(PolicyObject,
                                             PolicyInformation);
             break;
 
-        case PolicyDnsDomainInformation:     /* 12 (0xc) */
-            Status = LsarQueryDnsDomain(PolicyHandle,
+        case PolicyDefaultQuotaInformation:  /* 8 */
+            Status = LsarQueryDefaultQuota(PolicyObject,
+                                           PolicyInformation);
+            break;
+
+        case PolicyModificationInformation:  /* 9 */
+            Status = LsarQueryModification(PolicyObject,
+                                           PolicyInformation);
+            break;
+
+        case PolicyAuditFullQueryInformation: /* 11 (0xB) */
+            Status = LsarQueryAuditFull(PolicyObject,
                                         PolicyInformation);
             break;
 
-        case PolicyAuditLogInformation:
-        case PolicyPdAccountInformation:
-        case PolicyLsaServerRoleInformation:
-        case PolicyReplicaSourceInformation:
-        case PolicyDefaultQuotaInformation:
-        case PolicyModificationInformation:
-        case PolicyAuditFullSetInformation:
-        case PolicyAuditFullQueryInformation:
-        case PolicyEfsInformation:
-            FIXME("category not implemented\n");
-            Status = STATUS_UNSUCCESSFUL;
+        case PolicyDnsDomainInformation:      /* 12 (0xC) */
+            Status = LsarQueryDnsDomain(PolicyObject,
+                                        PolicyInformation);
+            break;
+
+        case PolicyDnsDomainInformationInt:   /* 13 (0xD) */
+            Status = LsarQueryDnsDomainInt(PolicyObject,
+                                           PolicyInformation);
+            break;
+
+        case PolicyLocalAccountDomainInformation: /* 14 (0xE) */
+            Status = LsarQueryLocalAccountDomain(PolicyObject,
+                                                 PolicyInformation);
             break;
+
+        default:
+            ERR("Invalid InformationClass!\n");
+            Status = STATUS_INVALID_PARAMETER;
     }
 
     return Status;
@@ -244,6 +645,8 @@ NTSTATUS WINAPI LsarSetInformationPolicy(
     POLICY_INFORMATION_CLASS InformationClass,
     PLSAPR_POLICY_INFORMATION PolicyInformation)
 {
+    PLSA_DB_OBJECT PolicyObject;
+    ACCESS_MASK DesiredAccess = 0;
     NTSTATUS Status;
 
     TRACE("LsarSetInformationPolicy(%p,0x%08x,%p)\n",
@@ -254,35 +657,116 @@ NTSTATUS WINAPI LsarSetInformationPolicy(
         TRACE("*PolicyInformation %p\n", *PolicyInformation);
     }
 
+    switch (InformationClass)
+    {
+        case PolicyAuditLogInformation:
+        case PolicyAuditFullSetInformation:
+            DesiredAccess = POLICY_AUDIT_LOG_ADMIN;
+            break;
+
+        case PolicyAuditEventsInformation:
+            DesiredAccess = POLICY_SET_AUDIT_REQUIREMENTS;
+            break;
+
+        case PolicyPrimaryDomainInformation:
+        case PolicyAccountDomainInformation:
+        case PolicyDnsDomainInformation:
+        case PolicyDnsDomainInformationInt:
+        case PolicyLocalAccountDomainInformation:
+            DesiredAccess = POLICY_TRUST_ADMIN;
+            break;
+
+        case PolicyLsaServerRoleInformation:
+        case PolicyReplicaSourceInformation:
+            DesiredAccess = POLICY_SERVER_ADMIN;
+            break;
+
+        case PolicyDefaultQuotaInformation:
+            DesiredAccess = POLICY_SET_DEFAULT_QUOTA_LIMITS;
+            break;
+
+        default:
+            ERR("Invalid InformationClass!\n");
+            return STATUS_INVALID_PARAMETER;
+    }
+
     Status = LsapValidateDbObject(PolicyHandle,
                                   LsaDbPolicyObject,
-                                  0); /* FIXME */
+                                  DesiredAccess,
+                                  &PolicyObject);
     if (!NT_SUCCESS(Status))
         return Status;
 
     switch (InformationClass)
     {
-        case PolicyAuditEventsInformation:
-            Status = STATUS_NOT_IMPLEMENTED;
+        case PolicyAuditLogInformation:      /* 1 */
+            Status = LsarSetAuditLog(PolicyObject,
+                                     (PPOLICY_AUDIT_LOG_INFO)PolicyInformation);
             break;
 
-        case PolicyPrimaryDomainInformation:
-            Status = LsarSetPrimaryDomain(PolicyHandle,
+        case PolicyAuditEventsInformation:   /* 2 */
+            Status = LsarSetAuditEvents(PolicyObject,
+                                        (PLSAPR_POLICY_AUDIT_EVENTS_INFO)PolicyInformation);
+            if (NT_SUCCESS(Status))
+                LsapNotifyPolicyChange(PolicyNotifyAuditEventsInformation);
+            break;
+
+        case PolicyPrimaryDomainInformation: /* 3 */
+            Status = LsarSetPrimaryDomain(PolicyObject,
                                           (PLSAPR_POLICY_PRIMARY_DOM_INFO)PolicyInformation);
+            if (NT_SUCCESS(Status))
+                LsapNotifyPolicyChange(PolicyNotifyDnsDomainInformation);
             break;
 
-        case PolicyAccountDomainInformation:
-            Status = LsarSetAccountDomain(PolicyHandle,
+        case PolicyAccountDomainInformation: /* 5 */
+            Status = LsarSetAccountDomain(PolicyObject,
                                           (PLSAPR_POLICY_ACCOUNT_DOM_INFO)PolicyInformation);
+            if (NT_SUCCESS(Status))
+                LsapNotifyPolicyChange(PolicyNotifyAccountDomainInformation);
             break;
 
-        case PolicyDnsDomainInformation:
-            Status = LsarSetDnsDomain(PolicyHandle,
+        case PolicyLsaServerRoleInformation: /* 6 */
+            Status = LsarSetServerRole(PolicyObject,
+                                       (PPOLICY_LSA_SERVER_ROLE_INFO)PolicyInformation);
+            if (NT_SUCCESS(Status))
+                LsapNotifyPolicyChange(PolicyNotifyServerRoleInformation);
+            break;
+
+        case PolicyReplicaSourceInformation: /* 7 */
+            Status = LsarSetReplicaSource(PolicyObject,
+                                          (PPOLICY_LSA_REPLICA_SRCE_INFO)PolicyInformation);
+            break;
+
+        case PolicyDefaultQuotaInformation:  /* 8 */
+            Status = LsarSetDefaultQuota(PolicyObject,
+                                         (PPOLICY_DEFAULT_QUOTA_INFO)PolicyInformation);
+            break;
+
+        case PolicyModificationInformation:  /* 9 */
+            Status = LsarSetModification(PolicyObject,
+                                         (PPOLICY_MODIFICATION_INFO)PolicyInformation);
+            break;
+
+        case PolicyAuditFullSetInformation:  /* 10 (0xA) */
+            Status = LsarSetAuditFull(PolicyObject,
+                                      (PPOLICY_AUDIT_FULL_QUERY_INFO)PolicyInformation);
+            break;
+
+        case PolicyDnsDomainInformation:      /* 12 (0xC) */
+            Status = LsarSetDnsDomain(PolicyObject,
                                       (PLSAPR_POLICY_DNS_DOMAIN_INFO)PolicyInformation);
+            if (NT_SUCCESS(Status))
+                LsapNotifyPolicyChange(PolicyNotifyDnsDomainInformation);
             break;
 
-        case PolicyLsaServerRoleInformation:
-            Status = STATUS_NOT_IMPLEMENTED;
+        case PolicyDnsDomainInformationInt:   /* 13 (0xD) */
+            Status = LsarSetDnsDomainInt(PolicyObject,
+                                         (PLSAPR_POLICY_DNS_DOMAIN_INFO)PolicyInformation);
+            break;
+
+        case PolicyLocalAccountDomainInformation: /* 14 (0xE) */
+            Status = LsarSetLocalAccountDomain(PolicyObject,
+                                               (PLSAPR_POLICY_ACCOUNT_DOM_INFO)PolicyInformation);
             break;
 
         default:
@@ -303,51 +787,368 @@ NTSTATUS WINAPI LsarClearAuditLog(
 }
 
 
-/* Function 10 */
-NTSTATUS WINAPI LsarCreateAccount(
-    LSAPR_HANDLE PolicyHandle,
+NTSTATUS
+LsarpCreateAccount(
+    PLSA_DB_OBJECT PolicyObject,
     PRPC_SID AccountSid,
     ACCESS_MASK DesiredAccess,
-    LSAPR_HANDLE *AccountHandle)
+    PLSA_DB_OBJECT *AccountObject)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
+    LPWSTR SidString = NULL;
+    PSECURITY_DESCRIPTOR AccountSd = NULL;
+    ULONG AccountSdSize;
+    NTSTATUS Status = STATUS_SUCCESS;
 
+    /* Create SID string */
+    if (!ConvertSidToStringSid((PSID)AccountSid,
+                               &SidString))
+    {
+        ERR("ConvertSidToStringSid failed\n");
+        return STATUS_INVALID_PARAMETER;
+    }
 
-/* Function 11 */
-NTSTATUS WINAPI LsarEnumerateAccounts(
-    LSAPR_HANDLE PolicyHandle,
-    DWORD *EnumerationContext,
-    PLSAPR_ACCOUNT_ENUM_BUFFER EnumerationBuffer,
-    DWORD PreferedMaximumLength)
-{
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
+    /* Create a security descriptor for the account */
+    Status = LsapCreateAccountSd(&AccountSd,
+                                 &AccountSdSize);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapCreateAccountSd returned 0x%08lx\n", Status);
+        goto done;
+    }
 
+    /* Create the Account object */
+    Status = LsapCreateDbObject(PolicyObject,
+                                L"Accounts",
+                                SidString,
+                                LsaDbAccountObject,
+                                DesiredAccess,
+                                PolicyObject->Trusted,
+                                AccountObject);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapCreateDbObject failed (Status 0x%08lx)\n", Status);
+        goto done;
+    }
 
-/* Function 12 */
-NTSTATUS WINAPI LsarCreateTrustedDomain(
-    LSAPR_HANDLE PolicyHandle,
-    PLSAPR_TRUST_INFORMATION TrustedDomainInformation,
-    ACCESS_MASK DesiredAccess,
-    LSAPR_HANDLE *TrustedDomainHandle)
-{
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
+    /* Set the Sid attribute */
+    Status = LsapSetObjectAttribute(*AccountObject,
+                                    L"Sid",
+                                    (PVOID)AccountSid,
+                                    GetLengthSid(AccountSid));
+    if (!NT_SUCCESS(Status))
+        goto done;
 
+    /* Set the SecDesc attribute */
+    Status = LsapSetObjectAttribute(*AccountObject,
+                                    L"SecDesc",
+                                    AccountSd,
+                                    AccountSdSize);
 
-/* Function 13 */
+done:
+    if (SidString != NULL)
+        LocalFree(SidString);
+
+    if (AccountSd != NULL)
+        RtlFreeHeap(RtlGetProcessHeap(), 0, AccountSd);
+
+    return Status;
+}
+
+
+/* Function 10 */
+NTSTATUS WINAPI LsarCreateAccount(
+    LSAPR_HANDLE PolicyHandle,
+    PRPC_SID AccountSid,
+    ACCESS_MASK DesiredAccess,
+    LSAPR_HANDLE *AccountHandle)
+{
+    PLSA_DB_OBJECT PolicyObject;
+    PLSA_DB_OBJECT AccountObject = NULL;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    TRACE("LsarCreateAccount(%p %p %lx %p)\n",
+          PolicyHandle, AccountSid, DesiredAccess, AccountHandle);
+
+    /* Validate the AccountSid */
+    if (!RtlValidSid(AccountSid))
+        return STATUS_INVALID_PARAMETER;
+
+    /* Validate the PolicyHandle */
+    Status = LsapValidateDbObject(PolicyHandle,
+                                  LsaDbPolicyObject,
+                                  POLICY_CREATE_ACCOUNT,
+                                  &PolicyObject);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapValidateDbObject returned 0x%08lx\n", Status);
+        return Status;
+    }
+
+
+    Status = LsarpCreateAccount(PolicyObject,
+                                AccountSid,
+                                DesiredAccess,
+                                &AccountObject);
+    if (NT_SUCCESS(Status))
+    {
+        *AccountHandle = (LSAPR_HANDLE)AccountObject;
+    }
+
+    return Status;
+}
+
+
+/* Function 11 */
+NTSTATUS WINAPI LsarEnumerateAccounts(
+    LSAPR_HANDLE PolicyHandle,
+    DWORD *EnumerationContext,
+    PLSAPR_ACCOUNT_ENUM_BUFFER EnumerationBuffer,
+    DWORD PreferedMaximumLength)
+{
+    LSAPR_ACCOUNT_ENUM_BUFFER EnumBuffer = {0, NULL};
+    PLSA_DB_OBJECT PolicyObject = NULL;
+    PWSTR AccountKeyBuffer = NULL;
+    HANDLE AccountsKeyHandle = NULL;
+    HANDLE AccountKeyHandle;
+    HANDLE SidKeyHandle;
+    ULONG AccountKeyBufferSize;
+    ULONG EnumIndex;
+    ULONG EnumCount;
+    ULONG RequiredLength;
+    ULONG DataLength;
+    ULONG i;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    TRACE("LsarEnumerateAccount(%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;
+
+    Status = LsapRegQueryKeyInfo(AccountsKeyHandle,
+                                 NULL,
+                                 &AccountKeyBufferSize,
+                                 NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapRegQueryKeyInfo returned 0x%08lx\n", Status);
+        return Status;
+    }
+
+    AccountKeyBufferSize += sizeof(WCHAR);
+    AccountKeyBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, AccountKeyBufferSize);
+    if (AccountKeyBuffer == NULL)
+    {
+        return STATUS_NO_MEMORY;
+    }
+
+    EnumIndex = *EnumerationContext;
+    EnumCount = 0;
+    RequiredLength = 0;
+
+    while (TRUE)
+    {
+        Status = LsapRegEnumerateSubKey(AccountsKeyHandle,
+                                        EnumIndex,
+                                        AccountKeyBufferSize,
+                                        AccountKeyBuffer);
+        if (!NT_SUCCESS(Status))
+            break;
+
+        TRACE("EnumIndex: %lu\n", EnumIndex);
+        TRACE("Account key name: %S\n", AccountKeyBuffer);
+
+        Status = LsapRegOpenKey(AccountsKeyHandle,
+                                AccountKeyBuffer,
+                                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,
+                                        AccountKeyBufferSize,
+                                        AccountKeyBuffer);
+        if (!NT_SUCCESS(Status))
+            break;
+
+        TRACE("EnumIndex: %lu\n", EnumIndex);
+        TRACE("Account key name: %S\n", AccountKeyBuffer);
+
+        Status = LsapRegOpenKey(AccountsKeyHandle,
+                                AccountKeyBuffer,
+                                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 (AccountKeyBuffer != NULL)
+        RtlFreeHeap(RtlGetProcessHeap(), 0, AccountKeyBuffer);
+
+    if (AccountsKeyHandle != NULL)
+        LsapRegCloseKey(AccountsKeyHandle);
+
+    return Status;
+}
+
+
+/* Function 12 */
+NTSTATUS WINAPI LsarCreateTrustedDomain(
+    LSAPR_HANDLE PolicyHandle,
+    PLSAPR_TRUST_INFORMATION TrustedDomainInformation,
+    ACCESS_MASK DesiredAccess,
+    LSAPR_HANDLE *TrustedDomainHandle)
+{
+    /* FIXME: We are not running an AD yet */
+    return STATUS_DIRECTORY_SERVICE_REQUIRED;
+}
+
+
+/* Function 13 */
 NTSTATUS WINAPI LsarEnumerateTrustedDomains(
     LSAPR_HANDLE PolicyHandle,
     DWORD *EnumerationContext,
     PLSAPR_TRUSTED_ENUM_BUFFER EnumerationBuffer,
     DWORD PreferedMaximumLength)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    /* FIXME: We are not running an AD yet */
+    EnumerationBuffer->EntriesRead = 0;
+    EnumerationBuffer->Information = NULL;
+    return STATUS_NO_MORE_ENTRIES;
 }
 
 
@@ -361,89 +1162,53 @@ NTSTATUS WINAPI LsarLookupNames(
     LSAP_LOOKUP_LEVEL LookupLevel,
     DWORD *MappedCount)
 {
-    SID_IDENTIFIER_AUTHORITY IdentifierAuthority = {SECURITY_NT_AUTHORITY};
-    static const UNICODE_STRING DomainName = RTL_CONSTANT_STRING(L"DOMAIN");
-    PLSAPR_REFERENCED_DOMAIN_LIST OutputDomains = NULL;
-    PLSA_TRANSLATED_SID OutputSids = NULL;
-    ULONG OutputSidsLength;
+    LSAPR_TRANSLATED_SIDS_EX2 TranslatedSidsEx2;
     ULONG i;
-    PSID Sid;
-    ULONG SidLength;
     NTSTATUS Status;
 
-    TRACE("LsarLookupNames(%p, %lu, %p, %p, %p, %d, %p)\n",
+    TRACE("LsarLookupNames(%p %lu %p %p %p %d %p)\n",
           PolicyHandle, Count, Names, ReferencedDomains, TranslatedSids,
           LookupLevel, MappedCount);
 
-    TranslatedSids->Entries = Count;
+    TranslatedSids->Entries = 0;
     TranslatedSids->Sids = NULL;
     *ReferencedDomains = NULL;
 
-    OutputSidsLength = Count * sizeof(LSA_TRANSLATED_SID);
-    OutputSids = MIDL_user_allocate(OutputSidsLength);
-    if (OutputSids == NULL)
-    {
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    RtlZeroMemory(OutputSids, OutputSidsLength);
-
-    OutputDomains = MIDL_user_allocate(sizeof(LSAPR_REFERENCED_DOMAIN_LIST));
-    if (OutputDomains == NULL)
-    {
-        MIDL_user_free(OutputSids);
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    OutputDomains->Entries = Count;
-    OutputDomains->Domains = MIDL_user_allocate(Count * sizeof(LSA_TRUST_INFORMATION));
-    if (OutputDomains->Domains == NULL)
-    {
-        MIDL_user_free(OutputDomains);
-        MIDL_user_free(OutputSids);
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
+    if (Count == 0)
+        return STATUS_NONE_MAPPED;
 
-    Status = RtlAllocateAndInitializeSid(&IdentifierAuthority,
-                                         2,
-                                         SECURITY_BUILTIN_DOMAIN_RID,
-                                         DOMAIN_ALIAS_RID_ADMINS,
-                                         0, 0, 0, 0, 0, 0,
-                                         &Sid);
+    TranslatedSidsEx2.Entries = 0;
+    TranslatedSidsEx2.Sids = NULL;
+
+    Status = LsapLookupNames(Count,
+                             Names,
+                             ReferencedDomains,
+                             &TranslatedSidsEx2,
+                             LookupLevel,
+                             MappedCount,
+                             0,
+                             0);
     if (!NT_SUCCESS(Status))
-    {
-        MIDL_user_free(OutputDomains->Domains);
-        MIDL_user_free(OutputDomains);
-        MIDL_user_free(OutputSids);
         return Status;
-    }
-
-    SidLength = RtlLengthSid(Sid);
 
-    for (i = 0; i < Count; i++)
+    TranslatedSids->Entries = TranslatedSidsEx2.Entries;
+    TranslatedSids->Sids = MIDL_user_allocate(TranslatedSids->Entries * sizeof(LSA_TRANSLATED_SID));
+    if (TranslatedSids->Sids == NULL)
     {
-        OutputDomains->Domains[i].Sid = MIDL_user_allocate(SidLength);
-        RtlCopyMemory(OutputDomains->Domains[i].Sid, Sid, SidLength);
-
-        OutputDomains->Domains[i].Name.Buffer = MIDL_user_allocate(DomainName.MaximumLength);
-        OutputDomains->Domains[i].Name.Length = DomainName.Length;
-        OutputDomains->Domains[i].Name.MaximumLength = DomainName.MaximumLength;
-        RtlCopyMemory(OutputDomains->Domains[i].Name.Buffer, DomainName.Buffer, DomainName.MaximumLength);
+        MIDL_user_free(TranslatedSidsEx2.Sids);
+        MIDL_user_free(*ReferencedDomains);
+        *ReferencedDomains = NULL;
+        return STATUS_INSUFFICIENT_RESOURCES;
     }
 
-    for (i = 0; i < Count; i++)
+    for (i = 0; i < TranslatedSidsEx2.Entries; i++)
     {
-        OutputSids[i].Use = SidTypeWellKnownGroup;
-        OutputSids[i].RelativeId = DOMAIN_USER_RID_ADMIN; //DOMAIN_ALIAS_RID_ADMINS;
-        OutputSids[i].DomainIndex = i;
+        TranslatedSids->Sids[i].Use = TranslatedSidsEx2.Sids[i].Use;
+        TranslatedSids->Sids[i].RelativeId = LsapGetRelativeIdFromSid(TranslatedSidsEx2.Sids[i].Sid);
+        TranslatedSids->Sids[i].DomainIndex = TranslatedSidsEx2.Sids[i].DomainIndex;
     }
 
-    *ReferencedDomains = OutputDomains;
-
-    *MappedCount = Count;
-
-    TranslatedSids->Entries = Count;
-    TranslatedSids->Sids = OutputSids;
+    MIDL_user_free(TranslatedSidsEx2.Sids);
 
     return STATUS_SUCCESS;
 }
@@ -458,99 +1223,199 @@ NTSTATUS WINAPI LsarLookupSids(
     LSAP_LOOKUP_LEVEL LookupLevel,
     DWORD *MappedCount)
 {
-    SID_IDENTIFIER_AUTHORITY IdentifierAuthority = {SECURITY_NT_AUTHORITY};
-    static const UNICODE_STRING DomainName = RTL_CONSTANT_STRING(L"DOMAIN");
-    PLSAPR_REFERENCED_DOMAIN_LIST OutputDomains = NULL;
-    PLSAPR_TRANSLATED_NAME OutputNames = NULL;
-    ULONG OutputNamesLength;
+    LSAPR_TRANSLATED_NAMES_EX TranslatedNamesEx;
     ULONG i;
-    PSID Sid;
-    ULONG SidLength;
     NTSTATUS Status;
 
-    TRACE("LsarLookupSids(%p, %p, %p, %p, %d, %p)\n",
+    TRACE("LsarLookupSids(%p %p %p %p %d %p)\n",
           PolicyHandle, SidEnumBuffer, ReferencedDomains, TranslatedNames,
           LookupLevel, MappedCount);
 
+    /* FIXME: Fail, if there is an invalid SID in the SidEnumBuffer */
+
     TranslatedNames->Entries = SidEnumBuffer->Entries;
     TranslatedNames->Names = NULL;
     *ReferencedDomains = NULL;
 
-    OutputNamesLength = SidEnumBuffer->Entries * sizeof(LSA_TRANSLATED_NAME);
-    OutputNames = MIDL_user_allocate(OutputNamesLength);
-    if (OutputNames == NULL)
+    TranslatedNamesEx.Entries = SidEnumBuffer->Entries;
+    TranslatedNamesEx.Names = NULL;
+
+    Status = LsapLookupSids(SidEnumBuffer,
+                            ReferencedDomains,
+                            &TranslatedNamesEx,
+                            LookupLevel,
+                            MappedCount,
+                            0,
+                            0);
+    if (!NT_SUCCESS(Status))
+        return Status;
+
+    TranslatedNames->Entries = SidEnumBuffer->Entries;
+    TranslatedNames->Names = MIDL_user_allocate(SidEnumBuffer->Entries * sizeof(LSAPR_TRANSLATED_NAME));
+    if (TranslatedNames->Names == NULL)
     {
+        MIDL_user_free(TranslatedNamesEx.Names);
+        MIDL_user_free(*ReferencedDomains);
+        *ReferencedDomains = NULL;
         return STATUS_INSUFFICIENT_RESOURCES;
     }
 
-    RtlZeroMemory(OutputNames, OutputNamesLength);
+    for (i = 0; i < TranslatedNamesEx.Entries; i++)
+    {
+        TranslatedNames->Names[i].Use = TranslatedNamesEx.Names[i].Use;
+        TranslatedNames->Names[i].Name.Length = TranslatedNamesEx.Names[i].Name.Length;
+        TranslatedNames->Names[i].Name.MaximumLength = TranslatedNamesEx.Names[i].Name.MaximumLength;
+        TranslatedNames->Names[i].Name.Buffer = TranslatedNamesEx.Names[i].Name.Buffer;
+        TranslatedNames->Names[i].DomainIndex = TranslatedNamesEx.Names[i].DomainIndex;
+    }
+
+    MIDL_user_free(TranslatedNamesEx.Names);
+
+    return Status;
+}
+
+
+/* Function 16 */
+NTSTATUS WINAPI LsarCreateSecret(
+    LSAPR_HANDLE PolicyHandle,
+    PRPC_UNICODE_STRING SecretName,
+    ACCESS_MASK DesiredAccess,
+    LSAPR_HANDLE *SecretHandle)
+{
+    PLSA_DB_OBJECT PolicyObject;
+    PLSA_DB_OBJECT SecretObject = NULL;
+    LARGE_INTEGER Time;
+    PSECURITY_DESCRIPTOR SecretSd = NULL;
+    ULONG SecretSdSize;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    TRACE("LsarCreateSecret(%p %wZ %lx %p)\n",
+          PolicyHandle, SecretName, DesiredAccess, SecretHandle);
 
-    OutputDomains = MIDL_user_allocate(sizeof(LSAPR_REFERENCED_DOMAIN_LIST));
-    if (OutputDomains == NULL)
+    /* Validate the PolicyHandle */
+    Status = LsapValidateDbObject(PolicyHandle,
+                                  LsaDbPolicyObject,
+                                  POLICY_CREATE_SECRET,
+                                  &PolicyObject);
+    if (!NT_SUCCESS(Status))
     {
-        MIDL_user_free(OutputNames);
-        return STATUS_INSUFFICIENT_RESOURCES;
+        ERR("LsapValidateDbObject returned 0x%08lx\n", Status);
+        return Status;
     }
 
-    OutputDomains->Entries = SidEnumBuffer->Entries;
-    OutputDomains->Domains = MIDL_user_allocate(SidEnumBuffer->Entries * sizeof(LSA_TRUST_INFORMATION));
-    if (OutputDomains->Domains == NULL)
+    /* Get the current time */
+    Status = NtQuerySystemTime(&Time);
+    if (!NT_SUCCESS(Status))
     {
-        MIDL_user_free(OutputDomains);
-        MIDL_user_free(OutputNames);
-        return STATUS_INSUFFICIENT_RESOURCES;
+        ERR("NtQuerySystemTime failed (Status 0x%08lx)\n", Status);
+        goto done;
     }
 
-    Status = RtlAllocateAndInitializeSid(&IdentifierAuthority,
-                                         2,
-                                         SECURITY_BUILTIN_DOMAIN_RID,
-                                         DOMAIN_ALIAS_RID_ADMINS,
-                                         0, 0, 0, 0, 0, 0,
-                                         &Sid);
+    /* Create a security descriptor for the secret */
+    Status = LsapCreateSecretSd(&SecretSd,
+                                &SecretSdSize);
     if (!NT_SUCCESS(Status))
     {
-        MIDL_user_free(OutputDomains->Domains);
-        MIDL_user_free(OutputDomains);
-        MIDL_user_free(OutputNames);
+        ERR("LsapCreateAccountSd returned 0x%08lx\n", Status);
         return Status;
     }
 
-    SidLength = RtlLengthSid(Sid);
-
-    for (i = 0; i < SidEnumBuffer->Entries; i++)
+    /* Create the Secret object */
+    Status = LsapCreateDbObject(PolicyObject,
+                                L"Secrets",
+                                SecretName->Buffer,
+                                LsaDbSecretObject,
+                                DesiredAccess,
+                                PolicyObject->Trusted,
+                                &SecretObject);
+    if (!NT_SUCCESS(Status))
     {
-        OutputDomains->Domains[i].Sid = MIDL_user_allocate(SidLength);
-        RtlCopyMemory(OutputDomains->Domains[i].Sid, Sid, SidLength);
+        ERR("LsapCreateDbObject failed (Status 0x%08lx)\n", Status);
+        goto done;
+    }
 
-        OutputDomains->Domains[i].Name.Buffer = MIDL_user_allocate(DomainName.MaximumLength);
-        OutputDomains->Domains[i].Name.Length = DomainName.Length;
-        OutputDomains->Domains[i].Name.MaximumLength = DomainName.MaximumLength;
-        RtlCopyMemory(OutputDomains->Domains[i].Name.Buffer, DomainName.Buffer, DomainName.MaximumLength);
+    /* Set the CurrentTime attribute */
+    Status = LsapSetObjectAttribute(SecretObject,
+                                    L"CurrentTime",
+                                    (PVOID)&Time,
+                                    sizeof(LARGE_INTEGER));
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapSetObjectAttribute (CurrentTime) failed (Status 0x%08lx)\n", Status);
+        goto done;
     }
 
-    Status = LsapLookupSids(SidEnumBuffer,
-                            OutputNames);
+    /* Set the OldTime attribute */
+    Status = LsapSetObjectAttribute(SecretObject,
+                                    L"OldTime",
+                                    (PVOID)&Time,
+                                    sizeof(LARGE_INTEGER));
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapSetObjectAttribute (OldTime) failed (Status 0x%08lx)\n", Status);
+        goto done;
+    }
 
-    *ReferencedDomains = OutputDomains;
+    /* Set the SecDesc attribute */
+    Status = LsapSetObjectAttribute(SecretObject,
+                                    L"SecDesc",
+                                    SecretSd,
+                                    SecretSdSize);
 
-    *MappedCount = SidEnumBuffer->Entries;
+done:
+    if (SecretSd != NULL)
+        RtlFreeHeap(RtlGetProcessHeap(), 0, SecretSd);
 
-    TranslatedNames->Entries = SidEnumBuffer->Entries;
-    TranslatedNames->Names = OutputNames;
+    if (!NT_SUCCESS(Status))
+    {
+        if (SecretObject != NULL)
+            LsapCloseDbObject(SecretObject);
+    }
+    else
+    {
+        *SecretHandle = (LSAPR_HANDLE)SecretObject;
+    }
 
-    return Status;
+    return STATUS_SUCCESS;
 }
 
 
-/* Function 16 */
-NTSTATUS WINAPI LsarCreateSecret(
-    LSAPR_HANDLE PolicyHandle,
-    PRPC_UNICODE_STRING SecretName,
-    ACCESS_MASK DesiredAccess,
-    LSAPR_HANDLE *SecretHandle)
+static
+NTSTATUS
+LsarpOpenAccount(
+    IN PLSA_DB_OBJECT PolicyObject,
+    IN PRPC_SID AccountSid,
+    IN ACCESS_MASK DesiredAccess,
+    OUT PLSA_DB_OBJECT *AccountObject)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    LPWSTR SidString = NULL;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    /* Create SID string */
+    if (!ConvertSidToStringSid((PSID)AccountSid,
+                               &SidString))
+    {
+        ERR("ConvertSidToStringSid failed\n");
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Create the Account object */
+    Status = LsapOpenDbObject(PolicyObject,
+                              L"Accounts",
+                              SidString,
+                              LsaDbAccountObject,
+                              DesiredAccess,
+                              PolicyObject->Trusted,
+                              AccountObject);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapOpenDbObject(Accounts/%S) failed (Status 0x%08lx)\n", SidString, Status);
+    }
+
+    if (SidString != NULL)
+        LocalFree(SidString);
+
+    return Status;
 }
 
 
@@ -561,8 +1426,33 @@ NTSTATUS WINAPI LsarOpenAccount(
     ACCESS_MASK DesiredAccess,
     LSAPR_HANDLE *AccountHandle)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PLSA_DB_OBJECT PolicyObject;
+    NTSTATUS Status;
+
+    TRACE("LsarOpenAccount(%p %p %lx %p)\n",
+          PolicyHandle, AccountSid, DesiredAccess, AccountHandle);
+
+    /* Validate the AccountSid */
+    if (!RtlValidSid(AccountSid))
+        return STATUS_INVALID_PARAMETER;
+
+    /* Validate the PolicyHandle */
+    Status = LsapValidateDbObject(PolicyHandle,
+                                  LsaDbPolicyObject,
+                                  0,
+                                  &PolicyObject);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapValidateDbObject returned 0x%08lx\n", Status);
+        return Status;
+    }
+
+
+    /* Open the Account object */
+    return LsarpOpenAccount(PolicyObject,
+                            AccountSid,
+                            DesiredAccess,
+                            (PLSA_DB_OBJECT *)AccountHandle);
 }
 
 
@@ -571,8 +1461,55 @@ NTSTATUS WINAPI LsarEnumeratePrivilegesAccount(
     LSAPR_HANDLE AccountHandle,
     PLSAPR_PRIVILEGE_SET *Privileges)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PLSA_DB_OBJECT AccountObject;
+    ULONG PrivilegeSetSize = 0;
+    PLSAPR_PRIVILEGE_SET PrivilegeSet = NULL;
+    NTSTATUS Status;
+
+    TRACE("LsarEnumeratePrivilegesAccount(%p %p)\n",
+          AccountHandle, Privileges);
+
+    *Privileges = NULL;
+
+    /* Validate the AccountHandle */
+    Status = LsapValidateDbObject(AccountHandle,
+                                  LsaDbAccountObject,
+                                  ACCOUNT_VIEW,
+                                  &AccountObject);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapValidateDbObject returned 0x%08lx\n", Status);
+        return Status;
+    }
+
+    /* Get the size of the privilege set */
+    Status = LsapGetObjectAttribute(AccountObject,
+                                    L"Privilgs",
+                                    NULL,
+                                    &PrivilegeSetSize);
+    if (!NT_SUCCESS(Status))
+        return Status;
+
+    /* Allocate a buffer for the privilege set */
+    PrivilegeSet = MIDL_user_allocate(PrivilegeSetSize);
+    if (PrivilegeSet == NULL)
+        return STATUS_NO_MEMORY;
+
+    /* Get the privilege set */
+    Status = LsapGetObjectAttribute(AccountObject,
+                                    L"Privilgs",
+                                    PrivilegeSet,
+                                    &PrivilegeSetSize);
+    if (!NT_SUCCESS(Status))
+    {
+        MIDL_user_free(PrivilegeSet);
+        return Status;
+    }
+
+    /* Return a pointer to the privilege set */
+    *Privileges = PrivilegeSet;
+
+    return STATUS_SUCCESS;
 }
 
 
@@ -581,19 +1518,309 @@ NTSTATUS WINAPI LsarAddPrivilegesToAccount(
     LSAPR_HANDLE AccountHandle,
     PLSAPR_PRIVILEGE_SET Privileges)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PLSA_DB_OBJECT AccountObject;
+    PPRIVILEGE_SET CurrentPrivileges = NULL;
+    PPRIVILEGE_SET NewPrivileges = NULL;
+    ULONG PrivilegeSetSize = 0;
+    ULONG PrivilegeCount;
+    ULONG i, j;
+    BOOL bFound;
+    NTSTATUS Status;
+
+    TRACE("LsarAddPrivilegesToAccount(%p %p)\n",
+          AccountHandle, Privileges);
+
+    /* Validate the AccountHandle */
+    Status = LsapValidateDbObject(AccountHandle,
+                                  LsaDbAccountObject,
+                                  ACCOUNT_ADJUST_PRIVILEGES,
+                                  &AccountObject);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapValidateDbObject returned 0x%08lx\n", Status);
+        return Status;
+    }
+
+    /* Get the size of the Privilgs attribute */
+    Status = LsapGetObjectAttribute(AccountObject,
+                                    L"Privilgs",
+                                    NULL,
+                                    &PrivilegeSetSize);
+    if (!NT_SUCCESS(Status) || PrivilegeSetSize == 0)
+    {
+        /* The Privilgs attribute does not exist */
+
+        PrivilegeSetSize = sizeof(PRIVILEGE_SET) +
+                           (Privileges->PrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES);
+        Status = LsapSetObjectAttribute(AccountObject,
+                                        L"Privilgs",
+                                        Privileges,
+                                        PrivilegeSetSize);
+    }
+    else
+    {
+        /* The Privilgs attribute exists */
+
+        /* Allocate memory for the stored privilege set */
+        CurrentPrivileges = MIDL_user_allocate(PrivilegeSetSize);
+        if (CurrentPrivileges == NULL)
+            return STATUS_NO_MEMORY;
+
+        /* Get the current privilege set */
+        Status = LsapGetObjectAttribute(AccountObject,
+                                        L"Privilgs",
+                                        CurrentPrivileges,
+                                        &PrivilegeSetSize);
+        if (!NT_SUCCESS(Status))
+        {
+            TRACE("LsapGetObjectAttribute() failed (Status 0x%08lx)\n", Status);
+            goto done;
+        }
+
+        PrivilegeCount = CurrentPrivileges->PrivilegeCount;
+        TRACE("Current privilege count: %lu\n", PrivilegeCount);
+
+        /* Calculate the number of privileges in the combined privilege set */
+        for (i = 0; i < Privileges->PrivilegeCount; i++)
+        {
+            bFound = FALSE;
+            for (j = 0; j < CurrentPrivileges->PrivilegeCount; j++)
+            {
+                if (RtlEqualLuid(&(Privileges->Privilege[i].Luid),
+                                 &(CurrentPrivileges->Privilege[i].Luid)))
+                {
+                    bFound = TRUE;
+                    break;
+                }
+            }
+
+            if (bFound == FALSE)
+            {
+                TRACE("Found new privilege\n");
+                PrivilegeCount++;
+            }
+        }
+        TRACE("New privilege count: %lu\n", PrivilegeCount);
+
+        /* Calculate the size of the new privilege set and allocate it */
+        PrivilegeSetSize = sizeof(PRIVILEGE_SET) +
+                           (PrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES);
+        NewPrivileges = MIDL_user_allocate(PrivilegeSetSize);
+        if (NewPrivileges == NULL)
+        {
+            Status = STATUS_NO_MEMORY;
+            goto done;
+        }
+
+        /* Initialize the new privilege set */
+        NewPrivileges->PrivilegeCount = PrivilegeCount;
+        NewPrivileges->Control = 0;
+
+        /* Copy all privileges from the current privilege set */
+        RtlCopyLuidAndAttributesArray(CurrentPrivileges->PrivilegeCount,
+                                      &(CurrentPrivileges->Privilege[0]),
+                                      &(NewPrivileges->Privilege[0]));
+
+        /* Add new privileges to the new privilege set */
+        PrivilegeCount = CurrentPrivileges->PrivilegeCount;
+        for (i = 0; i < Privileges->PrivilegeCount; i++)
+        {
+            bFound = FALSE;
+            for (j = 0; j < CurrentPrivileges->PrivilegeCount; j++)
+            {
+                if (RtlEqualLuid(&(Privileges->Privilege[i].Luid),
+                                 &(CurrentPrivileges->Privilege[i].Luid)))
+                {
+                    /* Overwrite attributes if a matching privilege was found */
+                    NewPrivileges->Privilege[j].Attributes = Privileges->Privilege[i].Attributes;
+
+                    bFound = TRUE;
+                    break;
+                }
+            }
+
+            if (bFound == FALSE)
+            {
+                /* Copy the new privilege */
+                RtlCopyLuidAndAttributesArray(1,
+                                              (PLUID_AND_ATTRIBUTES)&(Privileges->Privilege[i]),
+                                              &(NewPrivileges->Privilege[PrivilegeCount]));
+                PrivilegeCount++;
+            }
+        }
+
+        /* Set the new privilege set */
+        Status = LsapSetObjectAttribute(AccountObject,
+                                        L"Privilgs",
+                                        NewPrivileges,
+                                        PrivilegeSetSize);
+    }
+
+done:
+    if (CurrentPrivileges != NULL)
+        MIDL_user_free(CurrentPrivileges);
+
+    if (NewPrivileges != NULL)
+        MIDL_user_free(NewPrivileges);
+
+    return Status;
 }
 
 
 /* Function 20 */
 NTSTATUS WINAPI LsarRemovePrivilegesFromAccount(
     LSAPR_HANDLE AccountHandle,
-    BOOL AllPrivileges,
+    BOOLEAN AllPrivileges,
     PLSAPR_PRIVILEGE_SET Privileges)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PLSA_DB_OBJECT AccountObject;
+    PPRIVILEGE_SET CurrentPrivileges = NULL;
+    PPRIVILEGE_SET NewPrivileges = NULL;
+    ULONG PrivilegeSetSize = 0;
+    ULONG PrivilegeCount;
+    ULONG i, j, k;
+    BOOL bFound;
+    NTSTATUS Status;
+
+    TRACE("LsarRemovePrivilegesFromAccount(%p %u %p)\n",
+          AccountHandle, AllPrivileges, Privileges);
+
+    /* */
+    if (((AllPrivileges == FALSE) && (Privileges == NULL)) ||
+        ((AllPrivileges != FALSE) && (Privileges != NULL)))
+            return STATUS_INVALID_PARAMETER;
+
+    /* Validate the AccountHandle */
+    Status = LsapValidateDbObject(AccountHandle,
+                                  LsaDbAccountObject,
+                                  ACCOUNT_ADJUST_PRIVILEGES,
+                                  &AccountObject);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapValidateDbObject returned 0x%08lx\n", Status);
+        return Status;
+    }
+
+    if (AllPrivileges != FALSE)
+    {
+        /* Delete the Privilgs attribute */
+        Status = LsapDeleteObjectAttribute(AccountObject,
+                                           L"Privilgs");
+        if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
+            Status = STATUS_SUCCESS;
+    }
+    else
+    {
+        /* Get the size of the Privilgs attribute */
+        Status = LsapGetObjectAttribute(AccountObject,
+                                        L"Privilgs",
+                                        NULL,
+                                        &PrivilegeSetSize);
+        if (!NT_SUCCESS(Status))
+            goto done;
+
+        /* Succeed, if there is no privilege set to remove privileges from */
+        if (PrivilegeSetSize == 0)
+        {
+            Status = STATUS_SUCCESS;
+            goto done;
+        }
+
+        /* Allocate memory for the stored privilege set */
+        CurrentPrivileges = MIDL_user_allocate(PrivilegeSetSize);
+        if (CurrentPrivileges == NULL)
+            return STATUS_NO_MEMORY;
+
+        /* Get the current privilege set */
+        Status = LsapGetObjectAttribute(AccountObject,
+                                        L"Privilgs",
+                                        CurrentPrivileges,
+                                        &PrivilegeSetSize);
+        if (!NT_SUCCESS(Status))
+        {
+            TRACE("LsapGetObjectAttribute() failed (Status 0x%08lx)\n", Status);
+            goto done;
+        }
+
+        PrivilegeCount = CurrentPrivileges->PrivilegeCount;
+        TRACE("Current privilege count: %lu\n", PrivilegeCount);
+
+        /* Calculate the number of privileges in the new privilege set */
+        for (i = 0; i < CurrentPrivileges->PrivilegeCount; i++)
+        {
+            for (j = 0; j < Privileges->PrivilegeCount; j++)
+            {
+                if (RtlEqualLuid(&(CurrentPrivileges->Privilege[i].Luid),
+                                 &(Privileges->Privilege[j].Luid)))
+                {
+                    if (PrivilegeCount > 0)
+                        PrivilegeCount--;
+                }
+            }
+        }
+        TRACE("New privilege count: %lu\n", PrivilegeCount);
+
+        if (PrivilegeCount == 0)
+        {
+            /* Delete the Privilgs attribute */
+            Status = LsapDeleteObjectAttribute(AccountObject,
+                                               L"Privilgs");
+            if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
+                Status = STATUS_SUCCESS;
+        }
+        else
+        {
+            /* Calculate the size of the new privilege set and allocate it */
+            PrivilegeSetSize = sizeof(PRIVILEGE_SET) +
+                               (PrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES);
+            NewPrivileges = MIDL_user_allocate(PrivilegeSetSize);
+            if (NewPrivileges == NULL)
+            {
+                Status = STATUS_NO_MEMORY;
+                goto done;
+            }
+
+            /* Initialize the new privilege set */
+            NewPrivileges->PrivilegeCount = PrivilegeCount;
+            NewPrivileges->Control = 0;
+
+            /* Copy the privileges which are not to be removed */
+            for (i = 0, k = 0; i < CurrentPrivileges->PrivilegeCount; i++)
+            {
+                bFound = FALSE;
+                for (j = 0; j < Privileges->PrivilegeCount; j++)
+                {
+                    if (RtlEqualLuid(&(CurrentPrivileges->Privilege[i].Luid),
+                                     &(Privileges->Privilege[j].Luid)))
+                        bFound = TRUE;
+                }
+
+                if (bFound == FALSE)
+                {
+                    /* Copy the privilege */
+                    RtlCopyLuidAndAttributesArray(1,
+                                                  &(CurrentPrivileges->Privilege[i]),
+                                                  &(NewPrivileges->Privilege[k]));
+                    k++;
+                }
+            }
+
+            /* Set the new privilege set */
+            Status = LsapSetObjectAttribute(AccountObject,
+                                            L"Privilgs",
+                                            NewPrivileges,
+                                            PrivilegeSetSize);
+        }
+    }
+
+done:
+    if (CurrentPrivileges != NULL)
+        MIDL_user_free(CurrentPrivileges);
+
+    if (NewPrivileges != NULL)
+        MIDL_user_free(NewPrivileges);
+
+    return Status;
 }
 
 
@@ -602,8 +1829,31 @@ NTSTATUS WINAPI LsarGetQuotasForAccount(
     LSAPR_HANDLE AccountHandle,
     PQUOTA_LIMITS QuotaLimits)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PLSA_DB_OBJECT AccountObject;
+    ULONG Size;
+    NTSTATUS Status;
+
+    TRACE("LsarGetQuotasForAccount(%p %p)\n",
+          AccountHandle, QuotaLimits);
+
+    /* Validate the account handle */
+    Status = LsapValidateDbObject(AccountHandle,
+                                  LsaDbAccountObject,
+                                  ACCOUNT_VIEW,
+                                  &AccountObject);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("Invalid handle (Status %lx)\n", Status);
+        return Status;
+    }
+
+    /* Get the quota attribute */
+    Status = LsapGetObjectAttribute(AccountObject,
+                                    L"DefQuota",
+                                    QuotaLimits,
+                                    &Size);
+
+    return Status;
 }
 
 
@@ -612,8 +1862,60 @@ NTSTATUS WINAPI LsarSetQuotasForAccount(
     LSAPR_HANDLE AccountHandle,
     PQUOTA_LIMITS QuotaLimits)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PLSA_DB_OBJECT AccountObject;
+    QUOTA_LIMITS InternalQuotaLimits;
+    ULONG Size;
+    NTSTATUS Status;
+
+    TRACE("LsarSetQuotasForAccount(%p %p)\n",
+          AccountHandle, QuotaLimits);
+
+    /* Validate the account handle */
+    Status = LsapValidateDbObject(AccountHandle,
+                                  LsaDbAccountObject,
+                                  ACCOUNT_ADJUST_QUOTAS,
+                                  &AccountObject);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("Invalid handle (Status %lx)\n", Status);
+        return Status;
+    }
+
+    /* Get the quota limits attribute */
+    Size = sizeof(QUOTA_LIMITS);
+    Status = LsapGetObjectAttribute(AccountObject,
+                                    L"DefQuota",
+                                    &InternalQuotaLimits,
+                                    &Size);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("LsapGetObjectAttribute() failed (Status 0x%08lx)\n", Status);
+        return Status;
+    }
+
+    /* Update the quota limits */
+    if (QuotaLimits->PagedPoolLimit != 0)
+        InternalQuotaLimits.PagedPoolLimit = QuotaLimits->PagedPoolLimit;
+
+    if (QuotaLimits->NonPagedPoolLimit != 0)
+        InternalQuotaLimits.NonPagedPoolLimit = QuotaLimits->NonPagedPoolLimit;
+
+    if (QuotaLimits->MinimumWorkingSetSize != 0)
+        InternalQuotaLimits.MinimumWorkingSetSize = QuotaLimits->MinimumWorkingSetSize;
+
+    if (QuotaLimits->MaximumWorkingSetSize != 0)
+        InternalQuotaLimits.MaximumWorkingSetSize = QuotaLimits->MaximumWorkingSetSize;
+
+    if (QuotaLimits->PagefileLimit != 0)
+        InternalQuotaLimits.PagefileLimit = QuotaLimits->PagefileLimit;
+
+    /* Set the quota limits attribute */
+    Status = LsapSetObjectAttribute(AccountObject,
+                                    L"DefQuota",
+                                    &InternalQuotaLimits,
+                                    sizeof(QUOTA_LIMITS));
+
+    return Status;
 }
 
 
@@ -622,8 +1924,31 @@ NTSTATUS WINAPI LsarGetSystemAccessAccount(
     LSAPR_HANDLE AccountHandle,
     ACCESS_MASK *SystemAccess)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PLSA_DB_OBJECT AccountObject;
+    ULONG Size = sizeof(ACCESS_MASK);
+    NTSTATUS Status;
+
+    TRACE("LsarGetSystemAccessAccount(%p %p)\n",
+          AccountHandle, SystemAccess);
+
+    /* Validate the account handle */
+    Status = LsapValidateDbObject(AccountHandle,
+                                  LsaDbAccountObject,
+                                  ACCOUNT_VIEW,
+                                  &AccountObject);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("Invalid handle (Status %lx)\n", Status);
+        return Status;
+    }
+
+    /* Get the system access flags */
+    Status = LsapGetObjectAttribute(AccountObject,
+                                    L"ActSysAc",
+                                    SystemAccess,
+                                    &Size);
+
+    return Status;
 }
 
 
@@ -632,8 +1957,30 @@ NTSTATUS WINAPI LsarSetSystemAccessAccount(
     LSAPR_HANDLE AccountHandle,
     ACCESS_MASK SystemAccess)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PLSA_DB_OBJECT AccountObject;
+    NTSTATUS Status;
+
+    TRACE("LsarSetSystemAccessAccount(%p %lx)\n",
+          AccountHandle, SystemAccess);
+
+    /* Validate the account handle */
+    Status = LsapValidateDbObject(AccountHandle,
+                                  LsaDbAccountObject,
+                                  ACCOUNT_ADJUST_SYSTEM_ACCESS,
+                                  &AccountObject);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("Invalid handle (Status %lx)\n", Status);
+        return Status;
+    }
+
+    /* Set the system access flags */
+    Status = LsapSetObjectAttribute(AccountObject,
+                                    L"ActSysAc",
+                                    &SystemAccess,
+                                    sizeof(ACCESS_MASK));
+
+    return Status;
 }
 
 
@@ -678,19 +2025,148 @@ NTSTATUS WINAPI LsarOpenSecret(
     ACCESS_MASK DesiredAccess,
     LSAPR_HANDLE *SecretHandle)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PLSA_DB_OBJECT PolicyObject;
+    PLSA_DB_OBJECT SecretObject = NULL;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    TRACE("LsarOpenSecret(%p %wZ %lx %p)\n",
+          PolicyHandle, SecretName, DesiredAccess, SecretHandle);
+
+    /* Validate the PolicyHandle */
+    Status = LsapValidateDbObject(PolicyHandle,
+                                  LsaDbPolicyObject,
+                                  0,
+                                  &PolicyObject);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapValidateDbObject returned 0x%08lx\n", Status);
+        return Status;
+    }
+
+    /* Create the secret object */
+    Status = LsapOpenDbObject(PolicyObject,
+                              L"Secrets",
+                              SecretName->Buffer,
+                              LsaDbSecretObject,
+                              DesiredAccess,
+                              PolicyObject->Trusted,
+                              &SecretObject);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapOpenDbObject failed (Status 0x%08lx)\n", Status);
+        goto done;
+    }
+
+done:
+    if (!NT_SUCCESS(Status))
+    {
+        if (SecretObject != NULL)
+            LsapCloseDbObject(SecretObject);
+    }
+    else
+    {
+        *SecretHandle = (LSAPR_HANDLE)SecretObject;
+    }
+
+    return Status;
 }
 
 
 /* Function 29 */
 NTSTATUS WINAPI LsarSetSecret(
-    LSAPR_HANDLE *SecretHandle,
+    LSAPR_HANDLE SecretHandle,
     PLSAPR_CR_CIPHER_VALUE EncryptedCurrentValue,
     PLSAPR_CR_CIPHER_VALUE EncryptedOldValue)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PLSA_DB_OBJECT SecretObject;
+    PBYTE CurrentValue = NULL;
+    PBYTE OldValue = NULL;
+    ULONG CurrentValueLength = 0;
+    ULONG OldValueLength = 0;
+    LARGE_INTEGER Time;
+    NTSTATUS Status;
+
+    TRACE("LsarSetSecret(%p %p %p)\n", SecretHandle,
+          EncryptedCurrentValue, EncryptedOldValue);
+
+    /* Validate the SecretHandle */
+    Status = LsapValidateDbObject(SecretHandle,
+                                  LsaDbSecretObject,
+                                  SECRET_SET_VALUE,
+                                  &SecretObject);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapValidateDbObject returned 0x%08lx\n", Status);
+        return Status;
+    }
+
+    if (EncryptedCurrentValue != NULL)
+    {
+        /* FIXME: Decrypt the current value */
+        CurrentValue = EncryptedCurrentValue->Buffer;
+        CurrentValueLength = EncryptedCurrentValue->MaximumLength;
+    }
+
+    /* Set the current value */
+    Status = LsapSetObjectAttribute(SecretObject,
+                                    L"CurrentValue",
+                                    CurrentValue,
+                                    CurrentValueLength);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapSetObjectAttribute failed (Status 0x%08lx)\n", Status);
+        goto done;
+    }
+
+    /* Get the current time */
+    Status = NtQuerySystemTime(&Time);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("NtQuerySystemTime failed (Status 0x%08lx)\n", Status);
+        goto done;
+    }
+
+    /* Set the current time */
+    Status = LsapSetObjectAttribute(SecretObject,
+                                    L"CurrentTime",
+                                    &Time,
+                                    sizeof(LARGE_INTEGER));
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapSetObjectAttribute failed (Status 0x%08lx)\n", Status);
+        goto done;
+    }
+
+    if (EncryptedOldValue != NULL)
+    {
+        /* FIXME: Decrypt the old value */
+        OldValue = EncryptedOldValue->Buffer;
+        OldValueLength = EncryptedOldValue->MaximumLength;
+    }
+
+    /* Set the old value */
+    Status = LsapSetObjectAttribute(SecretObject,
+                                    L"OldValue",
+                                    OldValue,
+                                    OldValueLength);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapSetObjectAttribute failed (Status 0x%08lx)\n", Status);
+        goto done;
+    }
+
+    /* Set the old time */
+    Status = LsapSetObjectAttribute(SecretObject,
+                                    L"OldTime",
+                                    &Time,
+                                    sizeof(LARGE_INTEGER));
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapSetObjectAttribute failed (Status 0x%08lx)\n", Status);
+    }
+
+done:
+    return Status;
 }
 
 
@@ -702,8 +2178,175 @@ NTSTATUS WINAPI LsarQuerySecret(
     PLSAPR_CR_CIPHER_VALUE *EncryptedOldValue,
     PLARGE_INTEGER OldValueSetTime)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PLSA_DB_OBJECT SecretObject;
+    PLSAPR_CR_CIPHER_VALUE EncCurrentValue = NULL;
+    PLSAPR_CR_CIPHER_VALUE EncOldValue = NULL;
+    PBYTE CurrentValue = NULL;
+    PBYTE OldValue = NULL;
+    ULONG CurrentValueLength = 0;
+    ULONG OldValueLength = 0;
+    ULONG BufferSize;
+    NTSTATUS Status;
+
+    TRACE("LsarQuerySecret(%p %p %p %p %p)\n", SecretHandle,
+          EncryptedCurrentValue, CurrentValueSetTime,
+          EncryptedOldValue, OldValueSetTime);
+
+    /* Validate the SecretHandle */
+    Status = LsapValidateDbObject(SecretHandle,
+                                  LsaDbSecretObject,
+                                  SECRET_QUERY_VALUE,
+                                  &SecretObject);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapValidateDbObject returned 0x%08lx\n", Status);
+        return Status;
+    }
+
+    if (EncryptedCurrentValue != NULL)
+    {
+        CurrentValueLength = 0;
+
+        /* Get the size of the current value */
+        Status = LsapGetObjectAttribute(SecretObject,
+                                        L"CurrentValue",
+                                        NULL,
+                                        &CurrentValueLength);
+        if (!NT_SUCCESS(Status))
+            goto done;
+
+        /* Allocate a buffer for the current value */
+        CurrentValue = midl_user_allocate(CurrentValueLength);
+        if (CurrentValue == NULL)
+        {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            goto done;
+        }
+
+        /* Get the current value */
+        Status = LsapGetObjectAttribute(SecretObject,
+                                        L"CurrentValue",
+                                        CurrentValue,
+                                        &CurrentValueLength);
+        if (!NT_SUCCESS(Status))
+            goto done;
+
+        /* Allocate a buffer for the encrypted current value */
+        EncCurrentValue = midl_user_allocate(sizeof(LSAPR_CR_CIPHER_VALUE));
+        if (EncCurrentValue == NULL)
+        {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            goto done;
+        }
+
+        /* FIXME: Encrypt the current value */
+        EncCurrentValue->Length = (USHORT)(CurrentValueLength - sizeof(WCHAR));
+        EncCurrentValue->MaximumLength = (USHORT)CurrentValueLength;
+        EncCurrentValue->Buffer = (PBYTE)CurrentValue;
+    }
+
+    if (CurrentValueSetTime != NULL)
+    {
+        BufferSize = sizeof(LARGE_INTEGER);
+
+        /* Get the current value time */
+        Status = LsapGetObjectAttribute(SecretObject,
+                                        L"CurrentTime",
+                                        (PBYTE)CurrentValueSetTime,
+                                        &BufferSize);
+        if (!NT_SUCCESS(Status))
+            goto done;
+    }
+
+    if (EncryptedOldValue != NULL)
+    {
+        OldValueLength = 0;
+
+        /* Get the size of the old value */
+        Status = LsapGetObjectAttribute(SecretObject,
+                                        L"OldValue",
+                                        NULL,
+                                        &OldValueLength);
+        if (!NT_SUCCESS(Status))
+            goto done;
+
+        /* Allocate a buffer for the old value */
+        OldValue = midl_user_allocate(OldValueLength);
+        if (OldValue == NULL)
+        {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            goto done;
+        }
+
+        /* Get the old value */
+        Status = LsapGetObjectAttribute(SecretObject,
+                                        L"OldValue",
+                                        OldValue,
+                                        &OldValueLength);
+        if (!NT_SUCCESS(Status))
+            goto done;
+
+        /* Allocate a buffer for the encrypted old value */
+        EncOldValue = midl_user_allocate(sizeof(LSAPR_CR_CIPHER_VALUE) + OldValueLength);
+        if (EncOldValue == NULL)
+        {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            goto done;
+        }
+
+        /* FIXME: Encrypt the old value */
+        EncOldValue->Length = (USHORT)(OldValueLength - sizeof(WCHAR));
+        EncOldValue->MaximumLength = (USHORT)OldValueLength;
+        EncOldValue->Buffer = (PBYTE)OldValue;
+    }
+
+    if (OldValueSetTime != NULL)
+    {
+        BufferSize = sizeof(LARGE_INTEGER);
+
+        /* Get the old value time */
+        Status = LsapGetObjectAttribute(SecretObject,
+                                        L"OldTime",
+                                        (PBYTE)OldValueSetTime,
+                                        &BufferSize);
+        if (!NT_SUCCESS(Status))
+            goto done;
+    }
+
+
+done:
+    if (NT_SUCCESS(Status))
+    {
+        if (EncryptedCurrentValue != NULL)
+            *EncryptedCurrentValue = EncCurrentValue;
+
+        if (EncryptedOldValue != NULL)
+            *EncryptedOldValue = EncOldValue;
+    }
+    else
+    {
+        if (EncryptedCurrentValue != NULL)
+            *EncryptedCurrentValue = NULL;
+
+        if (EncryptedOldValue != NULL)
+            *EncryptedOldValue = NULL;
+
+        if (EncCurrentValue != NULL)
+            midl_user_free(EncCurrentValue);
+
+        if (EncOldValue != NULL)
+            midl_user_free(EncOldValue);
+
+        if (CurrentValue != NULL)
+            midl_user_free(CurrentValue);
+
+        if (OldValue != NULL)
+            midl_user_free(OldValue);
+    }
+
+    TRACE("LsarQuerySecret done (Status 0x%08lx)\n", Status);
+
+    return Status;
 }
 
 
@@ -713,6 +2356,7 @@ NTSTATUS WINAPI LsarLookupPrivilegeValue(
     PRPC_UNICODE_STRING Name,
     PLUID Value)
 {
+    PLUID pValue;
     NTSTATUS Status;
 
     TRACE("LsarLookupPrivilegeValue(%p, %wZ, %p)\n",
@@ -720,7 +2364,8 @@ NTSTATUS WINAPI LsarLookupPrivilegeValue(
 
     Status = LsapValidateDbObject(PolicyHandle,
                                   LsaDbPolicyObject,
-                                  0); /* FIXME */
+                                  POLICY_LOOKUP_NAMES,
+                                  NULL);
     if (!NT_SUCCESS(Status))
     {
         ERR("Invalid handle (Status %lx)\n", Status);
@@ -729,10 +2374,13 @@ NTSTATUS WINAPI LsarLookupPrivilegeValue(
 
     TRACE("Privilege: %wZ\n", Name);
 
-    Status = LsarpLookupPrivilegeValue((PUNICODE_STRING)Name,
-                                       Value);
+    pValue = LsarpLookupPrivilegeValue(Name);
+    if (pValue == NULL)
+        return STATUS_NO_SUCH_PRIVILEGE;
 
-    return Status;
+    RtlCopyLuid(Value, pValue);
+
+    return STATUS_SUCCESS;
 }
 
 
@@ -749,14 +2397,16 @@ NTSTATUS WINAPI LsarLookupPrivilegeName(
 
     Status = LsapValidateDbObject(PolicyHandle,
                                   LsaDbPolicyObject,
-                                  0); /* FIXME */
+                                  POLICY_LOOKUP_NAMES,
+                                  NULL);
     if (!NT_SUCCESS(Status))
     {
         ERR("Invalid handle\n");
         return Status;
     }
 
-    Status = LsarpLookupPrivilegeName(Value, (PUNICODE_STRING*)Name);
+    Status = LsarpLookupPrivilegeName(Value,
+                                      Name);
 
     return Status;
 }
@@ -771,8 +2421,28 @@ NTSTATUS WINAPI LsarLookupPrivilegeDisplayName(
     PRPC_UNICODE_STRING *DisplayName,
     USHORT *LanguageReturned)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    NTSTATUS Status;
+
+    TRACE("LsarLookupPrivilegeDisplayName(%p, %p, %u, %u, %p, %p)\n",
+          PolicyHandle, Name, ClientLanguage, ClientSystemDefaultLanguage, DisplayName, LanguageReturned);
+
+    Status = LsapValidateDbObject(PolicyHandle,
+                                  LsaDbPolicyObject,
+                                  POLICY_LOOKUP_NAMES,
+                                  NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("Invalid handle\n");
+        return Status;
+    }
+
+    Status = LsarpLookupPrivilegeDisplayName(Name,
+                                             ClientLanguage,
+                                             ClientSystemDefaultLanguage,
+                                             DisplayName,
+                                             LanguageReturned);
+
+    return Status;
 }
 
 
@@ -780,8 +2450,41 @@ NTSTATUS WINAPI LsarLookupPrivilegeDisplayName(
 NTSTATUS WINAPI LsarDeleteObject(
     LSAPR_HANDLE *ObjectHandle)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PLSA_DB_OBJECT DbObject;
+    NTSTATUS Status;
+
+    TRACE("LsarDeleteObject(%p)\n", ObjectHandle);
+
+    if (ObjectHandle == NULL)
+        return STATUS_INVALID_PARAMETER;
+
+    /* Validate the ObjectHandle */
+    Status = LsapValidateDbObject(*ObjectHandle,
+                                  LsaDbIgnoreObject,
+                                  DELETE,
+                                  &DbObject);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapValidateDbObject returned 0x%08lx\n", Status);
+        return Status;
+    }
+
+    /* You cannot delete the policy object */
+    if (DbObject->ObjectType == LsaDbPolicyObject)
+        return STATUS_INVALID_PARAMETER;
+
+    /* Delete the database object */
+    Status = LsapDeleteDbObject(DbObject);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapDeleteDbObject returned 0x%08lx\n", Status);
+        return Status;
+    }
+
+    /* Invalidate the object handle */
+    *ObjectHandle = NULL;
+
+    return STATUS_SUCCESS;
 }
 
 
@@ -791,30 +2494,422 @@ NTSTATUS WINAPI LsarEnumerateAccountsWithUserRight(
     PRPC_UNICODE_STRING UserRight,
     PLSAPR_ACCOUNT_ENUM_BUFFER EnumerationBuffer)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PLSA_DB_OBJECT PolicyObject;
+    ACCESS_MASK AccountRight = 0;
+    PLUID Luid = NULL;
+    ULONG AccountKeyBufferSize;
+    PWSTR AccountKeyBuffer = NULL;
+    HKEY AccountsKeyHandle = NULL;
+    HKEY AccountKeyHandle = NULL;
+    HKEY AttributeKeyHandle;
+    ACCESS_MASK SystemAccess;
+    PPRIVILEGE_SET PrivilegeSet;
+    PLSAPR_ACCOUNT_INFORMATION EnumBuffer = NULL, ReturnBuffer;
+    ULONG SubKeyCount = 0;
+    ULONG EnumIndex, EnumCount;
+    ULONG Size, i;
+    BOOL Found;
+    NTSTATUS Status;
+
+    TRACE("LsarEnumerateAccountsWithUserRights(%p %wZ %p)\n",
+          PolicyHandle, UserRight, EnumerationBuffer);
+
+    /* Validate the privilege and account right names */
+    if (UserRight != NULL)
+    {
+        Luid = LsarpLookupPrivilegeValue(UserRight);
+        if (Luid == NULL)
+        {
+            AccountRight = LsapLookupAccountRightValue(UserRight);
+            if (AccountRight == 0)
+                return STATUS_NO_SUCH_PRIVILEGE;
+        }
+    }
+
+    if (EnumerationBuffer == NULL)
+        return STATUS_INVALID_PARAMETER;
+
+    EnumerationBuffer->EntriesRead = 0;
+    EnumerationBuffer->Information = NULL;
+
+    /* Validate the PolicyHandle */
+    Status = LsapValidateDbObject(PolicyHandle,
+                                  LsaDbPolicyObject,
+                                  POLICY_LOOKUP_NAMES | 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))
+    {
+        ERR("LsapRegOpenKey returned 0x%08lx\n", Status);
+        return Status;
+    }
+
+    Status = LsapRegQueryKeyInfo(AccountsKeyHandle,
+                                 &SubKeyCount,
+                                 &AccountKeyBufferSize,
+                                 NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapRegOpenKey returned 0x%08lx\n", Status);
+        return Status;
+    }
+
+    AccountKeyBufferSize += sizeof(WCHAR);
+    AccountKeyBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, AccountKeyBufferSize);
+    if (AccountKeyBuffer == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    EnumBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
+                                 HEAP_ZERO_MEMORY,
+                                 SubKeyCount * sizeof(LSAPR_ACCOUNT_INFORMATION));
+    if (EnumBuffer == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto done;
+    }
+
+    EnumCount = 0;
+    EnumIndex = 0;
+    while (TRUE)
+    {
+        Found = FALSE;
+
+        Status = LsapRegEnumerateSubKey(AccountsKeyHandle,
+                                        EnumIndex,
+                                        AccountKeyBufferSize,
+                                        AccountKeyBuffer);
+        if (!NT_SUCCESS(Status))
+        {
+            if (Status == STATUS_NO_MORE_ENTRIES)
+                Status = STATUS_SUCCESS;
+            break;
+        }
+
+        TRACE("EnumIndex: %lu\n", EnumIndex);
+        TRACE("Account key name: %S\n", AccountKeyBuffer);
+
+        Status = LsapRegOpenKey(AccountsKeyHandle,
+                                AccountKeyBuffer,
+                                KEY_READ,
+                                &AccountKeyHandle);
+        if (NT_SUCCESS(Status))
+        {
+            if (Luid != NULL || AccountRight != 0)
+            {
+                Status = LsapRegOpenKey(AccountKeyHandle,
+                                        (Luid != NULL) ? L"Privilgs" : L"ActSysAc",
+                                        KEY_READ,
+                                        &AttributeKeyHandle);
+                if (NT_SUCCESS(Status))
+                {
+                    if (Luid != NULL)
+                    {
+                        Size = 0;
+                        LsapRegQueryValue(AttributeKeyHandle,
+                                          NULL,
+                                          NULL,
+                                          NULL,
+                                          &Size);
+                        if (Size != 0)
+                        {
+                            PrivilegeSet = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);
+                            if (PrivilegeSet)
+                            {
+                                if (LsapRegQueryValue(AttributeKeyHandle,
+                                                      NULL,
+                                                      NULL,
+                                                      PrivilegeSet,
+                                                      &Size) == STATUS_SUCCESS)
+                                {
+                                    for (i = 0; i < PrivilegeSet->PrivilegeCount; i++)
+                                    {
+                                        if (RtlEqualLuid(&(PrivilegeSet->Privilege[i].Luid), Luid))
+                                        {
+                                            TRACE("%S got the privilege!\n", AccountKeyBuffer);
+                                            Found = TRUE;
+                                            break;
+                                        }
+                                    }
+                                }
+
+                                RtlFreeHeap(RtlGetProcessHeap(), 0, PrivilegeSet);
+                            }
+                        }
+                    }
+                    else if (AccountRight != 0)
+                    {
+                        SystemAccess = 0;
+                        Size = sizeof(ACCESS_MASK);
+                        LsapRegQueryValue(AttributeKeyHandle,
+                                          NULL,
+                                          NULL,
+                                          &SystemAccess,
+                                          &Size);
+                        if (SystemAccess & AccountRight)
+                        {
+                            TRACE("%S got the account right!\n", AccountKeyBuffer);
+                            Found = TRUE;
+                        }
+                    }
+
+                    LsapRegCloseKey(AttributeKeyHandle);
+                }
+            }
+            else
+            {
+                /* enumerate all accounts */
+                Found = TRUE;
+            }
+
+            if (Found == TRUE)
+            {
+                TRACE("Add account: %S\n", AccountKeyBuffer);
+
+                Status = LsapRegOpenKey(AccountKeyHandle,
+                                        L"Sid",
+                                        KEY_READ,
+                                        &AttributeKeyHandle);
+                if (NT_SUCCESS(Status))
+                {
+                    Size = 0;
+                    LsapRegQueryValue(AttributeKeyHandle,
+                                      NULL,
+                                      NULL,
+                                      NULL,
+                                      &Size);
+                    if (Size != 0)
+                    {
+                        EnumBuffer[EnumCount].Sid = midl_user_allocate(Size);
+                        if (EnumBuffer[EnumCount].Sid != NULL)
+                        {
+                            Status = LsapRegQueryValue(AttributeKeyHandle,
+                                                       NULL,
+                                                       NULL,
+                                                       EnumBuffer[EnumCount].Sid,
+                                                       &Size);
+                            if (NT_SUCCESS(Status))
+                            {
+                                EnumCount++;
+                            }
+                            else
+                            {
+                                TRACE("SampRegQueryValue returned %08lX\n", Status);
+                                midl_user_free(EnumBuffer[EnumCount].Sid);
+                                EnumBuffer[EnumCount].Sid = NULL;
+                            }
+                        }
+                    }
+
+                    LsapRegCloseKey(AttributeKeyHandle);
+                }
+            }
+
+            LsapRegCloseKey(AccountKeyHandle);
+        }
+
+        EnumIndex++;
+    }
+
+    TRACE("EnumCount: %lu\n", EnumCount);
+
+    if (NT_SUCCESS(Status) && EnumCount != 0)
+    {
+        ReturnBuffer = midl_user_allocate(EnumCount * sizeof(LSAPR_ACCOUNT_INFORMATION));
+        if (ReturnBuffer == NULL)
+        {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            goto done;
+        }
+
+        RtlCopyMemory(ReturnBuffer,
+                      EnumBuffer,
+                      EnumCount * sizeof(LSAPR_ACCOUNT_INFORMATION));
+
+        EnumerationBuffer->EntriesRead = EnumCount;
+        EnumerationBuffer->Information = ReturnBuffer;
+    }
+
+done:
+    if (EnumBuffer != NULL)
+    {
+        if (Status != STATUS_SUCCESS)
+        {
+            for (i = 0; i < EnumCount; i++)
+            {
+                if (EnumBuffer[i].Sid != NULL)
+                    midl_user_free(EnumBuffer[i].Sid);
+            }
+        }
+
+        RtlFreeHeap(RtlGetProcessHeap(), 0, EnumBuffer);
+    }
+
+    if (AccountKeyBuffer != NULL)
+        RtlFreeHeap(RtlGetProcessHeap(), 0, AccountKeyBuffer);
+
+    if (Status == STATUS_SUCCESS && EnumCount == 0)
+        Status = STATUS_NO_MORE_ENTRIES;
+
+    return Status;
 }
 
 
 /* Function 36 */
-NTSTATUS WINAPI LsarEnmuerateAccountRights(
+NTSTATUS WINAPI LsarEnumerateAccountRights(
     LSAPR_HANDLE PolicyHandle,
     PRPC_SID AccountSid,
     PLSAPR_USER_RIGHT_SET UserRights)
 {
+    LSAPR_HANDLE AccountHandle;
+    PLSAPR_PRIVILEGE_SET PrivilegeSet = NULL;
+    PRPC_UNICODE_STRING RightsBuffer = NULL;
+    PRPC_UNICODE_STRING PrivilegeString;
+    ACCESS_MASK SystemAccess = 0;
+    ULONG RightsCount = 0;
+    ULONG Index;
+    ULONG i;
     NTSTATUS Status;
 
-    FIXME("(%p,%p,%p) stub\n", PolicyHandle, AccountSid, UserRights);
+    TRACE("LsarEnumerateAccountRights(%p %p %p)\n",
+          PolicyHandle, AccountSid, UserRights);
 
-    Status = LsapValidateDbObject(PolicyHandle,
-                                  LsaDbPolicyObject,
-                                  0); /* FIXME */
+    /* Open the account */
+    Status = LsarOpenAccount(PolicyHandle,
+                             AccountSid,
+                             ACCOUNT_VIEW,
+                             &AccountHandle);
     if (!NT_SUCCESS(Status))
+    {
+        WARN("LsarOpenAccount returned 0x%08lx\n", Status);
         return Status;
+    }
 
-    UserRights->Entries = 0;
-    UserRights->UserRights = NULL;
-    return STATUS_OBJECT_NAME_NOT_FOUND;
+    /* Enumerate the privileges */
+    Status = LsarEnumeratePrivilegesAccount(AccountHandle,
+                                            &PrivilegeSet);
+    if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
+    {
+        WARN("LsarEnumeratePrivilegesAccount returned 0x%08lx\n", Status);
+        goto done;
+    }
+
+    /* Get account rights */
+    Status = LsarGetSystemAccessAccount(AccountHandle,
+                                        &SystemAccess);
+    if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
+    {
+        WARN("LsarGetSystemAccessAccount returned 0x%08lx\n", Status);
+        goto done;
+    }
+
+    RightsCount = PrivilegeSet->PrivilegeCount;
+
+    /* Count account rights */
+    for (i = 0; i < sizeof(ACCESS_MASK) * 8; i++)
+    {
+        if (SystemAccess & (1 << i))
+            RightsCount++;
+    }
+
+    /* We are done if there are no rights to be enumerated */
+    if (RightsCount == 0)
+    {
+        UserRights->Entries = 0;
+        UserRights->UserRights = NULL;
+        Status = STATUS_SUCCESS;
+        goto done;
+    }
+
+    /* Allocate a buffer for the account rights */
+    RightsBuffer = MIDL_user_allocate(RightsCount * sizeof(RPC_UNICODE_STRING));
+    if (RightsBuffer == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto done;
+    }
+
+    /* Copy the privileges into the buffer */
+    Index = 0;
+    if (PrivilegeSet)
+    {
+        for (i = 0; i < PrivilegeSet->PrivilegeCount; i++)
+        {
+            PrivilegeString = NULL;
+            Status = LsarLookupPrivilegeName(PolicyHandle,
+                                             (PLUID)&PrivilegeSet->Privilege[i].Luid,
+                                             &PrivilegeString);
+            if (!NT_SUCCESS(Status))
+            {
+                WARN("LsarLookupPrivilegeName returned 0x%08lx\n", Status);
+                goto done;
+            }
+
+            RightsBuffer[Index].Length = PrivilegeString->Length;
+            RightsBuffer[Index].MaximumLength = PrivilegeString->MaximumLength;
+            RightsBuffer[Index].Buffer = PrivilegeString->Buffer;
+
+            MIDL_user_free(PrivilegeString);
+            Index++;
+        }
+    }
+
+    /* Copy account rights into the buffer */
+    for (i = 0; i < sizeof(ACCESS_MASK) * 8; i++)
+    {
+        if (SystemAccess & (1 << i))
+        {
+            Status = LsapLookupAccountRightName(1 << i,
+                                                &PrivilegeString);
+            if (!NT_SUCCESS(Status))
+            {
+                WARN("LsarLookupAccountRightName returned 0x%08lx\n", Status);
+                goto done;
+            }
+
+            RightsBuffer[Index].Length = PrivilegeString->Length;
+            RightsBuffer[Index].MaximumLength = PrivilegeString->MaximumLength;
+            RightsBuffer[Index].Buffer = PrivilegeString->Buffer;
+
+            MIDL_user_free(PrivilegeString);
+            Index++;
+        }
+    }
+
+    UserRights->Entries = RightsCount;
+    UserRights->UserRights = (PRPC_UNICODE_STRING)RightsBuffer;
+
+done:
+    if (!NT_SUCCESS(Status))
+    {
+        if (RightsBuffer != NULL)
+        {
+            for (Index = 0; Index < RightsCount; Index++)
+            {
+                if (RightsBuffer[Index].Buffer != NULL)
+                    MIDL_user_free(RightsBuffer[Index].Buffer);
+            }
+
+            MIDL_user_free(RightsBuffer);
+        }
+    }
+
+    if (PrivilegeSet != NULL)
+        MIDL_user_free(PrivilegeSet);
+
+    LsarClose(&AccountHandle);
+
+    return Status;
 }
 
 
@@ -824,8 +2919,206 @@ NTSTATUS WINAPI LsarAddAccountRights(
     PRPC_SID AccountSid,
     PLSAPR_USER_RIGHT_SET UserRights)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PLSA_DB_OBJECT PolicyObject;
+    PLSA_DB_OBJECT AccountObject = NULL;
+    ULONG ulNewPrivileges = 0, ulNewRights = 0;
+    ACCESS_MASK SystemAccess = 0;
+    ULONG Size, Value, i, j;
+    PPRIVILEGE_SET PrivilegeSet = NULL;
+    ULONG PrivilegeSetBufferSize = 0;
+    ULONG PrivilegeCount;
+    BOOLEAN bFound;
+    PLUID pLuid;
+    NTSTATUS Status;
+
+    TRACE("LsarAddAccountRights(%p %p %p)\n",
+          PolicyHandle, AccountSid, UserRights);
+
+    /* Validate the AccountSid */
+    if (!RtlValidSid(AccountSid))
+        return STATUS_INVALID_PARAMETER;
+
+    /* Validate the UserRights */
+    if (UserRights == NULL)
+        return STATUS_INVALID_PARAMETER;
+
+    /* Validate the privilege and account right names */
+    for (i = 0; i < UserRights->Entries; i++)
+    {
+        if (LsarpLookupPrivilegeValue(&UserRights->UserRights[i]) != NULL)
+        {
+            ulNewPrivileges++;
+        }
+        else
+        {
+            if (LsapLookupAccountRightValue(&UserRights->UserRights[i]) == 0)
+                return STATUS_NO_SUCH_PRIVILEGE;
+
+            ulNewRights++;
+        }
+    }
+
+    TRACE("ulNewPrivileges: %lu\n", ulNewPrivileges);
+    TRACE("ulNewRights: %lu\n", ulNewRights);
+
+    /* Validate the PolicyHandle */
+    Status = LsapValidateDbObject(PolicyHandle,
+                                  LsaDbPolicyObject,
+                                  POLICY_LOOKUP_NAMES,
+                                  &PolicyObject);
+    if (!NT_SUCCESS(Status))
+    {
+        WARN("LsapValidateDbObject returned 0x%08lx\n", Status);
+        return Status;
+    }
+
+    /* Open the account */
+    Status = LsarpOpenAccount(PolicyObject,
+                              AccountSid,
+                              0,
+                              &AccountObject);
+    if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
+    {
+        WARN("LsarpOpenAccount returned 0x%08lx\n", Status);
+        goto done;
+    }
+    else if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
+    {
+        /* Create a new account if it does not yet exist */
+        Status = LsarpCreateAccount(PolicyObject,
+                                    AccountSid,
+                                    0,
+                                    &AccountObject);
+        if (!NT_SUCCESS(Status))
+        {
+            WARN("LsarpCreateAccount returned 0x%08lx\n", Status);
+            goto done;
+        }
+    }
+
+    if (ulNewPrivileges > 0)
+    {
+        Size = 0;
+
+        /* Get the size of the Privilgs attribute */
+        Status = LsapGetObjectAttribute(AccountObject,
+                                        L"Privilgs",
+                                        NULL,
+                                        &Size);
+        if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
+            goto done;
+
+        /* Calculate the required privilege set buffer size */
+        if (Size == 0)
+            PrivilegeSetBufferSize = sizeof(PRIVILEGE_SET) +
+                                     (ulNewPrivileges - 1) * sizeof(LUID_AND_ATTRIBUTES);
+        else
+            PrivilegeSetBufferSize = Size +
+                                     ulNewPrivileges * sizeof(LUID_AND_ATTRIBUTES);
+
+        /* Allocate the privilege set buffer */
+        PrivilegeSet = RtlAllocateHeap(RtlGetProcessHeap(),
+                                       HEAP_ZERO_MEMORY,
+                                       PrivilegeSetBufferSize);
+        if (PrivilegeSet == NULL)
+            return STATUS_NO_MEMORY;
+
+        /* Get the privilege set */
+        if (Size != 0)
+        {
+            Status = LsapGetObjectAttribute(AccountObject,
+                                            L"Privilgs",
+                                            PrivilegeSet,
+                                            &Size);
+            if (!NT_SUCCESS(Status))
+            {
+                WARN("LsapGetObjectAttribute() failed (Status 0x%08lx)\n", Status);
+                goto done;
+            }
+        }
+
+        PrivilegeCount = PrivilegeSet->PrivilegeCount;
+        TRACE("Privilege count: %lu\n", PrivilegeCount);
+
+        for (i = 0; i < UserRights->Entries; i++)
+        {
+            pLuid = LsarpLookupPrivilegeValue(&UserRights->UserRights[i]);
+            if (pLuid == NULL)
+                continue;
+
+            bFound = FALSE;
+            for (j = 0; j < PrivilegeSet->PrivilegeCount; j++)
+            {
+                if (RtlEqualLuid(&(PrivilegeSet->Privilege[j].Luid), pLuid))
+                {
+                    bFound = TRUE;
+                    break;
+                }
+            }
+
+            if (bFound == FALSE)
+            {
+                /* Copy the new privilege */
+                RtlCopyMemory(&(PrivilegeSet->Privilege[PrivilegeSet->PrivilegeCount]),
+                              pLuid,
+                              sizeof(LUID));
+                PrivilegeSet->PrivilegeCount++;
+            }
+        }
+
+        /* Store the extended privilege set */
+        if (PrivilegeCount != PrivilegeSet->PrivilegeCount)
+        {
+            Size = sizeof(PRIVILEGE_SET) +
+                   (PrivilegeSet->PrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES);
+
+            Status = LsapSetObjectAttribute(AccountObject,
+                                            L"Privilgs",
+                                            PrivilegeSet,
+                                            Size);
+            if (!NT_SUCCESS(Status))
+            {
+                WARN("LsapSetObjectAttribute() failed (Status 0x%08lx)\n", Status);
+                goto done;
+            }
+        }
+    }
+
+    if (ulNewRights > 0)
+    {
+        Size = sizeof(ACCESS_MASK);
+
+        /* Get the system access flags, if the attribute exists */
+        Status = LsapGetObjectAttribute(AccountObject,
+                                        L"ActSysAc",
+                                        &SystemAccess,
+                                        &Size);
+        if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
+            goto done;
+
+        /* Set the new access rights */
+        for (i = 0; i < UserRights->Entries; i++)
+        {
+            Value = LsapLookupAccountRightValue(&UserRights->UserRights[i]);
+            if (Value != 0)
+                SystemAccess |= Value;
+        }
+
+        /* Set the system access flags */
+        Status = LsapSetObjectAttribute(AccountObject,
+                                        L"ActSysAc",
+                                        &SystemAccess,
+                                        sizeof(ACCESS_MASK));
+    }
+
+done:
+    if (PrivilegeSet != NULL)
+        RtlFreeHeap(RtlGetProcessHeap(), 0, PrivilegeSet);
+
+    if (AccountObject != NULL)
+        LsapCloseDbObject(AccountObject);
+
+    return Status;
 }
 
 
@@ -833,11 +3126,193 @@ NTSTATUS WINAPI LsarAddAccountRights(
 NTSTATUS WINAPI LsarRemoveAccountRights(
     LSAPR_HANDLE PolicyHandle,
     PRPC_SID AccountSid,
-    BOOL AllRights,
+    BOOLEAN AllRights,
     PLSAPR_USER_RIGHT_SET UserRights)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PLSA_DB_OBJECT PolicyObject;
+    PLSA_DB_OBJECT AccountObject = NULL;
+    ULONG PrivilegesToRemove = 0, RightsToRemove = 0;
+    ACCESS_MASK SystemAccess = 0;
+    ULONG Size, Value, i, j, Index;
+    PPRIVILEGE_SET PrivilegeSet = NULL;
+    ULONG PrivilegeCount;
+    PLUID pLuid;
+    NTSTATUS Status;
+
+    TRACE("LsarRemoveAccountRights(%p %p %lu %p)\n",
+          PolicyHandle, AccountSid, AllRights, UserRights);
+
+    /* Validate the AccountSid */
+    if (!RtlValidSid(AccountSid))
+        return STATUS_INVALID_PARAMETER;
+
+    /* Validate the UserRights */
+    if (UserRights == NULL)
+        return STATUS_INVALID_PARAMETER;
+
+    /* Validate the privilege and account right names */
+    for (i = 0; i < UserRights->Entries; i++)
+    {
+        if (LsarpLookupPrivilegeValue(&UserRights->UserRights[i]) != NULL)
+        {
+            PrivilegesToRemove++;
+        }
+        else
+        {
+            if (LsapLookupAccountRightValue(&UserRights->UserRights[i]) == 0)
+                return STATUS_NO_SUCH_PRIVILEGE;
+
+            RightsToRemove++;
+        }
+    }
+
+    /* Validate the PolicyHandle */
+    Status = LsapValidateDbObject(PolicyHandle,
+                                  LsaDbPolicyObject,
+                                  POLICY_LOOKUP_NAMES,
+                                  &PolicyObject);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapValidateDbObject returned 0x%08lx\n", Status);
+        return Status;
+    }
+
+    /* Open the account */
+    Status = LsarpOpenAccount(PolicyObject,
+                              AccountSid,
+                              0,
+                              &AccountObject);
+    if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
+    {
+        ERR("LsarpOpenAccount returned 0x%08lx\n", Status);
+        goto done;
+    }
+
+    if (AllRights == FALSE)
+    {
+        /* Get the size of the Privilgs attribute */
+        Size = 0;
+        Status = LsapGetObjectAttribute(AccountObject,
+                                        L"Privilgs",
+                                        NULL,
+                                        &Size);
+        if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
+            goto done;
+
+        if ((Size != 0) && (PrivilegesToRemove != 0))
+        {
+            /* Allocate the privilege set buffer */
+            PrivilegeSet = RtlAllocateHeap(RtlGetProcessHeap(),
+                                           HEAP_ZERO_MEMORY,
+                                           Size);
+            if (PrivilegeSet == NULL)
+                return STATUS_NO_MEMORY;
+
+            /* Get the privilege set */
+            Status = LsapGetObjectAttribute(AccountObject,
+                                            L"Privilgs",
+                                            PrivilegeSet,
+                                            &Size);
+            if (!NT_SUCCESS(Status))
+            {
+                ERR("LsapGetObjectAttribute() failed (Status 0x%08lx)\n", Status);
+                goto done;
+            }
+
+            PrivilegeCount = PrivilegeSet->PrivilegeCount;
+
+            for (i = 0; i < UserRights->Entries; i++)
+            {
+                pLuid = LsarpLookupPrivilegeValue(&UserRights->UserRights[i]);
+                if (pLuid == NULL)
+                    continue;
+
+                Index = -1;
+                for (j = 0; j < PrivilegeSet->PrivilegeCount; j++)
+                {
+                    if (RtlEqualLuid(&(PrivilegeSet->Privilege[j].Luid), pLuid))
+                    {
+                        Index = j;
+                        break;
+                    }
+                }
+
+                if (Index != -1)
+                {
+                    /* Remove the privilege */
+                    if ((PrivilegeSet->PrivilegeCount > 1) &&
+                        (Index < PrivilegeSet->PrivilegeCount - 1))
+                        RtlMoveMemory(&(PrivilegeSet->Privilege[Index]),
+                                      &(PrivilegeSet->Privilege[Index + 1]),
+                                      (Index - PrivilegeSet->PrivilegeCount - 1) * sizeof(LUID));
+
+                    /* Wipe the last entry */
+                    RtlZeroMemory(&(PrivilegeSet->Privilege[PrivilegeSet->PrivilegeCount - 1]),
+                                  sizeof(LUID));
+
+                    PrivilegeSet->PrivilegeCount--;
+                }
+            }
+
+            /* Store the extended privilege set */
+            if (PrivilegeCount != PrivilegeSet->PrivilegeCount)
+            {
+                Size = sizeof(PRIVILEGE_SET) +
+                       (PrivilegeSet->PrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES);
+
+                Status = LsapSetObjectAttribute(AccountObject,
+                                                L"Privilgs",
+                                                PrivilegeSet,
+                                                Size);
+                if (!NT_SUCCESS(Status))
+                {
+                    ERR("LsapSetObjectAttribute() failed (Status 0x%08lx)\n", Status);
+                    goto done;
+                }
+            }
+        }
+
+        /* Get the system access flags, if the attribute exists */
+        Size = 0;
+        Status = LsapGetObjectAttribute(AccountObject,
+                                        L"ActSysAc",
+                                        &SystemAccess,
+                                        &Size);
+        if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
+            goto done;
+
+        if ((Size != 0) && (RightsToRemove != 0))
+        {
+            ERR("Rights: 0x%lx\n", SystemAccess);
+
+            /* Set the new access rights */
+            for (i = 0; i < UserRights->Entries; i++)
+            {
+                Value = LsapLookupAccountRightValue(&UserRights->UserRights[i]);
+                if (Value != 0)
+                    SystemAccess &= ~Value;
+            }
+            ERR("New Rights: 0x%lx\n", SystemAccess);
+
+            /* Set the system access flags */
+            Status = LsapSetObjectAttribute(AccountObject,
+                                            L"ActSysAc",
+                                            &SystemAccess,
+                                            sizeof(ACCESS_MASK));
+        }
+    }
+    else
+    {
+    }
+
+done:
+    if (PrivilegeSet != NULL)
+        RtlFreeHeap(RtlGetProcessHeap(), 0, PrivilegeSet);
+
+    if (AccountObject != NULL)
+        LsapCloseDbObject(AccountObject);
+
+    return Status;
 }
 
 
@@ -848,8 +3323,8 @@ NTSTATUS WINAPI LsarQueryTrustedDomainInfo(
     TRUSTED_INFORMATION_CLASS InformationClass,
     PLSAPR_TRUSTED_DOMAIN_INFO *TrustedDomainInformation)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    /* FIXME: We are not running an AD yet */
+    return STATUS_DIRECTORY_SERVICE_REQUIRED;
 }
 
 
@@ -860,8 +3335,8 @@ NTSTATUS WINAPI LsarSetTrustedDomainInfo(
     TRUSTED_INFORMATION_CLASS InformationClass,
     PLSAPR_TRUSTED_DOMAIN_INFO TrustedDomainInformation)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    /* FIXME: We are not running an AD yet */
+    return STATUS_DIRECTORY_SERVICE_REQUIRED;
 }
 
 
@@ -870,8 +3345,8 @@ NTSTATUS WINAPI LsarDeleteTrustedDomain(
     LSAPR_HANDLE PolicyHandle,
     PRPC_SID TrustedDomainSid)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    /* FIXME: We are not running an AD yet */
+    return STATUS_DIRECTORY_SERVICE_REQUIRED;
 }
 
 
@@ -881,19 +3356,254 @@ NTSTATUS WINAPI LsarStorePrivateData(
     PRPC_UNICODE_STRING KeyName,
     PLSAPR_CR_CIPHER_VALUE EncryptedData)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PLSA_DB_OBJECT PolicyObject = NULL;
+    PLSA_DB_OBJECT SecretsObject = NULL;
+    PLSA_DB_OBJECT SecretObject = NULL;
+    LARGE_INTEGER Time;
+    PBYTE Value = NULL;
+    ULONG ValueLength = 0;
+    NTSTATUS Status;
+
+    TRACE("LsarStorePrivateData(%p %p %p)\n",
+          PolicyHandle, KeyName, EncryptedData);
+
+    /* Validate the SecretHandle */
+    Status = LsapValidateDbObject(PolicyHandle,
+                                  LsaDbPolicyObject,
+                                  POLICY_CREATE_SECRET,
+                                  &PolicyObject);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapValidateDbObject returned 0x%08lx\n", Status);
+        return Status;
+    }
+
+    /* Open the 'Secrets' object */
+    Status = LsapOpenDbObject(PolicyObject,
+                              NULL,
+                              L"Secrets",
+                              LsaDbIgnoreObject,
+                              0,
+                              PolicyObject->Trusted,
+                              &SecretsObject);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapOpenDbObject failed (Status 0x%08lx)\n", Status);
+        goto done;
+    }
+
+    if (EncryptedData == NULL)
+    {
+        /* Open the Secret object */
+        Status = LsapOpenDbObject(SecretsObject,
+                                  NULL,
+                                  KeyName->Buffer,
+                                  LsaDbSecretObject,
+                                  0,
+                                  PolicyObject->Trusted,
+                                  &SecretObject);
+        if (!NT_SUCCESS(Status))
+        {
+            ERR("LsapOpenDbObject failed (Status 0x%08lx)\n", Status);
+            goto done;
+        }
+
+        /* Delete the secret */
+        Status = LsapDeleteDbObject(SecretObject);
+        if (NT_SUCCESS(Status))
+            SecretObject = NULL;
+    }
+    else
+    {
+        /* Create the Secret object */
+        Status = LsapCreateDbObject(SecretsObject,
+                                    NULL,
+                                    KeyName->Buffer,
+                                    LsaDbSecretObject,
+                                    0,
+                                    PolicyObject->Trusted,
+                                    &SecretObject);
+        if (!NT_SUCCESS(Status))
+        {
+            ERR("LsapCreateDbObject failed (Status 0x%08lx)\n", Status);
+            goto done;
+        }
+
+        /* FIXME: Decrypt data */
+        Value = EncryptedData->Buffer;
+        ValueLength = EncryptedData->MaximumLength;
+
+        /* Get the current time */
+        Status = NtQuerySystemTime(&Time);
+        if (!NT_SUCCESS(Status))
+        {
+            ERR("NtQuerySystemTime failed (Status 0x%08lx)\n", Status);
+            goto done;
+        }
+
+        /* Set the current value */
+        Status = LsapSetObjectAttribute(SecretObject,
+                                        L"CurrentValue",
+                                        Value,
+                                        ValueLength);
+        if (!NT_SUCCESS(Status))
+        {
+            ERR("LsapSetObjectAttribute failed (Status 0x%08lx)\n", Status);
+            goto done;
+        }
+
+        /* Set the current time */
+        Status = LsapSetObjectAttribute(SecretObject,
+                                        L"CurrentTime",
+                                        &Time,
+                                        sizeof(LARGE_INTEGER));
+        if (!NT_SUCCESS(Status))
+        {
+            ERR("LsapSetObjectAttribute failed (Status 0x%08lx)\n", Status);
+            goto done;
+        }
+
+        /* Get the current time */
+        Status = NtQuerySystemTime(&Time);
+        if (!NT_SUCCESS(Status))
+        {
+            ERR("NtQuerySystemTime failed (Status 0x%08lx)\n", Status);
+            goto done;
+        }
+
+        /* Set the old value */
+        Status = LsapSetObjectAttribute(SecretObject,
+                                        L"OldValue",
+                                        NULL,
+                                        0);
+        if (!NT_SUCCESS(Status))
+        {
+            ERR("LsapSetObjectAttribute failed (Status 0x%08lx)\n", Status);
+            goto done;
+        }
+
+        /* Set the old time */
+        Status = LsapSetObjectAttribute(SecretObject,
+                                        L"OldTime",
+                                        &Time,
+                                        sizeof(LARGE_INTEGER));
+        if (!NT_SUCCESS(Status))
+        {
+            ERR("LsapSetObjectAttribute failed (Status 0x%08lx)\n", Status);
+        }
+    }
+
+done:
+    if (SecretObject != NULL)
+        LsapCloseDbObject(SecretObject);
+
+    if (SecretsObject != NULL)
+        LsapCloseDbObject(SecretsObject);
+
+    return Status;
 }
 
 
-/* Function 43 */
-NTSTATUS WINAPI LsarRetrievePrivateData(
-    LSAPR_HANDLE PolicyHandle,
-    PRPC_UNICODE_STRING KeyName,
-    PLSAPR_CR_CIPHER_VALUE *EncryptedData)
-{
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+/* Function 43 */
+NTSTATUS WINAPI LsarRetrievePrivateData(
+    LSAPR_HANDLE PolicyHandle,
+    PRPC_UNICODE_STRING KeyName,
+    PLSAPR_CR_CIPHER_VALUE *EncryptedData)
+{
+    PLSA_DB_OBJECT PolicyObject = NULL;
+    PLSA_DB_OBJECT SecretObject = NULL;
+    PLSAPR_CR_CIPHER_VALUE EncCurrentValue = NULL;
+    ULONG CurrentValueLength = 0;
+    PBYTE CurrentValue = NULL;
+    NTSTATUS Status;
+
+    TRACE("LsarRetrievePrivateData(%p %wZ %p)\n",
+          PolicyHandle, KeyName, EncryptedData);
+
+    /* Validate the SecretHandle */
+    Status = LsapValidateDbObject(PolicyHandle,
+                                  LsaDbPolicyObject,
+                                  POLICY_CREATE_SECRET,
+                                  &PolicyObject);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapValidateDbObject returned 0x%08lx\n", Status);
+        return Status;
+    }
+
+    /* Open the secret object */
+    Status = LsapOpenDbObject(PolicyObject,
+                              L"Secrets",
+                              KeyName->Buffer,
+                              LsaDbSecretObject,
+                              0,
+                              PolicyObject->Trusted,
+                              &SecretObject);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapOpenDbObject failed (Status 0x%08lx)\n", Status);
+        goto done;
+    }
+
+    /* Get the size of the current value */
+    Status = LsapGetObjectAttribute(SecretObject,
+                                    L"CurrentValue",
+                                    NULL,
+                                    &CurrentValueLength);
+    if (!NT_SUCCESS(Status))
+        goto done;
+
+    /* Allocate a buffer for the current value */
+    CurrentValue = midl_user_allocate(CurrentValueLength);
+    if (CurrentValue == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto done;
+    }
+
+    /* Get the current value */
+    Status = LsapGetObjectAttribute(SecretObject,
+                                    L"CurrentValue",
+                                    CurrentValue,
+                                    &CurrentValueLength);
+    if (!NT_SUCCESS(Status))
+        goto done;
+
+    /* Allocate a buffer for the encrypted current value */
+    EncCurrentValue = midl_user_allocate(sizeof(LSAPR_CR_CIPHER_VALUE) + CurrentValueLength);
+    if (EncCurrentValue == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto done;
+    }
+
+    /* FIXME: Encrypt the current value */
+    EncCurrentValue->Length = (USHORT)(CurrentValueLength - sizeof(WCHAR));
+    EncCurrentValue->MaximumLength = (USHORT)CurrentValueLength;
+    EncCurrentValue->Buffer = (PBYTE)(EncCurrentValue + 1);
+    RtlCopyMemory(EncCurrentValue->Buffer,
+                  CurrentValue,
+                  CurrentValueLength);
+
+done:
+    if (NT_SUCCESS(Status))
+    {
+        if (EncryptedData != NULL)
+            *EncryptedData = EncCurrentValue;
+    }
+    else
+    {
+        if (EncryptedData != NULL)
+            *EncryptedData = NULL;
+
+        if (EncCurrentValue != NULL)
+            midl_user_free(EncCurrentValue);
+    }
+
+    if (SecretObject != NULL)
+        LsapCloseDbObject(SecretObject);
+
+    return Status;
 }
 
 
@@ -904,8 +3614,10 @@ NTSTATUS WINAPI LsarOpenPolicy2(
     ACCESS_MASK DesiredAccess,
     LSAPR_HANDLE *PolicyHandle)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    return LsarOpenPolicy(SystemName,
+                          ObjectAttributes,
+                          DesiredAccess,
+                          PolicyHandle);
 }
 
 
@@ -924,10 +3636,11 @@ NTSTATUS WINAPI LsarGetUserName(
 NTSTATUS WINAPI LsarQueryInformationPolicy2(
     LSAPR_HANDLE PolicyHandle,
     POLICY_INFORMATION_CLASS InformationClass,
-    unsigned long *PolicyInformation)
+    PLSAPR_POLICY_INFORMATION *PolicyInformation)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    return LsarQueryInformationPolicy(PolicyHandle,
+                                      InformationClass,
+                                      PolicyInformation);
 }
 
 
@@ -935,10 +3648,11 @@ NTSTATUS WINAPI LsarQueryInformationPolicy2(
 NTSTATUS WINAPI LsarSetInformationPolicy2(
     LSAPR_HANDLE PolicyHandle,
     POLICY_INFORMATION_CLASS InformationClass,
-    unsigned long PolicyInformation)
+    PLSAPR_POLICY_INFORMATION PolicyInformation)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    return LsarSetInformationPolicy(PolicyHandle,
+                                    InformationClass,
+                                    PolicyInformation);
 }
 
 
@@ -947,10 +3661,10 @@ NTSTATUS WINAPI LsarQueryTrustedDomainInfoByName(
     LSAPR_HANDLE PolicyHandle,
     PRPC_UNICODE_STRING TrustedDomainName,
     POLICY_INFORMATION_CLASS InformationClass,
-    unsigned long *PolicyInformation)
+    PLSAPR_TRUSTED_DOMAIN_INFO *PolicyInformation)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    /* FIXME: We are not running an AD yet */
+    return STATUS_OBJECT_NAME_NOT_FOUND;
 }
 
 
@@ -959,10 +3673,10 @@ NTSTATUS WINAPI LsarSetTrustedDomainInfoByName(
     LSAPR_HANDLE PolicyHandle,
     PRPC_UNICODE_STRING TrustedDomainName,
     POLICY_INFORMATION_CLASS InformationClass,
-    unsigned long PolicyInformation)
+    PLSAPR_TRUSTED_DOMAIN_INFO PolicyInformation)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    /* FIXME: We are not running an AD yet */
+    return STATUS_OBJECT_NAME_NOT_FOUND;
 }
 
 
@@ -973,8 +3687,10 @@ NTSTATUS WINAPI LsarEnumerateTrustedDomainsEx(
     PLSAPR_TRUSTED_ENUM_BUFFER_EX EnumerationBuffer,
     DWORD PreferedMaximumLength)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    /* FIXME: We are not running an AD yet */
+    EnumerationBuffer->EntriesRead = 0;
+    EnumerationBuffer->EnumerationBuffer = NULL;
+    return STATUS_NO_MORE_ENTRIES;
 }
 
 
@@ -986,8 +3702,8 @@ NTSTATUS WINAPI LsarCreateTrustedDomainEx(
     ACCESS_MASK DesiredAccess,
     LSAPR_HANDLE *TrustedDomainHandle)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    /* FIXME: We are not running an AD yet */
+    return STATUS_DIRECTORY_SERVICE_REQUIRED;
 }
 
 
@@ -1004,7 +3720,7 @@ NTSTATUS WINAPI LsarSetPolicyReplicationHandle(
 NTSTATUS WINAPI LsarQueryDomainInformationPolicy(
     LSAPR_HANDLE PolicyHandle,
     POLICY_INFORMATION_CLASS InformationClass,
-    unsigned long *PolicyInformation)
+    PLSAPR_POLICY_DOMAIN_INFORMATION *PolicyInformation)
 {
     UNIMPLEMENTED;
     return STATUS_NOT_IMPLEMENTED;
@@ -1015,7 +3731,7 @@ NTSTATUS WINAPI LsarQueryDomainInformationPolicy(
 NTSTATUS WINAPI LsarSetDomainInformationPolicy(
     LSAPR_HANDLE PolicyHandle,
     POLICY_INFORMATION_CLASS InformationClass,
-    unsigned long PolicyInformation)
+    PLSAPR_POLICY_DOMAIN_INFORMATION PolicyInformation)
 {
     UNIMPLEMENTED;
     return STATUS_NOT_IMPLEMENTED;
@@ -1029,8 +3745,8 @@ NTSTATUS WINAPI LsarOpenTrustedDomainByName(
     ACCESS_MASK DesiredAccess,
     LSAPR_HANDLE *TrustedDomainHandle)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    /* FIXME: We are not running an AD yet */
+    return STATUS_OBJECT_NAME_NOT_FOUND;
 }
 
 
@@ -1054,8 +3770,27 @@ NTSTATUS WINAPI LsarLookupSids2(
     DWORD LookupOptions,
     DWORD ClientRevision)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    NTSTATUS Status;
+
+    TRACE("LsarLookupSids2(%p %p %p %p %d %p %lu %lu)\n",
+          PolicyHandle, SidEnumBuffer, ReferencedDomains, TranslatedNames,
+          LookupLevel, MappedCount, LookupOptions, ClientRevision);
+
+    TranslatedNames->Entries = SidEnumBuffer->Entries;
+    TranslatedNames->Names = NULL;
+    *ReferencedDomains = NULL;
+
+    /* FIXME: Fail, if there is an invalid SID in the SidEnumBuffer */
+
+    Status = LsapLookupSids(SidEnumBuffer,
+                            ReferencedDomains,
+                            TranslatedNames,
+                            LookupLevel,
+                            MappedCount,
+                            LookupOptions,
+                            ClientRevision);
+
+    return Status;
 }
 
 
@@ -1071,8 +3806,56 @@ NTSTATUS WINAPI LsarLookupNames2(
     DWORD LookupOptions,
     DWORD ClientRevision)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    LSAPR_TRANSLATED_SIDS_EX2 TranslatedSidsEx2;
+    ULONG i;
+    NTSTATUS Status;
+
+    TRACE("LsarLookupNames2(%p %lu %p %p %p %d %p %lu %lu)\n",
+          PolicyHandle, Count, Names, ReferencedDomains, TranslatedSids,
+          LookupLevel, MappedCount, LookupOptions, ClientRevision);
+
+    TranslatedSids->Entries = 0;
+    TranslatedSids->Sids = NULL;
+    *ReferencedDomains = NULL;
+
+    if (Count == 0)
+        return STATUS_NONE_MAPPED;
+
+    TranslatedSidsEx2.Entries = 0;
+    TranslatedSidsEx2.Sids = NULL;
+
+    Status = LsapLookupNames(Count,
+                             Names,
+                             ReferencedDomains,
+                             &TranslatedSidsEx2,
+                             LookupLevel,
+                             MappedCount,
+                             LookupOptions,
+                             ClientRevision);
+    if (!NT_SUCCESS(Status))
+        return Status;
+
+    TranslatedSids->Entries = TranslatedSidsEx2.Entries;
+    TranslatedSids->Sids = MIDL_user_allocate(TranslatedSids->Entries * sizeof(LSA_TRANSLATED_SID));
+    if (TranslatedSids->Sids == NULL)
+    {
+        MIDL_user_free(TranslatedSidsEx2.Sids);
+        MIDL_user_free(*ReferencedDomains);
+        *ReferencedDomains = NULL;
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    for (i = 0; i < TranslatedSidsEx2.Entries; i++)
+    {
+        TranslatedSids->Sids[i].Use = TranslatedSidsEx2.Sids[i].Use;
+        TranslatedSids->Sids[i].RelativeId = LsapGetRelativeIdFromSid(TranslatedSidsEx2.Sids[i].Sid);
+        TranslatedSids->Sids[i].DomainIndex = TranslatedSidsEx2.Sids[i].DomainIndex;
+        TranslatedSids->Sids[i].Flags = TranslatedSidsEx2.Sids[i].Flags;
+    }
+
+    MIDL_user_free(TranslatedSidsEx2.Sids);
+
+    return STATUS_SUCCESS;
 }
 
 
@@ -1084,14 +3867,14 @@ NTSTATUS WINAPI LsarCreateTrustedDomainEx2(
     ACCESS_MASK DesiredAccess,
     LSAPR_HANDLE *TrustedDomainHandle)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    /* FIXME: We are not running an AD yet */
+    return STATUS_DIRECTORY_SERVICE_REQUIRED;
 }
 
 
 /* Function 60 */
 NTSTATUS WINAPI CredrWrite(
-    handle_t hBinding)
+    PLSAPR_SERVER_NAME SystemName)
 {
     UNIMPLEMENTED;
     return STATUS_NOT_IMPLEMENTED;
@@ -1100,7 +3883,7 @@ NTSTATUS WINAPI CredrWrite(
 
 /* Function 61 */
 NTSTATUS WINAPI CredrRead(
-    handle_t hBinding)
+    PLSAPR_SERVER_NAME SystemName)
 {
     UNIMPLEMENTED;
     return STATUS_NOT_IMPLEMENTED;
@@ -1109,7 +3892,7 @@ NTSTATUS WINAPI CredrRead(
 
 /* Function 62 */
 NTSTATUS WINAPI CredrEnumerate(
-    handle_t hBinding)
+    PLSAPR_SERVER_NAME SystemName)
 {
     UNIMPLEMENTED;
     return STATUS_NOT_IMPLEMENTED;
@@ -1118,7 +3901,7 @@ NTSTATUS WINAPI CredrEnumerate(
 
 /* Function 63 */
 NTSTATUS WINAPI CredrWriteDomainCredentials(
-    handle_t hBinding)
+    PLSAPR_SERVER_NAME SystemName)
 {
     UNIMPLEMENTED;
     return STATUS_NOT_IMPLEMENTED;
@@ -1127,7 +3910,7 @@ NTSTATUS WINAPI CredrWriteDomainCredentials(
 
 /* Function 64 */
 NTSTATUS WINAPI CredrReadDomainCredentials(
-    handle_t hBinding)
+    PLSAPR_SERVER_NAME SystemName)
 {
     UNIMPLEMENTED;
     return STATUS_NOT_IMPLEMENTED;
@@ -1135,8 +3918,13 @@ NTSTATUS WINAPI CredrReadDomainCredentials(
 
 
 /* Function 65 */
-NTSTATUS WINAPI CredrDelete(
-    handle_t hBinding)
+NTSTATUS
+WINAPI
+CredrDelete(
+    PLSAPR_SERVER_NAME SystemName,
+    LPWSTR TargetName,
+    DWORD Type,
+    DWORD Flags)
 {
     UNIMPLEMENTED;
     return STATUS_NOT_IMPLEMENTED;
@@ -1144,8 +3932,13 @@ NTSTATUS WINAPI CredrDelete(
 
 
 /* Function 66 */
-NTSTATUS WINAPI CredrGetTargetInfo(
-    handle_t hBinding)
+NTSTATUS
+WINAPI
+CredrGetTargetInfo(
+    PLSAPR_SERVER_NAME SystemName,
+    LPWSTR TargetName,
+    DWORD Flags,
+    CREDPR_TARGET_INFORMATION *TargetInformation)
 {
     UNIMPLEMENTED;
     return STATUS_NOT_IMPLEMENTED;
@@ -1153,8 +3946,10 @@ NTSTATUS WINAPI CredrGetTargetInfo(
 
 
 /* Function 67 */
-NTSTATUS WINAPI CredrProfileLoaded(
-    handle_t hBinding)
+NTSTATUS
+WINAPI
+CredrProfileLoaded(
+    PLSAPR_SERVER_NAME SystemName)
 {
     UNIMPLEMENTED;
     return STATUS_NOT_IMPLEMENTED;
@@ -1173,132 +3968,39 @@ NTSTATUS WINAPI LsarLookupNames3(
     DWORD LookupOptions,
     DWORD ClientRevision)
 {
-    SID_IDENTIFIER_AUTHORITY IdentifierAuthority = {SECURITY_NT_AUTHORITY};
-    static const UNICODE_STRING DomainName = RTL_CONSTANT_STRING(L"DOMAIN");
-    PLSAPR_REFERENCED_DOMAIN_LIST DomainsBuffer = NULL;
-    PLSAPR_TRANSLATED_SID_EX2 SidsBuffer = NULL;
-    ULONG SidsBufferLength;
-    ULONG DomainSidLength;
-    ULONG AccountSidLength;
-    PSID DomainSid;
-    PSID AccountSid;
-    ULONG i;
     NTSTATUS Status;
 
-    TRACE("LsarLookupNames3(%p, %lu, %p, %p, %p, %d, %p, %lu, %lu)\n",
+    TRACE("LsarLookupNames3(%p %lu %p %p %p %d %p %lu %lu)\n",
           PolicyHandle, Count, Names, ReferencedDomains, TranslatedSids,
           LookupLevel, MappedCount, LookupOptions, ClientRevision);
 
-    if (Count == 0)
-        return STATUS_NONE_MAPPED;
-
-    TranslatedSids->Entries = Count;
+    TranslatedSids->Entries = 0;
     TranslatedSids->Sids = NULL;
     *ReferencedDomains = NULL;
 
-    SidsBufferLength = Count * sizeof(LSAPR_TRANSLATED_SID_EX2);
-    SidsBuffer = MIDL_user_allocate(SidsBufferLength);
-    if (SidsBuffer == NULL)
-        return STATUS_INSUFFICIENT_RESOURCES;
-
-    for (i = 0; i < Count; i++)
-    {
-        SidsBuffer[i].Use = SidTypeUser;
-        SidsBuffer[i].Sid = NULL;
-        SidsBuffer[i].DomainIndex = -1;
-        SidsBuffer[i].Flags = 0;
-    }
-
-    DomainsBuffer = MIDL_user_allocate(sizeof(LSAPR_REFERENCED_DOMAIN_LIST));
-    if (DomainsBuffer == NULL)
-    {
-        MIDL_user_free(SidsBuffer);
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    DomainsBuffer->Entries = Count;
-    DomainsBuffer->Domains = MIDL_user_allocate(Count * sizeof(LSA_TRUST_INFORMATION));
-    if (DomainsBuffer->Domains == NULL)
-    {
-        MIDL_user_free(DomainsBuffer);
-        MIDL_user_free(SidsBuffer);
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    Status = RtlAllocateAndInitializeSid(&IdentifierAuthority,
-                                         2,
-                                         SECURITY_BUILTIN_DOMAIN_RID,
-                                         DOMAIN_ALIAS_RID_ADMINS,
-                                         0, 0, 0, 0, 0, 0,
-                                         &DomainSid);
-    if (!NT_SUCCESS(Status))
-    {
-        MIDL_user_free(DomainsBuffer->Domains);
-        MIDL_user_free(DomainsBuffer);
-        MIDL_user_free(SidsBuffer);
-        return Status;
-    }
-
-    DomainSidLength = RtlLengthSid(DomainSid);
-
-    for (i = 0; i < Count; i++)
-    {
-        DomainsBuffer->Domains[i].Sid = MIDL_user_allocate(DomainSidLength);
-        RtlCopyMemory(DomainsBuffer->Domains[i].Sid,
-                      DomainSid,
-                      DomainSidLength);
-
-        DomainsBuffer->Domains[i].Name.Buffer = MIDL_user_allocate(DomainName.MaximumLength);
-        DomainsBuffer->Domains[i].Name.Length = DomainName.Length;
-        DomainsBuffer->Domains[i].Name.MaximumLength = DomainName.MaximumLength;
-        RtlCopyMemory(DomainsBuffer->Domains[i].Name.Buffer,
-                      DomainName.Buffer,
-                      DomainName.MaximumLength);
-    }
-
-    Status = RtlAllocateAndInitializeSid(&IdentifierAuthority,
-                                         3,
-                                         SECURITY_BUILTIN_DOMAIN_RID,
-                                         DOMAIN_ALIAS_RID_ADMINS,
-                                         DOMAIN_USER_RID_ADMIN,
-                                         0, 0, 0, 0, 0,
-                                         &AccountSid);
-    if (!NT_SUCCESS(Status))
-    {
-        MIDL_user_free(DomainsBuffer->Domains);
-        MIDL_user_free(DomainsBuffer);
-        MIDL_user_free(SidsBuffer);
-        return Status;
-    }
-
-    AccountSidLength = RtlLengthSid(AccountSid);
-
-    for (i = 0; i < Count; i++)
-    {
-        SidsBuffer[i].Use = SidTypeWellKnownGroup;
-        SidsBuffer[i].Sid = MIDL_user_allocate(AccountSidLength);
-
-        RtlCopyMemory(SidsBuffer[i].Sid,
-                      AccountSid,
-                      AccountSidLength);
-
-        SidsBuffer[i].DomainIndex = i;
-        SidsBuffer[i].Flags = 0;
-    }
-
-    *ReferencedDomains = DomainsBuffer;
-    *MappedCount = Count;
+    if (Count == 0)
+        return STATUS_NONE_MAPPED;
 
-    TranslatedSids->Entries = Count;
-    TranslatedSids->Sids = SidsBuffer;
+    Status = LsapLookupNames(Count,
+                             Names,
+                             ReferencedDomains,
+                             TranslatedSids,
+                             LookupLevel,
+                             MappedCount,
+                             LookupOptions,
+                             ClientRevision);
 
-    return STATUS_SUCCESS;
+    return Status;
 }
 
 
 /* Function 69 */
-NTSTATUS WINAPI CredrGetSessionTypes(
-    handle_t hBinding)
+NTSTATUS
+WINAPI
+CredrGetSessionTypes(
+    PLSAPR_SERVER_NAME SystemName,
+    DWORD MaximumPersistCount,
+    DWORD *MaximumPersist)
 {
     UNIMPLEMENTED;
     return STATUS_NOT_IMPLEMENTED;
@@ -1350,7 +4052,7 @@ NTSTATUS WINAPI LsarSetForestTrustInformation(
     PLSA_UNICODE_STRING TrustedDomainName,
     LSA_FOREST_TRUST_RECORD_TYPE HighestRecordType,
     PLSA_FOREST_TRUST_INFORMATION ForestTrustInfo,
-    BOOL CheckOnly,
+    BOOLEAN CheckOnly,
     PLSA_FOREST_TRUST_COLLISION_INFORMATION *CollisionInfo)
 {
     UNIMPLEMENTED;
@@ -1359,8 +4061,14 @@ NTSTATUS WINAPI LsarSetForestTrustInformation(
 
 
 /* Function 75 */
-NTSTATUS WINAPI CredrRename(
-    handle_t hBinding)
+NTSTATUS
+WINAPI
+CredrRename(
+    PLSAPR_SERVER_NAME SystemName,
+    LPWSTR OldTargetName,
+    LPWSTR NewTargetName,
+    DWORD Type,
+    DWORD Flags)
 {
     UNIMPLEMENTED;
     return STATUS_NOT_IMPLEMENTED;
@@ -1378,8 +4086,27 @@ NTSTATUS WINAPI LsarLookupSids3(
     DWORD LookupOptions,
     DWORD ClientRevision)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    NTSTATUS Status;
+
+    TRACE("LsarLookupSids3(%p %p %p %p %d %p %lu %lu)\n",
+          PolicyHandle, SidEnumBuffer, ReferencedDomains, TranslatedNames,
+          LookupLevel, MappedCount, LookupOptions, ClientRevision);
+
+    TranslatedNames->Entries = SidEnumBuffer->Entries;
+    TranslatedNames->Names = NULL;
+    *ReferencedDomains = NULL;
+
+    /* FIXME: Fail, if there is an invalid SID in the SidEnumBuffer */
+
+    Status = LsapLookupSids(SidEnumBuffer,
+                            ReferencedDomains,
+                            TranslatedNames,
+                            LookupLevel,
+                            MappedCount,
+                            LookupOptions,
+                            ClientRevision);
+
+    return Status;
 }
 
 
@@ -1395,14 +4122,38 @@ NTSTATUS WINAPI LsarLookupNames4(
     DWORD LookupOptions,
     DWORD ClientRevision)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    NTSTATUS Status;
+
+    TRACE("LsarLookupNames4(%p %lu %p %p %p %d %p %lu %lu)\n",
+          RpcHandle, Count, Names, ReferencedDomains, TranslatedSids,
+          LookupLevel, MappedCount, LookupOptions, ClientRevision);
+
+    TranslatedSids->Entries = 0;
+    TranslatedSids->Sids = NULL;
+    *ReferencedDomains = NULL;
+
+    if (Count == 0)
+        return STATUS_NONE_MAPPED;
+
+    Status = LsapLookupNames(Count,
+                             Names,
+                             ReferencedDomains,
+                             TranslatedSids,
+                             LookupLevel,
+                             MappedCount,
+                             LookupOptions,
+                             ClientRevision);
+
+    return Status;
 }
 
 
 /* Function 78 */
 NTSTATUS WINAPI LsarOpenPolicySce(
-    handle_t hBinding)
+    LPWSTR SystemName,
+    PLSAPR_OBJECT_ATTRIBUTES ObjectAttributes,
+    ACCESS_MASK DesiredAccess,
+    LSAPR_HANDLE *PolicyHandle)
 {
     UNIMPLEMENTED;
     return STATUS_NOT_IMPLEMENTED;
@@ -1435,121 +4186,4 @@ NTSTATUS WINAPI LsarAdtReportSecurityEvent(
     return STATUS_NOT_IMPLEMENTED;
 }
 
-
-/* Function 82 */
-NTSTATUS WINAPI CredrFindBestCredential(
-    handle_t hBinding)
-{
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
-
-
-/* Function 83 */
-NTSTATUS WINAPI LsarSetAuditPolicy(
-    handle_t hBinding)
-{
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
-
-
-/* Function 84 */
-NTSTATUS WINAPI LsarQueryAuditPolicy(
-    handle_t hBinding)
-{
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
-
-
-/* Function 85 */
-NTSTATUS WINAPI LsarEnumerateAuditPolicy(
-    handle_t hBinding)
-{
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
-
-
-/* Function 86 */
-NTSTATUS WINAPI LsarEnumerateAuditCategories(
-    handle_t hBinding)
-{
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
-
-
-/* Function 87 */
-NTSTATUS WINAPI LsarEnumerateAuditSubCategories(
-    handle_t hBinding)
-{
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
-
-
-/* Function 88 */
-NTSTATUS WINAPI LsarLookupAuditCategoryName(
-    handle_t hBinding)
-{
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
-
-
-/* Function 89 */
-NTSTATUS WINAPI LsarLookupAuditSubCategoryName(
-    handle_t hBinding)
-{
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
-
-
-/* Function 90 */
-NTSTATUS WINAPI LsarSetAuditSecurity(
-    handle_t hBinding)
-{
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
-
-
-/* Function 91 */
-NTSTATUS WINAPI LsarQueryAuditSecurity(
-    handle_t hBinding)
-{
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
-
-
-/* Function 92 */
-NTSTATUS WINAPI CredReadByTokenHandle(
-    handle_t hBinding)
-{
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
-
-
-/* Function 93 */
-NTSTATUS WINAPI CredrRestoreCredentials(
-    handle_t hBinding)
-{
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
-
-
-/* Function 94 */
-NTSTATUS WINAPI CredrBackupCredentials(
-    handle_t hBinding)
-{
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
-
 /* EOF */