/*
 * COPYRIGHT:       See COPYING in the top level directory
 * PROJECT:         Local Security Authority (LSA) Server
 * FILE:            reactos/dll/win32/lsasrv/lsarpc.h
 * PURPOSE:         RPC interface functions
 *
 * PROGRAMMERS:     Eric Kohl
 */

#include "lsasrv.h"

/* GLOBALS *****************************************************************/

static RTL_CRITICAL_SECTION PolicyHandleTableLock;

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 ***************************************************************/

NTSTATUS
LsarStartRpcServer(VOID)
{
    RPC_STATUS Status;
    DWORD dwError;
    HANDLE hEvent;

    RtlInitializeCriticalSection(&PolicyHandleTableLock);

    TRACE("LsarStartRpcServer() called\n");

    Status = RpcServerUseProtseqEpW(L"ncacn_np",
                                    RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
                                    L"\\pipe\\lsarpc",
                                    NULL);
    if (Status != RPC_S_OK)
    {
        WARN("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
        return I_RpcMapWin32Status(Status);
    }

    Status = RpcServerRegisterIf(lsarpc_v0_0_s_ifspec,
                                 NULL,
                                 NULL);
    if (Status != RPC_S_OK)
    {
        WARN("RpcServerRegisterIf() failed (Status %lx)\n", Status);
        return I_RpcMapWin32Status(Status);
    }

    DsSetupInit();

    Status = RpcServerListen(1, 20, TRUE);
    if (Status != RPC_S_OK)
    {
        WARN("RpcServerListen() failed (Status %lx)\n", Status);
        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;
}


void
__RPC_USER
LSAPR_HANDLE_rundown(
    LSAPR_HANDLE hHandle)
{
}


/* Function 0 */
NTSTATUS
WINAPI
LsarClose(
    LSAPR_HANDLE *ObjectHandle)
{
    PLSA_DB_OBJECT DbObject;
    NTSTATUS Status = STATUS_SUCCESS;

    TRACE("LsarClose(%p)\n", ObjectHandle);

//    RtlEnterCriticalSection(&PolicyHandleTableLock);

    Status = LsapValidateDbObject(*ObjectHandle,
                                  LsaDbIgnoreObject,
                                  0,
                                  &DbObject);
    if (Status == STATUS_SUCCESS)
    {
        Status = LsapCloseDbObject(DbObject);
        *ObjectHandle = NULL;
    }

//    RtlLeaveCriticalSection(&PolicyHandleTableLock);

    return Status;
}


/* Function 1 */
NTSTATUS
WINAPI
LsarDelete(
    LSAPR_HANDLE ObjectHandle)
{
    TRACE("LsarDelete(%p)\n", ObjectHandle);

    return LsarDeleteObject(&ObjectHandle);
}


/* Function 2 */
NTSTATUS
WINAPI
LsarEnumeratePrivileges(
    LSAPR_HANDLE PolicyHandle,
    DWORD *EnumerationContext,
    PLSAPR_PRIVILEGE_ENUM_BUFFER EnumerationBuffer,
    DWORD PreferedMaximumLength)
{
    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);
}


/* Function 3 */
NTSTATUS
WINAPI
LsarQuerySecurityObject(
    LSAPR_HANDLE ObjectHandle,
    SECURITY_INFORMATION SecurityInformation,
    PLSAPR_SR_SECURITY_DESCRIPTOR *SecurityDescriptor)
{
    PLSA_DB_OBJECT DbObject = NULL;
    PISECURITY_DESCRIPTOR_RELATIVE 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))
        RelativeSd->Owner = 0;

    if (!(SecurityInformation & GROUP_SECURITY_INFORMATION))
        RelativeSd->Group = 0;

    if (!(SecurityInformation & DACL_SECURITY_INFORMATION))
        RelativeSd->Control &= ~SE_DACL_PRESENT;

    if (!(SecurityInformation & SACL_SECURITY_INFORMATION))
        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 = ResultSdSize;
    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;
}


/* Function 4 */
NTSTATUS
WINAPI
LsarSetSecurityObject(
    LSAPR_HANDLE ObjectHandle,
    SECURITY_INFORMATION SecurityInformation,
    PLSAPR_SR_SECURITY_DESCRIPTOR SecurityDescriptor)
{
    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;
}


/* Function 5 */
NTSTATUS
WINAPI
LsarChangePassword(
    handle_t IDL_handle,
    PRPC_UNICODE_STRING String1,
    PRPC_UNICODE_STRING String2,
    PRPC_UNICODE_STRING String3,
    PRPC_UNICODE_STRING String4,
    PRPC_UNICODE_STRING String5)
{
    /* Deprecated */
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 6 */
NTSTATUS
WINAPI
LsarOpenPolicy(
    LPWSTR SystemName,
    PLSAPR_OBJECT_ATTRIBUTES ObjectAttributes,
    ACCESS_MASK DesiredAccess,
    LSAPR_HANDLE *PolicyHandle)
{
    PLSA_DB_OBJECT PolicyObject;
    NTSTATUS Status;

    TRACE("LsarOpenPolicy(%S %p %lx %p)\n",
          SystemName, ObjectAttributes, DesiredAccess, PolicyHandle);

    RtlEnterCriticalSection(&PolicyHandleTableLock);

    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;
}


/* Function 7 */
NTSTATUS
WINAPI
LsarQueryInformationPolicy(
    LSAPR_HANDLE PolicyHandle,
    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",
          PolicyHandle, InformationClass, PolicyInformation);

    if (PolicyInformation)
    {
        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,
                                  DesiredAccess,
                                  &PolicyObject);
    if (!NT_SUCCESS(Status))
        return Status;

    switch (InformationClass)
    {
        case PolicyAuditLogInformation:      /* 1 */
            Status = LsarQueryAuditLog(PolicyObject,
                                       PolicyInformation);
            break;

        case PolicyAuditEventsInformation:   /* 2 */
            Status = LsarQueryAuditEvents(PolicyObject,
                                          PolicyInformation);
            break;

        case PolicyPrimaryDomainInformation: /* 3 */
            Status = LsarQueryPrimaryDomain(PolicyObject,
                                            PolicyInformation);
            break;

        case PolicyPdAccountInformation:     /* 4 */
            Status = LsarQueryPdAccount(PolicyObject,
                                        PolicyInformation);
            break;

        case PolicyAccountDomainInformation: /* 5 */
            Status = LsarQueryAccountDomain(PolicyObject,
                                            PolicyInformation);
            break;

        case PolicyLsaServerRoleInformation: /* 6 */
            Status = LsarQueryServerRole(PolicyObject,
                                         PolicyInformation);
            break;

        case PolicyReplicaSourceInformation: /* 7 */
            Status = LsarQueryReplicaSource(PolicyObject,
                                            PolicyInformation);
            break;

        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 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;
}


/* Function 8 */
NTSTATUS
WINAPI
LsarSetInformationPolicy(
    LSAPR_HANDLE PolicyHandle,
    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",
          PolicyHandle, InformationClass, PolicyInformation);

    if (PolicyInformation)
    {
        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,
                                  DesiredAccess,
                                  &PolicyObject);
    if (!NT_SUCCESS(Status))
        return Status;

    switch (InformationClass)
    {
        case PolicyAuditLogInformation:      /* 1 */
            Status = LsarSetAuditLog(PolicyObject,
                                     (PPOLICY_AUDIT_LOG_INFO)PolicyInformation);
            break;

        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: /* 5 */
            Status = LsarSetAccountDomain(PolicyObject,
                                          (PLSAPR_POLICY_ACCOUNT_DOM_INFO)PolicyInformation);
            if (NT_SUCCESS(Status))
                LsapNotifyPolicyChange(PolicyNotifyAccountDomainInformation);
            break;

        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 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:
            Status = STATUS_INVALID_PARAMETER;
            break;
    }

    return Status;
}


/* Function 9 */
NTSTATUS
WINAPI
LsarClearAuditLog(
    LSAPR_HANDLE ObjectHandle)
{
    /* Deprecated */
    return STATUS_NOT_IMPLEMENTED;
}


NTSTATUS
LsarpCreateAccount(
    PLSA_DB_OBJECT PolicyObject,
    PRPC_SID AccountSid,
    ACCESS_MASK DesiredAccess,
    PLSA_DB_OBJECT *AccountObject)
{
    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;
    }

    /* 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;
    }

    /* 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);

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)
{
    /* Fail, if we are not a domain controller */
    if (LsapProductType != NtProductLanManNt)
        return STATUS_DIRECTORY_SERVICE_REQUIRED;

    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 13 */
NTSTATUS
WINAPI
LsarEnumerateTrustedDomains(
    LSAPR_HANDLE PolicyHandle,
    DWORD *EnumerationContext,
    PLSAPR_TRUSTED_ENUM_BUFFER EnumerationBuffer,
    DWORD PreferedMaximumLength)
{
    /* FIXME: We are not running an AD yet */
    EnumerationBuffer->EntriesRead = 0;
    EnumerationBuffer->Information = NULL;
    return STATUS_NO_MORE_ENTRIES;
}


/* Function 14 */
NTSTATUS
WINAPI
LsarLookupNames(
    LSAPR_HANDLE PolicyHandle,
    DWORD Count,
    PRPC_UNICODE_STRING Names,
    PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains,
    PLSAPR_TRANSLATED_SIDS TranslatedSids,
    LSAP_LOOKUP_LEVEL LookupLevel,
    DWORD *MappedCount)
{
    LSAPR_TRANSLATED_SIDS_EX2 TranslatedSidsEx2;
    ULONG i;
    NTSTATUS Status;

    TRACE("LsarLookupNames(%p %lu %p %p %p %d %p)\n",
          PolicyHandle, Count, Names, ReferencedDomains, TranslatedSids,
          LookupLevel, MappedCount);

    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,
                             0,
                             0);
    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;
    }

    MIDL_user_free(TranslatedSidsEx2.Sids);

    return STATUS_SUCCESS;
}


/* Function 15 */
NTSTATUS
WINAPI
LsarLookupSids(
    LSAPR_HANDLE PolicyHandle,
    PLSAPR_SID_ENUM_BUFFER SidEnumBuffer,
    PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains,
    PLSAPR_TRANSLATED_NAMES TranslatedNames,
    LSAP_LOOKUP_LEVEL LookupLevel,
    DWORD *MappedCount)
{
    LSAPR_TRANSLATED_NAMES_EX TranslatedNamesEx;
    ULONG i;
    NTSTATUS Status;

    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;

    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;
    }

    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);

    /* Validate the PolicyHandle */
    Status = LsapValidateDbObject(PolicyHandle,
                                  LsaDbPolicyObject,
                                  POLICY_CREATE_SECRET,
                                  &PolicyObject);
    if (!NT_SUCCESS(Status))
    {
        ERR("LsapValidateDbObject returned 0x%08lx\n", Status);
        return Status;
    }

    /* Get the current time */
    Status = NtQuerySystemTime(&Time);
    if (!NT_SUCCESS(Status))
    {
        ERR("NtQuerySystemTime failed (Status 0x%08lx)\n", Status);
        goto done;
    }

    /* Create a security descriptor for the secret */
    Status = LsapCreateSecretSd(&SecretSd,
                                &SecretSdSize);
    if (!NT_SUCCESS(Status))
    {
        ERR("LsapCreateAccountSd returned 0x%08lx\n", Status);
        return Status;
    }

    /* Create the Secret object */
    Status = LsapCreateDbObject(PolicyObject,
                                L"Secrets",
                                SecretName->Buffer,
                                LsaDbSecretObject,
                                DesiredAccess,
                                PolicyObject->Trusted,
                                &SecretObject);
    if (!NT_SUCCESS(Status))
    {
        ERR("LsapCreateDbObject failed (Status 0x%08lx)\n", Status);
        goto done;
    }

    /* 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;
    }

    /* 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;
    }

    /* Set the SecDesc attribute */
    Status = LsapSetObjectAttribute(SecretObject,
                                    L"SecDesc",
                                    SecretSd,
                                    SecretSdSize);

done:
    if (SecretSd != NULL)
        RtlFreeHeap(RtlGetProcessHeap(), 0, SecretSd);

    if (!NT_SUCCESS(Status))
    {
        if (SecretObject != NULL)
            LsapCloseDbObject(SecretObject);
    }
    else
    {
        *SecretHandle = (LSAPR_HANDLE)SecretObject;
    }

    return STATUS_SUCCESS;
}


static
NTSTATUS
LsarpOpenAccount(
    IN PLSA_DB_OBJECT PolicyObject,
    IN PRPC_SID AccountSid,
    IN ACCESS_MASK DesiredAccess,
    OUT PLSA_DB_OBJECT *AccountObject)
{
    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;
}


/* Function 17 */
NTSTATUS
WINAPI
LsarOpenAccount(
    LSAPR_HANDLE PolicyHandle,
    PRPC_SID AccountSid,
    ACCESS_MASK DesiredAccess,
    LSAPR_HANDLE *AccountHandle)
{
    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);
}


/* Function 18 */
NTSTATUS
WINAPI
LsarEnumeratePrivilegesAccount(
    LSAPR_HANDLE AccountHandle,
    PLSAPR_PRIVILEGE_SET *Privileges)
{
    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;
}


/* Function 19 */
NTSTATUS
WINAPI
LsarAddPrivilegesToAccount(
    LSAPR_HANDLE AccountHandle,
    PLSAPR_PRIVILEGE_SET Privileges)
{
    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,
    BOOLEAN AllPrivileges,
    PLSAPR_PRIVILEGE_SET Privileges)
{
    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;
}


/* Function 21 */
NTSTATUS
WINAPI
LsarGetQuotasForAccount(
    LSAPR_HANDLE AccountHandle,
    PQUOTA_LIMITS QuotaLimits)
{
    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;
}


/* Function 22 */
NTSTATUS
WINAPI
LsarSetQuotasForAccount(
    LSAPR_HANDLE AccountHandle,
    PQUOTA_LIMITS QuotaLimits)
{
    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;
}


/* Function 23 */
NTSTATUS
WINAPI
LsarGetSystemAccessAccount(
    LSAPR_HANDLE AccountHandle,
    ACCESS_MASK *SystemAccess)
{
    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;
}


/* Function 24 */
NTSTATUS
WINAPI
LsarSetSystemAccessAccount(
    LSAPR_HANDLE AccountHandle,
    ACCESS_MASK SystemAccess)
{
    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;
}


/* Function 25 */
NTSTATUS
WINAPI
LsarOpenTrustedDomain(
    LSAPR_HANDLE PolicyHandle,
    PRPC_SID TrustedDomainSid,
    ACCESS_MASK DesiredAccess,
    LSAPR_HANDLE *TrustedDomainHandle)
{
    /* Fail, if we are not a domain controller */
    if (LsapProductType != NtProductLanManNt)
        return STATUS_DIRECTORY_SERVICE_REQUIRED;

    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 26 */
NTSTATUS
WINAPI
LsarQueryInfoTrustedDomain(
    LSAPR_HANDLE TrustedDomainHandle,
    TRUSTED_INFORMATION_CLASS InformationClass,
    PLSAPR_TRUSTED_DOMAIN_INFO *TrustedDomainInformation)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 27 */
NTSTATUS
WINAPI
LsarSetInformationTrustedDomain(
    LSAPR_HANDLE TrustedDomainHandle,
    TRUSTED_INFORMATION_CLASS InformationClass,
    PLSAPR_TRUSTED_DOMAIN_INFO TrustedDomainInformation)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 28 */
NTSTATUS
WINAPI
LsarOpenSecret(
    LSAPR_HANDLE PolicyHandle,
    PRPC_UNICODE_STRING SecretName,
    ACCESS_MASK DesiredAccess,
    LSAPR_HANDLE *SecretHandle)
{
    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,
    PLSAPR_CR_CIPHER_VALUE EncryptedCurrentValue,
    PLSAPR_CR_CIPHER_VALUE EncryptedOldValue)
{
    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;
}


/* Function 30 */
NTSTATUS
WINAPI
LsarQuerySecret(
    LSAPR_HANDLE SecretHandle,
    PLSAPR_CR_CIPHER_VALUE *EncryptedCurrentValue,
    PLARGE_INTEGER CurrentValueSetTime,
    PLSAPR_CR_CIPHER_VALUE *EncryptedOldValue,
    PLARGE_INTEGER OldValueSetTime)
{
    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;
}


/* Function 31 */
NTSTATUS
WINAPI
LsarLookupPrivilegeValue(
    LSAPR_HANDLE PolicyHandle,
    PRPC_UNICODE_STRING Name,
    PLUID Value)
{
    PLUID pValue;
    NTSTATUS Status;

    TRACE("LsarLookupPrivilegeValue(%p, %wZ, %p)\n",
          PolicyHandle, Name, Value);

    Status = LsapValidateDbObject(PolicyHandle,
                                  LsaDbPolicyObject,
                                  POLICY_LOOKUP_NAMES,
                                  NULL);
    if (!NT_SUCCESS(Status))
    {
        ERR("Invalid handle (Status %lx)\n", Status);
        return Status;
    }

    TRACE("Privilege: %wZ\n", Name);

    pValue = LsarpLookupPrivilegeValue(Name);
    if (pValue == NULL)
        return STATUS_NO_SUCH_PRIVILEGE;

    RtlCopyLuid(Value, pValue);

    return STATUS_SUCCESS;
}


/* Function 32 */
NTSTATUS
WINAPI
LsarLookupPrivilegeName(
    LSAPR_HANDLE PolicyHandle,
    PLUID Value,
    PRPC_UNICODE_STRING *Name)
{
    NTSTATUS Status;

    TRACE("LsarLookupPrivilegeName(%p, %p, %p)\n",
          PolicyHandle, Value, Name);

    Status = LsapValidateDbObject(PolicyHandle,
                                  LsaDbPolicyObject,
                                  POLICY_LOOKUP_NAMES,
                                  NULL);
    if (!NT_SUCCESS(Status))
    {
        ERR("Invalid handle\n");
        return Status;
    }

    Status = LsarpLookupPrivilegeName(Value,
                                      Name);

    return Status;
}


/* Function 33 */
NTSTATUS
WINAPI
LsarLookupPrivilegeDisplayName(
    LSAPR_HANDLE PolicyHandle,
    PRPC_UNICODE_STRING Name,
    USHORT ClientLanguage,
    USHORT ClientSystemDefaultLanguage,
    PRPC_UNICODE_STRING *DisplayName,
    USHORT *LanguageReturned)
{
    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;
}


/* Function 34 */
NTSTATUS
WINAPI
LsarDeleteObject(
    LSAPR_HANDLE *ObjectHandle)
{
    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;
}


/* Function 35 */
NTSTATUS
WINAPI
LsarEnumerateAccountsWithUserRight(
    LSAPR_HANDLE PolicyHandle,
    PRPC_UNICODE_STRING UserRight,
    PLSAPR_ACCOUNT_ENUM_BUFFER EnumerationBuffer)
{
    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
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;

    TRACE("LsarEnumerateAccountRights(%p %p %p)\n",
          PolicyHandle, AccountSid, UserRights);

    /* Open the account */
    Status = LsarOpenAccount(PolicyHandle,
                             AccountSid,
                             ACCOUNT_VIEW,
                             &AccountHandle);
    if (!NT_SUCCESS(Status))
    {
        WARN("LsarOpenAccount returned 0x%08lx\n", Status);
        return Status;
    }

    /* 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;
}


/* Function 37 */
NTSTATUS
WINAPI
LsarAddAccountRights(
    LSAPR_HANDLE PolicyHandle,
    PRPC_SID AccountSid,
    PLSAPR_USER_RIGHT_SET UserRights)
{
    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;
}


/* Function 38 */
NTSTATUS
WINAPI
LsarRemoveAccountRights(
    LSAPR_HANDLE PolicyHandle,
    PRPC_SID AccountSid,
    BOOLEAN AllRights,
    PLSAPR_USER_RIGHT_SET UserRights)
{
    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;
}


/* Function 39 */
NTSTATUS
WINAPI
LsarQueryTrustedDomainInfo(
    LSAPR_HANDLE PolicyHandle,
    PRPC_SID TrustedDomainSid,
    TRUSTED_INFORMATION_CLASS InformationClass,
    PLSAPR_TRUSTED_DOMAIN_INFO *TrustedDomainInformation)
{
    /* Fail, if we are not a domain controller */
    if (LsapProductType != NtProductLanManNt)
        return STATUS_DIRECTORY_SERVICE_REQUIRED;

    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 40 */
NTSTATUS
WINAPI
LsarSetTrustedDomainInfo(
    LSAPR_HANDLE PolicyHandle,
    PRPC_SID TrustedDomainSid,
    TRUSTED_INFORMATION_CLASS InformationClass,
    PLSAPR_TRUSTED_DOMAIN_INFO TrustedDomainInformation)
{
    /* Fail, if we are not a domain controller */
    if (LsapProductType != NtProductLanManNt)
        return STATUS_DIRECTORY_SERVICE_REQUIRED;

    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 41 */
NTSTATUS
WINAPI
LsarDeleteTrustedDomain(
    LSAPR_HANDLE PolicyHandle,
    PRPC_SID TrustedDomainSid)
{
    /* Fail, if we are not a domain controller */
    if (LsapProductType != NtProductLanManNt)
        return STATUS_DIRECTORY_SERVICE_REQUIRED;

    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 42 */
NTSTATUS
WINAPI
LsarStorePrivateData(
    LSAPR_HANDLE PolicyHandle,
    PRPC_UNICODE_STRING KeyName,
    PLSAPR_CR_CIPHER_VALUE EncryptedData)
{
    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)
{
    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;
}


/* Function 44 */
NTSTATUS
WINAPI
LsarOpenPolicy2(
    LPWSTR SystemName,
    PLSAPR_OBJECT_ATTRIBUTES ObjectAttributes,
    ACCESS_MASK DesiredAccess,
    LSAPR_HANDLE *PolicyHandle)
{
    return LsarOpenPolicy(SystemName,
                          ObjectAttributes,
                          DesiredAccess,
                          PolicyHandle);
}


/* Function 45 */
NTSTATUS
WINAPI
LsarGetUserName(
    LPWSTR SystemName,
    PRPC_UNICODE_STRING *UserName,
    PRPC_UNICODE_STRING *DomainName)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 46 */
NTSTATUS
WINAPI
LsarQueryInformationPolicy2(
    LSAPR_HANDLE PolicyHandle,
    POLICY_INFORMATION_CLASS InformationClass,
    PLSAPR_POLICY_INFORMATION *PolicyInformation)
{
    return LsarQueryInformationPolicy(PolicyHandle,
                                      InformationClass,
                                      PolicyInformation);
}


/* Function 47 */
NTSTATUS
WINAPI
LsarSetInformationPolicy2(
    LSAPR_HANDLE PolicyHandle,
    POLICY_INFORMATION_CLASS InformationClass,
    PLSAPR_POLICY_INFORMATION PolicyInformation)
{
    return LsarSetInformationPolicy(PolicyHandle,
                                    InformationClass,
                                    PolicyInformation);
}


/* Function 48 */
NTSTATUS
WINAPI
LsarQueryTrustedDomainInfoByName(
    LSAPR_HANDLE PolicyHandle,
    PRPC_UNICODE_STRING TrustedDomainName,
    POLICY_INFORMATION_CLASS InformationClass,
    PLSAPR_TRUSTED_DOMAIN_INFO *PolicyInformation)
{
    /* Fail, if we are not a domain controller */
    if (LsapProductType != NtProductLanManNt)
        return STATUS_DIRECTORY_SERVICE_REQUIRED;

    /* FIXME: We are not running an AD yet */
    return STATUS_OBJECT_NAME_NOT_FOUND;
}


/* Function 49 */
NTSTATUS
WINAPI
LsarSetTrustedDomainInfoByName(
    LSAPR_HANDLE PolicyHandle,
    PRPC_UNICODE_STRING TrustedDomainName,
    POLICY_INFORMATION_CLASS InformationClass,
    PLSAPR_TRUSTED_DOMAIN_INFO PolicyInformation)
{
    /* Fail, if we are not a domain controller */
    if (LsapProductType != NtProductLanManNt)
        return STATUS_DIRECTORY_SERVICE_REQUIRED;

    /* FIXME: We are not running an AD yet */
    return STATUS_OBJECT_NAME_NOT_FOUND;
}


/* Function 50 */
NTSTATUS
WINAPI
LsarEnumerateTrustedDomainsEx(
    LSAPR_HANDLE PolicyHandle,
    DWORD *EnumerationContext,
    PLSAPR_TRUSTED_ENUM_BUFFER_EX EnumerationBuffer,
    DWORD PreferedMaximumLength)
{
    /* Fail, if we are not a domain controller */
    if (LsapProductType != NtProductLanManNt)
        return STATUS_DIRECTORY_SERVICE_REQUIRED;

    /* FIXME: We are not running an AD yet */
    EnumerationBuffer->EntriesRead = 0;
    EnumerationBuffer->EnumerationBuffer = NULL;
    return STATUS_NO_MORE_ENTRIES;
}


/* Function 51 */
NTSTATUS
WINAPI
LsarCreateTrustedDomainEx(
    LSAPR_HANDLE PolicyHandle,
    PLSAPR_TRUSTED_DOMAIN_INFORMATION_EX TrustedDomainInformation,
    PLSAPR_TRUSTED_DOMAIN_AUTH_INFORMATION AuthentificationInformation,
    ACCESS_MASK DesiredAccess,
    LSAPR_HANDLE *TrustedDomainHandle)
{
    /* Fail, if we are not a domain controller */
    if (LsapProductType != NtProductLanManNt)
        return STATUS_DIRECTORY_SERVICE_REQUIRED;

    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 52 */
NTSTATUS
WINAPI
LsarSetPolicyReplicationHandle(
    PLSAPR_HANDLE PolicyHandle)
{
    /* Deprecated */
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 53 */
NTSTATUS
WINAPI
LsarQueryDomainInformationPolicy(
    LSAPR_HANDLE PolicyHandle,
    POLICY_INFORMATION_CLASS InformationClass,
    PLSAPR_POLICY_DOMAIN_INFORMATION *PolicyInformation)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 54 */
NTSTATUS
WINAPI
LsarSetDomainInformationPolicy(
    LSAPR_HANDLE PolicyHandle,
    POLICY_INFORMATION_CLASS InformationClass,
    PLSAPR_POLICY_DOMAIN_INFORMATION PolicyInformation)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 55 */
NTSTATUS
WINAPI
LsarOpenTrustedDomainByName(
    LSAPR_HANDLE PolicyHandle,
    PRPC_UNICODE_STRING TrustedDomainName,
    ACCESS_MASK DesiredAccess,
    LSAPR_HANDLE *TrustedDomainHandle)
{
    /* Fail, if we are not a domain controller */
    if (LsapProductType != NtProductLanManNt)
        return STATUS_DIRECTORY_SERVICE_REQUIRED;

    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 56 */
NTSTATUS
WINAPI
LsarTestCall(
    handle_t hBinding)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 57 */
NTSTATUS
WINAPI
LsarLookupSids2(
    LSAPR_HANDLE PolicyHandle,
    PLSAPR_SID_ENUM_BUFFER SidEnumBuffer,
    PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains,
    PLSAPR_TRANSLATED_NAMES_EX TranslatedNames,
    LSAP_LOOKUP_LEVEL LookupLevel,
    DWORD *MappedCount,
    DWORD LookupOptions,
    DWORD ClientRevision)
{
    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;
}


/* Function 58 */
NTSTATUS
WINAPI
LsarLookupNames2(
    LSAPR_HANDLE PolicyHandle,
    DWORD Count,
    PRPC_UNICODE_STRING Names,
    PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains,
    PLSAPR_TRANSLATED_SIDS_EX TranslatedSids,
    LSAP_LOOKUP_LEVEL LookupLevel,
    DWORD *MappedCount,
    DWORD LookupOptions,
    DWORD ClientRevision)
{
    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;
}


/* Function 59 */
NTSTATUS
WINAPI
LsarCreateTrustedDomainEx2(
    LSAPR_HANDLE PolicyHandle,
    PLSAPR_TRUSTED_DOMAIN_INFORMATION_EX TrustedDomainInformation,
    PLSAPR_TRUSTED_DOMAIN_AUTH_INFORMATION_INTERNAL AuthentificationInformation,
    ACCESS_MASK DesiredAccess,
    LSAPR_HANDLE *TrustedDomainHandle)
{
    /* Fail, if we are not a domain controller */
    if (LsapProductType != NtProductLanManNt)
        return STATUS_DIRECTORY_SERVICE_REQUIRED;

    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 60 */
NTSTATUS
WINAPI
CredrWrite(
    PLSAPR_SERVER_NAME SystemName)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 61 */
NTSTATUS
WINAPI
CredrRead(
    PLSAPR_SERVER_NAME SystemName)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 62 */
NTSTATUS
WINAPI
CredrEnumerate(
    PLSAPR_SERVER_NAME SystemName)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 63 */
NTSTATUS
WINAPI
CredrWriteDomainCredentials(
    PLSAPR_SERVER_NAME SystemName)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 64 */
NTSTATUS
WINAPI
CredrReadDomainCredentials(
    PLSAPR_SERVER_NAME SystemName)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 65 */
NTSTATUS
WINAPI
CredrDelete(
    PLSAPR_SERVER_NAME SystemName,
    LPWSTR TargetName,
    DWORD Type,
    DWORD Flags)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 66 */
NTSTATUS
WINAPI
CredrGetTargetInfo(
    PLSAPR_SERVER_NAME SystemName,
    LPWSTR TargetName,
    DWORD Flags,
    CREDPR_TARGET_INFORMATION *TargetInformation)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 67 */
NTSTATUS
WINAPI
CredrProfileLoaded(
    PLSAPR_SERVER_NAME SystemName)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 68 */
NTSTATUS
WINAPI
LsarLookupNames3(
    LSAPR_HANDLE PolicyHandle,
    DWORD Count,
    PRPC_UNICODE_STRING Names,
    PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains,
    PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
    LSAP_LOOKUP_LEVEL LookupLevel,
    DWORD *MappedCount,
    DWORD LookupOptions,
    DWORD ClientRevision)
{
    NTSTATUS Status;

    TRACE("LsarLookupNames3(%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;

    Status = LsapLookupNames(Count,
                             Names,
                             ReferencedDomains,
                             TranslatedSids,
                             LookupLevel,
                             MappedCount,
                             LookupOptions,
                             ClientRevision);

    return Status;
}


/* Function 69 */
NTSTATUS
WINAPI
CredrGetSessionTypes(
    PLSAPR_SERVER_NAME SystemName,
    DWORD MaximumPersistCount,
    DWORD *MaximumPersist)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 70 */
NTSTATUS
WINAPI
LsarRegisterAuditEvent(
    handle_t hBinding)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 71 */
NTSTATUS
WINAPI
LsarGenAuditEvent(
    handle_t hBinding)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 72 */
NTSTATUS
WINAPI
LsarUnregisterAuditEvent(
    handle_t hBinding)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 73 */
NTSTATUS
WINAPI
LsarQueryForestTrustInformation(
    LSAPR_HANDLE PolicyHandle,
    PLSA_UNICODE_STRING TrustedDomainName,
    LSA_FOREST_TRUST_RECORD_TYPE HighestRecordType,
    PLSA_FOREST_TRUST_INFORMATION *ForestTrustInfo)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 74 */
NTSTATUS
WINAPI
LsarSetForestTrustInformation(
    LSAPR_HANDLE PolicyHandle,
    PLSA_UNICODE_STRING TrustedDomainName,
    LSA_FOREST_TRUST_RECORD_TYPE HighestRecordType,
    PLSA_FOREST_TRUST_INFORMATION ForestTrustInfo,
    BOOLEAN CheckOnly,
    PLSA_FOREST_TRUST_COLLISION_INFORMATION *CollisionInfo)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 75 */
NTSTATUS
WINAPI
CredrRename(
    PLSAPR_SERVER_NAME SystemName,
    LPWSTR OldTargetName,
    LPWSTR NewTargetName,
    DWORD Type,
    DWORD Flags)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 76 */
NTSTATUS
WINAPI
LsarLookupSids3(
    LSAPR_HANDLE PolicyHandle,
    PLSAPR_SID_ENUM_BUFFER SidEnumBuffer,
    PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains,
    PLSAPR_TRANSLATED_NAMES_EX TranslatedNames,
    LSAP_LOOKUP_LEVEL LookupLevel,
    DWORD *MappedCount,
    DWORD LookupOptions,
    DWORD ClientRevision)
{
    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;
}


/* Function 77 */
NTSTATUS
WINAPI
LsarLookupNames4(
    handle_t RpcHandle,
    DWORD Count,
    PRPC_UNICODE_STRING Names,
    PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains,
    PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
    LSAP_LOOKUP_LEVEL LookupLevel,
    DWORD *MappedCount,
    DWORD LookupOptions,
    DWORD ClientRevision)
{
    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(
    LPWSTR SystemName,
    PLSAPR_OBJECT_ATTRIBUTES ObjectAttributes,
    ACCESS_MASK DesiredAccess,
    LSAPR_HANDLE *PolicyHandle)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 79 */
NTSTATUS
WINAPI
LsarAdtRegisterSecurityEventSource(
    handle_t hBinding)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 80 */
NTSTATUS
WINAPI
LsarAdtUnregisterSecurityEventSource(
    handle_t hBinding)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}


/* Function 81 */
NTSTATUS
WINAPI
LsarAdtReportSecurityEvent(
    handle_t hBinding)
{
    UNIMPLEMENTED;
    return STATUS_NOT_IMPLEMENTED;
}

/* EOF */
