Example #1
0
DWORD
ADLdap_MoveHashKeysToArray(
    IN OUT PLW_HASH_TABLE pHash,
    OUT PDWORD pCount,
    OUT PVOID** pppValues
    )
{
    LW_HASH_ITERATOR hashIterator = {0};
    DWORD count = (DWORD) LwHashGetKeyCount(pHash);
    DWORD index = 0;
    DWORD dwError = 0;
    PVOID* ppValues = NULL;
    LW_HASH_ENTRY*   pHashEntry = NULL;
    
    if (count)
    {
        dwError = LwAllocateMemory(
            sizeof(ppValues[0]) * count,
            OUT_PPVOID(&ppValues));
        BAIL_ON_LSA_ERROR(dwError);
    
        dwError = LwHashGetIterator(pHash, &hashIterator);
        BAIL_ON_LSA_ERROR(dwError);
        
        for (index = 0; (pHashEntry = LwHashNext(&hashIterator)) != NULL; index++)
        {
            ppValues[index] = pHashEntry->pKey;
        }
    }

    *pCount = count;
    *pppValues = ppValues;

cleanup:
    return dwError;

error:
    *pCount = 0;
    *pppValues = NULL;
    LW_SAFE_FREE_MEMORY(ppValues);
    goto cleanup;
}
Example #2
0
DWORD
LocalDirQueryMemberOf(
    IN HANDLE hProvider,
    IN LSA_FIND_FLAGS FindFlags,
    IN DWORD dwSidCount,
    IN PSTR* ppszSids,
    OUT PDWORD pdwGroupSidCount,
    OUT PSTR** pppszGroupSids
    )
{
    DWORD dwError = 0;
    DWORD dwIndex = 0;
    PLW_HASH_TABLE   pGroupHash = NULL;
    LW_HASH_ITERATOR hashIterator = {0};
    LW_HASH_ENTRY*   pHashEntry = NULL;
    DWORD dwGroupSidCount = 0;
    PSTR* ppszGroupSids = NULL;

    dwError = LwHashCreate(
                    13,
                    LwHashCaselessStringCompare,
                    LwHashCaselessStringHash,
                    NULL,
                    NULL,
                    &pGroupHash);
    BAIL_ON_LSA_ERROR(dwError);

    for (dwIndex = 0; dwIndex < dwSidCount; dwIndex++)
    {
        dwError = LocalDirQueryMemberOfInternal(
            hProvider,
            FindFlags,
            ppszSids[dwIndex],
            pGroupHash);
        BAIL_ON_LSA_ERROR(dwError);
    }

    dwGroupSidCount = (DWORD) LwHashGetKeyCount(pGroupHash);
    
    if (dwGroupSidCount)
    {
        dwError = LwAllocateMemory(
            sizeof(*ppszGroupSids) * dwGroupSidCount,
            OUT_PPVOID(&ppszGroupSids));
        BAIL_ON_LSA_ERROR(dwError);
    
        dwError = LwHashGetIterator(pGroupHash, &hashIterator);
        BAIL_ON_LSA_ERROR(dwError);
        
        for(dwIndex = 0; (pHashEntry = LwHashNext(&hashIterator)) != NULL; dwIndex++)
        {
            ppszGroupSids[dwIndex] = (PSTR) pHashEntry->pValue;
            pHashEntry->pValue = NULL;
        }
    }

    *pdwGroupSidCount = dwGroupSidCount;
    *pppszGroupSids = ppszGroupSids;

cleanup:

    if (pGroupHash)
    {
        if (LwHashGetIterator(pGroupHash, &hashIterator) == 0)
        {
            while ((pHashEntry = LwHashNext(&hashIterator)))
            {
                LW_SAFE_FREE_MEMORY(pHashEntry->pValue);
            }
        }

        LwHashSafeFree(&pGroupHash);
    }

    return dwError;

error:

    *pdwGroupSidCount = 0;
    *pppszGroupSids = NULL;

    if (ppszGroupSids)
    {
        LwFreeStringArray(ppszGroupSids, dwGroupSidCount);
    }

    goto cleanup;
}
Example #3
0
static
DWORD
UmnSrvUpdateADAccountsByHash(
    HANDLE hLsass,
    PLW_EVENTLOG_CONNECTION pEventlog,
    HANDLE hReg,
    HKEY hParameters,
    PLW_HASH_TABLE pUsers,
    long long PreviousRun,
    long long Now
    )
{
    DWORD dwError = 0;
    HKEY hUsers = NULL;
    HKEY hGroups = NULL;
    LW_HASH_ITERATOR usersIterator = { 0 };
    LW_HASH_ENTRY* pEntry = NULL;
    DWORD groupSidCount = 0;
    PSTR* ppGroupSids = NULL;
    DWORD lookupGroupSidCount = 0;
    DWORD lookupGroupSidCapacity = 0;
    // Only free the first level of this array, do not free the strings it
    // points to.
    PSTR* ppLookupGroupSids = NULL;
    LSA_QUERY_LIST list = { 0 };
    PLSA_SECURITY_OBJECT *ppLookedupGroups = NULL;
    PLW_HASH_TABLE pGroups = NULL;
    PLW_HASH_TABLE pNameToUser = NULL;
    PLW_HASH_TABLE pNameToGroup = NULL;
    DWORD i = 0;
    // Do not free
    PLSA_SECURITY_OBJECT pGroup = NULL;
    // Do not free
    PLSA_SECURITY_OBJECT pExisting = NULL;
    PSTR pNewName = NULL;

    dwError = LwHashCreate(
                    100,
                    LwHashStringCompare,
                    LwHashStringHash,
                    UmnSrvHashFreeObjectValue,
                    NULL,
                    &pGroups);
    BAIL_ON_UMN_ERROR(dwError);

    dwError = LwHashCreate(
                    100,
                    LwHashStringCompare,
                    LwHashStringHash,
                    NULL,
                    NULL,
                    &pNameToGroup);
    BAIL_ON_UMN_ERROR(dwError);

    dwError = LwHashCreate(
                    pUsers->sCount * 2,
                    LwHashStringCompare,
                    LwHashStringHash,
                    NULL,
                    NULL,
                    &pNameToUser);
    BAIL_ON_UMN_ERROR(dwError);

    dwError = RegOpenKeyExA(
                hReg,
                hParameters,
                "AD Users",
                0,
                KEY_ALL_ACCESS,
                &hUsers);
    BAIL_ON_UMN_ERROR(dwError);

    dwError = RegOpenKeyExA(
                hReg,
                hParameters,
                "AD Groups",
                0,
                KEY_ALL_ACCESS,
                &hGroups);
    BAIL_ON_UMN_ERROR(dwError);

    dwError = LwHashGetIterator(
                    pUsers,
                    &usersIterator);
    BAIL_ON_UMN_ERROR(dwError);

    while((pEntry = LwHashNext(&usersIterator)) != NULL)
    {
        PLSA_SECURITY_OBJECT pUser = (PLSA_SECURITY_OBJECT)pEntry->pValue;

        if (gbPollerThreadShouldExit)
        {
            dwError = ERROR_CANCELLED;
            BAIL_ON_UMN_ERROR(dwError);
        }

        dwError = LwHashGetValue(
                        pNameToUser,
                        pUser->userInfo.pszUnixName,
                        (PVOID*)&pExisting);
        if (dwError != ERROR_NOT_FOUND)
        {
            BAIL_ON_UMN_ERROR(dwError);

            dwError = LwAllocateStringPrintf(
                            &pNewName,
                            "%s\\%s",
                            pUser->pszNetbiosDomainName,
                            pUser->pszSamAccountName);
            BAIL_ON_UMN_ERROR(dwError);

            UMN_LOG_ERROR("Found conflict on user name '%hhs'. Sid %hhs will now be reported as name '%s' instead because its alias conflicts with sid %hhs.",
                                    pUser->userInfo.pszUnixName,
                                    pUser->pszObjectSid,
                                    pNewName,
                                    pExisting->pszObjectSid);
            BAIL_ON_UMN_ERROR(dwError);

            LW_SAFE_FREE_STRING(pUser->userInfo.pszUnixName);
            pUser->userInfo.pszUnixName = pNewName;
            pNewName = NULL;
        }

        dwError = LwHashSetValue(
                        pNameToUser,
                        pUser->userInfo.pszUnixName,
                        pUser);
        BAIL_ON_UMN_ERROR(dwError);

        dwError = UmnSrvUpdateADUser(
                        pEventlog,
                        hReg,
                        hUsers,
                        PreviousRun,
                        Now,
                        pUser);
        if (dwError == ERROR_NO_UNICODE_TRANSLATION)
        {
            // Error message already logged
            dwError = 0;
            continue;
        }
        BAIL_ON_UMN_ERROR(dwError);

        if (ppGroupSids)
        {
            LsaFreeSidList(
                    groupSidCount,
                    ppGroupSids);
        }
        dwError = LsaQueryMemberOf(
                        hLsass,
                        NULL,
                        0,
                        1,
                        &pUser->pszObjectSid,
                        &groupSidCount,
                        &ppGroupSids);
        BAIL_ON_UMN_ERROR(dwError);

        if (groupSidCount > lookupGroupSidCapacity)
        {
            LW_SAFE_FREE_MEMORY(ppLookupGroupSids);

            dwError = LwAllocateMemory(
                            groupSidCount * sizeof(ppLookupGroupSids[0]),
                            (PVOID*)&ppLookupGroupSids);
            BAIL_ON_UMN_ERROR(dwError);

            lookupGroupSidCapacity = groupSidCount;
        }

        lookupGroupSidCount = 0;

        for (i = 0; i < groupSidCount; i++)
        {
            dwError = LwHashGetValue(
                            pGroups,
                            ppGroupSids[i],
                            (PVOID*)&pGroup);
            if (dwError == ERROR_NOT_FOUND)
            {
                ppLookupGroupSids[lookupGroupSidCount++] = ppGroupSids[i];
            }
            else
            {
                BAIL_ON_UMN_ERROR(dwError);

                UMN_LOG_VERBOSE("Found AD user %s is a member of processed group %s",
                        pUser->userInfo.pszUnixName,
                        pGroup->groupInfo.pszUnixName);

                if (!pGroup->enabled)
                {
                    UMN_LOG_VERBOSE("Skipping unenabled group %s",
                        pGroup->groupInfo.pszUnixName);
                }
                else
                {
                    dwError = UmnSrvUpdateADGroupMember(
                                    pEventlog,
                                    hReg,
                                    hGroups,
                                    PreviousRun,
                                    Now,
                                    pGroup,
                                    pUser->userInfo.pszUnixName);
                    BAIL_ON_UMN_ERROR(dwError);
                }
            }
        }
        
        if (lookupGroupSidCount)
        {
            list.ppszStrings = (PCSTR *)ppLookupGroupSids;

            dwError = LsaFindObjects(
                            hLsass,
                            NULL,
                            0,
                            LSA_OBJECT_TYPE_GROUP,
                            LSA_QUERY_TYPE_BY_SID,
                            lookupGroupSidCount,
                            list,
                            &ppLookedupGroups);
            BAIL_ON_UMN_ERROR(dwError);

            for (i = 0; i < lookupGroupSidCount; i++)
            {
                if (gbPollerThreadShouldExit)
                {
                    dwError = ERROR_CANCELLED;
                    BAIL_ON_UMN_ERROR(dwError);
                }
                pGroup = ppLookedupGroups[i];

                if (!pGroup)
                {
                    UMN_LOG_ERROR("Unable to find group sid %s that user %s is a member of",
                            ppLookupGroupSids[i],
                            pUser->userInfo.pszUnixName);
                    continue;
                }

                UMN_LOG_VERBOSE("Found AD user %s is a member of unprocessed group %s",
                        pUser->userInfo.pszUnixName,
                        pGroup->groupInfo.pszUnixName);

                dwError = LwHashGetValue(
                                pNameToGroup,
                                pGroup->groupInfo.pszUnixName,
                                (PVOID*)&pExisting);
                if (dwError != ERROR_NOT_FOUND)
                {
                    BAIL_ON_UMN_ERROR(dwError);

                    dwError = LwAllocateStringPrintf(
                                    &pNewName,
                                    "%s\\%s",
                                    pGroup->pszNetbiosDomainName,
                                    pGroup->pszSamAccountName);
                    BAIL_ON_UMN_ERROR(dwError);

                    UMN_LOG_ERROR("Found conflict on group name '%hhs'. Sid %hhs will now be reported as name '%s' instead because its alias conflicts with sid %hhs.",
                                            pGroup->groupInfo.pszUnixName,
                                            pGroup->pszObjectSid,
                                            pNewName,
                                            pExisting->pszObjectSid);
                    BAIL_ON_UMN_ERROR(dwError);

                    LW_SAFE_FREE_STRING(pGroup->groupInfo.pszUnixName);
                    pGroup->groupInfo.pszUnixName = pNewName;
                    pNewName = NULL;
                }

                dwError = LwHashSetValue(
                                pNameToGroup,
                                pGroup->groupInfo.pszUnixName,
                                pGroup);
                BAIL_ON_UMN_ERROR(dwError);

                if (!pGroup->enabled)
                {
                    UMN_LOG_VERBOSE("Skipping unenabled group %s",
                        pGroup->groupInfo.pszUnixName);
                }
                else
                {
                    dwError = UmnSrvUpdateADGroup(
                                    pEventlog,
                                    hReg,
                                    hGroups,
                                    PreviousRun,
                                    Now,
                                    pGroup);
                    BAIL_ON_UMN_ERROR(dwError);

                    dwError = UmnSrvUpdateADGroupMember(
                                    pEventlog,
                                    hReg,
                                    hGroups,
                                    PreviousRun,
                                    Now,
                                    pGroup,
                                    pUser->userInfo.pszUnixName);
                    BAIL_ON_UMN_ERROR(dwError);
                }
                dwError = LwHashSetValue(
                                pGroups,
                                pGroup->pszObjectSid,
                                pGroup);
                BAIL_ON_UMN_ERROR(dwError);

                ppLookedupGroups[i] = NULL;
            }

            LsaFreeSecurityObjectList(
                lookupGroupSidCount,
                ppLookedupGroups);
            ppLookedupGroups = NULL;
        }
    }

    dwError = UmnSrvFindDeletedUsers(
                    pEventlog,
                    hReg,
                    "AD Users",
                    hUsers,
                    Now);
    BAIL_ON_UMN_ERROR(dwError);

    dwError = UmnSrvFindDeletedGroups(
                    pEventlog,
                    hReg,
                    "AD Groups",
                    hGroups,
                    Now);
    BAIL_ON_UMN_ERROR(dwError);

cleanup:
    LW_SAFE_FREE_STRING(pNewName);
    LW_SAFE_FREE_MEMORY(ppLookupGroupSids);
    if (ppGroupSids)
    {
        LsaFreeSidList(
                groupSidCount,
                ppGroupSids);
    }
    if (ppLookedupGroups)
    {
        LsaFreeSecurityObjectList(
            lookupGroupSidCount,
            ppLookedupGroups);
    }
    if (hUsers)
    {
        RegCloseKey(hReg, hUsers);
    }
    if (hGroups)
    {
        RegCloseKey(hReg, hGroups);
    }
    LwHashSafeFree(&pGroups);
    LwHashSafeFree(&pNameToUser);
    LwHashSafeFree(&pNameToGroup);
    return dwError;
    
error:
    goto cleanup;
}
Example #4
0
DWORD
AD_GroupExpansionDataGetResults(
    IN PLSA_AD_GROUP_EXPANSION_DATA pExpansionData,
    OUT OPTIONAL PBOOLEAN pbIsFullyExpanded,
    OUT size_t* psUserMembersCount,
    OUT PLSA_SECURITY_OBJECT** pppUserMembers
    )
{
    DWORD dwError = 0;
    LW_HASH_ITERATOR hashIterator;
    LW_HASH_ENTRY* pHashEntry = NULL;
    size_t sHashCount = 0;
    PLSA_SECURITY_OBJECT* ppUserMembers = NULL;
    size_t sUserMembersCount = 0;
    BOOLEAN bIsFullyExpanded = FALSE;

    dwError = pExpansionData->dwLastError;
    BAIL_ON_LSA_ERROR(dwError);

    // Fill in the final list of users and return it.
    sHashCount = pExpansionData->pUsers->sCount;
    dwError = LwAllocateMemory(
                sizeof(*ppUserMembers) * sHashCount,
                (PVOID*)&ppUserMembers);
    BAIL_ON_LSA_ERROR(dwError);

    dwError = LwHashGetIterator(pExpansionData->pUsers, &hashIterator);
    BAIL_ON_LSA_ERROR(dwError);

    for (sUserMembersCount = 0;
         (pHashEntry = LwHashNext(&hashIterator)) != NULL;
         sUserMembersCount++)
    {
        PLSA_SECURITY_OBJECT pUser = (PLSA_SECURITY_OBJECT) pHashEntry->pKey;

        dwError = LwHashRemoveKey(pExpansionData->pUsers, pUser);
        BAIL_ON_LSA_ERROR(dwError);

        ppUserMembers[sUserMembersCount] = pUser;
    }

    if (sUserMembersCount != sHashCount)
    {
        dwError = LW_ERROR_INTERNAL;
        BAIL_ON_LSA_ERROR(dwError);
    }

    if (!pExpansionData->bDiscardedDueToDepth &&
        (pExpansionData->pGroupsToExpand->sCount == 0))
    {
        bIsFullyExpanded = TRUE;
    }

cleanup:
    if (pbIsFullyExpanded)
    {
        *pbIsFullyExpanded = bIsFullyExpanded;
    }

    *psUserMembersCount = sUserMembersCount;
    *pppUserMembers = ppUserMembers;

    return dwError;

error:
    ADCacheSafeFreeObjectList(sUserMembersCount, &ppUserMembers);
    sUserMembersCount = 0;

    if (dwError && !pExpansionData->dwLastError)
    {
        pExpansionData->dwLastError = dwError;
    }
    goto cleanup;
}
Example #5
0
DWORD
AD_GroupExpansionDataGetNextGroupToExpand(
    IN PLSA_AD_GROUP_EXPANSION_DATA pExpansionData,
    OUT PLSA_SECURITY_OBJECT* ppGroupToExpand,
    OUT PDWORD pdwGroupToExpandDepth
    )
{
    DWORD dwError = 0;
    PLSA_SECURITY_OBJECT pGroupToExpand = NULL;
    DWORD dwGroupToExpandDepth = 0;
    const LW_HASH_ENTRY* pHashEntry = NULL;

    dwError = pExpansionData->dwLastError;
    BAIL_ON_LSA_ERROR(dwError);

    if (pExpansionData->pGroupsToExpand->sCount < 1)
    {
        // Nothing to return
        goto cleanup;
    }

    if (pExpansionData->bIsIteratorInitialized)
    {
        pHashEntry = LwHashNext(&pExpansionData->GroupsToExpandIterator);
    }

    if (!pHashEntry)
    {
        // Either the iterator is not initialized or we
        // reached the end of the hash table and need to start over.
        dwError = LwHashGetIterator(
                    pExpansionData->pGroupsToExpand,
                    &pExpansionData->GroupsToExpandIterator);
        BAIL_ON_LSA_ERROR(dwError);

        pExpansionData->bIsIteratorInitialized = TRUE;

        pHashEntry = LwHashNext(&pExpansionData->GroupsToExpandIterator);
        if (!pHashEntry)
        {
            dwError = LW_ERROR_INTERNAL;
            BAIL_ON_LSA_ERROR(dwError);
        }
    }

    pGroupToExpand = (PLSA_SECURITY_OBJECT) pHashEntry->pKey;
    dwGroupToExpandDepth = (size_t) pHashEntry->pValue;
    dwGroupToExpandDepth++;

    // Move the object to the expanded list.  Note that the object is
    // not necessarily expanded yet, but we must remove it from
    // the "to expand" list.  It does not hurt to track it in the
    // "expanded" list.

    dwError = LwHashSetValue(pExpansionData->pExpandedGroups,
                              pGroupToExpand,
                              (PVOID)(size_t)dwGroupToExpandDepth);
    BAIL_ON_LSA_ERROR(dwError);

    dwError = LwHashRemoveKey(pExpansionData->pGroupsToExpand, pGroupToExpand);
    if (dwError)
    {
        LSA_LOG_DEBUG("ASSERT: cannot fail");
    }
    BAIL_ON_LSA_ERROR(dwError);

cleanup:
    *ppGroupToExpand = pGroupToExpand;
    *pdwGroupToExpandDepth = dwGroupToExpandDepth;

    return dwError;

error:
    ADCacheSafeFreeObject(&pGroupToExpand);
    dwGroupToExpandDepth = 0;

    if (dwError && !pExpansionData->dwLastError)
    {
        pExpansionData->dwLastError = dwError;
    }
    goto cleanup;
}