/*
 * COPYRIGHT:       See COPYING in the top level directory
 * PROJECT:         Local Security Authority (LSA) Server
 * FILE:            reactos/dll/win32/lsasrv/lookup.c
 * PURPOSE:         Sid / Name lookup functions
 *
 * PROGRAMMERS:     Eric Kohl
 */
#include "lsasrv.h"

WINE_DEFAULT_DEBUG_CHANNEL(lsasrv);

typedef wchar_t *PSAMPR_SERVER_NAME;
typedef void *SAMPR_HANDLE;

typedef struct _SAMPR_RETURNED_USTRING_ARRAY
{
    unsigned long Count;
    PRPC_UNICODE_STRING Element;
} SAMPR_RETURNED_USTRING_ARRAY, *PSAMPR_RETURNED_USTRING_ARRAY;

typedef struct _SAMPR_ULONG_ARRAY
{
    unsigned long Count;
    unsigned long *Element;
} SAMPR_ULONG_ARRAY, *PSAMPR_ULONG_ARRAY;


VOID
NTAPI
SamIFree_SAMPR_RETURNED_USTRING_ARRAY(PSAMPR_RETURNED_USTRING_ARRAY Ptr);

VOID
NTAPI
SamIFree_SAMPR_ULONG_ARRAY(PSAMPR_ULONG_ARRAY Ptr);

NTSTATUS
NTAPI
SamrConnect(IN PSAMPR_SERVER_NAME ServerName,
            OUT SAMPR_HANDLE *ServerHandle,
            IN ACCESS_MASK DesiredAccess);

NTSTATUS
NTAPI
SamrCloseHandle(IN OUT SAMPR_HANDLE *SamHandle);

NTSTATUS
NTAPI
SamrOpenDomain(IN SAMPR_HANDLE ServerHandle,
               IN ACCESS_MASK DesiredAccess,
               IN PRPC_SID DomainId,
               OUT SAMPR_HANDLE *DomainHandle);

NTSTATUS
NTAPI
SamrLookupIdsInDomain(IN SAMPR_HANDLE DomainHandle,
                      IN ULONG Count,
                      IN ULONG *RelativeIds,
                      OUT PSAMPR_RETURNED_USTRING_ARRAY Names,
                      OUT PSAMPR_ULONG_ARRAY Use);

NTSTATUS
NTAPI
SamrLookupNamesInDomain(IN SAMPR_HANDLE DomainHandle,
                        IN ULONG Count,
                        IN RPC_UNICODE_STRING Names[],
                        OUT PSAMPR_ULONG_ARRAY RelativeIds,
                        OUT PSAMPR_ULONG_ARRAY Use);


typedef struct _WELL_KNOWN_SID
{
    LIST_ENTRY ListEntry;
    PSID Sid;
    UNICODE_STRING AccountName;
    UNICODE_STRING DomainName;
    SID_NAME_USE Use;
} WELL_KNOWN_SID, *PWELL_KNOWN_SID;


LIST_ENTRY WellKnownSidListHead;

#if 0
typedef struct _AccountSid
{
    WELL_KNOWN_SID_TYPE type;
    LPCWSTR account;
    LPCWSTR domain;
    SID_NAME_USE name_use;
} AccountSid;

static const WCHAR Account_Operators[] = { 'A','c','c','o','u','n','t',' ','O','p','e','r','a','t','o','r','s',0 };
static const WCHAR Administrator[] = {'A','d','m','i','n','i','s','t','r','a','t','o','r',0 };
static const WCHAR Administrators[] = { 'A','d','m','i','n','i','s','t','r','a','t','o','r','s',0 };
static const WCHAR ANONYMOUS_LOGON[] = { 'A','N','O','N','Y','M','O','U','S',' ','L','O','G','O','N',0 };
static const WCHAR Authenticated_Users[] = { 'A','u','t','h','e','n','t','i','c','a','t','e','d',' ','U','s','e','r','s',0 };
static const WCHAR Backup_Operators[] = { 'B','a','c','k','u','p',' ','O','p','e','r','a','t','o','r','s',0 };
static const WCHAR BATCH[] = { 'B','A','T','C','H',0 };
static const WCHAR Blank[] = { 0 };
static const WCHAR BUILTIN[] = { 'B','U','I','L','T','I','N',0 };
static const WCHAR Cert_Publishers[] = { 'C','e','r','t',' ','P','u','b','l','i','s','h','e','r','s',0 };
static const WCHAR CREATOR_GROUP[] = { 'C','R','E','A','T','O','R',' ','G','R','O','U','P',0 };
static const WCHAR CREATOR_GROUP_SERVER[] = { 'C','R','E','A','T','O','R',' ','G','R','O','U','P',' ','S','E','R','V','E','R',0 };
static const WCHAR CREATOR_OWNER[] = { 'C','R','E','A','T','O','R',' ','O','W','N','E','R',0 };
static const WCHAR CREATOR_OWNER_SERVER[] = { 'C','R','E','A','T','O','R',' ','O','W','N','E','R',' ','S','E','R','V','E','R',0 };
static const WCHAR DIALUP[] = { 'D','I','A','L','U','P',0 };
static const WCHAR Digest_Authentication[] = { 'D','i','g','e','s','t',' ','A','u','t','h','e','n','t','i','c','a','t','i','o','n',0 };
static const WCHAR DOMAIN[] = {'D','O','M','A','I','N',0};
static const WCHAR Domain_Admins[] = { 'D','o','m','a','i','n',' ','A','d','m','i','n','s',0 };
static const WCHAR Domain_Computers[] = { 'D','o','m','a','i','n',' ','C','o','m','p','u','t','e','r','s',0 };
static const WCHAR Domain_Controllers[] = { 'D','o','m','a','i','n',' ','C','o','n','t','r','o','l','l','e','r','s',0 };
static const WCHAR Domain_Guests[] = { 'D','o','m','a','i','n',' ','G','u','e','s','t','s',0 };
static const WCHAR Domain_Users[] = { 'D','o','m','a','i','n',' ','U','s','e','r','s',0 };
static const WCHAR Enterprise_Admins[] = { 'E','n','t','e','r','p','r','i','s','e',' ','A','d','m','i','n','s',0 };
static const WCHAR ENTERPRISE_DOMAIN_CONTROLLERS[] = { 'E','N','T','E','R','P','R','I','S','E',' ','D','O','M','A','I','N',' ','C','O','N','T','R','O','L','L','E','R','S',0 };
static const WCHAR Everyone[] = { 'E','v','e','r','y','o','n','e',0 };
static const WCHAR Group_Policy_Creator_Owners[] = { 'G','r','o','u','p',' ','P','o','l','i','c','y',' ','C','r','e','a','t','o','r',' ','O','w','n','e','r','s',0 };
static const WCHAR Guest[] = { 'G','u','e','s','t',0 };
static const WCHAR Guests[] = { 'G','u','e','s','t','s',0 };
static const WCHAR INTERACTIVE[] = { 'I','N','T','E','R','A','C','T','I','V','E',0 };
static const WCHAR LOCAL[] = { 'L','O','C','A','L',0 };
static const WCHAR LOCAL_SERVICE[] = { 'L','O','C','A','L',' ','S','E','R','V','I','C','E',0 };
static const WCHAR NETWORK[] = { 'N','E','T','W','O','R','K',0 };
static const WCHAR Network_Configuration_Operators[] = { 'N','e','t','w','o','r','k',' ','C','o','n','f','i','g','u','r','a','t','i','o','n',' ','O','p','e','r','a','t','o','r','s',0 };
static const WCHAR NETWORK_SERVICE[] = { 'N','E','T','W','O','R','K',' ','S','E','R','V','I','C','E',0 };
static const WCHAR NT_AUTHORITY[] = { 'N','T',' ','A','U','T','H','O','R','I','T','Y',0 };
static const WCHAR NT_Pseudo_Domain[] = { 'N','T',' ','P','s','e','u','d','o',' ','D','o','m','a','i','n',0 };
static const WCHAR NTML_Authentication[] = { 'N','T','M','L',' ','A','u','t','h','e','n','t','i','c','a','t','i','o','n',0 };
static const WCHAR NULL_SID[] = { 'N','U','L','L',' ','S','I','D',0 };
static const WCHAR Other_Organization[] = { 'O','t','h','e','r',' ','O','r','g','a','n','i','z','a','t','i','o','n',0 };
static const WCHAR Performance_Log_Users[] = { 'P','e','r','f','o','r','m','a','n','c','e',' ','L','o','g',' ','U','s','e','r','s',0 };
static const WCHAR Performance_Monitor_Users[] = { 'P','e','r','f','o','r','m','a','n','c','e',' ','M','o','n','i','t','o','r',' ','U','s','e','r','s',0 };
static const WCHAR Power_Users[] = { 'P','o','w','e','r',' ','U','s','e','r','s',0 };
static const WCHAR Pre_Windows_2000_Compatible_Access[] = { 'P','r','e','-','W','i','n','d','o','w','s',' ','2','0','0','0',' ','C','o','m','p','a','t','i','b','l','e',' ','A','c','c','e','s','s',0 };
static const WCHAR Print_Operators[] = { 'P','r','i','n','t',' ','O','p','e','r','a','t','o','r','s',0 };
static const WCHAR PROXY[] = { 'P','R','O','X','Y',0 };
static const WCHAR RAS_and_IAS_Servers[] = { 'R','A','S',' ','a','n','d',' ','I','A','S',' ','S','e','r','v','e','r','s',0 };
static const WCHAR Remote_Desktop_Users[] = { 'R','e','m','o','t','e',' ','D','e','s','k','t','o','p',' ','U','s','e','r','s',0 };
static const WCHAR REMOTE_INTERACTIVE_LOGON[] = { 'R','E','M','O','T','E',' ','I','N','T','E','R','A','C','T','I','V','E',' ','L','O','G','O','N',0 };
static const WCHAR Replicators[] = { 'R','e','p','l','i','c','a','t','o','r','s',0 };
static const WCHAR RESTRICTED[] = { 'R','E','S','T','R','I','C','T','E','D',0 };
static const WCHAR SChannel_Authentication[] = { 'S','C','h','a','n','n','e','l',' ','A','u','t','h','e','n','t','i','c','a','t','i','o','n',0 };
static const WCHAR Schema_Admins[] = { 'S','c','h','e','m','a',' ','A','d','m','i','n','s',0 };
static const WCHAR SELF[] = { 'S','E','L','F',0 };
static const WCHAR Server_Operators[] = { 'S','e','r','v','e','r',' ','O','p','e','r','a','t','o','r','s',0 };
static const WCHAR SERVICE[] = { 'S','E','R','V','I','C','E',0 };
static const WCHAR SYSTEM[] = { 'S','Y','S','T','E','M',0 };
static const WCHAR TERMINAL_SERVER_USER[] = { 'T','E','R','M','I','N','A','L',' ','S','E','R','V','E','R',' ','U','S','E','R',0 };
static const WCHAR This_Organization[] = { 'T','h','i','s',' ','O','r','g','a','n','i','z','a','t','i','o','n',0 };
static const WCHAR Users[] = { 'U','s','e','r','s',0 };

static const AccountSid ACCOUNT_SIDS[] = {
//    { WinNullSid, NULL_SID, Blank, SidTypeWellKnownGroup },
//    { WinWorldSid, Everyone, Blank, SidTypeWellKnownGroup },
//    { WinLocalSid, LOCAL, Blank, SidTypeWellKnownGroup },
//    { WinCreatorOwnerSid, CREATOR_OWNER, Blank, SidTypeWellKnownGroup },
//    { WinCreatorGroupSid, CREATOR_GROUP, Blank, SidTypeWellKnownGroup },
//    { WinCreatorOwnerServerSid, CREATOR_OWNER_SERVER, Blank, SidTypeWellKnownGroup },
//    { WinCreatorGroupServerSid, CREATOR_GROUP_SERVER, Blank, SidTypeWellKnownGroup },
//    { WinNtAuthoritySid, NT_Pseudo_Domain, NT_Pseudo_Domain, SidTypeDomain },
//    { WinDialupSid, DIALUP, NT_AUTHORITY, SidTypeWellKnownGroup },
//    { WinNetworkSid, NETWORK, NT_AUTHORITY, SidTypeWellKnownGroup },
//    { WinBatchSid, BATCH, NT_AUTHORITY, SidTypeWellKnownGroup },
//    { WinInteractiveSid, INTERACTIVE, NT_AUTHORITY, SidTypeWellKnownGroup },
//    { WinServiceSid, SERVICE, NT_AUTHORITY, SidTypeWellKnownGroup },
//    { WinAnonymousSid, ANONYMOUS_LOGON, NT_AUTHORITY, SidTypeWellKnownGroup },
//    { WinProxySid, PROXY, NT_AUTHORITY, SidTypeWellKnownGroup },
//    { WinEnterpriseControllersSid, ENTERPRISE_DOMAIN_CONTROLLERS, NT_AUTHORITY, SidTypeWellKnownGroup },
//    { WinSelfSid, SELF, NT_AUTHORITY, SidTypeWellKnownGroup },
//    { WinAuthenticatedUserSid, Authenticated_Users, NT_AUTHORITY, SidTypeWellKnownGroup },
//    { WinRestrictedCodeSid, RESTRICTED, NT_AUTHORITY, SidTypeWellKnownGroup },
//    { WinTerminalServerSid, TERMINAL_SERVER_USER, NT_AUTHORITY, SidTypeWellKnownGroup },
//    { WinRemoteLogonIdSid, REMOTE_INTERACTIVE_LOGON, NT_AUTHORITY, SidTypeWellKnownGroup },
//    { WinLocalSystemSid, SYSTEM, NT_AUTHORITY, SidTypeWellKnownGroup },
//    { WinLocalServiceSid, LOCAL_SERVICE, NT_AUTHORITY, SidTypeWellKnownGroup },
//    { WinNetworkServiceSid, NETWORK_SERVICE, NT_AUTHORITY, SidTypeWellKnownGroup },
//    { WinBuiltinDomainSid, BUILTIN, BUILTIN, SidTypeDomain },
//    { WinBuiltinAdministratorsSid, Administrators, BUILTIN, SidTypeAlias },
//    { WinBuiltinUsersSid, Users, BUILTIN, SidTypeAlias },
//    { WinBuiltinGuestsSid, Guests, BUILTIN, SidTypeAlias },
//    { WinBuiltinPowerUsersSid, Power_Users, BUILTIN, SidTypeAlias },
//    { WinBuiltinAccountOperatorsSid, Account_Operators, BUILTIN, SidTypeAlias },
//    { WinBuiltinSystemOperatorsSid, Server_Operators, BUILTIN, SidTypeAlias },
//    { WinBuiltinPrintOperatorsSid, Print_Operators, BUILTIN, SidTypeAlias },
//    { WinBuiltinBackupOperatorsSid, Backup_Operators, BUILTIN, SidTypeAlias },
//    { WinBuiltinReplicatorSid, Replicators, BUILTIN, SidTypeAlias },
//    { WinBuiltinPreWindows2000CompatibleAccessSid, Pre_Windows_2000_Compatible_Access, BUILTIN, SidTypeAlias },
//    { WinBuiltinRemoteDesktopUsersSid, Remote_Desktop_Users, BUILTIN, SidTypeAlias },
//    { WinBuiltinNetworkConfigurationOperatorsSid, Network_Configuration_Operators, BUILTIN, SidTypeAlias },
    { WinNTLMAuthenticationSid, NTML_Authentication, NT_AUTHORITY, SidTypeWellKnownGroup },
    { WinDigestAuthenticationSid, Digest_Authentication, NT_AUTHORITY, SidTypeWellKnownGroup },
    { WinSChannelAuthenticationSid, SChannel_Authentication, NT_AUTHORITY, SidTypeWellKnownGroup },
//    { WinThisOrganizationSid, This_Organization, NT_AUTHORITY, SidTypeWellKnownGroup },
    { WinOtherOrganizationSid, Other_Organization, NT_AUTHORITY, SidTypeWellKnownGroup },
    { WinBuiltinPerfMonitoringUsersSid, Performance_Monitor_Users, BUILTIN, SidTypeAlias },
    { WinBuiltinPerfLoggingUsersSid, Performance_Log_Users, BUILTIN, SidTypeAlias },
};
#endif


BOOLEAN
LsapCreateSid(PSID_IDENTIFIER_AUTHORITY IdentifierAuthority,
              UCHAR SubAuthorityCount,
              PULONG SubAuthorities,
              PWSTR AccountName,
              PWSTR DomainName,
              SID_NAME_USE Use)
{
    PWELL_KNOWN_SID SidEntry;
    PULONG p;
    ULONG i;

    SidEntry = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WELL_KNOWN_SID));
    if (SidEntry == NULL)
        return FALSE;

    InitializeListHead(&SidEntry->ListEntry);

    SidEntry->Sid = RtlAllocateHeap(RtlGetProcessHeap(),
                                    0,
                                    RtlLengthRequiredSid(SubAuthorityCount));
    if (SidEntry->Sid == NULL)
    {
        RtlFreeHeap(RtlGetProcessHeap(), 0, SidEntry);
        return FALSE;
    }

    RtlInitializeSid(SidEntry->Sid,
                     IdentifierAuthority,
                     SubAuthorityCount);

    for (i = 0; i < (ULONG)SubAuthorityCount; i++)
    {
        p = RtlSubAuthoritySid(SidEntry->Sid, i);
        *p = SubAuthorities[i];
    }

//    RtlInitUnicodeString(&SidEntry->AccountName,
//                         AccountName);
    SidEntry->AccountName.Length = wcslen(AccountName) * sizeof(WCHAR);
    SidEntry->AccountName.MaximumLength = SidEntry->AccountName.Length + sizeof(WCHAR);
    SidEntry->AccountName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0,
                                                   SidEntry->AccountName.MaximumLength);
    if (SidEntry->AccountName.Buffer == NULL)
    {
        RtlFreeHeap(RtlGetProcessHeap(), 0, SidEntry->Sid);
        RtlFreeHeap(RtlGetProcessHeap(), 0, SidEntry);
        return FALSE;
    }

    wcscpy(SidEntry->AccountName.Buffer,
           AccountName);

//    RtlInitUnicodeString(&SidEntry->DomainName,
//                         DomainName);
    SidEntry->DomainName.Length = wcslen(DomainName) * sizeof(WCHAR);
    SidEntry->DomainName.MaximumLength = SidEntry->DomainName.Length + sizeof(WCHAR);
    SidEntry->DomainName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0,
                                                  SidEntry->DomainName.MaximumLength);
    if (SidEntry->DomainName.Buffer == NULL)
    {
        RtlFreeHeap(RtlGetProcessHeap(), 0, SidEntry->AccountName.Buffer);
        RtlFreeHeap(RtlGetProcessHeap(), 0, SidEntry->Sid);
        RtlFreeHeap(RtlGetProcessHeap(), 0, SidEntry);
        return FALSE;
    }

    wcscpy(SidEntry->DomainName.Buffer,
           DomainName);

    SidEntry->Use = Use;

    InsertTailList(&WellKnownSidListHead,
                   &SidEntry->ListEntry);

    return TRUE;
}


NTSTATUS
LsapInitSids(VOID)
{
    WCHAR szAccountName[80];
    WCHAR szDomainName[80];
    ULONG SubAuthorities[8];
    HINSTANCE hInstance;

    InitializeListHead(&WellKnownSidListHead);

    hInstance = GetModuleHandleW(L"lsasrv.dll");

    /* NT Authority */

    LsapLoadString(hInstance, IDS_NT_AUTHORITY, szAccountName, 80);
    LsapLoadString(hInstance, IDS_NT_AUTHORITY, szDomainName, 80);
    LsapCreateSid(&NtAuthority,
                  0,
                  NULL,
                  szAccountName,
                  szDomainName,
                  SidTypeDomain);

    /* Null Sid */
    LsapLoadString(hInstance, IDS_NULL_RID, szAccountName, 80);

    SubAuthorities[0] = SECURITY_NULL_RID;
    LsapCreateSid(&NullSidAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  L"",
                  SidTypeWellKnownGroup);

    /* World Sid */
    LsapLoadString(hInstance, IDS_WORLD_RID, szAccountName, 80);

    SubAuthorities[0] = SECURITY_WORLD_RID;
    LsapCreateSid(&WorldSidAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  L"",
                  SidTypeWellKnownGroup);

    /* Local Sid */
    LsapLoadString(hInstance, IDS_LOCAL_RID, szAccountName, 80);

    SubAuthorities[0] = SECURITY_LOCAL_RID;
    LsapCreateSid(&LocalSidAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  L"",
                  SidTypeWellKnownGroup);

    /* Creator Owner Sid */
    LsapLoadString(hInstance, IDS_CREATOR_OWNER_RID, szAccountName, 80);

    SubAuthorities[0] = SECURITY_CREATOR_OWNER_RID;
    LsapCreateSid(&CreatorSidAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  L"",
                  SidTypeWellKnownGroup);

    /* Creator Group Sid */
    LsapLoadString(hInstance, IDS_CREATOR_GROUP_RID, szAccountName, 80);

    SubAuthorities[0] = SECURITY_CREATOR_GROUP_RID;
    LsapCreateSid(&CreatorSidAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  L"",
                  SidTypeWellKnownGroup);

    /* Creator Owner Server Sid */
    LsapLoadString(hInstance, IDS_CREATOR_OWNER_SERVER_RID, szAccountName, 80);

    SubAuthorities[0] = SECURITY_CREATOR_OWNER_SERVER_RID;
    LsapCreateSid(&CreatorSidAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  L"",
                  SidTypeWellKnownGroup);

    /* Creator Group Server Sid */
    LsapLoadString(hInstance, IDS_CREATOR_GROUP_SERVER_RID, szAccountName, 80);

    SubAuthorities[0] = SECURITY_CREATOR_GROUP_SERVER_RID;
    LsapCreateSid(&CreatorSidAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  L"",
                  SidTypeWellKnownGroup);

    /* Dialup Sid */
    LsapLoadString(hInstance, IDS_DIALUP_RID, szAccountName, 80);
    LsapLoadString(hInstance, IDS_NT_AUTHORITY, szDomainName, 80);

    SubAuthorities[0] = SECURITY_DIALUP_RID;
    LsapCreateSid(&NtAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeWellKnownGroup);

    /* Network Sid */
    LsapLoadString(hInstance, IDS_DIALUP_RID, szAccountName, 80);

    SubAuthorities[0] = SECURITY_NETWORK_RID;
    LsapCreateSid(&NtAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeWellKnownGroup);

    /* Batch Sid*/
    LsapLoadString(hInstance, IDS_BATCH_RID, szAccountName, 80);

    SubAuthorities[0] = SECURITY_BATCH_RID;
    LsapCreateSid(&NtAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeWellKnownGroup);

    /* Interactive Sid */
    LsapLoadString(hInstance, IDS_INTERACTIVE_RID, szAccountName, 80);

    SubAuthorities[0] = SECURITY_INTERACTIVE_RID;
    LsapCreateSid(&NtAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeWellKnownGroup);

    /* Service Sid */
    LsapLoadString(hInstance, IDS_SERVICE_RID, szAccountName, 80);

    SubAuthorities[0] = SECURITY_SERVICE_RID;
    LsapCreateSid(&NtAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeWellKnownGroup);

    /* Anonymous Logon Sid */
    LsapLoadString(hInstance, IDS_ANONYMOUS_LOGON_RID, szAccountName, 80);

    SubAuthorities[0] = SECURITY_ANONYMOUS_LOGON_RID;
    LsapCreateSid(&NtAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeWellKnownGroup);

    /* Proxy Sid */
    LsapLoadString(hInstance, IDS_PROXY_RID, szAccountName, 80);

    SubAuthorities[0] = SECURITY_PROXY_RID;
    LsapCreateSid(&NtAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeWellKnownGroup);

    /* Enterprise Controllers Sid */
    LsapLoadString(hInstance, IDS_ENTERPRISE_CONTROLLERS_RID, szAccountName, 80);

    SubAuthorities[0] = SECURITY_ENTERPRISE_CONTROLLERS_RID;
    LsapCreateSid(&NtAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeWellKnownGroup);

    /* Principal Self Sid */
    LsapLoadString(hInstance, IDS_PRINCIPAL_SELF_RID, szAccountName, 80);

    SubAuthorities[0] = SECURITY_PRINCIPAL_SELF_RID;
    LsapCreateSid(&NtAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeWellKnownGroup);

    /* Authenticated Users Sid */
    LsapLoadString(hInstance, IDS_AUTHENTICATED_USER_RID, szAccountName, 80);

    SubAuthorities[0] = SECURITY_AUTHENTICATED_USER_RID;
    LsapCreateSid(&NtAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeWellKnownGroup);

    /* Restricted Code Sid */
    LsapLoadString(hInstance, IDS_RESTRICTED_CODE_RID, szAccountName, 80);

    SubAuthorities[0] = SECURITY_RESTRICTED_CODE_RID;
    LsapCreateSid(&NtAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeWellKnownGroup);

    /* Terminal Server Sid */
    LsapLoadString(hInstance, IDS_TERMINAL_SERVER_RID, szAccountName, 80);

    SubAuthorities[0] = SECURITY_TERMINAL_SERVER_RID;
    LsapCreateSid(&NtAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeWellKnownGroup);

    /* Remote Logon Sid */
    LsapLoadString(hInstance, IDS_REMOTE_LOGON_RID, szAccountName, 80);

    SubAuthorities[0] = SECURITY_REMOTE_LOGON_RID;
    LsapCreateSid(&NtAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeWellKnownGroup);

    /* This Organization Sid */
    LsapLoadString(hInstance, IDS_THIS_ORGANIZATION_RID, szAccountName, 80);

    SubAuthorities[0] = SECURITY_THIS_ORGANIZATION_RID;
    LsapCreateSid(&NtAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeWellKnownGroup);

    /* Local System Sid */
    LsapLoadString(hInstance, IDS_LOCAL_SYSTEM_RID, szAccountName, 80);

    SubAuthorities[0] = SECURITY_LOCAL_SYSTEM_RID;
    LsapCreateSid(&NtAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeWellKnownGroup);

    /* Local Service Sid */
    LsapLoadString(hInstance, IDS_LOCAL_SERVICE_RID, szAccountName, 80);

    SubAuthorities[0] = SECURITY_LOCAL_SERVICE_RID;
    LsapCreateSid(&NtAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeWellKnownGroup);

    LsapCreateSid(&NtAuthority,
                  1,
                  SubAuthorities,
                  L"LOCALSERVICE",
                  L"NT AUTHORITY",
                  SidTypeWellKnownGroup);

    /* Network Service Sid */
    LsapLoadString(hInstance, IDS_NETWORK_SERVICE_RID, szAccountName, 80);

    SubAuthorities[0] = SECURITY_NETWORK_SERVICE_RID;
    LsapCreateSid(&NtAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeWellKnownGroup);

    LsapCreateSid(&NtAuthority,
                  1,
                  SubAuthorities,
                  L"NETWORKSERVICE",
                  L"NT AUTHORITY",
                  SidTypeWellKnownGroup);

    /* Builtin Domain Sid */
    LsapLoadString(hInstance, IDS_BUILTIN_DOMAIN_RID, szAccountName, 80);
    LsapLoadString(hInstance, IDS_BUILTIN_DOMAIN_RID, szDomainName, 80);

    SubAuthorities[0] = SECURITY_BUILTIN_DOMAIN_RID;
    LsapCreateSid(&NtAuthority,
                  1,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeDomain);

    /* Administrators Alias Sid */
    LsapLoadString(hInstance, IDS_ALIAS_RID_ADMINS, szAccountName, 80);

    SubAuthorities[0] = SECURITY_BUILTIN_DOMAIN_RID;
    SubAuthorities[1] = DOMAIN_ALIAS_RID_ADMINS;
    LsapCreateSid(&NtAuthority,
                  2,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeAlias);

    /* Users Alias Sid */
    LsapLoadString(hInstance, IDS_ALIAS_RID_USERS, szAccountName, 80);

    SubAuthorities[0] = SECURITY_BUILTIN_DOMAIN_RID;
    SubAuthorities[1] = DOMAIN_ALIAS_RID_USERS;
    LsapCreateSid(&NtAuthority,
                  2,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeAlias);

    /* Guests Alias Sid */
    LsapLoadString(hInstance, IDS_ALIAS_RID_GUESTS, szAccountName, 80);

    SubAuthorities[0] = SECURITY_BUILTIN_DOMAIN_RID;
    SubAuthorities[1] = DOMAIN_ALIAS_RID_GUESTS;
    LsapCreateSid(&NtAuthority,
                  2,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeAlias);

    /* Power User Alias Sid */
    LsapLoadString(hInstance, IDS_ALIAS_RID_POWER_USERS, szAccountName, 80);

    SubAuthorities[0] = SECURITY_BUILTIN_DOMAIN_RID;
    SubAuthorities[1] = DOMAIN_ALIAS_RID_POWER_USERS;
    LsapCreateSid(&NtAuthority,
                  2,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeAlias);

    /* Account Operators Alias Sid */
    LsapLoadString(hInstance, IDS_ALIAS_RID_ACCOUNT_OPS, szAccountName, 80);

    SubAuthorities[0] = SECURITY_BUILTIN_DOMAIN_RID;
    SubAuthorities[1] = DOMAIN_ALIAS_RID_ACCOUNT_OPS;
    LsapCreateSid(&NtAuthority,
                  2,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeAlias);

    /* System Operators Alias Sid */
    LsapLoadString(hInstance, IDS_ALIAS_RID_SYSTEM_OPS, szAccountName, 80);

    SubAuthorities[0] = SECURITY_BUILTIN_DOMAIN_RID;
    SubAuthorities[1] = DOMAIN_ALIAS_RID_SYSTEM_OPS;
    LsapCreateSid(&NtAuthority,
                  2,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeAlias);

    /* Print Operators Alias Sid */
    LsapLoadString(hInstance, IDS_ALIAS_RID_PRINT_OPS, szAccountName, 80);

    SubAuthorities[0] = SECURITY_BUILTIN_DOMAIN_RID;
    SubAuthorities[1] = DOMAIN_ALIAS_RID_PRINT_OPS;
    LsapCreateSid(&NtAuthority,
                  2,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeAlias);

    /* Backup Operators Alias Sid */
    LsapLoadString(hInstance, IDS_ALIAS_RID_BACKUP_OPS, szAccountName, 80);

    SubAuthorities[0] = SECURITY_BUILTIN_DOMAIN_RID;
    SubAuthorities[1] = DOMAIN_ALIAS_RID_BACKUP_OPS;
    LsapCreateSid(&NtAuthority,
                  2,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeAlias);

    /* Replicators Alias Sid */
    LsapLoadString(hInstance, IDS_ALIAS_RID_REPLICATOR, szAccountName, 80);

    SubAuthorities[0] = SECURITY_BUILTIN_DOMAIN_RID;
    SubAuthorities[1] = DOMAIN_ALIAS_RID_REPLICATOR;
    LsapCreateSid(&NtAuthority,
                  2,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeAlias);

    /* RAS Servers Alias Sid */
    LsapLoadString(hInstance, IDS_ALIAS_RID_RAS_SERVERS, szAccountName, 80);

    SubAuthorities[0] = SECURITY_BUILTIN_DOMAIN_RID;
    SubAuthorities[1] = DOMAIN_ALIAS_RID_RAS_SERVERS;
    LsapCreateSid(&NtAuthority,
                  2,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeAlias);

    /* Pre-Windows 2000 Compatible Access Alias Sid */
    LsapLoadString(hInstance, IDS_ALIAS_RID_PREW2KCOMPACCESS, szAccountName, 80);

    SubAuthorities[0] = SECURITY_BUILTIN_DOMAIN_RID;
    SubAuthorities[1] = DOMAIN_ALIAS_RID_PREW2KCOMPACCESS;
    LsapCreateSid(&NtAuthority,
                  2,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeAlias);

    /* Remote Desktop Users Alias Sid */
    LsapLoadString(hInstance, IDS_ALIAS_RID_REMOTE_DESKTOP_USERS, szAccountName, 80);

    SubAuthorities[0] = SECURITY_BUILTIN_DOMAIN_RID;
    SubAuthorities[1] = DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS;
    LsapCreateSid(&NtAuthority,
                  2,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeAlias);

    /* Network Configuration Operators Alias Sid */
    LsapLoadString(hInstance, IDS_ALIAS_RID_NETWORK_CONFIGURATION_OPS, szAccountName, 80);

    SubAuthorities[0] = SECURITY_BUILTIN_DOMAIN_RID;
    SubAuthorities[1] = DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS;
    LsapCreateSid(&NtAuthority,
                  2,
                  SubAuthorities,
                  szAccountName,
                  szDomainName,
                  SidTypeAlias);

    /* FIXME: Add more well known sids */

    return STATUS_SUCCESS;
}


PWELL_KNOWN_SID
LsapLookupWellKnownSid(PSID Sid)
{
    PLIST_ENTRY ListEntry;
    PWELL_KNOWN_SID Ptr;

    ListEntry = WellKnownSidListHead.Flink;
    while (ListEntry != &WellKnownSidListHead)
    {
        Ptr = CONTAINING_RECORD(ListEntry,
                                WELL_KNOWN_SID,
                                ListEntry);
        if (RtlEqualSid(Sid, Ptr->Sid))
        {
            return Ptr;
        }

        ListEntry = ListEntry->Flink;
    }

    return NULL;
}


PWELL_KNOWN_SID
LsapLookupIsolatedWellKnownName(PUNICODE_STRING AccountName)
{
    PLIST_ENTRY ListEntry;
    PWELL_KNOWN_SID Ptr;

    ListEntry = WellKnownSidListHead.Flink;
    while (ListEntry != &WellKnownSidListHead)
    {
        Ptr = CONTAINING_RECORD(ListEntry,
                                WELL_KNOWN_SID,
                                ListEntry);
        if (RtlEqualUnicodeString(AccountName, &Ptr->AccountName, TRUE))
        {
            return Ptr;
        }

        ListEntry = ListEntry->Flink;
    }

    return NULL;
}


PWELL_KNOWN_SID
LsapLookupFullyQualifiedWellKnownName(PUNICODE_STRING AccountName,
                                      PUNICODE_STRING DomainName)
{
    PLIST_ENTRY ListEntry;
    PWELL_KNOWN_SID Ptr;

    ListEntry = WellKnownSidListHead.Flink;
    while (ListEntry != &WellKnownSidListHead)
    {
        Ptr = CONTAINING_RECORD(ListEntry,
                                WELL_KNOWN_SID,
                                ListEntry);
        if (RtlEqualUnicodeString(AccountName, &Ptr->AccountName, TRUE) &&
            RtlEqualUnicodeString(DomainName, &Ptr->DomainName, TRUE))
        {
            return Ptr;
        }

        ListEntry = ListEntry->Flink;
    }

    return NULL;
}


static
NTSTATUS
LsapSplitNames(DWORD Count,
               PRPC_UNICODE_STRING Names,
               PRPC_UNICODE_STRING *DomainNames,
               PRPC_UNICODE_STRING *AccountNames)
{
    PRPC_UNICODE_STRING DomainsBuffer = NULL;
    PRPC_UNICODE_STRING AccountsBuffer = NULL;
    ULONG DomainLength;
    ULONG AccountLength;
    ULONG i;
    LPWSTR Ptr;
    NTSTATUS Status = STATUS_SUCCESS;

    DomainsBuffer = MIDL_user_allocate(Count * sizeof(RPC_UNICODE_STRING));
    if (DomainsBuffer == NULL)
    {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto done;
    }

    AccountsBuffer = MIDL_user_allocate(Count * sizeof(RPC_UNICODE_STRING));
    if (AccountsBuffer == NULL)
    {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto done;
    }

    for (i = 0; i < Count; i++)
    {
//TRACE("Name: %wZ\n", &Names[i]);

        Ptr = wcschr(Names[i].Buffer, L'\\');
        if (Ptr == NULL)
        {
            AccountLength = Names[i].Length / sizeof(WCHAR);

            AccountsBuffer[i].Length = Names[i].Length;
            AccountsBuffer[i].MaximumLength = AccountsBuffer[i].Length + sizeof(WCHAR);
            AccountsBuffer[i].Buffer = MIDL_user_allocate(AccountsBuffer[i].MaximumLength);
            if (AccountsBuffer[i].Buffer == NULL)
            {
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto done;
            }

            CopyMemory(AccountsBuffer[i].Buffer,
                       Names[i].Buffer,
                       AccountsBuffer[i].Length);
            AccountsBuffer[i].Buffer[AccountLength] = UNICODE_NULL;

//TRACE("Account name: %wZ\n", &AccountsBuffer[i]);
        }
        else
        {
            DomainLength = (ULONG)(ULONG_PTR)(Ptr - Names[i].Buffer);
            AccountLength = (Names[i].Length / sizeof(WCHAR)) - DomainLength - 1;
//TRACE("DomainLength: %u\n", DomainLength);
//TRACE("AccountLength: %u\n", AccountLength);

            if (DomainLength > 0)
            {
                DomainsBuffer[i].Length = (USHORT)DomainLength * sizeof(WCHAR);
                DomainsBuffer[i].MaximumLength = DomainsBuffer[i].Length + sizeof(WCHAR);
                DomainsBuffer[i].Buffer = MIDL_user_allocate(DomainsBuffer[i].MaximumLength);
                if (DomainsBuffer[i].Buffer == NULL)
                {
                    Status = STATUS_INSUFFICIENT_RESOURCES;
                    goto done;
                }

                CopyMemory(DomainsBuffer[i].Buffer,
                           Names[i].Buffer,
                           DomainsBuffer[i].Length);
                DomainsBuffer[i].Buffer[DomainLength] = UNICODE_NULL;

//TRACE("Domain name: %wZ\n", &DomainsBuffer[i]);
            }

            AccountsBuffer[i].Length = (USHORT)AccountLength * sizeof(WCHAR);
            AccountsBuffer[i].MaximumLength = AccountsBuffer[i].Length + sizeof(WCHAR);
            AccountsBuffer[i].Buffer = MIDL_user_allocate(AccountsBuffer[i].MaximumLength);
            if (AccountsBuffer[i].Buffer == NULL)
            {
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto done;
            }

            CopyMemory(AccountsBuffer[i].Buffer,
                       &(Names[i].Buffer[DomainLength + 1]),
                       AccountsBuffer[i].Length);
            AccountsBuffer[i].Buffer[AccountLength] = UNICODE_NULL;

//TRACE("Account name: %wZ\n", &AccountsBuffer[i]);
        }
    }

done:
    if (!NT_SUCCESS(Status))
    {
        if (AccountsBuffer != NULL)
        {
            for (i = 0; i < Count; i++)
            {
                if (AccountsBuffer[i].Buffer != NULL)
                    MIDL_user_free(AccountsBuffer[i].Buffer);
            }

            MIDL_user_free(AccountsBuffer);
        }

        if (DomainsBuffer != NULL)
        {
            for (i = 0; i < Count; i++)
            {
                if (DomainsBuffer[i].Buffer != NULL)
                    MIDL_user_free(DomainsBuffer[i].Buffer);
            }

            MIDL_user_free(DomainsBuffer);
        }
    }
    else
    {
        *DomainNames = DomainsBuffer;
        *AccountNames = AccountsBuffer;
    }

    return Status;
}


static NTSTATUS
LsapAddDomainToDomainsList(PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
                           PUNICODE_STRING Name,
                           PSID Sid,
                           PULONG Index)
{
    ULONG i;

    i = 0;
    while (i < ReferencedDomains->Entries &&
           ReferencedDomains->Domains[i].Sid != NULL)
    {
        if (RtlEqualSid(Sid, ReferencedDomains->Domains[i].Sid))
        {
            *Index = i;
            return STATUS_SUCCESS;
        }

        i++;
    }

    ReferencedDomains->Domains[i].Sid = MIDL_user_allocate(RtlLengthSid(Sid));
    if (ReferencedDomains->Domains[i].Sid == NULL)
        return STATUS_INSUFFICIENT_RESOURCES;

    RtlCopySid(RtlLengthSid(Sid), ReferencedDomains->Domains[i].Sid, Sid);

    ReferencedDomains->Domains[i].Name.Length = Name->Length;
    ReferencedDomains->Domains[i].Name.MaximumLength = Name->MaximumLength;
    ReferencedDomains->Domains[i].Name.Buffer = MIDL_user_allocate(Name->MaximumLength);
    if (ReferencedDomains->Domains[i].Sid == NULL)
    {
        MIDL_user_free(ReferencedDomains->Domains[i].Sid);
        ReferencedDomains->Domains[i].Sid = NULL;
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    RtlCopyMemory(ReferencedDomains->Domains[i].Name.Buffer,
                  Name->Buffer,
                  Name->MaximumLength);

    ReferencedDomains->Entries++;
    *Index = i;

    return STATUS_SUCCESS;
}


static BOOLEAN
LsapIsPrefixSid(IN PSID PrefixSid,
                IN PSID Sid)
{
    PISID Sid1 = PrefixSid, Sid2 = Sid;
    ULONG i;

    if (Sid1->Revision != Sid2->Revision)
        return FALSE;

    if ((Sid1->IdentifierAuthority.Value[0] != Sid2->IdentifierAuthority.Value[0]) ||
        (Sid1->IdentifierAuthority.Value[1] != Sid2->IdentifierAuthority.Value[1]) ||
        (Sid1->IdentifierAuthority.Value[2] != Sid2->IdentifierAuthority.Value[2]) ||
        (Sid1->IdentifierAuthority.Value[3] != Sid2->IdentifierAuthority.Value[3]) ||
        (Sid1->IdentifierAuthority.Value[4] != Sid2->IdentifierAuthority.Value[4]) ||
        (Sid1->IdentifierAuthority.Value[5] != Sid2->IdentifierAuthority.Value[5]))
        return FALSE;

    if (Sid1->SubAuthorityCount >= Sid2->SubAuthorityCount)
        return FALSE;

    if (Sid1->SubAuthorityCount == 0)
        return TRUE;

    for (i = 0; i < Sid1->SubAuthorityCount; i++)
    {
        if (Sid1->SubAuthority[i] != Sid2->SubAuthority[i])
            return FALSE;
    }

    return TRUE;
}


ULONG
LsapGetRelativeIdFromSid(PSID Sid_)
{
    PISID Sid = Sid_;

    if (Sid->SubAuthorityCount != 0)
        return Sid->SubAuthority[Sid->SubAuthorityCount - 1];

    return 0;
}


static PSID
CreateSidFromSidAndRid(PSID SrcSid,
                       ULONG RelativeId)
{
    UCHAR RidCount;
    PSID DstSid;
    ULONG i;
    ULONG DstSidSize;
    PULONG p, q;

    RidCount = *RtlSubAuthorityCountSid(SrcSid);
    if (RidCount >= 8)
        return NULL;

    DstSidSize = RtlLengthRequiredSid(RidCount + 1);

    DstSid = MIDL_user_allocate(DstSidSize);
    if (DstSid == NULL)
        return NULL;

    RtlInitializeSid(DstSid,
                     RtlIdentifierAuthoritySid(SrcSid),
                     RidCount + 1);

    for (i = 0; i < (ULONG)RidCount; i++)
    {
        p = RtlSubAuthoritySid(SrcSid, i);
        q = RtlSubAuthoritySid(DstSid, i);
        *q = *p;
    }

    q = RtlSubAuthoritySid(DstSid, (ULONG)RidCount);
    *q = RelativeId;

    return DstSid;
}


static PSID
CreateDomainSidFromAccountSid(PSID AccountSid)
{
    UCHAR RidCount;
    PSID DomainSid;
    ULONG i;
    ULONG DstSidSize;
    PULONG p, q;

    RidCount = *RtlSubAuthorityCountSid(AccountSid);
    if (RidCount > 0)
        RidCount--;

    DstSidSize = RtlLengthRequiredSid(RidCount);

    DomainSid = MIDL_user_allocate(DstSidSize);
    if (DomainSid == NULL)
        return NULL;

    RtlInitializeSid(DomainSid,
                     RtlIdentifierAuthoritySid(AccountSid),
                     RidCount);

    for (i = 0; i < (ULONG)RidCount; i++)
    {
        p = RtlSubAuthoritySid(AccountSid, i);
        q = RtlSubAuthoritySid(DomainSid, i);
        *q = *p;
    }

    return DomainSid;
}


static PSID
LsapCopySid(PSID SrcSid)
{
    UCHAR RidCount;
    PSID DstSid;
    ULONG i;
    ULONG DstSidSize;
    PULONG p, q;

    RidCount = *RtlSubAuthorityCountSid(SrcSid);
    DstSidSize = RtlLengthRequiredSid(RidCount);

    DstSid = MIDL_user_allocate(DstSidSize);
    if (DstSid == NULL)
        return NULL;

    RtlInitializeSid(DstSid,
                     RtlIdentifierAuthoritySid(SrcSid),
                     RidCount);

    for (i = 0; i < (ULONG)RidCount; i++)
    {
        p = RtlSubAuthoritySid(SrcSid, i);
        q = RtlSubAuthoritySid(DstSid, i);
        *q = *p;
    }

    return DstSid;
}


static
NTSTATUS
LsapLookupIsolatedNames(DWORD Count,
                        PRPC_UNICODE_STRING DomainNames,
                        PRPC_UNICODE_STRING AccountNames,
                        PLSAPR_REFERENCED_DOMAIN_LIST DomainsBuffer,
                        PLSAPR_TRANSLATED_SID_EX2 SidsBuffer,
                        PULONG Mapped)
{
    UNICODE_STRING EmptyDomainName = RTL_CONSTANT_STRING(L"");
    PWELL_KNOWN_SID ptr, ptr2;
    PSID DomainSid;
    ULONG DomainIndex;
    ULONG i;
    NTSTATUS Status = STATUS_SUCCESS;

    for (i = 0; i < Count; i++)
    {
        /* Ignore names which were already mapped */
        if (SidsBuffer[i].Use != SidTypeUnknown)
            continue;

        /* Ignore fully qualified account names */
        if (DomainNames[i].Length != 0)
            continue;

        TRACE("Mapping name: %wZ\n", &AccountNames[i]);

        /* Look-up all well-known names */
        ptr = LsapLookupIsolatedWellKnownName((PUNICODE_STRING)&AccountNames[i]);
        if (ptr != NULL)
        {
            SidsBuffer[i].Use = ptr->Use;
            SidsBuffer[i].Sid = LsapCopySid(ptr->Sid);
            if (SidsBuffer[i].Sid == NULL)
            {
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto done;
            }

            SidsBuffer[i].DomainIndex = -1;
            SidsBuffer[i].Flags = 0;

            if (ptr->Use == SidTypeDomain)
            {
                Status = LsapAddDomainToDomainsList(DomainsBuffer,
                                                    &ptr->AccountName,
                                                    ptr->Sid,
                                                    &DomainIndex);
                if (!NT_SUCCESS(Status))
                    goto done;

                SidsBuffer[i].DomainIndex = DomainIndex;
            }
            else
            {
                ptr2= LsapLookupIsolatedWellKnownName(&ptr->DomainName);
                if (ptr2 != NULL)
                {
                    Status = LsapAddDomainToDomainsList(DomainsBuffer,
                                                        &ptr2->AccountName,
                                                        ptr2->Sid,
                                                        &DomainIndex);
                    if (!NT_SUCCESS(Status))
                        goto done;

                    SidsBuffer[i].DomainIndex = DomainIndex;
                }
                else
                {
                    DomainSid = CreateDomainSidFromAccountSid(ptr->Sid);
                    if (DomainSid == NULL)
                    {
                        Status = STATUS_INSUFFICIENT_RESOURCES;
                        goto done;
                    }

                    Status = LsapAddDomainToDomainsList(DomainsBuffer,
                                                        &EmptyDomainName,
                                                        DomainSid,
                                                        &DomainIndex);

                    if (DomainSid != NULL)
                    {
                        MIDL_user_free(DomainSid);
                        DomainSid = NULL;
                    }

                    if (!NT_SUCCESS(Status))
                        goto done;

                    SidsBuffer[i].DomainIndex = DomainIndex;
                }
            }

            (*Mapped)++;
            continue;
        }

        /* Look-up the built-in domain */
        if (RtlEqualUnicodeString((PUNICODE_STRING)&AccountNames[i], &BuiltinDomainName, TRUE))
        {
            SidsBuffer[i].Use = SidTypeDomain;
            SidsBuffer[i].Sid = LsapCopySid(BuiltinDomainSid);
            if (SidsBuffer[i].Sid == NULL)
            {
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto done;
            }

            SidsBuffer[i].DomainIndex = -1;
            SidsBuffer[i].Flags = 0;

            Status = LsapAddDomainToDomainsList(DomainsBuffer,
                                                &BuiltinDomainName,
                                                BuiltinDomainSid,
                                                &DomainIndex);
            if (!NT_SUCCESS(Status))
                goto done;

            SidsBuffer[i].DomainIndex = DomainIndex;

            (*Mapped)++;
            continue;
        }

        /* Look-up the account domain */
        if (RtlEqualUnicodeString((PUNICODE_STRING)&AccountNames[i], &AccountDomainName, TRUE))
        {
            SidsBuffer[i].Use = SidTypeDomain;
            SidsBuffer[i].Sid = LsapCopySid(AccountDomainSid);
            if (SidsBuffer[i].Sid == NULL)
            {
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto done;
            }
            SidsBuffer[i].DomainIndex = -1;
            SidsBuffer[i].Flags = 0;

            Status = LsapAddDomainToDomainsList(DomainsBuffer,
                                                &AccountDomainName,
                                                AccountDomainSid,
                                                &DomainIndex);
            if (!NT_SUCCESS(Status))
                goto done;

            SidsBuffer[i].DomainIndex = DomainIndex;

            (*Mapped)++;
            continue;
        }

        /* FIXME: Look-up the primary domain */

        /* FIXME: Look-up the trusted domains */

    }

done:

    return Status;
}


static
NTSTATUS
LsapLookupIsolatedBuiltinNames(DWORD Count,
                               PRPC_UNICODE_STRING DomainNames,
                               PRPC_UNICODE_STRING AccountNames,
                               PLSAPR_REFERENCED_DOMAIN_LIST DomainsBuffer,
                               PLSAPR_TRANSLATED_SID_EX2 SidsBuffer,
                               PULONG Mapped)
{
    SAMPR_HANDLE ServerHandle = NULL;
    SAMPR_HANDLE DomainHandle = NULL;
    SAMPR_ULONG_ARRAY RelativeIds = {0, NULL};
    SAMPR_ULONG_ARRAY Use = {0, NULL};
    ULONG DomainIndex;
    ULONG i;
    NTSTATUS Status = STATUS_SUCCESS;

    Status = SamrConnect(NULL,
                         &ServerHandle,
                         SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SamrConnect failed (Status %08lx)\n", Status);
        goto done;
    }

    Status = SamrOpenDomain(ServerHandle,
                            DOMAIN_LOOKUP,
                            BuiltinDomainSid,
                            &DomainHandle);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SamOpenDomain failed (Status %08lx)\n", Status);
        goto done;
    }

    for (i = 0; i < Count; i++)
    {
        /* Ignore names which were already mapped */
        if (SidsBuffer[i].Use != SidTypeUnknown)
            continue;

        /* Ignore fully qualified account names */
        if (DomainNames[i].Length != 0)
            continue;

        TRACE("Mapping name: %wZ\n", &AccountNames[i]);

        Status = SamrLookupNamesInDomain(DomainHandle,
                                         1,
                                         &AccountNames[i],
                                         &RelativeIds,
                                         &Use);
        if (NT_SUCCESS(Status))
        {
            TRACE("Found relative ID: %lu\n", RelativeIds.Element[0]);

            SidsBuffer[i].Use = Use.Element[0];
            SidsBuffer[i].Sid = CreateSidFromSidAndRid(BuiltinDomainSid,
                                                       RelativeIds.Element[0]);
            if (SidsBuffer[i].Sid == NULL)
            {
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto done;
            }

            SidsBuffer[i].DomainIndex = -1;
            SidsBuffer[i].Flags = 0;

            Status = LsapAddDomainToDomainsList(DomainsBuffer,
                                                &BuiltinDomainName,
                                                BuiltinDomainSid,
                                                &DomainIndex);
            if (!NT_SUCCESS(Status))
                goto done;

            SidsBuffer[i].DomainIndex = DomainIndex;

            (*Mapped)++;
        }

        SamIFree_SAMPR_ULONG_ARRAY(&RelativeIds);
        SamIFree_SAMPR_ULONG_ARRAY(&Use);
    }

done:
    if (DomainHandle != NULL)
        SamrCloseHandle(&DomainHandle);

    if (ServerHandle != NULL)
        SamrCloseHandle(&ServerHandle);

    return Status;
}


static
NTSTATUS
LsapLookupIsolatedAccountNames(DWORD Count,
                               PRPC_UNICODE_STRING DomainNames,
                               PRPC_UNICODE_STRING AccountNames,
                               PLSAPR_REFERENCED_DOMAIN_LIST DomainsBuffer,
                               PLSAPR_TRANSLATED_SID_EX2 SidsBuffer,
                               PULONG Mapped)
{
    SAMPR_HANDLE ServerHandle = NULL;
    SAMPR_HANDLE DomainHandle = NULL;
    SAMPR_ULONG_ARRAY RelativeIds = {0, NULL};
    SAMPR_ULONG_ARRAY Use = {0, NULL};
    ULONG DomainIndex;
    ULONG i;
    NTSTATUS Status = STATUS_SUCCESS;

    TRACE("()\n");

    Status = SamrConnect(NULL,
                         &ServerHandle,
                         SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SamrConnect failed (Status %08lx)\n", Status);
        goto done;
    }

    Status = SamrOpenDomain(ServerHandle,
                            DOMAIN_LOOKUP,
                            AccountDomainSid,
                            &DomainHandle);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SamOpenDomain failed (Status %08lx)\n", Status);
        goto done;
    }

    for (i = 0; i < Count; i++)
    {
        /* Ignore names which were already mapped */
        if (SidsBuffer[i].Use != SidTypeUnknown)
            continue;

        /* Ignore fully qualified account names */
        if (DomainNames[i].Length != 0)
            continue;

        TRACE("Mapping name: %wZ\n", &AccountNames[i]);

        Status = SamrLookupNamesInDomain(DomainHandle,
                                         1,
                                         &AccountNames[i],
                                         &RelativeIds,
                                         &Use);
        if (NT_SUCCESS(Status))
        {
            TRACE("Found relative ID: %lu\n", RelativeIds.Element[0]);

            SidsBuffer[i].Use = Use.Element[0];
            SidsBuffer[i].Sid = CreateSidFromSidAndRid(AccountDomainSid,
                                                       RelativeIds.Element[0]);
            if (SidsBuffer[i].Sid == NULL)
            {
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto done;
            }

            SidsBuffer[i].DomainIndex = -1;
            SidsBuffer[i].Flags = 0;

            Status = LsapAddDomainToDomainsList(DomainsBuffer,
                                                &AccountDomainName,
                                                AccountDomainSid,
                                                &DomainIndex);
            if (!NT_SUCCESS(Status))
                goto done;

            SidsBuffer[i].DomainIndex = DomainIndex;

            (*Mapped)++;
        }

        SamIFree_SAMPR_ULONG_ARRAY(&RelativeIds);
        SamIFree_SAMPR_ULONG_ARRAY(&Use);
    }

done:
    if (DomainHandle != NULL)
        SamrCloseHandle(&DomainHandle);

    if (ServerHandle != NULL)
        SamrCloseHandle(&ServerHandle);

    return Status;
}


static
NTSTATUS
LsapLookupFullyQualifiedWellKnownNames(DWORD Count,
                                       PRPC_UNICODE_STRING DomainNames,
                                       PRPC_UNICODE_STRING AccountNames,
                                       PLSAPR_REFERENCED_DOMAIN_LIST DomainsBuffer,
                                       PLSAPR_TRANSLATED_SID_EX2 SidsBuffer,
                                       PULONG Mapped)
{
    UNICODE_STRING EmptyDomainName = RTL_CONSTANT_STRING(L"");
    PWELL_KNOWN_SID ptr, ptr2;
    PSID DomainSid;
    ULONG DomainIndex;
    ULONG i;
    NTSTATUS Status = STATUS_SUCCESS;

    for (i = 0; i < Count; i++)
    {
        /* Ignore names which were already mapped */
        if (SidsBuffer[i].Use != SidTypeUnknown)
            continue;

        /* Ignore isolated account names */
        if (DomainNames[i].Length == 0)
            continue;

        TRACE("Mapping name: %wZ\\%wZ\n", &DomainNames[i], &AccountNames[i]);

        /* Look-up all well-known names */
        ptr = LsapLookupFullyQualifiedWellKnownName((PUNICODE_STRING)&AccountNames[i],
                                                    (PUNICODE_STRING)&DomainNames[i]);
        if (ptr != NULL)
        {
            TRACE("Found it! (%wZ\\%wZ)\n", &ptr->DomainName, &ptr->AccountName);

            SidsBuffer[i].Use = ptr->Use;
            SidsBuffer[i].Sid = LsapCopySid(ptr->Sid);
            if (SidsBuffer[i].Sid == NULL)
            {
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto done;
            }

            SidsBuffer[i].DomainIndex = -1;
            SidsBuffer[i].Flags = 0;

            if (ptr->Use == SidTypeDomain)
            {
                Status = LsapAddDomainToDomainsList(DomainsBuffer,
                                                    &ptr->AccountName,
                                                    ptr->Sid,
                                                    &DomainIndex);
                if (!NT_SUCCESS(Status))
                    goto done;

                SidsBuffer[i].DomainIndex = DomainIndex;
            }
            else
            {
                ptr2= LsapLookupIsolatedWellKnownName(&ptr->DomainName);
                if (ptr2 != NULL)
                {
                    Status = LsapAddDomainToDomainsList(DomainsBuffer,
                                                        &ptr2->AccountName,
                                                        ptr2->Sid,
                                                        &DomainIndex);
                    if (!NT_SUCCESS(Status))
                        goto done;

                    SidsBuffer[i].DomainIndex = DomainIndex;
                }
                else
                {
                    DomainSid = CreateDomainSidFromAccountSid(ptr->Sid);
                    if (DomainSid == NULL)
                    {
                        Status = STATUS_INSUFFICIENT_RESOURCES;
                        goto done;
                    }

                    Status = LsapAddDomainToDomainsList(DomainsBuffer,
                                                        &EmptyDomainName,
                                                        DomainSid,
                                                        &DomainIndex);

                    if (DomainSid != NULL)
                    {
                        MIDL_user_free(DomainSid);
                        DomainSid = NULL;
                    }

                    if (!NT_SUCCESS(Status))
                        goto done;

                    SidsBuffer[i].DomainIndex = DomainIndex;
                }
            }

            (*Mapped)++;
            continue;
        }
    }

done:
    return Status;
}


static
NTSTATUS
LsapLookupBuiltinNames(DWORD Count,
                       PRPC_UNICODE_STRING DomainNames,
                       PRPC_UNICODE_STRING AccountNames,
                       PLSAPR_REFERENCED_DOMAIN_LIST DomainsBuffer,
                       PLSAPR_TRANSLATED_SID_EX2 SidsBuffer,
                       PULONG Mapped)
{
    SAMPR_HANDLE ServerHandle = NULL;
    SAMPR_HANDLE DomainHandle = NULL;
    SAMPR_ULONG_ARRAY RelativeIds = {0, NULL};
    SAMPR_ULONG_ARRAY Use = {0, NULL};
    ULONG DomainIndex;
    ULONG i;
    NTSTATUS Status = STATUS_SUCCESS;

    Status = SamrConnect(NULL,
                         &ServerHandle,
                         SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SamrConnect failed (Status %08lx)\n", Status);
        goto done;
    }

    Status = SamrOpenDomain(ServerHandle,
                            DOMAIN_LOOKUP,
                            BuiltinDomainSid,
                            &DomainHandle);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SamOpenDomain failed (Status %08lx)\n", Status);
        goto done;
    }

    for (i = 0; i < Count; i++)
    {
        /* Ignore names which were already mapped */
        if (SidsBuffer[i].Use != SidTypeUnknown)
            continue;

        /* Ignore isolated account names */
        if (DomainNames[i].Length == 0)
            continue;

        if (!RtlEqualUnicodeString((PUNICODE_STRING)&DomainNames[i], &BuiltinDomainName, TRUE))
            continue;

        TRACE("Mapping name: %wZ\\%wZ\n", &DomainNames[i], &AccountNames[i]);

        Status = SamrLookupNamesInDomain(DomainHandle,
                                         1,
                                         &AccountNames[i],
                                         &RelativeIds,
                                         &Use);
        if (NT_SUCCESS(Status))
        {
            SidsBuffer[i].Use = Use.Element[0];
            SidsBuffer[i].Sid = CreateSidFromSidAndRid(BuiltinDomainSid,
                                                       RelativeIds.Element[0]);
            if (SidsBuffer[i].Sid == NULL)
            {
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto done;
            }

            SidsBuffer[i].DomainIndex = -1;
            SidsBuffer[i].Flags = 0;

            Status = LsapAddDomainToDomainsList(DomainsBuffer,
                                                &BuiltinDomainName,
                                                BuiltinDomainSid,
                                                &DomainIndex);
            if (!NT_SUCCESS(Status))
                goto done;

            SidsBuffer[i].DomainIndex = DomainIndex;

            (*Mapped)++;
        }

        SamIFree_SAMPR_ULONG_ARRAY(&RelativeIds);
        SamIFree_SAMPR_ULONG_ARRAY(&Use);
    }

done:
    if (DomainHandle != NULL)
        SamrCloseHandle(&DomainHandle);

    if (ServerHandle != NULL)
        SamrCloseHandle(&ServerHandle);

    return Status;
}


static
NTSTATUS
LsapLookupAccountNames(DWORD Count,
                       PRPC_UNICODE_STRING DomainNames,
                       PRPC_UNICODE_STRING AccountNames,
                       PLSAPR_REFERENCED_DOMAIN_LIST DomainsBuffer,
                       PLSAPR_TRANSLATED_SID_EX2 SidsBuffer,
                       PULONG Mapped)
{
    SAMPR_HANDLE ServerHandle = NULL;
    SAMPR_HANDLE DomainHandle = NULL;
    SAMPR_ULONG_ARRAY RelativeIds = {0, NULL};
    SAMPR_ULONG_ARRAY Use = {0, NULL};
    ULONG DomainIndex;
    ULONG i;
    NTSTATUS Status = STATUS_SUCCESS;

    Status = SamrConnect(NULL,
                         &ServerHandle,
                         SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SamrConnect failed (Status %08lx)\n", Status);
        goto done;
    }

    Status = SamrOpenDomain(ServerHandle,
                            DOMAIN_LOOKUP,
                            AccountDomainSid,
                            &DomainHandle);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SamOpenDomain failed (Status %08lx)\n", Status);
        goto done;
    }

    for (i = 0; i < Count; i++)
    {
        /* Ignore names which were already mapped */
        if (SidsBuffer[i].Use != SidTypeUnknown)
            continue;

        /* Ignore isolated account names */
        if (DomainNames[i].Length == 0)
            continue;

        if (!RtlEqualUnicodeString((PUNICODE_STRING)&DomainNames[i], &AccountDomainName, TRUE))
            continue;

        TRACE("Mapping name: %wZ\\%wZ\n", &DomainNames[i], &AccountNames[i]);

        Status = SamrLookupNamesInDomain(DomainHandle,
                                         1,
                                         &AccountNames[i],
                                         &RelativeIds,
                                         &Use);
        if (NT_SUCCESS(Status))
        {
            SidsBuffer[i].Use = Use.Element[0];
            SidsBuffer[i].Sid = CreateSidFromSidAndRid(AccountDomainSid,
                                                       RelativeIds.Element[0]);
            if (SidsBuffer[i].Sid == NULL)
            {
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto done;
            }

            SidsBuffer[i].DomainIndex = -1;
            SidsBuffer[i].Flags = 0;

            Status = LsapAddDomainToDomainsList(DomainsBuffer,
                                                &AccountDomainName,
                                                AccountDomainSid,
                                                &DomainIndex);
            if (!NT_SUCCESS(Status))
                goto done;

            SidsBuffer[i].DomainIndex = DomainIndex;

            (*Mapped)++;
        }

        SamIFree_SAMPR_ULONG_ARRAY(&RelativeIds);
        SamIFree_SAMPR_ULONG_ARRAY(&Use);
    }

done:
    if (DomainHandle != NULL)
        SamrCloseHandle(&DomainHandle);

    if (ServerHandle != NULL)
        SamrCloseHandle(&ServerHandle);

    return Status;
}


NTSTATUS
LsapLookupNames(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)
{
    PLSAPR_REFERENCED_DOMAIN_LIST DomainsBuffer = NULL;
    PLSAPR_TRANSLATED_SID_EX2 SidsBuffer = NULL;
    PRPC_UNICODE_STRING DomainNames = NULL;
    PRPC_UNICODE_STRING AccountNames = NULL;
    ULONG SidsBufferLength;
    ULONG i;
    ULONG Mapped = 0;
    NTSTATUS Status = STATUS_SUCCESS;

//TRACE("()\n");

    TranslatedSids->Entries = 0;
    TranslatedSids->Sids = NULL;
    *ReferencedDomains = NULL;

    SidsBufferLength = Count * sizeof(LSAPR_TRANSLATED_SID_EX2);
    SidsBuffer = MIDL_user_allocate(SidsBufferLength);
    if (SidsBuffer == NULL)
    {
//TRACE("\n");
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto done;
    }

    DomainsBuffer = MIDL_user_allocate(sizeof(LSAPR_REFERENCED_DOMAIN_LIST));
    if (DomainsBuffer == NULL)
    {
//TRACE("\n");
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto done;
    }

    DomainsBuffer->Domains = MIDL_user_allocate(Count * sizeof(LSA_TRUST_INFORMATION));
    if (DomainsBuffer->Domains == NULL)
    {
//TRACE("\n");
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto done;
    }
    DomainsBuffer->Entries = 0;
    DomainsBuffer->MaxEntries = Count;

    for (i = 0; i < Count; i++)
    {
        SidsBuffer[i].Use = SidTypeUnknown;
        SidsBuffer[i].Sid = NULL;
        SidsBuffer[i].DomainIndex = -1;
        SidsBuffer[i].Flags = 0;
    }

    Status = LsapSplitNames(Count,
                            Names,
                            &DomainNames,
                            &AccountNames);
    if (!NT_SUCCESS(Status))
    {
        TRACE("LsapSplitNames failed! (Status %lx)\n", Status);
        goto done;
    }


    Status = LsapLookupIsolatedNames(Count,
                                     DomainNames,
                                     AccountNames,
                                     DomainsBuffer,
                                     SidsBuffer,
                                     &Mapped);
    if (!NT_SUCCESS(Status) &&
        Status != STATUS_NONE_MAPPED &&
        Status != STATUS_SOME_NOT_MAPPED)
    {
        TRACE("LsapLookupIsolatedNames failed! (Status %lx)\n", Status);
        goto done;
    }

    if (Mapped == Count)
        goto done;


    Status = LsapLookupIsolatedBuiltinNames(Count,
                                            DomainNames,
                                            AccountNames,
                                            DomainsBuffer,
                                            SidsBuffer,
                                            &Mapped);
    if (!NT_SUCCESS(Status) &&
        Status != STATUS_NONE_MAPPED &&
        Status != STATUS_SOME_NOT_MAPPED)
    {
        TRACE("LsapLookupIsolatedBuiltinNames failed! (Status %lx)\n", Status);
        goto done;
    }

    if (Mapped == Count)
        goto done;


    Status = LsapLookupIsolatedAccountNames(Count,
                                            DomainNames,
                                            AccountNames,
                                            DomainsBuffer,
                                            SidsBuffer,
                                            &Mapped);
    if (!NT_SUCCESS(Status) &&
        Status != STATUS_NONE_MAPPED &&
        Status != STATUS_SOME_NOT_MAPPED)
    {
        TRACE("LsapLookupIsolatedAccountNames failed! (Status %lx)\n", Status);
        goto done;
    }

    if (Mapped == Count)
        goto done;

    Status = LsapLookupFullyQualifiedWellKnownNames(Count,
                                                    DomainNames,
                                                    AccountNames,
                                                    DomainsBuffer,
                                                    SidsBuffer,
                                                    &Mapped);
    if (!NT_SUCCESS(Status) &&
        Status != STATUS_NONE_MAPPED &&
        Status != STATUS_SOME_NOT_MAPPED)
    {
        TRACE("LsapLookupFullyQualifiedWellKnownNames failed! (Status %lx)\n", Status);
        goto done;
    }

    if (Mapped == Count)
        goto done;

    Status = LsapLookupBuiltinNames(Count,
                                    DomainNames,
                                    AccountNames,
                                    DomainsBuffer,
                                    SidsBuffer,
                                    &Mapped);
    if (!NT_SUCCESS(Status) &&
        Status != STATUS_NONE_MAPPED &&
        Status != STATUS_SOME_NOT_MAPPED)
    {
        TRACE("LsapLookupBuiltinNames failed! (Status %lx)\n", Status);
        goto done;
    }

    if (Mapped == Count)
        goto done;


    Status = LsapLookupAccountNames(Count,
                                    DomainNames,
                                    AccountNames,
                                    DomainsBuffer,
                                    SidsBuffer,
                                    &Mapped);
    if (!NT_SUCCESS(Status) &&
        Status != STATUS_NONE_MAPPED &&
        Status != STATUS_SOME_NOT_MAPPED)
    {
        TRACE("LsapLookupAccountNames failed! (Status %lx)\n", Status);
        goto done;
    }

    if (Mapped == Count)
        goto done;

done:
//    TRACE("done: Status %lx\n", Status);

    if (DomainNames != NULL)
    {
//TRACE("Free DomainNames\n");
        for (i = 0; i < Count; i++)
        {
            if (DomainNames[i].Buffer != NULL)
                MIDL_user_free(DomainNames[i].Buffer);
        }

        MIDL_user_free(DomainNames);
    }

    if (AccountNames != NULL)
    {
//TRACE("Free AccountNames\n");
        for (i = 0; i < Count; i++)
        {
//TRACE("i: %lu\n", i);
            if (AccountNames[i].Buffer != NULL)
            {
                MIDL_user_free(AccountNames[i].Buffer);
            }
        }

        MIDL_user_free(AccountNames);
    }

    if (!NT_SUCCESS(Status))
    {
//TRACE("Failure!\n");

//TRACE("Free DomainsBuffer\n");
        if (DomainsBuffer != NULL)
        {
            if (DomainsBuffer->Domains != NULL)
                MIDL_user_free(DomainsBuffer->Domains);

            MIDL_user_free(DomainsBuffer);
        }

//TRACE("Free SidsBuffer\n");
        if (SidsBuffer != NULL)
            MIDL_user_free(SidsBuffer);
    }
    else
    {
//TRACE("Success!\n");

        *ReferencedDomains = DomainsBuffer;
        TranslatedSids->Entries = Count;
        TranslatedSids->Sids = SidsBuffer;
        *MappedCount = Mapped;

        if (Mapped == 0)
            Status = STATUS_NONE_MAPPED;
        else if (Mapped < Count)
            Status = STATUS_SOME_NOT_MAPPED;
    }

//    TRACE("done: Status %lx\n", Status);

    return Status;
}


static NTSTATUS
LsapLookupWellKnownSids(PLSAPR_SID_ENUM_BUFFER SidEnumBuffer,
                        PLSAPR_TRANSLATED_NAME_EX NamesBuffer,
                        PLSAPR_REFERENCED_DOMAIN_LIST DomainsBuffer,
                        PULONG Mapped)
{
    PWELL_KNOWN_SID ptr, ptr2;
    LPWSTR SidString = NULL;
    ULONG DomainIndex;
    ULONG i;
    NTSTATUS Status = STATUS_SUCCESS;

    for (i = 0; i < SidEnumBuffer->Entries; i++)
    {
        /* Ignore SIDs which are already mapped */
        if (NamesBuffer[i].Use != SidTypeUnknown)
            continue;

        ConvertSidToStringSidW(SidEnumBuffer->SidInfo[i].Sid, &SidString);
        TRACE("Mapping SID: %S\n", SidString);
        LocalFree(SidString);
        SidString = NULL;

        ptr = LsapLookupWellKnownSid(SidEnumBuffer->SidInfo[i].Sid);
        if (ptr != NULL)
        {
            NamesBuffer[i].Use = ptr->Use;
            NamesBuffer[i].Flags = 0;

            NamesBuffer[i].Name.Length = ptr->AccountName.Length;
            NamesBuffer[i].Name.MaximumLength = ptr->AccountName.MaximumLength;
            NamesBuffer[i].Name.Buffer = MIDL_user_allocate(ptr->AccountName.MaximumLength);
            if (NamesBuffer[i].Name.Buffer == NULL)
            {
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto done;
            }

            RtlCopyMemory(NamesBuffer[i].Name.Buffer, ptr->AccountName.Buffer, ptr->AccountName.MaximumLength);

            ptr2= LsapLookupIsolatedWellKnownName(&ptr->DomainName);
            if (ptr2 != NULL)
            {
                Status = LsapAddDomainToDomainsList(DomainsBuffer,
                                                    &ptr2->AccountName,
                                                    ptr2->Sid,
                                                    &DomainIndex);
                if (!NT_SUCCESS(Status))
                    goto done;

                NamesBuffer[i].DomainIndex = DomainIndex;
            }

            TRACE("Mapped to: %wZ\n", &NamesBuffer[i].Name);

            (*Mapped)++;
        }
    }

done:
    return Status;
}


static NTSTATUS
LsapLookupBuiltinDomainSids(PLSAPR_SID_ENUM_BUFFER SidEnumBuffer,
                            PLSAPR_TRANSLATED_NAME_EX NamesBuffer,
                            PLSAPR_REFERENCED_DOMAIN_LIST DomainsBuffer,
                            PULONG Mapped)
{
    SAMPR_HANDLE ServerHandle = NULL;
    SAMPR_HANDLE DomainHandle = NULL;
    SAMPR_RETURNED_USTRING_ARRAY Names = {0, NULL};
    SAMPR_ULONG_ARRAY Use = {0, NULL};
    LPWSTR SidString = NULL;
    ULONG DomainIndex;
    ULONG RelativeIds[1];
    ULONG i;
    NTSTATUS Status = STATUS_SUCCESS;

    Status = SamrConnect(NULL,
                         &ServerHandle,
                         SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SamrConnect failed (Status %08lx)\n", Status);
        goto done;
    }

    Status = SamrOpenDomain(ServerHandle,
                            DOMAIN_LOOKUP,
                            BuiltinDomainSid,
                            &DomainHandle);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SamOpenDomain failed (Status %08lx)\n", Status);
        goto done;
    }

    for (i = 0; i < SidEnumBuffer->Entries; i++)
    {
        /* Ignore SIDs which are already mapped */
        if (NamesBuffer[i].Use != SidTypeUnknown)
            continue;

        ConvertSidToStringSidW(SidEnumBuffer->SidInfo[i].Sid, &SidString);
        TRACE("Mapping SID: %S\n", SidString);
        LocalFree(SidString);
        SidString = NULL;

        if (RtlEqualSid(BuiltinDomainSid, SidEnumBuffer->SidInfo[i].Sid))
        {
            TRACE("Found builtin domain!\n");

            NamesBuffer[i].Use = SidTypeDomain;
            NamesBuffer[i].Flags = 0;

            NamesBuffer[i].Name.Length = BuiltinDomainName.Length;
            NamesBuffer[i].Name.MaximumLength = BuiltinDomainName.MaximumLength;
            NamesBuffer[i].Name.Buffer = MIDL_user_allocate(BuiltinDomainName.MaximumLength);
            if (NamesBuffer[i].Name.Buffer == NULL)
            {
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto done;
            }

            RtlCopyMemory(NamesBuffer[i].Name.Buffer, BuiltinDomainName.Buffer, BuiltinDomainName.MaximumLength);

            Status = LsapAddDomainToDomainsList(DomainsBuffer,
                                                &BuiltinDomainName,
                                                BuiltinDomainSid,
                                                &DomainIndex);
            if (!NT_SUCCESS(Status))
                goto done;

            NamesBuffer[i].DomainIndex = DomainIndex;

            TRACE("Mapped to: %wZ\n", &NamesBuffer[i].Name);

            (*Mapped)++;
        }
        else if (LsapIsPrefixSid(BuiltinDomainSid, SidEnumBuffer->SidInfo[i].Sid))
        {
            TRACE("Found builtin domain account!\n");

            RelativeIds[0] = LsapGetRelativeIdFromSid(SidEnumBuffer->SidInfo[i].Sid);

            Status = SamrLookupIdsInDomain(DomainHandle,
                                           1,
                                           RelativeIds,
                                           &Names,
                                           &Use);
            if (NT_SUCCESS(Status))
            {
                NamesBuffer[i].Use = Use.Element[0];
                NamesBuffer[i].Flags = 0;

                NamesBuffer[i].Name.Length = Names.Element[0].Length;
                NamesBuffer[i].Name.MaximumLength = Names.Element[0].MaximumLength;
                NamesBuffer[i].Name.Buffer = MIDL_user_allocate(Names.Element[0].MaximumLength);
                if (NamesBuffer[i].Name.Buffer == NULL)
                {
                    SamIFree_SAMPR_RETURNED_USTRING_ARRAY(&Names);
                    SamIFree_SAMPR_ULONG_ARRAY(&Use);

                    Status = STATUS_INSUFFICIENT_RESOURCES;
                    goto done;
                }

                RtlCopyMemory(NamesBuffer[i].Name.Buffer,
                              Names.Element[0].Buffer,
                              Names.Element[0].MaximumLength);

                SamIFree_SAMPR_RETURNED_USTRING_ARRAY(&Names);
                SamIFree_SAMPR_ULONG_ARRAY(&Use);

                Status = LsapAddDomainToDomainsList(DomainsBuffer,
                                                    &BuiltinDomainName,
                                                    BuiltinDomainSid,
                                                    &DomainIndex);
                if (!NT_SUCCESS(Status))
                    goto done;

                NamesBuffer[i].DomainIndex = DomainIndex;

                TRACE("Mapped to: %wZ\n", &NamesBuffer[i].Name);

                (*Mapped)++;
            }
        }
    }

done:
    if (DomainHandle != NULL)
        SamrCloseHandle(&DomainHandle);

    if (ServerHandle != NULL)
        SamrCloseHandle(&ServerHandle);

    return Status;
}


static NTSTATUS
LsapLookupAccountDomainSids(PLSAPR_SID_ENUM_BUFFER SidEnumBuffer,
                            PLSAPR_TRANSLATED_NAME_EX NamesBuffer,
                            PLSAPR_REFERENCED_DOMAIN_LIST DomainsBuffer,
                            PULONG Mapped)
{
    SAMPR_HANDLE ServerHandle = NULL;
    SAMPR_HANDLE DomainHandle = NULL;
    SAMPR_RETURNED_USTRING_ARRAY Names = {0, NULL};
    SAMPR_ULONG_ARRAY Use = {0, NULL};
    LPWSTR SidString = NULL;
    ULONG DomainIndex;
    ULONG RelativeIds[1];
    ULONG i;
    NTSTATUS Status = STATUS_SUCCESS;

    Status = SamrConnect(NULL,
                         &ServerHandle,
                         SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SamrConnect failed (Status %08lx)\n", Status);
        goto done;
    }

    Status = SamrOpenDomain(ServerHandle,
                            DOMAIN_LOOKUP,
                            AccountDomainSid,
                            &DomainHandle);
    if (!NT_SUCCESS(Status))
    {
        TRACE("SamOpenDomain failed (Status %08lx)\n", Status);
        goto done;
    }

    for (i = 0; i < SidEnumBuffer->Entries; i++)
    {
        /* Ignore SIDs which are already mapped */
        if (NamesBuffer[i].Use != SidTypeUnknown)
            continue;

        ConvertSidToStringSidW(SidEnumBuffer->SidInfo[i].Sid, &SidString);
        TRACE("Mapping SID: %S\n", SidString);
        LocalFree(SidString);
        SidString = NULL;

        if (RtlEqualSid(AccountDomainSid, SidEnumBuffer->SidInfo[i].Sid))
        {
            TRACE("Found account domain!\n");

            NamesBuffer[i].Use = SidTypeDomain;
            NamesBuffer[i].Flags = 0;

            NamesBuffer[i].Name.Length = AccountDomainName.Length;
            NamesBuffer[i].Name.MaximumLength = AccountDomainName.MaximumLength;
            NamesBuffer[i].Name.Buffer = MIDL_user_allocate(AccountDomainName.MaximumLength);
            if (NamesBuffer[i].Name.Buffer == NULL)
            {
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto done;
            }

            RtlCopyMemory(NamesBuffer[i].Name.Buffer, AccountDomainName.Buffer, AccountDomainName.MaximumLength);

            Status = LsapAddDomainToDomainsList(DomainsBuffer,
                                                &AccountDomainName,
                                                AccountDomainSid,
                                                &DomainIndex);
            if (!NT_SUCCESS(Status))
                goto done;

            NamesBuffer[i].DomainIndex = DomainIndex;

            TRACE("Mapped to: %wZ\n", &NamesBuffer[i].Name);

            (*Mapped)++;
        }
        else if (LsapIsPrefixSid(AccountDomainSid, SidEnumBuffer->SidInfo[i].Sid))
        {
            TRACE("Found account domain account!\n");

            RelativeIds[0] = LsapGetRelativeIdFromSid(SidEnumBuffer->SidInfo[i].Sid);

            Status = SamrLookupIdsInDomain(DomainHandle,
                                           1,
                                           RelativeIds,
                                           &Names,
                                           &Use);
            if (NT_SUCCESS(Status))
            {
                NamesBuffer[i].Use = Use.Element[0];
                NamesBuffer[i].Flags = 0;

                NamesBuffer[i].Name.Length = Names.Element[0].Length;
                NamesBuffer[i].Name.MaximumLength = Names.Element[0].MaximumLength;
                NamesBuffer[i].Name.Buffer = MIDL_user_allocate(Names.Element[0].MaximumLength);
                if (NamesBuffer[i].Name.Buffer == NULL)
                {
                    SamIFree_SAMPR_RETURNED_USTRING_ARRAY(&Names);
                    SamIFree_SAMPR_ULONG_ARRAY(&Use);

                    Status = STATUS_INSUFFICIENT_RESOURCES;
                    goto done;
                }

                RtlCopyMemory(NamesBuffer[i].Name.Buffer,
                              Names.Element[0].Buffer,
                              Names.Element[0].MaximumLength);

                SamIFree_SAMPR_RETURNED_USTRING_ARRAY(&Names);
                SamIFree_SAMPR_ULONG_ARRAY(&Use);

                Status = LsapAddDomainToDomainsList(DomainsBuffer,
                                                    &AccountDomainName,
                                                    AccountDomainSid,
                                                    &DomainIndex);
                if (!NT_SUCCESS(Status))
                    goto done;

                NamesBuffer[i].DomainIndex = DomainIndex;

                TRACE("Mapped to: %wZ\n", &NamesBuffer[i].Name);

                (*Mapped)++;
            }
        }
    }

done:
    if (DomainHandle != NULL)
        SamrCloseHandle(&DomainHandle);

    if (ServerHandle != NULL)
        SamrCloseHandle(&ServerHandle);

    return Status;
}


NTSTATUS
LsapLookupSids(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)
{
    PLSAPR_REFERENCED_DOMAIN_LIST DomainsBuffer = NULL;
    PLSAPR_TRANSLATED_NAME_EX NamesBuffer = NULL;
    ULONG NamesBufferLength;
    ULONG i;
    ULONG Mapped = 0;
    NTSTATUS Status = STATUS_SUCCESS;

    NamesBufferLength = SidEnumBuffer->Entries * sizeof(LSAPR_TRANSLATED_NAME_EX);
    NamesBuffer = MIDL_user_allocate(NamesBufferLength);
    if (NamesBuffer == NULL)
    {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto done;
    }

    DomainsBuffer = MIDL_user_allocate(sizeof(LSAPR_REFERENCED_DOMAIN_LIST));
    if (DomainsBuffer == NULL)
    {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto done;
    }

    DomainsBuffer->Domains = MIDL_user_allocate(SidEnumBuffer->Entries * sizeof(LSA_TRUST_INFORMATION));
    if (DomainsBuffer->Domains == NULL)
    {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto done;
    }

    DomainsBuffer->Entries = 0;
    DomainsBuffer->MaxEntries = SidEnumBuffer->Entries;

    /* Initialize all name entries */
    for (i = 0; i < SidEnumBuffer->Entries; i++)
    {
        NamesBuffer[i].Use = SidTypeUnknown;
        NamesBuffer[i].Name.Length = 0;
        NamesBuffer[i].Name.MaximumLength = 0;
        NamesBuffer[i].Name.Buffer = NULL;
        NamesBuffer[i].DomainIndex = -1;
        NamesBuffer[i].Flags = 0;
    }

    /* Look-up well-known SIDs */
    Status = LsapLookupWellKnownSids(SidEnumBuffer,
                                     NamesBuffer,
                                     DomainsBuffer,
                                     &Mapped);
    if (!NT_SUCCESS(Status) &&
        Status != STATUS_NONE_MAPPED &&
        Status != STATUS_SOME_NOT_MAPPED)
        goto done;

    if (Mapped == SidEnumBuffer->Entries)
        goto done;

    /* Look-up builtin domain SIDs */
    Status = LsapLookupBuiltinDomainSids(SidEnumBuffer,
                                         NamesBuffer,
                                         DomainsBuffer,
                                         &Mapped);
    if (!NT_SUCCESS(Status) &&
        Status != STATUS_NONE_MAPPED &&
        Status != STATUS_SOME_NOT_MAPPED)
        goto done;

    if (Mapped == SidEnumBuffer->Entries)
        goto done;

    /* Look-up account domain SIDs */
    Status = LsapLookupAccountDomainSids(SidEnumBuffer,
                                         NamesBuffer,
                                         DomainsBuffer,
                                         &Mapped);
    if (!NT_SUCCESS(Status) &&
        Status != STATUS_NONE_MAPPED &&
        Status != STATUS_SOME_NOT_MAPPED)
        goto done;

    if (Mapped == SidEnumBuffer->Entries)
        goto done;

done:
    TRACE("done Status: %lx  Mapped: %lu\n", Status, Mapped);

    if (!NT_SUCCESS(Status))
    {
        if (DomainsBuffer != NULL)
        {
            if (DomainsBuffer->Domains != NULL)
                MIDL_user_free(DomainsBuffer->Domains);

            MIDL_user_free(DomainsBuffer);
        }

        if (NamesBuffer != NULL)
            MIDL_user_free(NamesBuffer);
    }
    else
    {
        *ReferencedDomains = DomainsBuffer;
        TranslatedNames->Entries = SidEnumBuffer->Entries;
        TranslatedNames->Names = NamesBuffer;
        *MappedCount = Mapped;

        if (Mapped == 0)
            Status = STATUS_NONE_MAPPED;
        else if (Mapped < SidEnumBuffer->Entries)
            Status = STATUS_SOME_NOT_MAPPED;
    }

    return Status;
}

/* EOF */
