/* Editor Settings: expandtabs and use 4 spaces for indentation
 * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: *
 */

/*
 * Copyright Likewise Software
 * All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the license, or (at
 * your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
 * General Public License for more details.  You should have received a copy
 * of the GNU Lesser General Public License along with this program.  If
 * not, see <http://www.gnu.org/licenses/>.
 *
 * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING
 * TERMS AS WELL.  IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT
 * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE
 * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU
 * LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE.  IF YOU
 * HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING
 * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT
 * license@likewisesoftware.com
 */

#include "includes.h"


typedef struct _TEST_LOOKUP
{
    PSTR    pszDomainName;
    PSTR    pszName;
    PSTR    pszSid;
    DWORD   dwRid;
    DWORD   dwType;
} TEST_LOOKUP, *PTEST_LOOKUP;


static
DWORD
TestFormatNT4Name(
    PWSTR  *ppwszNT4Name,
    PWSTR   pwszDomain,
    PWSTR   pwszName
    );

static
DWORD
TestGetLookupTestSet(
    PTEST_LOOKUP *ppTestSet,
    PDWORD pdwNumNames,
    PCSTR pszTestSetName,
    PRPCSERVER Server
    );

static
DWORD
RpctParseLsaLookupItem(
    PSTR *Items,
    PRPCSERVER Server,
    PVOID Context,
    DWORD TestItemIndex,
    PVOID TestItems
    );

static
VOID
RpctFreeTestSidEntry(
    const LW_HASH_ENTRY *pEntry
    );

static
DWORD
ParseTestAccountName(
    PCSTR Name,
    PSTR *pDomain,
    PSTR *pAccount
    );

static
DWORD
ParseTestAccountSid(
    PCSTR TestSid,
    PRPCSERVER Server,
    PLW_HASH_TABLE SidsTable,
    PSTR *pSid,
    PDWORD pRid
    );

static
DWORD
ResolveNameToSid(
    PSTR DomainName,
    PRPCSERVER Server,
    PSID *pDomainSid
    );

static
DWORD
ParseTestAccountRid(
    PSTR pszRid,
    PDWORD pRid
    );

static
DWORD
ParseTestAccountType(
    PCSTR AccountType,
    PDWORD pType
    );

static
DWORD
TestLsaLookupNames(
    PTEST         pTest,
    PRPCSERVER    Server,
    PCREDENTIALS  pCreds,
    PPARAMETER    pOptions,
    DWORD         dwOptcount
    );

static
DWORD
TestLsaLookupNames2(
    PTEST         pTest,
    PRPCSERVER    Server,
    PCREDENTIALS  pCreds,
    PPARAMETER    pOptions,
    DWORD         dwOptcount
    );

static
DWORD
TestLsaLookupNames3(
    PTEST         pTest,
    PRPCSERVER    Server,
    PCREDENTIALS  pCreds,
    PPARAMETER    pOptions,
    DWORD         dwOptcount
    );

static
DWORD
TestLsaLookupSids(
    PTEST         pTest,
    PRPCSERVER    Server,
    PCREDENTIALS  pCreds,
    PPARAMETER    pOptions,
    DWORD         dwOptcount
    );

static
DWORD
TestLsaLookup(
    PTEST         Test,
    PRPCSERVER    Server,
    PCREDENTIALS  Creds,
    PPARAMETER    Options,
    DWORD         OptionsCount
    );

static
DWORD
TestLsaQueryInfoPolicy(
    PTEST         pTest,
    PRPCSERVER    Server,
    PCREDENTIALS  pCreds,
    PPARAMETER    pOptions,
    DWORD         dwOptcount
    );

static
DWORD
TestLsaQueryInfoPolicy2(
    PTEST         pTest,
    PRPCSERVER    Server,
    PCREDENTIALS  pCreds,
    PPARAMETER    pOptions,
    DWORD         dwOptcount
    );

static
DWORD
TestLsaInfoPolicy(
    PTEST         pTest,
    PRPCSERVER    Server,
    PCREDENTIALS  pCreds,
    PPARAMETER    pOptions,
    DWORD         dwOptcount
    );

static
DWORD
TestLsaPolicy(
    PTEST         pTest,
    PRPCSERVER    Server,
    PCREDENTIALS  pCreds,
    PPARAMETER    pOptions,
    DWORD         dwOptcount
    );

static
BOOLEAN
TestLsaOpenPolicy(
    LSA_BINDING     hBinding,
    PWSTR           pwszSysName,
    DWORD           dwAccessRights,
    POLICY_HANDLE  *phPolicy,
    PWSTR          *ppwszDomainName,
    PWSTR          *ppwszDnsDomainName,
    PSID           *ppDomainSid
    );


static
BOOLEAN
CallLsaLookupNames(
    LSA_BINDING    hBinding,
    POLICY_HANDLE  hPolicy,
    DWORD          dwNumNames,
    PWSTR         *ppwszNames,
    DWORD          dwLevel,
    PSID         **pppSids,
    PDWORD        *ppdwTypes
    );


static
BOOLEAN
CallLsaLookupNames2(
    LSA_BINDING    hBinding,
    POLICY_HANDLE  hPolicy,
    DWORD          dwNumNames,
    PWSTR         *ppwszNames,
    DWORD          dwLevel,
    PSID         **pppSids,
    PDWORD        *ppdwTypes
    );


static
BOOLEAN
CallLsaLookupNames3(
    LSA_BINDING    hBinding,
    POLICY_HANDLE  hPolicy,
    DWORD          dwNumNames,
    PWSTR         *ppwszNames,
    DWORD          dwLevel,
    PSID         **pppSids,
    PDWORD        *ppdwTypes
    );


static
BOOLEAN
CallLsaLookupSids(
    LSA_BINDING    hBinding,
    POLICY_HANDLE  hPolicy,
    DWORD          dwNumSids,
    PSID          *ppSids,
    DWORD          dwLevel,
    PWSTR        **pppwszNames,
    PDWORD        *ppdwTypes
    );


static
NTSTATUS
CallLsaClosePolicy(
    LSA_BINDING    hBinding,
    POLICY_HANDLE *phPolicy
    );


static
TEST_LOOKUP StandaloneNames[] = {
    {
        .pszDomainName  = NULL,
        .pszName        = "Administrator",
        .pszSid         = NULL,
        .dwRid          = DOMAIN_USER_RID_ADMIN,
        .dwType         = SID_TYPE_USER,
    },
    {
        .pszDomainName  = NULL,
        .pszName        = "Guest",
        .pszSid         = NULL,
        .dwRid          = DOMAIN_USER_RID_GUEST,
        .dwType         = SID_TYPE_USER,
    },
    {
        .pszDomainName  = NULL,
        .pszName        = "_NonExistent",
        .pszSid         = NULL,
        .dwRid          = 0,
        .dwType         = SID_TYPE_UNKNOWN,
    },
    {
        .pszDomainName  = "BUILTIN",
        .pszName        = "Administrators",
        .pszSid         = "S-1-5-32-544",
        .dwRid          = DOMAIN_ALIAS_RID_ADMINS,
        .dwType         = SID_TYPE_ALIAS,
    },
    {
        .pszDomainName  = "BUILTIN",
        .pszName        = "Users",
        .pszSid         = "S-1-5-32-545",
        .dwRid          = DOMAIN_ALIAS_RID_USERS,
        .dwType         = SID_TYPE_ALIAS,
    },
};


static
TEST_LOOKUP DomainNames[] = {
    {
        .pszDomainName  = NULL,
        .pszName        = "_NonExistent",
        .pszSid         = NULL,
        .dwRid          = 0,
        .dwType         = SID_TYPE_UNKNOWN,
    },
    {
        .pszDomainName  = NULL,
        .pszName        = "Administrator",
        .pszSid         = NULL,
        .dwRid          = DOMAIN_USER_RID_ADMIN,
        .dwType         = SID_TYPE_USER,
    },
    {
        .pszDomainName  = NULL,
        .pszName        = "Guest",
        .pszSid         = NULL,
        .dwRid          = DOMAIN_USER_RID_GUEST,
        .dwType         = SID_TYPE_USER,
    },
    {
        .pszDomainName  = NULL,
        .pszName        = "Domain Admins",
        .pszSid         = NULL,
        .dwRid          = DOMAIN_GROUP_RID_ADMINS,
        .dwType         = SID_TYPE_DOM_GRP,
    },
    {
        .pszDomainName  = "BUILTIN",
        .pszName        = "Users",
        .pszSid         = "S-1-5-32-545",
        .dwRid          = DOMAIN_ALIAS_RID_USERS,
        .dwType         = SID_TYPE_ALIAS,
    },
    {
        .pszDomainName  = NULL,
        .pszName        = "Domain Users",
        .pszSid         = NULL,
        .dwRid          = DOMAIN_GROUP_RID_USERS,
        .dwType         = SID_TYPE_DOM_GRP,
    },
    {
        .pszDomainName  = "BUILTIN",
        .pszName        = "Guests",
        .pszSid         = "S-1-5-32-546",
        .dwRid          = DOMAIN_ALIAS_RID_GUESTS,
        .dwType         = SID_TYPE_ALIAS,
    },
};


static
TEST_LOOKUP DuplicateNames[] = {
    {
        .pszDomainName  = NULL,
        .pszName        = "Administrator",
        .pszSid         = NULL,
        .dwRid          = DOMAIN_USER_RID_ADMIN,
        .dwType         = SID_TYPE_USER,
    },
    {
        .pszDomainName  = NULL,
        .pszName        = "Administrator",
        .pszSid         = NULL,
        .dwRid          = DOMAIN_USER_RID_ADMIN,
        .dwType         = SID_TYPE_USER,
    },
    {
        .pszDomainName  = NULL,
        .pszName        = "Domain Users",
        .pszSid         = NULL,
        .dwRid          = DOMAIN_GROUP_RID_ADMINS,
        .dwType         = SID_TYPE_DOM_GRP,
    },
    {
        .pszDomainName  = NULL,
        .pszName        = "Administrator",
        .pszSid         = NULL,
        .dwRid          = DOMAIN_USER_RID_ADMIN,
        .dwType         = SID_TYPE_USER,
    },
    {
        .pszDomainName  = NULL,
        .pszName        = "Domain Users",
        .pszSid         = NULL,
        .dwRid          = DOMAIN_GROUP_RID_ADMINS,
        .dwType         = SID_TYPE_DOM_GRP,
    },
    {
        .pszDomainName  = NULL,
        .pszName        = "Domain Users",
        .pszSid         = NULL,
        .dwRid          = DOMAIN_GROUP_RID_ADMINS,
        .dwType         = SID_TYPE_DOM_GRP,
    },
    {
        .pszDomainName  = "BUILTIN",
        .pszName        = "_NotExisting",
        .pszSid         = NULL,
        .dwRid          = 0,
        .dwType         = SID_TYPE_UNKNOWN,
    },
    {
        .pszDomainName  = "BUILTIN",
        .pszName        = "_NotExisting",
        .pszSid         = NULL,
        .dwRid          = 0,
        .dwType         = SID_TYPE_UNKNOWN,
    },
};


static
NTSTATUS
CallLsaOpenPolicy(
    LSA_BINDING hLsa,
    PWSTR ServerName,
    PWSTR SystemName,
    DWORD SystemNameLength,
    DWORD AccessRights,
    POLICY_HANDLE* phPolicy,
    NTSTATUS expectedStatus,
    PBOOLEAN Passed
    )
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    DWORD error = ERROR_SUCCESS;
    BOOLEAN passed = TRUE;
    BOOLEAN connected = FALSE;
    PSTR name = NULL;
    POLICY_HANDLE hPolicy = NULL;
    POLICY_HANDLE h = NULL;
    DWORD accessRightsIndex = 0;
    DWORD accessRights[] = {
        LSA_ACCESS_LOOKUP_NAMES_SIDS,
        LSA_ACCESS_ENABLE_LSA,
        LSA_ACCESS_ADMIN_AUDIT_LOG_ATTRS,
        LSA_ACCESS_CHANGE_SYS_AUDIT_REQS,
        LSA_ACCESS_SET_DEFAULT_QUOTA,
        LSA_ACCESS_CREATE_PRIVILEGE,
        LSA_ACCESS_CREATE_SECRET_OBJECT,
        LSA_ACCESS_CREATE_SPECIAL_ACCOUNTS,
        LSA_ACCESS_CHANGE_DOMTRUST_RELATION,
        LSA_ACCESS_GET_SENSITIVE_POLICY_INFO,
        LSA_ACCESS_VIEW_SYS_AUDIT_REQS,
        LSA_ACCESS_VIEW_POLICY_INFO,
    };
    DWORD accessRightsCount = 0;
    DWORD systemNameLength = 0;
    PWSTR longSystemName = NULL;
    DWORD systemNameIndex = 0;

    if (AccessRights == (DWORD)-1)
    {
        accessRightsCount = sizeof(accessRights)/sizeof(accessRights[0]);
    }
    else
    {
        accessRights[0] = AccessRights;
        accessRightsCount = 1;
    }

    if (SystemName)
    {
        error = LwWc16sToMbs(SystemName, &name);
        BAIL_ON_WIN_ERROR(error);

        DISPLAY_COMMENT(("Testing LsaOpenPolicy2 with SystemName = %s\n", name));

        LW_SAFE_FREE_MEMORY(name);

        for (accessRightsIndex = 0;
             accessRightsIndex < accessRightsCount;
             accessRightsIndex++)
        {
            if (connected)
            {
                ntStatus = LsaClose(hLsa, hPolicy);
                BAIL_ON_NT_STATUS(ntStatus);

                connected = FALSE;
            }

            ntStatus = LsaOpenPolicy2(
                              hLsa,
                              SystemName,
                              NULL,
                              accessRights[accessRightsIndex],
                              &h);
            if (ntStatus == STATUS_SUCCESS)
            {
                connected = TRUE;
                hPolicy   = h;
            }

            if (ntStatus != expectedStatus)
            {
                DISPLAY_NTSTATUS(ntStatus);
                passed = FALSE;
            }
        }
    }

    if (ServerName)
    {
        error = LwWc16sToMbs(ServerName, &name);
        BAIL_ON_WIN_ERROR(error);

        DISPLAY_COMMENT(("Testing LsaOpenPolicy2 with ServerName = %s\n", name));

        LW_SAFE_FREE_MEMORY(name);

        for (accessRightsIndex = 0;
             accessRightsIndex < accessRightsCount;
             accessRightsIndex++)
        {
            if (connected)
            {
                ntStatus = LsaClose(hLsa, hPolicy);
                BAIL_ON_NT_STATUS(ntStatus);

                connected = FALSE;
            }

            ntStatus = LsaOpenPolicy2(
                              hLsa,
                              ServerName,
                              NULL,
                              accessRights[accessRightsIndex],
                              &h);
            if (ntStatus == STATUS_SUCCESS)
            {
                connected = TRUE;
                hPolicy   = h;
            }

            if (ntStatus != expectedStatus)
            {
                DISPLAY_NTSTATUS(ntStatus);
                passed = FALSE;
            }
        }
    }

    if (SystemNameLength)
    {
        DISPLAY_COMMENT(("Testing LsaOpenPolicy2 with long system name\n"));

        error = LwAllocateMemory(
                          sizeof(longSystemName[0]) * (SystemNameLength + 1),
                          OUT_PPVOID(&longSystemName));
        BAIL_ON_WIN_ERROR(error);

        for (; systemNameLength <= SystemNameLength; systemNameLength += 32)
        {
            DISPLAY_COMMENT(("Length = %u\n", systemNameLength));

            for (; systemNameIndex < systemNameLength; systemNameIndex++)
            {
                longSystemName[systemNameIndex] = (WCHAR)'l';
            }

            for (accessRightsIndex = 0;
                 accessRightsIndex < accessRightsCount;
                 accessRightsIndex++)
            {
                if (connected)
                {
                    ntStatus = LsaClose(hLsa, hPolicy);
                    BAIL_ON_NT_STATUS(ntStatus);

                    connected = FALSE;
                }

                ntStatus = LsaOpenPolicy2(
                                  hLsa,
                                  longSystemName,
                                  NULL,
                                  accessRights[accessRightsIndex],
                                  &h);
                if (ntStatus == STATUS_SUCCESS)
                {
                    connected = TRUE;
                    hPolicy   = h;
                }

                if (ntStatus != expectedStatus)
                {
                    DISPLAY_NTSTATUS(ntStatus);
                    passed = FALSE;
                }
            }
        }
    }

error:
    LW_SAFE_FREE_MEMORY(name);
    LW_SAFE_FREE_MEMORY(longSystemName);

    if (phPolicy)
    {
        *phPolicy = hPolicy;
    }
    else
    {
        LsaClose(hLsa, hPolicy);
    }

    *Passed = passed;

    if (ntStatus == STATUS_SUCCESS &&
        error != ERROR_SUCCESS)
    {
        ntStatus = LwWin32ErrorToNtStatus(error);
    }

    return ntStatus;
}


static
NTSTATUS
CallLsaClosePolicy(
    LSA_BINDING    hBinding,
    POLICY_HANDLE *phPolicy
    )
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    POLICY_HANDLE hPolicy = NULL;

    DISPLAY_COMMENT(("Testing LsaClose with POLICY_HANDLE\n"));

    hPolicy = *phPolicy;

    ntStatus = LsaClose(hBinding, hPolicy);
    if (ntStatus == STATUS_SUCCESS)
    {
        *phPolicy = NULL;
    }
    else
    {
        DISPLAY_NTSTATUS(ntStatus);
    }

    return ntStatus;
}


static
DWORD
TestLsaPolicy(
    PTEST         pTest,
    PRPCSERVER    Server,
    PCREDENTIALS  pCreds,
    PPARAMETER    pOptions,
    DWORD         dwOptcount
    )
{
    BOOLEAN bRet = TRUE;
    NTSTATUS ntStatus = STATUS_SUCCESS;
    DWORD error = ERROR_SUCCESS;
    LSA_BINDING hLsa = NULL;
    PWSTR systemName = NULL;
    DWORD accessRights = (DWORD)-1;     // Test various combinations
    DWORD maxSystemNameLength = 0;
    DWORD defMaxSystemNameLength = 1024;
    POLICY_HANDLE hPolicy = NULL;

    TESTINFO(pTest,
             "Test calls LsaOpenPolicy2 function with a few combinations\n"
             "of required access rights, gets POLICY_HANDLE from the last\n"
             "call and closes the handle afterwards.\n");

    error = RpctFetchParameterValue(
                       pOptions,
                       dwOptcount,
                       "systemname",
                       PT_WC16STRING,
                       &systemName,
                       NULL);
    BAIL_ON_WIN_ERROR(error);

    error = RpctFetchParameterValue(
                       pOptions,
                       dwOptcount,
                       "maxsystemnamelen",
                       PT_UINT32,
                       &maxSystemNameLength,
                       &defMaxSystemNameLength);
    BAIL_ON_WIN_ERROR(error);

    if (helpMode)
    {
        goto error;
    }

    ntStatus = CreateRpcBinding(
                       OUT_PPVOID(&hLsa),
                       RPC_LSA_BINDING,
                       Server,
                       pCreds);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = CallLsaOpenPolicy(
                       hLsa,
                       Server->Hostname,
                       systemName,
                       maxSystemNameLength,
                       accessRights,
                       &hPolicy,
                       0,
                       &bRet);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = CallLsaClosePolicy(
                       hLsa,
                       &hPolicy);
    BAIL_ON_NT_STATUS(ntStatus);

error:
    if (hLsa)
    {
        LsaFreeBinding(&hLsa);
    }

    return bRet;
}


static
DWORD
TestFormatNT4Name(
    PWSTR  *ppwszNT4Name,
    PWSTR   pwszDomain,
    PWSTR   pwszName
    )
{
    DWORD error = ERROR_SUCCESS;
    size_t sDomainLen = 0;
    size_t sNameLen = 0;
    DWORD dwNT4NameSize = 0;
    PWSTR pwszNT4Name = NULL;

    error = LwWc16sLen(pwszDomain, &sDomainLen);
    BAIL_ON_WIN_ERROR(error);

    error = LwWc16sLen(pwszName, &sNameLen);
    BAIL_ON_WIN_ERROR(error);

    dwNT4NameSize = sizeof(WCHAR) * (sDomainLen + 1 + sNameLen);

    error = LwAllocateMemory(dwNT4NameSize + sizeof(WCHAR),
                               OUT_PPVOID(&pwszNT4Name));
    BAIL_ON_WIN_ERROR(error);

    if (sDomainLen > 0 && sNameLen > 0)
    {
        if (sw16printfw(pwszNT4Name, dwNT4NameSize, L"%ws\\%ws",
                        pwszDomain, pwszName) < 0)
        {
            error = LwErrnoToWin32Error(errno);
        }
    }
    else if (sDomainLen == 0 && sNameLen > 0)
    {
        if (sw16printfw(pwszNT4Name, dwNT4NameSize, L"%ws",
                        pwszName) < 0)
        {
            error = LwErrnoToWin32Error(errno);
        }
    }
    else if (sDomainLen > 0 && sNameLen == 0)
    {
        if (sw16printfw(pwszNT4Name, dwNT4NameSize, L"%ws",
                        pwszDomain) < 0)
        {
            error = LwErrnoToWin32Error(errno);
        }
    }
    else
    {
        error = ERROR_INVALID_PARAMETER;
        BAIL_ON_WIN_ERROR(error);
    }

    *ppwszNT4Name = pwszNT4Name;

cleanup:
    return error;

error:
    LW_SAFE_FREE_MEMORY(pwszNT4Name);

    *ppwszNT4Name = NULL;

    goto cleanup;
}


static
DWORD
TestGetLookupTestSet(
    PTEST_LOOKUP *pTestSet,
    PDWORD pNumNames,
    PCSTR TestSetName,
    PRPCSERVER Server
    )
{
    DWORD error = ERROR_SUCCESS;
    PTEST_LOOKUP testSet = NULL;
    DWORD numNames = 0;
    PLW_HASH_TABLE sidsTable = NULL;

    if (strcmp(TestSetName, "standalone") == 0 ||
        strcmp(TestSetName, "STANDALONE") == 0)
    {
        testSet = StandaloneNames;
        numNames = (sizeof(StandaloneNames)
                    /sizeof(StandaloneNames[0]));
    }
    else if (strcmp(TestSetName, "domain") == 0 ||
             strcmp(TestSetName, "DOMAIN") == 0)
    {
        testSet = DomainNames;
        numNames = (sizeof(DomainNames)
                    /sizeof(DomainNames[0]));
    }
    else if (strcmp(TestSetName, "duplicate") == 0 ||
             strcmp(TestSetName, "DUPLICATE") == 0)
    {
        testSet = DuplicateNames;
        numNames = (sizeof(DuplicateNames)
                    /sizeof(DuplicateNames[0]));
    }
    else
    {
        error = RpctReadTestSetFile(
                             TestSetName,
                             Server,
                             RpctParseLsaLookupItem,
                             NULL,
                             &numNames,
                             (PVOID)testSet);
        BAIL_ON_WIN_ERROR(error);

        error = LwAllocateMemory(
                             sizeof(*testSet) * numNames,
                             OUT_PPVOID(&testSet));
        BAIL_ON_WIN_ERROR(error);

        //
        // Hash table is used to avoid redundant SID lookups
        //
        error = LwHashCreate(
                  (size_t)numNames,
                  LwHashStringCompare,
                  LwHashStringHash,
                  RpctFreeTestSidEntry,
                  NULL,
                  &sidsTable);
        BAIL_ON_WIN_ERROR(error);

        error = RpctReadTestSetFile(
                             TestSetName,
                             Server,
                             RpctParseLsaLookupItem,
                             sidsTable,
                             &numNames,
                             (PVOID)testSet);
        BAIL_ON_WIN_ERROR(error);

    }

    *pTestSet  = testSet;
    *pNumNames = numNames;

error:
    if (error)
    {
        DISPLAY_ERROR(("Error when processing test set %s\n", TestSetName));
    }

    LwHashSafeFree(&sidsTable);

    return error;
}


static
DWORD
RpctParseLsaLookupItem(
    PSTR *Items,
    PRPCSERVER Server,
    PVOID Context,
    DWORD TestItemIndex,
    PVOID TestItems
    )
{
    DWORD error = ERROR_SUCCESS;
    PTEST_LOOKUP testSet = &((PTEST_LOOKUP)TestItems)[TestItemIndex];
    DWORD itemIndex = 0;
    PSTR accountName = NULL;
    PSTR accountSid = NULL;
    PSTR accountType = NULL;
    PLW_HASH_TABLE sidsTable = (PLW_HASH_TABLE)Context;

    if (Items[itemIndex] == NULL)
    {
        error = ERROR_INVALID_PARAMETER;
        BAIL_ON_WIN_ERROR(error);
    }

    accountName = Items[itemIndex++];

    error = ParseTestAccountName(
                 accountName,
                 &testSet->pszDomainName,
                 &testSet->pszName);
    BAIL_ON_WIN_ERROR(error);

    if (Items[itemIndex] == NULL)
    {
        error = ERROR_INVALID_PARAMETER;
        BAIL_ON_WIN_ERROR(error);
    }
    accountSid = Items[itemIndex++];

    error = ParseTestAccountSid(
                 accountSid,
                 Server,
                 sidsTable,
                 &testSet->pszSid,
                 &testSet->dwRid);
    BAIL_ON_WIN_ERROR(error);

    if (Items[itemIndex] == NULL)
    {
        error = ERROR_INVALID_PARAMETER;
        BAIL_ON_WIN_ERROR(error);
    }
    accountType = Items[itemIndex++];

    error = ParseTestAccountType(
                 accountType,
                 &testSet->dwType);
    BAIL_ON_WIN_ERROR(error);

error:
    return error;
}


static
VOID
RpctFreeTestSidEntry(
    const LW_HASH_ENTRY *pEntry
    )
{
    free(pEntry->pKey);
    free(pEntry->pValue);
}


static
DWORD
ParseTestAccountName(
    PCSTR Name,
    PSTR *pDomain,
    PSTR *pAccount
    )
{
    DWORD err = ERROR_SUCCESS;
    PSTR account = NULL;
    PSTR separator = NULL;
    PSTR domainName = NULL;
    PSTR accountName = NULL;
    PSTR defaultDomain = "\\";

    err = LwAllocateString(Name, &account);
    BAIL_ON_WIN_ERROR(err);

    LwStripWhitespace(account, TRUE, TRUE);

    LwStrChr(account, '\\', &separator);
    if (account == separator)
    {
        domainName = NULL;

        separator++;
    }
    else if (separator != NULL)
    {
        *separator = 0;

        err = LwAllocateString(
                        account,
                        &domainName);
        BAIL_ON_WIN_ERROR(err);

        separator++;
    }
    else
    {
        err = LwAllocateString(
                        defaultDomain,
                        &domainName);
    }

    err = LwAllocateString((separator) ? separator : account,
                           &accountName);
    BAIL_ON_WIN_ERROR(err);

error:
    if (err)
    {
        LW_SAFE_FREE_MEMORY(domainName);
        LW_SAFE_FREE_MEMORY(accountName);
    }

    LW_SAFE_FREE_MEMORY(account);

    *pDomain  = domainName;
    *pAccount = accountName;

    return err;
}


static
DWORD
ParseTestAccountSid(
    PCSTR TestSid,
    PRPCSERVER Server,
    PLW_HASH_TABLE SidsTable,
    PSTR *pSid,
    PDWORD pRid
    )
{
    DWORD err = ERROR_SUCCESS;
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PSTR pszSid = NULL;
    PSTR pszValidSid = NULL;
    PCSTR sidToResolveToken = "SID=";
    PSTR tokenFound = NULL;
    CHAR ridSeparator = '+';
    PSID domainSid = NULL;
    PSTR domainName = NULL;
    PSTR domainNameKey = NULL;
    PSTR pszRid = NULL;
    DWORD rid = 0;
    DWORD accountSidLength = 0;
    PSID accountSid = NULL;
    PSID sid = NULL;

    err = LwAllocateString(TestSid, &pszSid);
    BAIL_ON_WIN_ERROR(err);

    LwStripWhitespace(pszSid, TRUE, TRUE);

    // Just return and leave the SID NULL if the line has an empty string
    if (strlen(pszSid) == 0)
    {
        goto error;
    }

    LwStrStr(pszSid, sidToResolveToken, &tokenFound);
    if (tokenFound != pszSid)
    {
        ntStatus = RtlAllocateSidFromCString(
                              &domainSid,
                              pszSid);
        BAIL_ON_NT_STATUS(ntStatus);

        // Cut off the rid part
        LwStrChr(domainName, ridSeparator, &tokenFound);
        if (tokenFound)
        {
            *(tokenFound++) = 0;
            pszRid = tokenFound;
        }

        pszValidSid = pszSid;
        pszSid = NULL;
    }
    else
    {
        domainName = &pszSid[strlen(sidToResolveToken)];
        if (*domainName == 0)
        {
            err = ERROR_INVALID_PARAMETER;
            BAIL_ON_WIN_ERROR(err);
        }

        // Cut off the rid part
        LwStrChr(domainName, ridSeparator, &tokenFound);
        if (tokenFound)
        {
            *(tokenFound++) = 0;
            pszRid = tokenFound;
        }

        err = LwHashGetValue(
                       SidsTable,
                       domainName,
                       (PVOID*)&domainSid);
        if (err == ERROR_NOT_FOUND)
        {
            err = ResolveNameToSid(
                           domainName,
                           Server,
                           &domainSid);
            BAIL_ON_WIN_ERROR(err);

            err = LwAllocateString(
                           domainName,
                           &domainNameKey);
            BAIL_ON_WIN_ERROR(err);

            err = LwHashSetValue(
                           SidsTable,
                           domainNameKey,
                           domainSid);
            BAIL_ON_WIN_ERROR(err);

            domainNameKey = NULL;
        }
        else if (err != ERROR_SUCCESS)
        {
            BAIL_ON_WIN_ERROR(err);
        }

        // At this point the SID either comes from the SIDs table
        // or has been saved there. It should not be freed in either case.
        ntStatus = RtlDuplicateSid(
                           &sid,
                           domainSid);
        BAIL_ON_NT_STATUS(ntStatus);

        domainSid = sid;
        sid = NULL;

        ntStatus = RtlAllocateCStringFromSid(
                           &pszValidSid,
                           domainSid);
        BAIL_ON_NT_STATUS(ntStatus);
    }

    if (pszRid)
    {
        err = ParseTestAccountRid(
                           pszRid,
                           &rid);
        BAIL_ON_WIN_ERROR(err);

        accountSidLength = RtlLengthRequiredSid(
                               domainSid->SubAuthorityCount + 1);
        err = LwAllocateMemory(
                           accountSidLength,
                           OUT_PPVOID(&accountSid));
        BAIL_ON_WIN_ERROR(err);

        ntStatus = RtlCopySid(
                           accountSidLength,
                           accountSid,
                           domainSid);
        BAIL_ON_NT_STATUS(ntStatus);

        ntStatus = RtlAppendRidSid(
                           accountSidLength,
                           accountSid,
                           rid);
        BAIL_ON_NT_STATUS(ntStatus);

        // Free pszValidSid since it has been allocated with domain SID
        // earlier (both to validate the SID and in case there was no RID
        // to be appended)
        LW_SAFE_FREE_MEMORY(pszValidSid);

        ntStatus = RtlAllocateCStringFromSid(
                           &pszValidSid,
                           accountSid);
        BAIL_ON_NT_STATUS(ntStatus);
    }
    else if (pszValidSid)
    {
        ntStatus = RtlAllocateSidFromCString(
                              &sid,
                              pszValidSid);
        BAIL_ON_NT_STATUS(ntStatus);

        ntStatus = RtlGetRidSid(&rid, sid);
        BAIL_ON_NT_STATUS(ntStatus);
    }

error:
    if (err)
    {
        LW_SAFE_FREE_MEMORY(pszValidSid);
    }

    LW_SAFE_FREE_MEMORY(pszSid);
    LW_SAFE_FREE_MEMORY(domainNameKey);
    RTL_FREE(&sid);
    RTL_FREE(&domainSid);
    RTL_FREE(&accountSid);

    *pSid = pszValidSid;
    *pRid = rid;

    return err;
}


static
DWORD
ResolveNameToSid(
    PSTR DomainName,
    PRPCSERVER Server,
    PSID *pDomainSid
    )
{
    DWORD err = ERROR_SUCCESS;
    NTSTATUS ntStatus = STATUS_SUCCESS;
    unsigned32 rpcStatus = RPC_S_OK;
    RPCSERVER server = {0};
    PSTR bindingString = NULL;
    PSTR bindingOptions = NULL;
    unsigned char *uuid = NULL;
    unsigned char *protSeq = NULL;
    unsigned char *networkAddr = NULL;
    unsigned char *endpoint = NULL;
    unsigned char *options = NULL;
    PWSTR hostname = NULL;
    LSA_BINDING hLsa = NULL;
    DWORD accessRights = LSA_ACCESS_LOOKUP_NAMES_SIDS;
    POLICY_HANDLE hPolicy = NULL;
    PWSTR pwszDomainName = NULL;
    RefDomainList *pDomains = NULL;
    TranslatedSid3 *pTransSid = NULL;
    DWORD level = LSA_LOOKUP_NAMES_ALL;
    DWORD count = 0;
    PSID domainSid = NULL;

    //
    // We want to connect to the server by default means
    // regardless of what endpoint user requested.
    //
    if (Server->Hostname)
    {
        server.Hostname = Server->Hostname;
    }
    else
    {
        //
        // Get hostname out of the binding string
        //
        err = LwWc16sToMbs(
                         Server->BindingString,
                         &bindingString);
        BAIL_ON_WIN_ERROR(err);

        // We need the second occurence of colon char
        LwStrChr(bindingString, ':', &bindingOptions);
        if (bindingOptions)
        {
            bindingOptions++;
            LwStrChr(bindingOptions, ':', &bindingOptions);
            if (bindingOptions)
            {
                bindingOptions[0] = 0;
            }
        }

        rpc_string_binding_parse((unsigned char*)bindingString,
                                 &uuid,
                                 &protSeq,
                                 &networkAddr,
                                 &endpoint,
                                 &options,
                                 &rpcStatus);
        if (rpcStatus)
        {
            ntStatus = LwRpcStatusToNtStatus(rpcStatus);
            BAIL_ON_NT_STATUS(ntStatus);
        }

        err = LwMbsToWc16s(
                          (PSTR)networkAddr,
                          &hostname);
        BAIL_ON_WIN_ERROR(err);

        server.Hostname = hostname;
    }

    ntStatus = CreateRpcBinding(
                        OUT_PPVOID(&hLsa),
                        RPC_LSA_BINDING,
                        &server,
                        NULL);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = LsaOpenPolicy2(hLsa,
                              server.Hostname,
                              NULL,
                              accessRights,
                              &hPolicy);
    BAIL_ON_NT_STATUS(ntStatus);

    err = LwMbsToWc16s(DomainName, &pwszDomainName);
    BAIL_ON_WIN_ERROR(err);

    ntStatus = LsaLookupNames3(hLsa,
                               hPolicy,
                               1,
                               &pwszDomainName,
                               &pDomains,
                               &pTransSid,
                               level,
                               &count);
    if (ntStatus != STATUS_SUCCESS &&
        ntStatus != STATUS_NONE_MAPPED)
    {
        BAIL_ON_NT_STATUS(ntStatus);
    }

    if (count > 0)
    {
        if (pTransSid[0].type == SID_TYPE_USE_NONE ||
            pTransSid[0].type == SID_TYPE_INVALID ||
            pTransSid[0].type == SID_TYPE_UNKNOWN)
        {
            ntStatus = STATUS_INVALID_PARAMETER;
            BAIL_ON_NT_STATUS(ntStatus);
        }

        ntStatus = RtlDuplicateSid(&domainSid,
                                   pTransSid[0].sid);
        BAIL_ON_NT_STATUS(ntStatus);
    }

error:
    if (err || ntStatus)
    {
        RTL_FREE(&domainSid);
    }

    if (pDomains)
    {
        LsaRpcFreeMemory(pDomains);
    }

    if (pTransSid)
    {
        LsaRpcFreeMemory(pTransSid);
    }

    if (hPolicy)
    {
        LsaClose(hLsa, hPolicy);
    }

    LsaFreeBinding(&hLsa);

    LW_SAFE_FREE_MEMORY(bindingString);
    rpc_string_free(&uuid, &rpcStatus);
    rpc_string_free(&protSeq, &rpcStatus);
    rpc_string_free(&networkAddr, &rpcStatus);
    rpc_string_free(&endpoint, &rpcStatus);
    rpc_string_free(&options, &rpcStatus);
    LW_SAFE_FREE_MEMORY(hostname);
    LW_SAFE_FREE_MEMORY(pwszDomainName);

    if (err == ERROR_SUCCESS &&
        ntStatus != STATUS_SUCCESS)
    {
        err = LwNtStatusToWin32Error(ntStatus);
    }

    *pDomainSid = domainSid;

    return err;
}


static
DWORD
ParseTestAccountRid(
    PSTR pszRid,
    PDWORD pRid
    )
{
    struct _NAME_TO_RID {
        PSTR Name;
        DWORD Rid;
    } nameToRidMap[] = {
        { "SECURITY_NULL_RID", SECURITY_NULL_RID },
        { "SECURITY_WORLD_RID", SECURITY_WORLD_RID },
        { "SECURITY_LOCAL_RID", SECURITY_LOCAL_RID },
        { "SECURITY_CREATOR_OWNER_RID", SECURITY_CREATOR_OWNER_RID },
        { "SECURITY_CREATOR_GROUP_RID", SECURITY_CREATOR_GROUP_RID },
        { "SECURITY_DIALUP_RID", SECURITY_DIALUP_RID },
        { "SECURITY_NETWORK_RID", SECURITY_NETWORK_RID },
        { "SECURITY_BATCH_RID", SECURITY_BATCH_RID },
        { "SECURITY_INTERACTIVE_RID", SECURITY_INTERACTIVE_RID },
        { "SECURITY_LOGON_IDS_RID", SECURITY_LOGON_IDS_RID },
        { "SECURITY_SERVICE_RID", SECURITY_SERVICE_RID },
        { "SECURITY_ANONYMOUS_LOGON_RID", SECURITY_ANONYMOUS_LOGON_RID },
        { "SECURITY_PROXY_RID", SECURITY_PROXY_RID },
        { "SECURITY_ENTERPRISE_CONTROLLERS_RID", SECURITY_ENTERPRISE_CONTROLLERS_RID },
        { "SECURITY_SERVER_LOGON_RID", SECURITY_SERVER_LOGON_RID },
        { "SECURITY_PRINCIPAL_SELF_RID", SECURITY_PRINCIPAL_SELF_RID },
        { "SECURITY_AUTHENTICATED_USER_RID", SECURITY_AUTHENTICATED_USER_RID },
        { "SECURITY_RESTRICTED_CODE_RID" , SECURITY_RESTRICTED_CODE_RID },
        { "SECURITY_TERMINAL_SERVER_RID", SECURITY_TERMINAL_SERVER_RID },
        { "SECURITY_REMOTE_LOGON_RID", SECURITY_REMOTE_LOGON_RID },
        { "SECURITY_THIS_ORGANIZATION_RID", SECURITY_THIS_ORGANIZATION_RID },
        { "SECURITY_IUSER_RID", SECURITY_IUSER_RID },
        { "SECURITY_LOCAL_SYSTEM_RID", SECURITY_LOCAL_SYSTEM_RID },
        { "SECURITY_LOCAL_SERVICE_RID", SECURITY_LOCAL_SERVICE_RID },
        { "SECURITY_NETWORK_SERVICE_RID", SECURITY_NETWORK_SERVICE_RID },
        { "SECURITY_NT_NON_UNIQUE", SECURITY_NT_NON_UNIQUE },
        { "SECURITY_BUILTIN_DOMAIN_RID", SECURITY_BUILTIN_DOMAIN_RID },
        { "SECURITY_PACKAGE_BASE_RID", SECURITY_PACKAGE_BASE_RID },
        { "SECURITY_OTHER_ORGANIZATION_RID", SECURITY_OTHER_ORGANIZATION_RID },
        { "DOMAIN_USER_RID_ADMIN", DOMAIN_USER_RID_ADMIN },
        { "DOMAIN_USER_RID_GUEST", DOMAIN_USER_RID_GUEST },
        { "DOMAIN_USER_RID_KRBTGT", DOMAIN_USER_RID_KRBTGT },
        { "DOMAIN_GROUP_RID_ADMINS", DOMAIN_GROUP_RID_ADMINS },
        { "DOMAIN_GROUP_RID_USERS", DOMAIN_GROUP_RID_USERS },
        { "DOMAIN_GROUP_RID_GUESTS", DOMAIN_GROUP_RID_GUESTS },
        { "DOMAIN_GROUP_RID_COMPUTERS", DOMAIN_GROUP_RID_COMPUTERS },
        { "DOMAIN_GROUP_RID_CONTROLLERS", DOMAIN_GROUP_RID_CONTROLLERS },
        { "DOMAIN_GROUP_RID_CERT_ADMINS", DOMAIN_GROUP_RID_CERT_ADMINS },
        { "DOMAIN_GROUP_RID_SCHEMA_ADMINS", DOMAIN_GROUP_RID_SCHEMA_ADMINS },
        { "DOMAIN_GROUP_RID_ENTERPRISE_ADMINS", DOMAIN_GROUP_RID_ENTERPRISE_ADMINS },
        { "DOMAIN_GROUP_RID_POLICY_ADMINS", DOMAIN_GROUP_RID_POLICY_ADMINS },
        { "DOMAIN_ALIAS_RID_ADMINS", DOMAIN_ALIAS_RID_ADMINS },
        { "DOMAIN_ALIAS_RID_USERS", DOMAIN_ALIAS_RID_USERS },
        { "DOMAIN_ALIAS_RID_GUESTS", DOMAIN_ALIAS_RID_GUESTS },
        { "DOMAIN_ALIAS_RID_POWER_USERS", DOMAIN_ALIAS_RID_POWER_USERS },
        { "DOMAIN_ALIAS_RID_ACCOUNT_OPS", DOMAIN_ALIAS_RID_ACCOUNT_OPS },
        { "DOMAIN_ALIAS_RID_SYSTEM_OPS", DOMAIN_ALIAS_RID_SYSTEM_OPS },
        { "DOMAIN_ALIAS_RID_PRINT_OPS", DOMAIN_ALIAS_RID_PRINT_OPS },
        { "DOMAIN_ALIAS_RID_BACKUP_OPS", DOMAIN_ALIAS_RID_BACKUP_OPS },
        { "DOMAIN_ALIAS_RID_REPLICATOR", DOMAIN_ALIAS_RID_REPLICATOR },
        { "DOMAIN_ALIAS_RID_RAS_SERVERS", DOMAIN_ALIAS_RID_RAS_SERVERS },
        { "DOMAIN_ALIAS_RID_PREW2KCOMPACCESS", DOMAIN_ALIAS_RID_PREW2KCOMPACCESS },
        { "DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS", DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS },
        { "DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS", DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS },
        { "DOMAIN_ALIAS_RID_INCOMING_FOREST_TRUST_BUILDERS", DOMAIN_ALIAS_RID_INCOMING_FOREST_TRUST_BUILDERS },
        { "DOMAIN_ALIAS_RID_MONITORING_USERS", DOMAIN_ALIAS_RID_MONITORING_USERS },
        { "DOMAIN_ALIAS_RID_LOGGING_USERS", DOMAIN_ALIAS_RID_LOGGING_USERS },
        { "DOMAIN_ALIAS_RID_AUTHORIZATIONACCESS", DOMAIN_ALIAS_RID_AUTHORIZATIONACCESS },
        { "DOMAIN_ALIAS_RID_TS_LICENSE_SERVERS", DOMAIN_ALIAS_RID_TS_LICENSE_SERVERS },
        { "DOMAIN_ALIAS_RID_DCOM_USERS", DOMAIN_ALIAS_RID_DCOM_USERS },
        { "DOMAIN_ALIAS_RID_IUSERS", DOMAIN_ALIAS_RID_IUSERS },
        { "DOMAIN_ALIAS_RID_CRYPTO_OPERATORS", DOMAIN_ALIAS_RID_CRYPTO_OPERATORS },
        { "DOMAIN_ALIAS_RID_EVENT_LOG_READERS_GROUP", DOMAIN_ALIAS_RID_EVENT_LOG_READERS_GROUP },
    };

    DWORD err = ERROR_SUCCESS;
    DWORD i = 0;
    DWORD rid = 0;

    rid = strtoul(pszRid, NULL, 10);
    if (rid == LW_MAXULONG && errno == ERANGE)
    {
        err = ERROR_INVALID_PARAMETER;
        BAIL_ON_WIN_ERROR(err);
    }

    if (rid == 0)
    {
        for (i = 0; i < (sizeof(nameToRidMap)/sizeof(nameToRidMap[0])); i++)
        {
            if (RtlCStringIsEqual(pszRid, nameToRidMap[i].Name, FALSE))
            {
                rid = nameToRidMap[i].Rid;
                break;
            }
        }
    }

error:
    *pRid = rid;

    return err;
}


static
DWORD
ParseTestAccountType(
    PCSTR AccountType,
    PDWORD pType
    )
{
    DWORD err = ERROR_SUCCESS;
    PSTR pszType = NULL;
    struct _NAME_TO_TYPE {
        PSTR Name;
        DWORD Type;
    } nameToTypeMap[] = {
        { "SID_TYPE_USER", SidTypeUser },
        { "SID_TYPE_DOMAIN_GROUP", SidTypeGroup },
        { "SID_TYPE_DOMAIN", SidTypeDomain },
        { "SID_TYPE_ALIAS", SidTypeAlias },
        { "SID_TYPE_WELL_KNOWN_GROUP", SidTypeWellKnownGroup },
        { "SID_TYPE_DELETED_ACCOUNT", SidTypeDeletedAccount },
        { "SID_TYPE_INVALID", SidTypeInvalid },
        { "SID_TYPE_UNKNOWN", SidTypeUnknown },
        { "SID_TYPE_COMPUTER", SidTypeComputer },
        { "SID_TYPE_LABEL", SidTypeLabel },
    };
    DWORD i = 0;
    DWORD type = 0;

    err = LwAllocateString(AccountType, &pszType);
    BAIL_ON_WIN_ERROR(err);

    LwStripWhitespace(pszType, TRUE, TRUE);

    type = strtoul(pszType, NULL, 10);
    if (type == LW_MAXULONG && errno == ERANGE)
    {
        err = ERROR_INVALID_PARAMETER;
        BAIL_ON_WIN_ERROR(err);
    }

    if (type == 0)
    {
        for (i = 0; i < (sizeof(nameToTypeMap)/sizeof(nameToTypeMap[0])); i++)
        {
            if (RtlCStringIsEqual(pszType, nameToTypeMap[i].Name, FALSE))
            {
                type = nameToTypeMap[i].Type;
                break;
            }
        }
    }

    if (type == 0)
    {
        DISPLAY_ERROR(("Unable to determine SID type for: %s\n",
                       AccountType));
        err = ERROR_INVALID_PARAMETER;
    }

error:
    LW_SAFE_FREE_MEMORY(pszType);

    *pType = type;

    return err;
}


static
DWORD
TestLsaLookupNames(
    PTEST         pTest,
    PRPCSERVER    Server,
    PCREDENTIALS  pCreds,
    PPARAMETER    pOptions,
    DWORD         dwOptcount
    )
{
    PCSTR pszDefSysName = "\\\\";
    const DWORD dwDefLevel = -1;
    const BOOLEAN defRevLookup = TRUE;
    PCSTR pszDefTestSetName = "standalone";

    BOOLEAN bRet = TRUE;
    DWORD error = ERROR_SUCCESS;
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PSTR pszTestSetName = NULL;
    LSA_BINDING hLsa = NULL;
    PWSTR pwszSysName = NULL;
    BOOLEAN revLookup = FALSE;
    PWSTR dcName = NULL;
    RPCSERVER server = {0};
    PRPCSERVER lookupServer = NULL;
    DWORD accessRights = LSA_ACCESS_LOOKUP_NAMES_SIDS;
    POLICY_HANDLE hPolicy = NULL;
    PWSTR pwszDomainName = NULL;
    DWORD dwSelectedLevels[] = {0};
    DWORD dwAvailableLevels[] = {LSA_LOOKUP_NAMES_ALL,
                                 LSA_LOOKUP_NAMES_DOMAINS_ONLY,
                                 LSA_LOOKUP_NAMES_PRIMARY_DOMAIN_ONLY,
                                 LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY,
                                 LSA_LOOKUP_NAMES_FOREST_TRUSTS,
                                 LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2};
    PDWORD pdwLevels = NULL;
    DWORD dwNumLevels = 0;
    DWORD dwLevel = 0;
    DWORD iLevel = 0;
    DWORD dwNumNames = 0;
    DWORD iName = 0;
    PWSTR *ppwszNames = NULL;
    PWSTR pwszNT4Name = NULL;
    PSID *ppSids = NULL;
    PDWORD pdwTypes = NULL;
    PWSTR *ppwszRetNames = NULL;
    PDWORD retTypes = NULL;
    PTEST_LOOKUP pTestNames = NULL;

    TESTINFO(pTest,
             "Test calls LsaLookupNames function with arguments specified\n"
             "by testset parameter. It can be one of builtin sets or a path\n"
             "to the scenario file describing arguments and expected results.\n"
             "By default (revlookup=1) LsaLookupSids is called afterwards to\n"
             "verify whether returned results match the arguments of LsaLookupNames.\n");

    error = RpctFetchParameterValue(
                       pOptions,
                       dwOptcount,
                       "systemname",
                       PT_WC16STRING,
                       &pwszSysName,
                       &pszDefSysName);
    BAIL_ON_WIN_ERROR(error);

    error = RpctFetchParameterValue(
                       pOptions,
                       dwOptcount,
                       "testset",
                       PT_CSTRING,
                       &pszTestSetName,
                       &pszDefTestSetName);
    BAIL_ON_WIN_ERROR(error);

    error = RpctFetchParameterValue(
                       pOptions,
                       dwOptcount,
                       "level",
                       PT_UINT32,
                       (UINT32*)&dwLevel,
                       (UINT32*)&dwDefLevel);
    BAIL_ON_WIN_ERROR(error);

    error = RpctFetchParameterValue(
                       pOptions,
                       dwOptcount,
                       "revlookup",
                       PT_BOOLEAN,
                       &revLookup,
                       &defRevLookup);
    BAIL_ON_WIN_ERROR(error);

    error = RpctFetchParameterValue(
                       pOptions,
                       dwOptcount,
                       "dcname",
                       PT_WC16STRING,
                       &dcName,
                       NULL);
    BAIL_ON_WIN_ERROR(error);

    if (dcName)
    {
        server.Hostname = dcName;
        lookupServer = &server;
    }
    else
    {
        lookupServer = Server;
    }

    error = TestGetLookupTestSet(&pTestNames,
                                 &dwNumNames,
                                 pszTestSetName,
                                 lookupServer);
    BAIL_ON_WIN_ERROR(error);

    if (dwLevel == (DWORD)(-1))
    {
        pdwLevels   = dwAvailableLevels;
        dwNumLevels = sizeof(dwAvailableLevels)/sizeof(dwAvailableLevels[0]);
    }
    else
    {
        dwSelectedLevels[0] = dwLevel;
        pdwLevels   = dwSelectedLevels;
        dwNumLevels = sizeof(dwSelectedLevels)/sizeof(dwSelectedLevels[0]);
    }

    ntStatus = CreateRpcBinding(
                        OUT_PPVOID(&hLsa),
                        RPC_LSA_BINDING,
                        Server,
                        pCreds);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = CallLsaOpenPolicy(
                        hLsa,
                        Server->Hostname,
                        NULL,
                        0,
                        accessRights,
                        &hPolicy,
                        0,
                        &bRet);
    BAIL_ON_NT_STATUS(ntStatus);

    for (iLevel = 0; iLevel < dwNumLevels; iLevel++)
    {
        dwLevel = pdwLevels[iLevel];

        error = LwAllocateMemory(sizeof(PWSTR) * dwNumNames,
                                   OUT_PPVOID(&ppwszNames));
        BAIL_ON_WIN_ERROR(error);

        for (iName = 0; iName < dwNumNames; iName++)
        {
            PWSTR pwszDomain = NULL;
            PWSTR pwszName = NULL;

            DISPLAY_COMMENT(("Formatting test NT4 name %u: Domain=%s, Name=%s\n",
                             iName,
                             pTestNames[iName].pszDomainName,
                             pTestNames[iName].pszName));

            if (pTestNames[iName].pszDomainName &&
                RtlCStringIsEqual(
                          pTestNames[iName].pszDomainName,
                          "\\",
                          TRUE))
            {
                // Substitute missing domain name with default domain
                error = LwAllocateWc16String(
                               &pwszDomain,
                               pwszDomainName);
            }
            else if (pTestNames[iName].pszDomainName)
            {
                error = LwMbsToWc16s(
                               pTestNames[iName].pszDomainName,
                               &pwszDomain);
                BAIL_ON_WIN_ERROR(error);
            }
            else
            {
                error = LwMbsToWc16s(
                               "",
                               &pwszDomain);
                BAIL_ON_WIN_ERROR(error);
            }

            error = LwMbsToWc16s(pTestNames[iName].pszName,
                                   &pwszName);
            BAIL_ON_WIN_ERROR(error);

            error = TestFormatNT4Name(&pwszNT4Name, pwszDomain, pwszName);
            BAIL_ON_WIN_ERROR(error);

            ppwszNames[iName] = pwszNT4Name;

            LW_SAFE_FREE_MEMORY(pwszDomain);
            LW_SAFE_FREE_MEMORY(pwszName);

            pwszDomain = NULL;
            pwszName   = NULL;
        }

        bRet &= CallLsaLookupNames(hLsa,
                                   hPolicy,
                                   dwNumNames,
                                   ppwszNames,
                                   dwLevel,
                                   &ppSids,
                                   &pdwTypes);
        if (!bRet)
        {
            DISPLAY_ERROR(("LsaLookupNames (level = %u) FAILED\n",
                           dwLevel));
        }

        for (iName = 0; iName < dwNumNames; iName++)
        {
            PSID pSid = NULL;
            DWORD dwReturnedRid = 0;
            DWORD dwReturnedType = pdwTypes[iName];

            if (dwReturnedType == SID_TYPE_USE_NONE ||
                dwReturnedType == SID_TYPE_INVALID ||
                dwReturnedType == SID_TYPE_UNKNOWN)
            {
                continue;
            }

            if (pTestNames[iName].pszSid)
            {
                ntStatus = RtlAllocateSidFromCString(
                                        &pSid,
                                        pTestNames[iName].pszSid);
                BAIL_ON_NT_STATUS(ntStatus);

                ASSERT_TEST_MSG((ppSids[iName] != NULL), ("(i = %u)\n", iName));

                ASSERT_SID_EQUAL_MSG(pSid, ppSids[iName], ("(i = %u)\n", iName));

                if (ppSids[iName])
                {
                    dwReturnedRid =
                        ppSids[iName]->SubAuthority[ppSids[iName]->SubAuthorityCount - 1];

                    ASSERT_TEST_MSG(dwReturnedRid == pTestNames[iName].dwRid,
                                    ("(i = %u)\n", iName));
                }
            }

            ASSERT_TEST_MSG(dwReturnedType == pTestNames[iName].dwType,
                            ("(i = %u)\n", iName));

            RTL_FREE(&pSid);
        }

        LW_SAFE_FREE_MEMORY(pdwTypes);
        pdwTypes = NULL;

        if (revLookup)
        {
            bRet &= CallLsaLookupSids(hLsa,
                                      hPolicy,
                                      dwNumNames,
                                      ppSids,
                                      dwLevel,
                                      &ppwszRetNames,
                                      &retTypes);
            if (!bRet)
            {
                DISPLAY_ERROR(("LsaLookupSids (level = %u) FAILED\n",
                               dwLevel));
            }
        }

        for (iName = 0; iName < dwNumNames; iName++)
        {
            LW_SAFE_FREE_MEMORY(ppwszNames[iName]);
            RTL_FREE(&ppSids[iName]);
        }

        for (iName = 0; iName < dwNumNames; iName++)
        {
            LW_SAFE_FREE_MEMORY(ppwszRetNames[iName]);
        }

        LW_SAFE_FREE_MEMORY(ppwszNames);
        LW_SAFE_FREE_MEMORY(ppSids);
        LW_SAFE_FREE_MEMORY(pdwTypes);
        LW_SAFE_FREE_MEMORY(ppwszRetNames);
        LW_SAFE_FREE_MEMORY(retTypes);

        ppwszNames = NULL;
        ppSids     = NULL;
        pdwTypes   = NULL;
    }

    ntStatus = CallLsaClosePolicy(hLsa, &hPolicy);
    BAIL_ON_NT_STATUS(ntStatus);

error:
    if (ntStatus != STATUS_SUCCESS ||
        error != ERROR_SUCCESS)
    {
        bRet = FALSE;
    }

    LW_SAFE_FREE_MEMORY(pwszSysName);
    LW_SAFE_FREE_MEMORY(pszTestSetName);
    LW_SAFE_FREE_MEMORY(dcName);
    LW_SAFE_FREE_MEMORY(pwszDomainName);

    return bRet;
}


DWORD
TestLsaLookupNames2(
    PTEST         pTest,
    PRPCSERVER    Server,
    PCREDENTIALS  pCreds,
    PPARAMETER    pOptions,
    DWORD         dwOptcount
    )
{
    PCSTR pszDefSysName = "\\\\";
    const DWORD dwDefLevel = -1;
    const BOOLEAN bDefRevLookup = TRUE;
    PCSTR pszDefTestSetName = "standalone";

    BOOLEAN bRet = TRUE;
    DWORD error = ERROR_SUCCESS;
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PSTR pszTestSetName = NULL;
    LSA_BINDING hLsa = NULL;
    PWSTR pwszSysName = NULL;
    BOOLEAN bRevLookup = TRUE;
    PWSTR dcName = NULL;
    RPCSERVER server = {0};
    PRPCSERVER lookupServer = NULL;
    POLICY_HANDLE hPolicy = NULL;
    PWSTR pwszDomainName = NULL;
    DWORD accessRights = LSA_ACCESS_LOOKUP_NAMES_SIDS;
    DWORD dwSelectedLevels[] = {0};
    DWORD dwAvailableLevels[] = {LSA_LOOKUP_NAMES_ALL,
                                 LSA_LOOKUP_NAMES_DOMAINS_ONLY,
                                 LSA_LOOKUP_NAMES_PRIMARY_DOMAIN_ONLY,
                                 LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY,
                                 LSA_LOOKUP_NAMES_FOREST_TRUSTS,
                                 LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2};
    PDWORD pdwLevels = NULL;
    DWORD dwNumLevels = 0;
    DWORD dwLevel = 0;
    DWORD iLevel = 0;
    DWORD dwNumNames = 0;
    DWORD iName = 0;
    PWSTR *ppwszNames = NULL;
    PWSTR pwszNT4Name = NULL;
    PSID *ppSids = NULL;
    PDWORD pdwTypes = NULL;
    PWSTR *ppwszRetNames = NULL;
    PTEST_LOOKUP pTestNames = NULL;

    TESTINFO(pTest,
             "Test calls LsaLookupNames2 function with arguments specified\n"
             "by testset parameter. It can be one of builtin sets or a path\n"
             "to the scenario file describing arguments and expected results.\n"
             "By default (revlookup=1) LsaLookupSids is called afterwards to\n"
             "verify whether returned results match the arguments of LsaLookupNames2.\n");

    error = RpctFetchParameterValue(
                       pOptions,
                       dwOptcount,
                       "systemname",
                       PT_WC16STRING,
                       &pwszSysName,
                       &pszDefSysName);
    BAIL_ON_WIN_ERROR(error);

    error = RpctFetchParameterValue(
                       pOptions,
                       dwOptcount,
                       "testset",
                       PT_CSTRING,
                       &pszTestSetName,
                       &pszDefTestSetName);
    BAIL_ON_WIN_ERROR(error);

    error = RpctFetchParameterValue(
                       pOptions,
                       dwOptcount,
                       "level",
                       PT_UINT32,
                       (UINT32*)&dwLevel,
                       (UINT32*)&dwDefLevel);
    BAIL_ON_WIN_ERROR(error);

    error = RpctFetchParameterValue(
                       pOptions,
                       dwOptcount,
                       "revlookup",
                       PT_UINT32,
                       (UINT32*)&bRevLookup,
                       (UINT32*)&bDefRevLookup);
    BAIL_ON_WIN_ERROR(error);

    error = RpctFetchParameterValue(
                       pOptions,
                       dwOptcount,
                       "dcname",
                       PT_WC16STRING,
                       &dcName,
                       NULL);
    BAIL_ON_WIN_ERROR(error);

    if (dcName)
    {
        server.Hostname = dcName;
        lookupServer = &server;
    }
    else
    {
        lookupServer = Server;
    }

    error = TestGetLookupTestSet(&pTestNames,
                                 &dwNumNames,
                                 pszTestSetName,
                                 lookupServer);
    BAIL_ON_WIN_ERROR(error);

    if (dwLevel == (DWORD)(-1))
    {
        pdwLevels   = dwAvailableLevels;
        dwNumLevels = sizeof(dwAvailableLevels)/sizeof(dwAvailableLevels[0]);
    }
    else
    {
        dwSelectedLevels[0] = dwLevel;
        pdwLevels   = dwSelectedLevels;
        dwNumLevels = sizeof(dwSelectedLevels)/sizeof(dwSelectedLevels[0]);
    }

    ntStatus = CreateRpcBinding(
                        OUT_PPVOID(&hLsa),
                        RPC_LSA_BINDING,
                        Server,
                        pCreds);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = CallLsaOpenPolicy(
                        hLsa,
                        Server->Hostname,
                        NULL,
                        0,
                        accessRights,
                        &hPolicy,
                        0,
                        &bRet);
    BAIL_ON_NT_STATUS(ntStatus);

    for (iLevel = 0; iLevel < dwNumLevels; iLevel++)
    {
        dwLevel = pdwLevels[iLevel];

        error = LwAllocateMemory(sizeof(PWSTR) * dwNumNames,
                                   OUT_PPVOID(&ppwszNames));
        BAIL_ON_WIN_ERROR(error);

        for (iName = 0; iName < dwNumNames; iName++)
        {
            PWSTR pwszDomain = NULL;
            PWSTR pwszName = NULL;

            DISPLAY_COMMENT(("Formatting test NT4 name %u: Domain=%s, Name=%s\n",
                             iName,
                             pTestNames[iName].pszDomainName,
                             pTestNames[iName].pszName));

            if (pTestNames[iName].pszDomainName &&
                RtlCStringIsEqual(
                          pTestNames[iName].pszDomainName,
                          "\\",
                          TRUE))
            {
                // Substitute missing domain name with default domain
                error = LwAllocateWc16String(
                               &pwszDomain,
                               pwszDomainName);
            }
            else if (pTestNames[iName].pszDomainName)
            {
                error = LwMbsToWc16s(
                               pTestNames[iName].pszDomainName,
                               &pwszDomain);
                BAIL_ON_WIN_ERROR(error);
            }
            else
            {
                error = LwMbsToWc16s(
                               "",
                               &pwszDomain);
                BAIL_ON_WIN_ERROR(error);
            }

            error = LwMbsToWc16s(pTestNames[iName].pszName,
                                 &pwszName);
            BAIL_ON_WIN_ERROR(error);

            error = TestFormatNT4Name(&pwszNT4Name, pwszDomain, pwszName);
            BAIL_ON_WIN_ERROR(error);

            ppwszNames[iName] = pwszNT4Name;

            LW_SAFE_FREE_MEMORY(pwszDomain);
            LW_SAFE_FREE_MEMORY(pwszName);

            pwszDomain = NULL;
            pwszName   = NULL;
        }

        bRet &= CallLsaLookupNames2(hLsa, hPolicy, dwNumNames, ppwszNames, dwLevel,
                                   &ppSids, &pdwTypes);

        for (iName = 0; iName < dwNumNames; iName++)
        {
            PSID pSid = NULL;
            DWORD dwReturnedRid = 0;
            DWORD dwReturnedType = pdwTypes[iName];

            if (dwReturnedType == SID_TYPE_USE_NONE ||
                dwReturnedType == SID_TYPE_INVALID ||
                dwReturnedType == SID_TYPE_UNKNOWN)
            {
                continue;
            }

            if (pTestNames[iName].pszSid)
            {
                ntStatus = RtlAllocateSidFromCString(
                                        &pSid,
                                        pTestNames[iName].pszSid);
                BAIL_ON_NT_STATUS(ntStatus);

                ASSERT_TEST_MSG((ppSids[iName] != NULL), ("(i = %u)\n", iName));

                ASSERT_SID_EQUAL_MSG(pSid, ppSids[iName], ("(i = %u)\n", iName));

                if (ppSids[iName])
                {
                    dwReturnedRid =
                        ppSids[iName]->SubAuthority[ppSids[iName]->SubAuthorityCount - 1];

                    ASSERT_TEST_MSG(dwReturnedRid == pTestNames[iName].dwRid,
                                    ("(i = %u)\n", iName));
                }
            }

            ASSERT_TEST_MSG(dwReturnedType == pTestNames[iName].dwType,
                            ("(i = %u)\n", iName));

            RTL_FREE(&pSid);
        }

        LW_SAFE_FREE_MEMORY(pdwTypes);
        pdwTypes = NULL;

        if (bRevLookup)
        {
            bRet &= CallLsaLookupSids(hLsa, hPolicy, dwNumNames, ppSids, dwLevel,
                                      &ppwszRetNames, &pdwTypes);
        }

        for (iName = 0; iName < dwNumNames; iName++)
        {
            LW_SAFE_FREE_MEMORY(ppwszNames[iName]);
            RTL_FREE(&ppSids[iName]);
        }

        LW_SAFE_FREE_MEMORY(ppwszNames);
        LW_SAFE_FREE_MEMORY(ppSids);
        LW_SAFE_FREE_MEMORY(pdwTypes);

        ppwszNames = NULL;
        ppSids     = NULL;
        pdwTypes   = NULL;
    }

    ntStatus = CallLsaClosePolicy(hLsa, &hPolicy);
    BAIL_ON_NT_STATUS(ntStatus);

error:
    if (ntStatus != STATUS_SUCCESS ||
        error != ERROR_SUCCESS)
    {
        bRet = FALSE;
    }

    return bRet;
}


DWORD
TestLsaLookupNames3(
    PTEST         pTest,
    PRPCSERVER    Server,
    PCREDENTIALS  pCreds,
    PPARAMETER    pOptions,
    DWORD         dwOptcount
    )
{
    PCSTR pszDefSysName = "\\\\";
    const DWORD dwDefLevel = -1;
    const BOOLEAN bDefRevLookup = TRUE;
    PCSTR pszDefTestSetName = "standalone";

    BOOLEAN bRet = TRUE;
    DWORD error = ERROR_SUCCESS;
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PSTR pszTestSetName = NULL;
    LSA_BINDING hLsa = NULL;
    PWSTR pwszSysName = NULL;
    BOOLEAN bRevLookup = TRUE;
    PWSTR dcName = NULL;
    RPCSERVER server = {0};
    PRPCSERVER lookupServer = NULL;
    POLICY_HANDLE hPolicy = NULL;
    PWSTR pwszDomainName = NULL;
    DWORD accessRights = LSA_ACCESS_LOOKUP_NAMES_SIDS;
    DWORD dwSelectedLevels[] = {0};
    DWORD dwAvailableLevels[] = {LSA_LOOKUP_NAMES_ALL,
                                 LSA_LOOKUP_NAMES_DOMAINS_ONLY,
                                 LSA_LOOKUP_NAMES_PRIMARY_DOMAIN_ONLY,
                                 LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY,
                                 LSA_LOOKUP_NAMES_FOREST_TRUSTS,
                                 LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2};
    PDWORD pdwLevels = NULL;
    DWORD dwNumLevels = 0;
    DWORD dwLevel = 0;
    DWORD iLevel = 0;
    DWORD dwNumNames = 0;
    DWORD iName = 0;
    PWSTR *ppwszNames = NULL;
    PWSTR pwszNT4Name = NULL;
    PSID *ppSids = NULL;
    PDWORD pdwTypes = NULL;
    PWSTR *ppwszRetNames = NULL;
    PTEST_LOOKUP pTestNames = NULL;

    TESTINFO(pTest,
             "Test calls LsaLookupNames3 function with arguments specified\n"
             "by testset parameter. It can be one of builtin sets or a path\n"
             "to the scenario file describing arguments and expected results.\n"
             "By default (revlookup=1) LsaLookupSids is called afterwards to\n"
             "verify whether returned results match the arguments of LsaLookupNames3.\n");

    error = RpctFetchParameterValue(
                       pOptions,
                       dwOptcount,
                       "systemname",
                       PT_WC16STRING,
                       &pwszSysName,
                       &pszDefSysName);
    BAIL_ON_WIN_ERROR(error);

    error = RpctFetchParameterValue(
                       pOptions,
                       dwOptcount,
                       "testset",
                       PT_CSTRING,
                       &pszTestSetName,
                       &pszDefTestSetName);
    BAIL_ON_WIN_ERROR(error);

    error = RpctFetchParameterValue(
                       pOptions,
                       dwOptcount,
                       "level",
                       PT_UINT32,
                       (UINT32*)&dwLevel,
                       (UINT32*)&dwDefLevel);
    BAIL_ON_WIN_ERROR(error);

    error = RpctFetchParameterValue(
                       pOptions,
                       dwOptcount,
                       "revlookup",
                       PT_UINT32,
                       (UINT32*)&bRevLookup,
                       (UINT32*)&bDefRevLookup);
    BAIL_ON_WIN_ERROR(error);

    error = RpctFetchParameterValue(
                       pOptions,
                       dwOptcount,
                       "dcname",
                       PT_WC16STRING,
                       &dcName,
                       NULL);
    BAIL_ON_WIN_ERROR(error);

    if (dcName)
    {
        server.Hostname = dcName;
        lookupServer = &server;
    }
    else
    {
        lookupServer = Server;
    }

    error = TestGetLookupTestSet(&pTestNames,
                                 &dwNumNames,
                                 pszTestSetName,
                                 lookupServer);
    BAIL_ON_WIN_ERROR(error);

    if (dwLevel == (DWORD)(-1))
    {
        pdwLevels   = dwAvailableLevels;
        dwNumLevels = sizeof(dwAvailableLevels)/sizeof(dwAvailableLevels[0]);
    }
    else
    {
        dwSelectedLevels[0] = dwLevel;
        pdwLevels   = dwSelectedLevels;
        dwNumLevels = sizeof(dwSelectedLevels)/sizeof(dwSelectedLevels[0]);
    }

    ntStatus = CreateRpcBinding(
                        OUT_PPVOID(&hLsa),
                        RPC_LSA_BINDING,
                        Server,
                        pCreds);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = CallLsaOpenPolicy(
                        hLsa,
                        Server->Hostname,
                        NULL,
                        0,
                        accessRights,
                        &hPolicy,
                        0,
                        &bRet);
    BAIL_ON_NT_STATUS(ntStatus);

    for (iLevel = 0; iLevel < dwNumLevels; iLevel++)
    {
        dwLevel = pdwLevels[iLevel];

        error = LwAllocateMemory(sizeof(PWSTR) * dwNumNames,
                                   OUT_PPVOID(&ppwszNames));
        BAIL_ON_WIN_ERROR(error);

        for (iName = 0; iName < dwNumNames; iName++)
        {
            PWSTR pwszDomain = NULL;
            PWSTR pwszName = NULL;

            DISPLAY_COMMENT(("Formatting test NT4 name %u: Domain=%s, Name=%s\n",
                             iName,
                             pTestNames[iName].pszDomainName,
                             pTestNames[iName].pszName));

            if (pTestNames[iName].pszDomainName &&
                RtlCStringIsEqual(
                          pTestNames[iName].pszDomainName,
                          "\\",
                          TRUE))
            {
                // Substitute missing domain name with default domain
                error = LwAllocateWc16String(
                               &pwszDomain,
                               pwszDomainName);
            }
            else if (pTestNames[iName].pszDomainName)
            {
                error = LwMbsToWc16s(
                               pTestNames[iName].pszDomainName,
                               &pwszDomain);
                BAIL_ON_WIN_ERROR(error);
            }
            else
            {
                error = LwMbsToWc16s(
                               "",
                               &pwszDomain);
                BAIL_ON_WIN_ERROR(error);
            }

            error = LwMbsToWc16s(pTestNames[iName].pszName,
                                   &pwszName);
            BAIL_ON_WIN_ERROR(error);

            error = TestFormatNT4Name(&pwszNT4Name, pwszDomain, pwszName);
            BAIL_ON_WIN_ERROR(error);

            ppwszNames[iName] = pwszNT4Name;

            LW_SAFE_FREE_MEMORY(pwszDomain);
            LW_SAFE_FREE_MEMORY(pwszName);

            pwszDomain = NULL;
            pwszName   = NULL;
        }

        bRet &= CallLsaLookupNames3(hLsa, hPolicy, dwNumNames, ppwszNames, dwLevel,
                                   &ppSids, &pdwTypes);

        for (iName = 0; iName < dwNumNames; iName++)
        {
            PSID pSid = NULL;
            DWORD dwReturnedRid = 0;
            DWORD dwReturnedType = pdwTypes[iName];

            if (dwReturnedType == SID_TYPE_USE_NONE ||
                dwReturnedType == SID_TYPE_INVALID ||
                dwReturnedType == SID_TYPE_UNKNOWN)
            {
                continue;
            }

            if (pTestNames[iName].pszSid)
            {
                ntStatus = RtlAllocateSidFromCString(
                                        &pSid,
                                        pTestNames[iName].pszSid);
                BAIL_ON_NT_STATUS(ntStatus);

                ASSERT_TEST_MSG((ppSids[iName] != NULL), ("(i = %u)\n", iName));

                ASSERT_SID_EQUAL_MSG(pSid, ppSids[iName], ("(i = %u)\n", iName));

                if (ppSids[iName])
                {
                    dwReturnedRid =
                        ppSids[iName]->SubAuthority[ppSids[iName]->SubAuthorityCount - 1];

                    ASSERT_TEST_MSG(dwReturnedRid == pTestNames[iName].dwRid,
                                    ("(i = %u)\n", iName));
                }
            }

            ASSERT_TEST_MSG(dwReturnedType == pTestNames[iName].dwType,
                            ("(i = %u)\n", iName));

            RTL_FREE(&pSid);
        }

        LW_SAFE_FREE_MEMORY(pdwTypes);
        pdwTypes = NULL;

        if (bRevLookup)
        {
            bRet &= CallLsaLookupSids(hLsa, hPolicy, dwNumNames, ppSids, dwLevel,
                                      &ppwszRetNames, &pdwTypes);
        }

        for (iName = 0; iName < dwNumNames; iName++)
        {
            LW_SAFE_FREE_MEMORY(ppwszNames[iName]);
            RTL_FREE(&ppSids[iName]);
        }

        LW_SAFE_FREE_MEMORY(ppwszNames);
        LW_SAFE_FREE_MEMORY(ppSids);
        LW_SAFE_FREE_MEMORY(pdwTypes);

        ppwszNames = NULL;
        ppSids     = NULL;
        pdwTypes   = NULL;
    }

    ntStatus = CallLsaClosePolicy(hLsa, &hPolicy);
    BAIL_ON_NT_STATUS(ntStatus);

error:
    if (ntStatus != STATUS_SUCCESS ||
        error != ERROR_SUCCESS)
    {
        bRet = FALSE;
    }

    return bRet;
}


static
DWORD
TestLsaLookupSids(
    PTEST         pTest,
    PRPCSERVER    Server,
    PCREDENTIALS  pCreds,
    PPARAMETER    pOptions,
    DWORD         dwOptcount
    )
{
    PCSTR pszDefSysName = "\\\\";
    const DWORD dwDefLevel = -1;
    const BOOLEAN bDefRevLookup = TRUE;
    PCSTR pszDefTestSetName = "standalone";

    BOOLEAN bRet = TRUE;
    DWORD error = ERROR_SUCCESS;
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PSTR pszTestSetName = NULL;
    LSA_BINDING hLsa = NULL;
    PWSTR pwszSysName = NULL;
    BOOLEAN bRevLookup = TRUE;
    POLICY_HANDLE hPolicy = NULL;
    PWSTR pwszDomainName = NULL;
    PSID pDomainSid = NULL;
    DWORD accessRights = LSA_ACCESS_LOOKUP_NAMES_SIDS;
    DWORD dwSelectedLevels[] = {0};
    DWORD dwAvailableLevels[] = {LSA_LOOKUP_NAMES_ALL,
                                 LSA_LOOKUP_NAMES_DOMAINS_ONLY,
                                 LSA_LOOKUP_NAMES_PRIMARY_DOMAIN_ONLY,
                                 LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY,
                                 LSA_LOOKUP_NAMES_FOREST_TRUSTS,
                                 LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2};
    PDWORD pdwLevels = NULL;
    DWORD dwNumLevels = 0;
    DWORD dwLevel = 0;
    DWORD iLevel = 0;
    DWORD dwNumSids = 0;
    DWORD iSid = 0;
    PSID *ppSids = NULL;
    PWSTR *ppwszNames = NULL;
    PDWORD pdwTypes = NULL;
    PTEST_LOOKUP pTestSids = NULL;
    PWSTR pwszNT4Name = NULL;

    error = RpctFetchParameterValue(pOptions, dwOptcount, "systemname", PT_WC16STRING,
                       &pwszSysName, &pszDefSysName);
    BAIL_ON_WIN_ERROR(error);

    error = RpctFetchParameterValue(pOptions, dwOptcount, "testset", PT_CSTRING,
                       (UINT32*)&pszTestSetName, (UINT32*)&pszDefTestSetName);
    BAIL_ON_WIN_ERROR(error);

    error = RpctFetchParameterValue(pOptions, dwOptcount, "level", PT_UINT32,
                       (UINT32*)&dwLevel, (UINT32*)&dwDefLevel);
    BAIL_ON_WIN_ERROR(error);

    error = RpctFetchParameterValue(pOptions, dwOptcount, "revlookup", PT_UINT32,
                       (UINT32*)&bRevLookup, (UINT32*)&bDefRevLookup);
    BAIL_ON_WIN_ERROR(error);

    error = TestGetLookupTestSet(&pTestSids,
                                 &dwNumSids,
                                 pszTestSetName,
                                 Server);
    BAIL_ON_WIN_ERROR(error);

    TESTINFO(pTest, "");

    if (dwLevel == (DWORD)(-1))
    {
        pdwLevels   = dwAvailableLevels;
        dwNumLevels = sizeof(dwAvailableLevels)/sizeof(dwAvailableLevels[0]);
    }
    else
    {
        dwSelectedLevels[0] = dwLevel;
        pdwLevels   = dwSelectedLevels;
        dwNumLevels = sizeof(dwSelectedLevels)/sizeof(dwSelectedLevels[0]);
    }

    ntStatus = CreateRpcBinding(
                        OUT_PPVOID(&hLsa),
                        RPC_LSA_BINDING,
                        Server,
                        pCreds);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = CallLsaOpenPolicy(
                        hLsa,
                        Server->Hostname,
                        NULL,
                        0,
                        accessRights,
                        &hPolicy,
                        0,
                        &bRet);
    BAIL_ON_NT_STATUS(ntStatus);

    for (iLevel = 0; iLevel < dwNumLevels; iLevel++)
    {
        dwLevel = pdwLevels[iLevel];

        error = LwAllocateMemory(sizeof(PSID) * dwNumSids,
                                   OUT_PPVOID(&ppSids));
        BAIL_ON_WIN_ERROR(error);

        for (iSid = 0; iSid < dwNumSids; iSid++)
        {
            PSID pSid = NULL;
            DWORD dwSidSize = 0;

            if (pTestSids[iSid].pszSid)
            {
                ntStatus = RtlAllocateSidFromCString(&pSid,
                                                     pTestSids[iSid].pszSid);
                BAIL_ON_NT_STATUS(ntStatus);
            }
            else
            {
                dwSidSize = RtlLengthRequiredSid(pDomainSid->SubAuthorityCount + 1);

                error = LwAllocateMemory(dwSidSize, OUT_PPVOID(&pSid));
                BAIL_ON_WIN_ERROR(error);

                ntStatus = RtlCopySid(dwSidSize, pSid, pDomainSid);
                BAIL_ON_NT_STATUS(ntStatus);

                ntStatus = RtlAppendRidSid(dwSidSize, pSid,
                                           pTestSids[iSid].dwRid);
                BAIL_ON_NT_STATUS(ntStatus);
            }

            ppSids[iSid] = pSid;
        }

        bRet &= CallLsaLookupSids(hLsa, hPolicy, dwNumSids, ppSids, dwLevel,
                                  &ppwszNames, &pdwTypes);

        for (iSid = 0; iSid < dwNumSids; iSid++)
        {
            PWSTR pwszDomain = NULL;
            PWSTR pwszName = ppwszNames[iSid];
            DWORD dwReturnedType = pdwTypes[iSid];

            if (dwReturnedType == SID_TYPE_USE_NONE ||
                dwReturnedType == SID_TYPE_INVALID ||
                dwReturnedType == SID_TYPE_UNKNOWN)
            {
                continue;
            }

            if (pTestSids[iSid].pszDomainName)
            {
                error = LwMbsToWc16s(pTestSids[iSid].pszDomainName,
                                       &pwszDomain);
                BAIL_ON_WIN_ERROR(error);
            }
            else
            {
                error = LwAllocateWc16String(&pwszDomain,
                                               pwszDomainName);
                BAIL_ON_WIN_ERROR(error);
            }

            error = LwMbsToWc16s(pTestSids[iSid].pszName, &pwszName);
            BAIL_ON_WIN_ERROR(error);

            error = TestFormatNT4Name(&pwszNT4Name, pwszDomain, pwszName);
            BAIL_ON_WIN_ERROR(error);

            ASSERT_TEST_MSG(ppwszNames[iSid] != NULL, ("(i = %u)\n", iSid));

            if (ppwszNames[iSid])
            {
                ASSERT_TEST_MSG(RtlWC16StringIsEqual(ppwszNames[iSid],
                                                     pwszNT4Name,
                                                     FALSE),
                                ("(i = %u)\n", iSid));
            }

            ASSERT_TEST_MSG(dwReturnedType == pTestSids[iSid].dwType,
                            ("(i = %u)\n", iSid));

            LW_SAFE_FREE_MEMORY(pwszDomain);
            LW_SAFE_FREE_MEMORY(pwszName);
            LW_SAFE_FREE_MEMORY(pwszNT4Name);

            pwszDomain   = NULL;
            pwszName     = NULL;
            pwszNT4Name  = NULL;
        }

        for (iSid = 0; iSid < dwNumSids; iSid++)
        {
            LW_SAFE_FREE_MEMORY(ppwszNames[iSid]);
        }

        LW_SAFE_FREE_MEMORY(ppwszNames);
        LW_SAFE_FREE_MEMORY(pdwTypes);

        ppwszNames = NULL;
        pdwTypes   = NULL;
    }

    ntStatus = CallLsaClosePolicy(hLsa, &hPolicy);
    BAIL_ON_NT_STATUS(ntStatus);

error:
    if (ntStatus != STATUS_SUCCESS ||
        error != ERROR_SUCCESS)
    {
        bRet = FALSE;
    }

    return bRet;
}


static
DWORD
TestLsaLookup(
    PTEST         Test,
    PRPCSERVER    Server,
    PCREDENTIALS  Creds,
    PPARAMETER    Options,
    DWORD         OptionsCount
    )
{
    BOOLEAN bRet = TRUE;

    bRet &= TestLsaLookupNames(Test,
                               Server,
                               Creds,
                               Options,
                               OptionsCount);

    bRet &= TestLsaLookupNames2(Test,
                                Server,
                                Creds,
                                Options,
                                OptionsCount);

    bRet &= TestLsaLookupNames3(Test,
                                Server,
                                Creds,
                                Options,
                                OptionsCount);

    bRet &= TestLsaLookupSids(Test,
                              Server,
                              Creds,
                              Options,
                              OptionsCount);

    return bRet;
}


static
DWORD
TestLsaQueryInfoPolicy(
    PTEST         pTest,
    PRPCSERVER    Server,
    PCREDENTIALS  pCreds,
    PPARAMETER    pOptions,
    DWORD         dwOptcount
    )
{
    const UINT32 access_rights = LSA_ACCESS_LOOKUP_NAMES_SIDS |
                                 LSA_ACCESS_VIEW_POLICY_INFO;

    const UINT32 def_level = 0;

    BOOLEAN bRet = TRUE;
    NTSTATUS ntStatus = STATUS_SUCCESS;
    DWORD error = ERROR_SUCCESS;
    LSA_BINDING hLsa = NULL;
    POLICY_HANDLE hPolicy = NULL;
    LsaPolicyInformation *info = NULL;
    UINT32 level = 0;

    TESTINFO(pTest, "");

    error = RpctFetchParameterValue(pOptions, dwOptcount, "level", PT_UINT32, &level,
                       &def_level);
    BAIL_ON_WIN_ERROR(error);

    bRet &= CreateRpcBinding(OUT_PPVOID(&hLsa),
                             RPC_LSA_BINDING,
                             Server,
                             pCreds);

    ntStatus = LsaOpenPolicy2(hLsa,
                              Server->Hostname,
                              NULL,
                              access_rights,
                              &hPolicy);
    BAIL_ON_NT_STATUS(ntStatus);

    /*
     * level = 1 doesn't work yet for some reason (unmarshalling error probably)
     */

    if (level) {
        if (level == 1)
        {
            DISPLAY_ERROR(("Level %u unsupported. Exiting...\n", level));
            bRet = FALSE;
            goto error;
        }

        INPUT_ARG_UINT(level);

        CALL_NT_API(ntStatus, LsaQueryInfoPolicy(hLsa, hPolicy,
                                              level, &info));
        if (info) {
            LsaRpcFreeMemory(info);
        }

    } else {
        for (level = 1; level <= 12; level++) {
            if (level == 1) continue;

            INPUT_ARG_UINT(level);

            CALL_NT_API(ntStatus, LsaQueryInfoPolicy(hLsa, hPolicy,
                                                  level, &info));
            if (info) {
                LsaRpcFreeMemory(info);
            }

            info = NULL;
        }
    }

    ntStatus = LsaClose(hLsa, hPolicy);
    LsaFreeBinding(&hLsa);

error:
    TEST_PASSED(("TestQueryInfoPolicy"), bRet);

    return bRet;
}


static
DWORD
TestLsaQueryInfoPolicy2(
    PTEST         pTest,
    PRPCSERVER    Server,
    PCREDENTIALS  pCreds,
    PPARAMETER    pOptions,
    DWORD         dwOptcount
    )
{
    const UINT32 access_rights = LSA_ACCESS_LOOKUP_NAMES_SIDS |
                                 LSA_ACCESS_ENABLE_LSA |
                                 LSA_ACCESS_ADMIN_AUDIT_LOG_ATTRS |
                                 LSA_ACCESS_CHANGE_SYS_AUDIT_REQS |
                                 LSA_ACCESS_SET_DEFAULT_QUOTA |
                                 LSA_ACCESS_CREATE_PRIVILEGE |
                                 LSA_ACCESS_CREATE_SECRET_OBJECT |
                                 LSA_ACCESS_CREATE_SPECIAL_ACCOUNTS |
                                 LSA_ACCESS_CHANGE_DOMTRUST_RELATION |
                                 LSA_ACCESS_GET_SENSITIVE_POLICY_INFO |
                                 LSA_ACCESS_VIEW_SYS_AUDIT_REQS |
                                 LSA_ACCESS_VIEW_POLICY_INFO;

    const UINT32 def_level = 0;

    BOOLEAN bRet = TRUE;
    NTSTATUS ntStatus = STATUS_SUCCESS;
    DWORD error = ERROR_SUCCESS;
    LSA_BINDING hLsa = NULL;
    POLICY_HANDLE hPolicy = NULL;
    LsaPolicyInformation *info = NULL;
    UINT32 level = 0;

    TESTINFO(pTest, "");

    error = RpctFetchParameterValue(pOptions, dwOptcount, "level", PT_UINT32, &level,
                       &def_level);
    BAIL_ON_WIN_ERROR(error);

    bRet &= CreateRpcBinding(OUT_PPVOID(&hLsa),
                             RPC_LSA_BINDING,
                             Server,
                             pCreds);

    ntStatus = LsaOpenPolicy2(hLsa,
                              Server->Hostname,
                              NULL,
                              access_rights,
                              &hPolicy);
    BAIL_ON_NT_STATUS(ntStatus);

    /*
     * level = 1 doesn't work yet for some reason (unmarshalling error probably)
     */

    if (level) {
        if (level == 1)
        {
            DISPLAY_ERROR(("Level %u unsupported. Exiting...\n", level));
            bRet = FALSE;
            goto error;
        }

        INPUT_ARG_UINT(level);

        CALL_NT_API(ntStatus, LsaQueryInfoPolicy2(hLsa, hPolicy,
                                               level, &info));
        if (info) {
            LsaRpcFreeMemory(info);
        }

    } else {
        for (level = 1; level <= 12; level++) {
            if (level == 1) continue;

            INPUT_ARG_UINT(level);

            CALL_NT_API(ntStatus, LsaQueryInfoPolicy2(hLsa, hPolicy,
                                                   level, &info));
            if (info) {
                LsaRpcFreeMemory(info);
            }

            info = NULL;
        }
    }

    ntStatus = LsaClose(hLsa, hPolicy);
    LsaFreeBinding(&hLsa);

error:
    return bRet;
}


static
BOOLEAN
CallLsaLookupNames(
    LSA_BINDING hBinding,
    POLICY_HANDLE hPolicy,
    DWORD dwNumNames,
    PWSTR *ppwszNames,
    DWORD dwLevel,
    PSID **pppSids,
    PDWORD *ppdwTypes
    )
{
    BOOLEAN bRet = TRUE;
    NTSTATUS ntStatus = STATUS_SUCCESS;
    DWORD error = ERROR_SUCCESS;
    RefDomainList *pDomains = NULL;
    TranslatedSid *pTransSids = NULL;
    PSID *ppSids = NULL;
    PDWORD pdwTypes = NULL;
    DWORD dwCount = 0;
    DWORD iSid = 0;

    DISPLAY_COMMENT(("Testing LsaLookupNames (Level = %u)\n",
                     dwLevel));

    ntStatus = LsaLookupNames(hBinding,
                              hPolicy,
                              dwNumNames,
                              ppwszNames,
                              &pDomains,
                              &pTransSids,
                              dwLevel,
                              &dwCount);
    if (ntStatus == STATUS_SOME_NOT_MAPPED ||
        ntStatus == STATUS_NONE_MAPPED)
    {
        ntStatus = STATUS_SUCCESS;
    }

    error = LwAllocateMemory(sizeof(PSID) * dwNumNames,
                               OUT_PPVOID(&ppSids));
    BAIL_ON_WIN_ERROR(error);

    error = LwAllocateMemory(sizeof(DWORD) * dwNumNames,
                               OUT_PPVOID(&pdwTypes));
    BAIL_ON_WIN_ERROR(error);

    for (iSid = 0; iSid < dwCount; iSid++)
    {
        DWORD iDomain = pTransSids[iSid].index;
        DWORD dwRid = pTransSids[iSid].rid;
        DWORD dwType = pTransSids[iSid].type;
        PSID pDomainSid = NULL;
        DWORD dwSidSize = 0;
        PSID pSid = NULL;

        ASSERT_TEST_MSG((dwType >= SID_TYPE_USE_NONE &&
                         dwType <= SID_TYPE_LABEL),
                        ("invalid type = %u (i = %u)\n", dwType, iSid));

        if (dwType == SID_TYPE_USE_NONE ||
            dwType == SID_TYPE_INVALID ||
            dwType == SID_TYPE_COMPUTER)
        {
            continue;
        }

        if (dwType == SID_TYPE_USER ||
            dwType == SID_TYPE_DOM_GRP ||
            dwType == SID_TYPE_ALIAS)
        {
            ASSERT_TEST_MSG(dwRid > 0,
                            ("invalid RID = %u with type = %u (i = %u)\n",
                             dwRid, dwType, iSid));
            ASSERT_TEST_MSG(iDomain < pDomains->count,
                            ("invalid domain index = %u (i = %u)\n",
                             iDomain, iSid));
        }
        else if (dwType == SID_TYPE_UNKNOWN)
        {
            ASSERT_TEST_MSG(iDomain == (DWORD)-1,
                            ("invalid domain index = %u (i = %u)\n",
                             iDomain, iSid));
        }
        else if (dwType == SID_TYPE_DOMAIN ||
                 dwType == SID_TYPE_WKN_GRP)
        {
            ASSERT_TEST_MSG(iDomain == pDomains->count,
                            ("invalid domain index = %u (i = %u)\n",
                             iDomain, iSid));
        }

        if (iDomain < pDomains->count)
        {
            pDomainSid = pDomains->domains[iDomain].sid;

            ASSERT_TEST_MSG(pDomainSid != NULL && RtlValidSid(pDomainSid),
                            ("invalid domain SID (i = %u)\n", iSid));

            if (RtlValidSid(pDomainSid))
            {
                dwSidSize = RtlLengthRequiredSid(pDomainSid->SubAuthorityCount + 1);

                error = LwAllocateMemory(dwSidSize, OUT_PPVOID(&pSid));
                BAIL_ON_WIN_ERROR(error);

                ntStatus = RtlCopySid(dwSidSize, pSid, pDomainSid);
                BAIL_ON_NT_STATUS(ntStatus);

                ntStatus = RtlAppendRidSid(dwSidSize, pSid, dwRid);
                BAIL_ON_NT_STATUS(ntStatus);
            }
        }

        pdwTypes[iSid] = dwType;
        ppSids[iSid]   = pSid;
    }

    *pppSids   = ppSids;
    *ppdwTypes = pdwTypes;

cleanup:
    if (pDomains)
    {
        LsaRpcFreeMemory(pDomains);
    }

    if (pTransSids)
    {
        LsaRpcFreeMemory(pTransSids);
    }

    if (ntStatus != STATUS_SUCCESS ||
        error != ERROR_SUCCESS)
    {
        bRet = FALSE;
    }

    return bRet;

error:
    for (iSid = 0; iSid < dwCount; iSid++)
    {
        RTL_FREE(&(ppSids[iSid]));
    }

    LW_SAFE_FREE_MEMORY(ppSids);
    LW_SAFE_FREE_MEMORY(pdwTypes);

    *pppSids   = NULL;
    *ppdwTypes = NULL;

    goto cleanup;
}


static
BOOLEAN
CallLsaLookupNames2(
    LSA_BINDING    hBinding,
    POLICY_HANDLE  hPolicy,
    DWORD          dwNumNames,
    PWSTR         *ppwszNames,
    DWORD          dwLevel,
    PSID         **pppSids,
    PDWORD        *ppdwTypes
    )
{
    BOOLEAN bRet = TRUE;
    NTSTATUS ntStatus = STATUS_SUCCESS;
    DWORD error = ERROR_SUCCESS;
    RefDomainList *pDomains = NULL;
    TranslatedSid2 *pTransSids = NULL;
    PSID *ppSids = NULL;
    PDWORD pdwTypes = NULL;
    DWORD dwCount = 0;
    DWORD iSid = 0;

    DISPLAY_COMMENT(("Testing LsaLookupNames2 (Level = %u)\n",
                     dwLevel));

    ntStatus = LsaLookupNames2(hBinding,
                               hPolicy,
                               dwNumNames,
                               ppwszNames,
                               &pDomains,
                               &pTransSids,
                               dwLevel,
                               &dwCount);
    if (ntStatus == STATUS_SOME_NOT_MAPPED ||
        ntStatus == STATUS_NONE_MAPPED)
    {
        ntStatus = STATUS_SUCCESS;
    }

    error = LwAllocateMemory(sizeof(PSID) * dwNumNames,
                               OUT_PPVOID(&ppSids));
    BAIL_ON_WIN_ERROR(error);

    error = LwAllocateMemory(sizeof(DWORD) * dwNumNames,
                               OUT_PPVOID(&pdwTypes));
    BAIL_ON_WIN_ERROR(error);

    for (iSid = 0; iSid < dwCount; iSid++)
    {
        DWORD iDomain = pTransSids[iSid].index;
        DWORD dwRid = pTransSids[iSid].rid;
        DWORD dwType = pTransSids[iSid].type;
        PSID pDomainSid = NULL;
        DWORD dwSidSize = 0;
        PSID pSid = NULL;

        ASSERT_TEST_MSG((dwType >= SID_TYPE_USE_NONE &&
                         dwType <= SID_TYPE_LABEL),
                        ("invalid type = %u (i = %u)\n", dwType, iSid));

        if (dwType == SID_TYPE_USE_NONE ||
            dwType == SID_TYPE_INVALID ||
            dwType == SID_TYPE_COMPUTER)
        {
            continue;
        }

        if (dwType == SID_TYPE_USER ||
            dwType == SID_TYPE_DOM_GRP ||
            dwType == SID_TYPE_ALIAS)
        {
            ASSERT_TEST_MSG(dwRid > 0,
                            ("invalid RID = %u with type = %u (i = %u)\n",
                             dwRid, dwType, iSid));
            ASSERT_TEST_MSG(iDomain < pDomains->count,
                            ("invalid domain index = %u (i = %u)\n",
                             iDomain, iSid));
        }
        else if (dwType == SID_TYPE_UNKNOWN)
        {
            ASSERT_TEST_MSG(iDomain == (DWORD)-1,
                            ("invalid domain index = %u (i = %u)\n",
                             iDomain, iSid));
        }
        else if (dwType == SID_TYPE_DOMAIN ||
                 dwType == SID_TYPE_WKN_GRP)
        {
            ASSERT_TEST_MSG(iDomain == pDomains->count,
                            ("invalid domain index = %u (i = %u)\n",
                             iDomain, iSid));
        }

        if (iDomain < pDomains->count)
        {
            pDomainSid = pDomains->domains[iDomain].sid;

            ASSERT_TEST_MSG(pDomainSid != NULL && RtlValidSid(pDomainSid),
                            ("invalid domain SID (i = %u)\n", iSid));

            if (RtlValidSid(pDomainSid))
            {
                dwSidSize = RtlLengthRequiredSid(pDomainSid->SubAuthorityCount + 1);

                error = LwAllocateMemory(dwSidSize, OUT_PPVOID(&pSid));
                BAIL_ON_WIN_ERROR(error);

                ntStatus = RtlCopySid(dwSidSize, pSid, pDomainSid);
                BAIL_ON_NT_STATUS(ntStatus);

                ntStatus = RtlAppendRidSid(dwSidSize, pSid, dwRid);
                BAIL_ON_NT_STATUS(ntStatus);
            }
        }

        pdwTypes[iSid] = dwType;
        ppSids[iSid]   = pSid;
    }

    *pppSids   = ppSids;
    *ppdwTypes = pdwTypes;

cleanup:
    if (pDomains)
    {
        LsaRpcFreeMemory(pDomains);
    }

    if (pTransSids)
    {
        LsaRpcFreeMemory(pTransSids);
    }

    if (ntStatus != STATUS_SUCCESS ||
        error != ERROR_SUCCESS)
    {
        bRet = FALSE;
    }

    return bRet;

error:
    for (iSid = 0; iSid < dwCount; iSid++)
    {
        RTL_FREE(&(ppSids[iSid]));
    }

    LW_SAFE_FREE_MEMORY(ppSids);
    LW_SAFE_FREE_MEMORY(pdwTypes);

    *pppSids   = NULL;
    *ppdwTypes = NULL;

    goto cleanup;
}


static
BOOLEAN
CallLsaLookupNames3(
    LSA_BINDING    hBinding,
    POLICY_HANDLE  hPolicy,
    DWORD          dwNumNames,
    PWSTR         *ppwszNames,
    DWORD          dwLevel,
    PSID         **pppSids,
    PDWORD        *ppdwTypes
    )
{
    BOOLEAN bRet = TRUE;
    NTSTATUS ntStatus = STATUS_SUCCESS;
    DWORD error = ERROR_SUCCESS;
    RefDomainList *pDomains = NULL;
    TranslatedSid3 *pTransSids = NULL;
    PSID *ppSids = NULL;
    PDWORD pdwTypes = NULL;
    DWORD dwCount = 0;
    DWORD iSid = 0;

    DISPLAY_COMMENT(("Testing LsaLookupNames3 (Level = %u)\n",
                     dwLevel));

    ntStatus = LsaLookupNames3(hBinding,
                               hPolicy,
                               dwNumNames,
                               ppwszNames,
                               &pDomains,
                               &pTransSids,
                               dwLevel,
                               &dwCount);
    if (ntStatus == STATUS_SOME_NOT_MAPPED ||
        ntStatus == STATUS_NONE_MAPPED)
    {
        ntStatus = STATUS_SUCCESS;
    }

    error = LwAllocateMemory(sizeof(PSID) * dwNumNames,
                               OUT_PPVOID(&ppSids));
    BAIL_ON_WIN_ERROR(error);

    error = LwAllocateMemory(sizeof(DWORD) * dwNumNames,
                               OUT_PPVOID(&pdwTypes));
    BAIL_ON_WIN_ERROR(error);

    for (iSid = 0; iSid < dwCount; iSid++)
    {
        DWORD iDomain = pTransSids[iSid].index;
        DWORD dwType = pTransSids[iSid].type;
        PSID pSid = pTransSids[iSid].sid;
        DWORD rid = 0;
        PSID pDomainSid = NULL;
        PSID pRetSid = NULL;

        ASSERT_TEST_MSG((dwType >= SID_TYPE_USE_NONE &&
                         dwType <= SID_TYPE_LABEL),
                        ("invalid type = %u (i = %u)\n", dwType, iSid));

        if (dwType == SID_TYPE_USE_NONE ||
            dwType == SID_TYPE_INVALID ||
            dwType == SID_TYPE_COMPUTER)
        {
            continue;
        }

        if (pSid && RtlValidSid(pSid))
        {
            ntStatus = RtlDuplicateSid(&pRetSid, pSid);
            BAIL_ON_NT_STATUS(ntStatus);

            rid = pSid->SubAuthority[pSid->SubAuthorityCount - 1];
        }
        else
        {
            ASSERT_TEST_MSG(pSid != NULL && RtlValidSid(pSid),
                            ("invalid SID (i = %u)\n", iSid));
        }

        if (dwType == SID_TYPE_USER ||
            dwType == SID_TYPE_DOM_GRP ||
            dwType == SID_TYPE_ALIAS)
        {
            ASSERT_TEST_MSG(rid > 0,
                            ("invalid RID = %u with type = %u (i = %u)\n",
                             rid, dwType, iSid));
            ASSERT_TEST_MSG(iDomain < pDomains->count,
                            ("invalid domain index = %u (i = %u)\n",
                             iDomain, iSid));
        }
        else if (dwType == SID_TYPE_UNKNOWN)
        {
            ASSERT_TEST_MSG(iDomain == (DWORD)-1,
                            ("invalid domain index = %u (i = %u)\n",
                             iDomain, iSid));
        }
        else if (dwType == SID_TYPE_DOMAIN ||
                 dwType == SID_TYPE_WKN_GRP)
        {
            ASSERT_TEST_MSG(iDomain == pDomains->count,
                            ("invalid domain index = %u (i = %u)\n",
                             iDomain, iSid));
        }

        if (iDomain < pDomains->count)
        {
            pDomainSid = pDomains->domains[iDomain].sid;

            ASSERT_TEST_MSG(pDomainSid != NULL && RtlValidSid(pDomainSid),
                            ("invalid domain SID (i = %u)\n", iSid));
        }

        pdwTypes[iSid] = dwType;
        ppSids[iSid]   = pRetSid;
    }

    *pppSids   = ppSids;
    *ppdwTypes = pdwTypes;

cleanup:
    if (pDomains)
    {
        LsaRpcFreeMemory(pDomains);
    }

    if (pTransSids)
    {
        LsaRpcFreeMemory(pTransSids);
    }

    if (ntStatus != STATUS_SUCCESS ||
        error != ERROR_SUCCESS)
    {
        bRet = FALSE;
    }

    return bRet;

error:
    for (iSid = 0; iSid < dwCount; iSid++)
    {
        RTL_FREE(&(ppSids[iSid]));
    }

    LW_SAFE_FREE_MEMORY(ppSids);
    LW_SAFE_FREE_MEMORY(pdwTypes);

    *pppSids   = NULL;
    *ppdwTypes = NULL;

    goto cleanup;
}


static
BOOLEAN
CallLsaLookupSids(
    LSA_BINDING    hBinding,
    POLICY_HANDLE  hPolicy,
    DWORD          dwNumSids,
    PSID          *ppSids,
    DWORD          dwLevel,
    PWSTR        **pppwszNames,
    PDWORD        *ppdwTypes
    )
{
    BOOLEAN bRet = TRUE;
    NTSTATUS ntStatus = STATUS_SUCCESS;
    DWORD error = ERROR_SUCCESS;
    SID_ARRAY Sids = {0};
    RefDomainList *pDomains = NULL;
    TranslatedName *pTransNames = NULL;
    PWSTR *ppwszNames = NULL;
    PDWORD pdwTypes = NULL;
    DWORD dwCount = 0;
    DWORD iSid = 0;
    DWORD iName = 0;
    PSID pInvalidSid = NULL;

    Sids.dwNumSids = dwNumSids;

    error = LwAllocateMemory(sizeof(SID_PTR) * dwNumSids,
                               OUT_PPVOID(&Sids.pSids));
    BAIL_ON_WIN_ERROR(error);

    ntStatus = RtlAllocateSidFromCString(&pInvalidSid,
                                         "S-1-5-32-0");
    BAIL_ON_NT_STATUS(ntStatus);

    for (iSid = 0; iSid < dwNumSids; iSid++)
    {
        /* Replace NULL SIDs with an invalid SID because CallLookupSids
           may be called in sequence of other lookup calls, so keeping
           "invalid" names/SIDs in the same indices is important for
           further validation */
        Sids.pSids[iSid].pSid = ppSids[iSid] ? ppSids[iSid] : pInvalidSid;
    }

    DISPLAY_COMMENT(("Testing LsaLookupNames (Level = %u)\n",
                     dwLevel));

    ntStatus = LsaLookupSids(hBinding,
                             hPolicy,
                             &Sids,
                             &pDomains,
                             &pTransNames,
                             dwLevel,
                             &dwCount);
    if (ntStatus == STATUS_SOME_NOT_MAPPED ||
        ntStatus == STATUS_NONE_MAPPED)
    {
        ntStatus = STATUS_SUCCESS;
    }

    error = LwAllocateMemory(sizeof(PWSTR) * dwNumSids,
                               OUT_PPVOID(&ppwszNames));
    BAIL_ON_WIN_ERROR(error);

    error = LwAllocateMemory(sizeof(DWORD) * dwNumSids,
                               OUT_PPVOID(&pdwTypes));
    BAIL_ON_WIN_ERROR(error);

    for (iName = 0; iName < dwCount; iName++)
    {
        DWORD iDomain = pTransNames[iName].sid_index;
        DWORD dwType = pTransNames[iName].type;
        PWSTR pwszDomainName = NULL;
        PWSTR pwszTranslatedName = NULL;
        PWSTR pwszName = NULL;

        ASSERT_TEST_MSG((dwType >= SID_TYPE_USE_NONE &&
                         dwType <= SID_TYPE_LABEL),
                        ("invalid type = %u (i = %u)\n", dwType, iName));

        if (dwType == SID_TYPE_USE_NONE ||
            dwType == SID_TYPE_INVALID ||
            dwType == SID_TYPE_COMPUTER)
        {
            continue;
        }

        if (dwType == SID_TYPE_USER ||
            dwType == SID_TYPE_DOM_GRP ||
            dwType == SID_TYPE_ALIAS)
        {
            ASSERT_TEST_MSG(iDomain < pDomains->count,
                            ("invalid domain index = %u (i = %u)\n",
                             iDomain, iName));
        }
        else if (dwType == SID_TYPE_UNKNOWN)
        {
            ASSERT_TEST_MSG(iDomain == (DWORD)-1,
                            ("invalid domain index = %u (i = %u)\n",
                             iDomain, iName));
        }
        else if (dwType == SID_TYPE_DOMAIN ||
                 dwType == SID_TYPE_WKN_GRP)
        {
            ASSERT_TEST_MSG(iDomain == pDomains->count,
                            ("invalid domain index = %u (i = %u)\n",
                             iDomain, iName));
        }

        if (iDomain < pDomains->count)
        {
            ASSERT_UNICODE_STRING_VALID_MSG(&(pDomains->domains[iDomain].name),
                                          ("invalid unicode name (i = %u)\n",
                                           iName));

            ASSERT_UNICODE_STRING_VALID_MSG(&(pTransNames[iName].name),
                                          ("invalid unicode name (i = %u)\n",
                                           iName));

            if (pDomains->domains[iDomain].name.Buffer)
            {
                error = LwAllocateWc16StringFromUnicodeString(
                                &pwszDomainName,
                                &pDomains->domains[iDomain].name);
            }
            else
            {
                error = LwMbsToWc16s("", &pwszDomainName);
            }
            BAIL_ON_WIN_ERROR(error);

            error = LwAllocateWc16StringFromUnicodeString(
                            &pwszTranslatedName,
                            &pTransNames[iName].name);
            BAIL_ON_WIN_ERROR(error);

            error = TestFormatNT4Name(
                            &pwszName,
                            pwszDomainName,
                            pwszTranslatedName);
            BAIL_ON_WIN_ERROR(error);
        }

        ppwszNames[iName] = pwszName;
        pdwTypes[iName]   = dwType;

        LW_SAFE_FREE_MEMORY(pwszDomainName);
        LW_SAFE_FREE_MEMORY(pwszTranslatedName);

        pwszDomainName = NULL;
        pwszTranslatedName = NULL;
    }

    *pppwszNames = ppwszNames;
    *ppdwTypes   = pdwTypes;

cleanup:
    if (pDomains)
    {
        LsaRpcFreeMemory(pDomains);
    }

    if (pTransNames)
    {
        LsaRpcFreeMemory(pTransNames);
    }

    LW_SAFE_FREE_MEMORY(Sids.pSids);
    RTL_FREE(&pInvalidSid);

    if (ntStatus != STATUS_SUCCESS ||
        error != ERROR_SUCCESS)
    {
        bRet = FALSE;
    }

    return bRet;

error:
    for (iName = 0; iName < dwCount; iName++)
    {
        LW_SAFE_FREE_MEMORY(ppwszNames[iName]);
    }

    LW_SAFE_FREE_MEMORY(ppwszNames);
    LW_SAFE_FREE_MEMORY(pdwTypes);

    *pppwszNames = NULL;
    *ppdwTypes   = NULL;

    goto cleanup;
}


static
BOOLEAN
TestLsaOpenPolicy(
    LSA_BINDING      hBinding,
    PWSTR            pwszSysName,
    DWORD            dwAccessRights,
    POLICY_HANDLE   *phPolicy,
    PWSTR           *ppwszDomainName,
    PWSTR           *ppwszDnsDomainName,
    PSID            *ppDomainSid
    )
{
    BOOLEAN bRet = TRUE;
    NTSTATUS ntStatus = STATUS_SUCCESS;
    DWORD error = ERROR_SUCCESS;
    DWORD dwMaxAccessRights = LSA_ACCESS_LOOKUP_NAMES_SIDS |
                              LSA_ACCESS_ENABLE_LSA |
                              LSA_ACCESS_ADMIN_AUDIT_LOG_ATTRS |
                              LSA_ACCESS_CHANGE_SYS_AUDIT_REQS |
                              LSA_ACCESS_SET_DEFAULT_QUOTA |
                              LSA_ACCESS_CREATE_PRIVILEGE |
                              LSA_ACCESS_CREATE_SECRET_OBJECT |
                              LSA_ACCESS_CREATE_SPECIAL_ACCOUNTS |
                              LSA_ACCESS_CHANGE_DOMTRUST_RELATION |
                              LSA_ACCESS_GET_SENSITIVE_POLICY_INFO |
                              LSA_ACCESS_VIEW_SYS_AUDIT_REQS |
                              LSA_ACCESS_VIEW_POLICY_INFO;
    DWORD dwMinAccessRights = LSA_ACCESS_LOOKUP_NAMES_SIDS;
    DWORD dwDefAccessRights = LSA_ACCESS_LOOKUP_NAMES_SIDS |
                              LSA_ACCESS_VIEW_POLICY_INFO;

    POLICY_HANDLE hPolicy = NULL;
    LsaPolicyInformation *pPolicyInfo = NULL;
    LsaPolicyInformation *pDomainInfo = NULL;
    LsaPolicyInformation *pDnsDomainInfo = NULL;
    DWORD i = 0;

    DISPLAY_COMMENT(("Testing LsaOpenPolicy2\n"));

    CALL_NT_API(ntStatus, LsaOpenPolicy2(hBinding,
                                        pwszSysName,
                                        NULL,
                                        dwMaxAccessRights,
                                        &hPolicy));
    BAIL_ON_NT_STATUS(ntStatus);

    for (i = 1; i <= 12; i++)
    {
        if (i == 1 ||
            i == 9 ||
            i == 10 ||
            i == 11) continue;

        DISPLAY_COMMENT(("Testing LsaQueryInfoPolicy (level = %u)\n", i));

        CALL_NT_API(ntStatus, LsaQueryInfoPolicy(hBinding,
                                                hPolicy,
                                                i,
                                                &pPolicyInfo));

        if (ntStatus != STATUS_SUCCESS) continue;

        switch (i)
        {
        case LSA_POLICY_INFO_DOMAIN:
            pDomainInfo = pPolicyInfo;
            break;

        case LSA_POLICY_INFO_DNS:
            pDnsDomainInfo = pPolicyInfo;
            break;

        default:
            if (pPolicyInfo)
            {
                LsaRpcFreeMemory(pPolicyInfo);
                pPolicyInfo = NULL;
            }
            break;
        }
    }

    ASSERT_UNICODE_STRING_EQUAL((PUNICODE_STRING)&pDomainInfo->domain.name,
                                (PUNICODE_STRING)&pDnsDomainInfo->dns.name);

    ASSERT_SID_EQUAL(pDomainInfo->domain.sid, pDnsDomainInfo->dns.sid);

    DISPLAY_COMMENT(("Testing LsaClose\n"));
    CALL_NT_API(ntStatus, LsaClose(hBinding, hPolicy));

    hPolicy = NULL;

    DISPLAY_COMMENT(("Testing LsaOpenPolicy2\n"));

    CALL_NT_API(ntStatus, LsaOpenPolicy2(hBinding,
                                        pwszSysName,
                                        NULL,
                                        dwMinAccessRights,
                                        &hPolicy));
    BAIL_ON_NT_STATUS(ntStatus);

    for (i = 1; i <= 12; i++)
    {
        if (i == 1 ||
            i == 9 ||
            i == 10 ||
            i == 11) continue;

        DISPLAY_COMMENT(("Testing LsaQueryInfoPolicy2 (level = %u)\n", i));

        ntStatus = LsaQueryInfoPolicy2(hBinding, hPolicy, i, &pPolicyInfo);

        if (i == LSA_POLICY_INFO_DB ||
            i == LSA_POLICY_INFO_AUDIT_FULL_SET ||
            i == LSA_POLICY_INFO_AUDIT_FULL_QUERY)
        {
            /* ignore audit-related info levels */
            continue;
        }
        ASSERT_TEST_MSG((ntStatus == STATUS_ACCESS_DENIED),
                        ("Expected: STATUS_ACCESS_DENIED, "
                         "Received: %s (0x%08x)\n",
                         LwNtStatusToName(ntStatus), ntStatus));

        ASSERT_TEST((pPolicyInfo == NULL));
    }

    DISPLAY_COMMENT(("Testing LsaClose\n"));
    CALL_NT_API(ntStatus, LsaClose(hBinding, hPolicy));

    hPolicy = NULL;

    DISPLAY_COMMENT(("Testing LsaOpenPolicy2\n"));

    if (dwAccessRights == 0)
    {
        dwAccessRights = dwDefAccessRights;
    }

    CALL_NT_API(ntStatus, LsaOpenPolicy2(hBinding,
                                        pwszSysName,
                                        NULL,
                                        dwAccessRights,
                                        &hPolicy));
    BAIL_ON_NT_STATUS(ntStatus);

    *phPolicy = hPolicy;

    if (ppwszDomainName)
    {
        error = LwAllocateWc16StringFromUnicodeString(
                                  ppwszDomainName,
                                  &pDomainInfo->domain.name);
        BAIL_ON_WIN_ERROR(error);
    }

    if (ppwszDnsDomainName)
    {
        error = LwAllocateWc16StringFromUnicodeString(
                                  ppwszDnsDomainName,
                                  &pDnsDomainInfo->dns.name);
        BAIL_ON_WIN_ERROR(error);
    }

    if (ppDomainSid)
    {
        ntStatus = RtlDuplicateSid(ppDomainSid, pDomainInfo->domain.sid);
        BAIL_ON_NT_STATUS(ntStatus);
    }

error:
    if (pDomainInfo)
    {
        LsaRpcFreeMemory(pDomainInfo);
    }

    if (pDnsDomainInfo)
    {
        LsaRpcFreeMemory(pDnsDomainInfo);
    }

    if (ntStatus != STATUS_SUCCESS &&
        error != ERROR_SUCCESS)
    {
        bRet = FALSE;
    }

    TEST_PASSED(("TestLsaOpenPolicy"), bRet);

    return bRet;
}


static
DWORD
TestLsaInfoPolicy(
    PTEST         pTest,
    PRPCSERVER    Server,
    PCREDENTIALS  pCreds,
    PPARAMETER    pOptions,
    DWORD         dwOptcount
    )
{
    PCSTR pszDefSysName = "";

    BOOL bRet = TRUE;
    NTSTATUS ntStatus = STATUS_SUCCESS;
    DWORD error = ERROR_SUCCESS;
    LSA_BINDING hLsa = NULL;
    POLICY_HANDLE hPolicy = NULL;
    PWSTR pwszSysName = NULL;

    error = RpctFetchParameterValue(pOptions, dwOptcount, "systemname", PT_WC16STRING,
                       &pwszSysName, &pszDefSysName);
    BAIL_ON_WIN_ERROR(error);

    TESTINFO(pTest, "");

    bRet &= CreateRpcBinding(OUT_PPVOID(&hLsa),
                             RPC_LSA_BINDING,
                             Server,
                             pCreds);

    bRet &= TestLsaOpenPolicy(hLsa, pwszSysName, 0, &hPolicy, NULL, NULL, NULL);

    ntStatus = CallLsaClosePolicy(hLsa, &hPolicy);
    BAIL_ON_NT_STATUS(ntStatus);

    LsaFreeBinding(&hLsa);

    bRet &= CreateRpcBinding(OUT_PPVOID(&hLsa),
                             RPC_LSA_BINDING,
                             Server,
                             pCreds);

    bRet &= TestLsaOpenPolicy(hLsa, pwszSysName, 0, &hPolicy, NULL, NULL, NULL);

    ntStatus = CallLsaClosePolicy(hLsa, &hPolicy);
    BAIL_ON_NT_STATUS(ntStatus);

error:
    LsaFreeBinding(&hLsa);

    LW_SAFE_FREE_MEMORY(pwszSysName);

    if (ntStatus != STATUS_SUCCESS)
    {
        bRet = FALSE;
    }

    return (int)bRet;
}


VOID
SetupLsaTests(PTEST t)
{
    AddTest(t, "LSA-POLICY", TestLsaPolicy);
    AddTest(t, "LSA-LOOKUP-NAMES", TestLsaLookupNames);
    AddTest(t, "LSA-LOOKUP-NAMES2", TestLsaLookupNames2);
    AddTest(t, "LSA-LOOKUP-NAMES3", TestLsaLookupNames3);
    AddTest(t, "LSA-LOOKUP-SIDS", TestLsaLookupSids);
    AddTest(t, "LSA-LOOKUP", TestLsaLookup);
    AddTest(t, "LSA-QUERY-INFO-POL", TestLsaQueryInfoPolicy);
    AddTest(t, "LSA-QUERY-INFO-POL2", TestLsaQueryInfoPolicy2);
    AddTest(t, "LSA-INFO-POLICY", TestLsaInfoPolicy);
}


/*
local variables:
mode: c
c-basic-offset: 4
indent-tabs-mode: nil
tab-width: 4
end:
*/
