Beispiel #1
0
static
DWORD
UmnSrvAddUsersFromMembership(
    HANDLE hLsass,
    LW_HASH_TABLE *pUsers,
    PCSTR pLookup
    )
{
    DWORD dwError = 0;
    LSA_QUERY_LIST list;
    PLSA_SECURITY_OBJECT *ppObjects = NULL;
    PLSA_SECURITY_OBJECT *ppMembers = NULL;
    DWORD memberCount = 0;
    DWORD i = 0;

    list.ppszStrings = &pLookup;

    dwError = LsaFindObjects(
                    hLsass,
                    NULL,
                    0,
                    LSA_OBJECT_TYPE_UNDEFINED,
                    LSA_QUERY_TYPE_BY_NT4,
                    1,
                    list,
                    &ppObjects);
    switch(dwError)
    {
        // The string was not a valid NT4 name
        case LW_ERROR_INVALID_PARAMETER:
        // The user/group does not exist
        case LW_ERROR_NO_SUCH_OBJECT:
            goto cleanup;
        default:
            BAIL_ON_UMN_ERROR(dwError);
    }

    if (ppObjects[0] && ppObjects[0]->type == LSA_OBJECT_TYPE_USER)
    {
        if (ppObjects[0]->enabled &&
                !LwHashExists(pUsers, ppObjects[0]->pszObjectSid))
        {
            dwError = LwHashSetValue(
                            pUsers,
                            ppObjects[0]->pszObjectSid,
                            ppObjects[0]);
            BAIL_ON_UMN_ERROR(dwError);
            ppObjects[0] = NULL;
        }
    }
    else if (ppObjects[0] && ppObjects[0]->type == LSA_OBJECT_TYPE_GROUP)
    {
        dwError = LsaQueryExpandedGroupMembers(
                        hLsass,
                        NULL,
                        0,
                        LSA_OBJECT_TYPE_USER,
                        ppObjects[0]->pszObjectSid,
                        &memberCount,
                        &ppMembers);
        BAIL_ON_UMN_ERROR(dwError);

        for (i = 0; i < memberCount; i++)
        {
            if (ppMembers[i]->enabled &&
                    !LwHashExists(pUsers, ppMembers[i]->pszObjectSid))
            {
                UMN_LOG_VERBOSE("Found AD user %s that can login because of group %s",
                        ppMembers[i]->userInfo.pszUnixName, pLookup);

                dwError = LwHashSetValue(
                                pUsers,
                                ppMembers[i]->pszObjectSid,
                                ppMembers[i]);
                BAIL_ON_UMN_ERROR(dwError);
                ppMembers[i] = NULL;
            }
        }
    }

cleanup:
    if (ppObjects)
    {
        LsaFreeSecurityObjectList(
            1,
            ppObjects);
    }
    if (ppMembers)
    {
        LsaFreeSecurityObjectList(
            memberCount,
            ppMembers);
    }
    return dwError;

error:
    goto cleanup;
}
Beispiel #2
0
DWORD
ADLdap_GetObjectGroupMembership(
    IN PAD_PROVIDER_CONTEXT pContext,
    IN PLSA_SECURITY_OBJECT pObject,
    OUT int* piPrimaryGroupIndex,
    OUT size_t* psNumGroupsFound,
    OUT PLSA_SECURITY_OBJECT** pppGroupInfoList
    )
{
    DWORD dwError =  0;
    PLSA_DM_LDAP_CONNECTION pConn = NULL;
    PSTR pszFullDomainName = NULL;
    INT i = 0;
    PLSA_SECURITY_OBJECT* ppGroupInfoList = NULL;
    size_t sNumGroupsFound = 0;
    int    iPrimaryGroupIndex = -1;
    DWORD gcMembershipCount = 0;
    PSTR* ppGcMembershipList = NULL;
    DWORD dcMembershipCount = 0;
    PSTR* ppDcMembershipList = NULL;
    PLW_HASH_TABLE pGroupHash = NULL;
    LSA_TRUST_DIRECTION trustDirection = LSA_TRUST_DIRECTION_UNKNOWN;
    LSA_TRUST_MODE trustMode = LSA_TRUST_MODE_UNKNOWN;
    DWORD index = 0;
    DWORD totalSidCount = 0;
    PSTR* ppTotalSidList = NULL;

    // If we cannot get dn, then we cannot get DN information for this objects, hence BAIL
    if (LW_IS_NULL_OR_EMPTY_STR(pObject->pszDN))
    {
        dwError = LW_ERROR_NO_SUCH_USER;
        BAIL_ON_LSA_ERROR(dwError);
    }

    dwError = LwLdapConvertDNToDomain(
                 pObject->pszDN,
                 &pszFullDomainName);
    BAIL_ON_LSA_ERROR(dwError);

    // Note that this function is called only for 2-way trusts.  However,
    // the trust could be an external trust or a forest trust.  We can only
    // query the GC if there is a forest trust.

    dwError = AD_DetermineTrustModeandDomainName(
                    pContext->pState,
                    pszFullDomainName,
                    &trustDirection,
                    &trustMode,
                    NULL,
                    NULL);
    BAIL_ON_LSA_ERROR(dwError);

    // We could only have the DN path for the user if (s)he came from a two way
    // trusted domain or the joined domain.
    LSA_ASSERT(LSA_TRUST_DIRECTION_TWO_WAY == trustDirection ||
            LSA_TRUST_DIRECTION_SELF == trustDirection);

    if (trustMode != LSA_TRUST_MODE_EXTERNAL)
    {
        // Get forest info from domain's GC since there is a forest trust.
        // This will only include universal group information.  (The domain
        // global groups will not include membership info in the GC.)
        dwError = LsaDmLdapOpenGc(
                      pContext,
                      pszFullDomainName,
                      &pConn);
        BAIL_ON_LSA_ERROR(dwError);

        dwError = ADLdap_GetAttributeValuesList(
                        pConn,
                        pObject->pszDN,
                        AD_LDAP_MEMBEROF_TAG,
                        TRUE,
                        TRUE,
                        &gcMembershipCount,
                        &ppGcMembershipList);
        BAIL_ON_LSA_ERROR(dwError);

        LsaDmLdapClose(pConn);
        pConn = NULL;
    }

    dwError = LsaDmLdapOpenDc(
                  pContext,
                  pszFullDomainName,
                  &pConn);
    BAIL_ON_LSA_ERROR(dwError);

    dwError = ADLdap_GetAttributeValuesList(
                    pConn,
                    pObject->pszDN,
                    AD_LDAP_MEMBEROF_TAG,
                    TRUE,
                    TRUE,
                    &dcMembershipCount,
                    &ppDcMembershipList);
    BAIL_ON_LSA_ERROR(dwError);

    dwError = LwHashCreate(
                    (dcMembershipCount + gcMembershipCount + 1) * 2,
                    LwHashCaselessStringCompare,
                    LwHashCaselessStringHash,
                    ADLdap_FreeHashStringValue,
                    NULL,
                    &pGroupHash);
    BAIL_ON_LSA_ERROR(dwError);

    for (index = 0; index < gcMembershipCount; index++)
    {
        PSTR pSid = ppGcMembershipList[index];
        if (!LwHashExists(pGroupHash, pSid))
        {
            // Set the value of the hash entry as NULL so this string is not
            // freed with the hash.
            dwError = LwHashSetValue(pGroupHash, pSid, NULL);
            BAIL_ON_LSA_ERROR(dwError);
        }
    }

    for (index = 0; index < dcMembershipCount; index++)
    {
        PSTR pSid = ppDcMembershipList[index];
        if (!LwHashExists(pGroupHash, pSid))
        {
            // Set the value of the hash entry as NULL so this string is not
            // freed with the hash.
            dwError = LwHashSetValue(pGroupHash, pSid, NULL);
            BAIL_ON_LSA_ERROR(dwError);
        }
    }

    if (pObject->type == LSA_OBJECT_TYPE_USER && pObject->userInfo.pszPrimaryGroupSid)
    {
        // Add the pszPrimaryGroupSID entry to the hash
        PSTR pSid = pObject->userInfo.pszPrimaryGroupSid;
        if (!LwHashExists(pGroupHash, pSid))
        {
            // Set the value of the hash entry as NULL so this string is not
            // freed with the hash.
            dwError = LwHashSetValue(pGroupHash, pSid, NULL);
            BAIL_ON_LSA_ERROR(dwError);
        }
    }

    // Check if the user came from a domain other than the computer's domain
    if (LSA_TRUST_DIRECTION_TWO_WAY == trustDirection)
    {
        dwError = ADLdap_AddDomainLocalGroups(
                        pContext,
                        pObject,
                        pGroupHash);
        BAIL_ON_LSA_ERROR(dwError);
    }

    dwError = ADLdap_MoveHashKeysToArray(
                    pGroupHash,
                    &totalSidCount,
                    (PVOID**)(PVOID)&ppTotalSidList);
    BAIL_ON_LSA_ERROR(dwError);
    
    dwError = AD_FindObjectsBySidList(
                    pContext,
                    totalSidCount,
                    ppTotalSidList,
                    &sNumGroupsFound,
                    &ppGroupInfoList);
    BAIL_ON_LSA_ERROR(dwError);

    AD_FilterNullEntries(
            ppGroupInfoList,
            &sNumGroupsFound);

    // Determine primary group index
    if (pObject->type == LSA_OBJECT_TYPE_USER &&
        pObject->userInfo.pszPrimaryGroupSid &&
        ppGroupInfoList &&
        sNumGroupsFound)
    {
        for (i = (INT)sNumGroupsFound - 1; i >= 0; i--)
        {
            if (!strcmp(ppGroupInfoList[i]->pszObjectSid, pObject->userInfo.pszPrimaryGroupSid))
            {
                iPrimaryGroupIndex = i;
                break;
            }
        }
    }

    *psNumGroupsFound = sNumGroupsFound;
    *pppGroupInfoList = ppGroupInfoList;
    *piPrimaryGroupIndex = iPrimaryGroupIndex;

cleanup:
    LwHashSafeFree(&pGroupHash);
    LW_SAFE_FREE_STRING(pszFullDomainName);
    LwFreeStringArray(ppGcMembershipList, gcMembershipCount);
    LwFreeStringArray(ppDcMembershipList, dcMembershipCount);
    // Do not free the string pointers inside. They are borrowed from the
    // hash.
    LW_SAFE_FREE_MEMORY(ppTotalSidList);

    LsaDmLdapClose(pConn);

    return dwError;

error:

    *pppGroupInfoList = NULL;
    *psNumGroupsFound = 0;
    *piPrimaryGroupIndex = -1;

    if ( dwError != LW_ERROR_DOMAIN_IS_OFFLINE )
    {
        LSA_LOG_ERROR("Failed to group memberships of SID=%s. [error code:%u]",
                      pObject->pszObjectSid, dwError);
    }

    ADCacheSafeFreeObjectList((DWORD)sNumGroupsFound, &ppGroupInfoList);

    goto cleanup;
}
Beispiel #3
0
DWORD
AD_GroupExpansionDataAddExpansionResults(
    IN PLSA_AD_GROUP_EXPANSION_DATA pExpansionData,
    IN DWORD dwExpandedGroupDepth,
    IN OUT size_t* psMembersCount,
    IN OUT PLSA_SECURITY_OBJECT** pppMembers
    )
{
    DWORD dwError = 0;
    size_t sMembersCount = *psMembersCount;
    PLSA_SECURITY_OBJECT* ppMembers = *pppMembers;

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

    if (dwExpandedGroupDepth > pExpansionData->dwMaxDepth)
    {
        // This should never happen
        dwError = LW_ERROR_INTERNAL;
        BAIL_ON_LSA_ERROR(dwError);
    }

    if ((sMembersCount + pExpansionData->pUsers->sCount) * 2 >
            pExpansionData->pUsers->sTableSize)
    {
        dwError = LwHashResize(
                        pExpansionData->pUsers,
                        (sMembersCount +
                             pExpansionData->pUsers->sCount + 10) * 3);
        BAIL_ON_LSA_ERROR(dwError);
    }

    if ((sMembersCount + pExpansionData->pGroupsToExpand->sCount) * 2 >
            pExpansionData->pGroupsToExpand->sTableSize)
    {
        dwError = LwHashResize(
                        pExpansionData->pGroupsToExpand,
                        (sMembersCount +
                             pExpansionData->pGroupsToExpand->sCount + 10) * 3);
        BAIL_ON_LSA_ERROR(dwError);
    }

    for (; sMembersCount > 0; sMembersCount--)
    {
        PLSA_SECURITY_OBJECT pCurrentMember = ppMembers[sMembersCount-1];

        if (!pCurrentMember)
        {
            continue;
        }

        if (pCurrentMember->type == LSA_OBJECT_TYPE_USER)
        {
            if (!LwHashExists(pExpansionData->pUsers,
                               ppMembers[sMembersCount-1]))
            {
                dwError = LwHashSetValue(
                    pExpansionData->pUsers,
                    ppMembers[sMembersCount-1],
                    (PVOID)(size_t)dwExpandedGroupDepth);
                BAIL_ON_LSA_ERROR(dwError);
                ppMembers[sMembersCount-1] = NULL;
            }
            else
            {
                ADCacheSafeFreeObject(&ppMembers[sMembersCount-1]);
            }
        }
        else if (pCurrentMember->type == LSA_OBJECT_TYPE_GROUP)
        {
            if (dwExpandedGroupDepth >= pExpansionData->dwMaxDepth)
            {
                pExpansionData->bDiscardedDueToDepth = TRUE;
                ADCacheSafeFreeObject(&ppMembers[sMembersCount-1]);
            }
            else if (LwHashExists(pExpansionData->pExpandedGroups,
                                   pCurrentMember) ||
                     LwHashExists(pExpansionData->pGroupsToExpand,
                                   pCurrentMember))
            {
                ADCacheSafeFreeObject(&ppMembers[sMembersCount-1]);
            }
            else
            {
                dwError = LwHashSetValue(
                            pExpansionData->pGroupsToExpand,
                            ppMembers[sMembersCount-1],
                            (PVOID)(size_t)dwExpandedGroupDepth);
                BAIL_ON_LSA_ERROR(dwError);
                ppMembers[sMembersCount-1] = NULL;
            }
        }
        else
        {
            // some other kind of object -- should not happen
            ADCacheSafeFreeObject(&ppMembers[sMembersCount-1]);
        }
    }

cleanup:
    if (ppMembers && (sMembersCount == 0))
    {
        ADCacheSafeFreeObjectList(sMembersCount, &ppMembers);
    }
    *psMembersCount = sMembersCount;
    *pppMembers = ppMembers;
    return dwError;

error:
    ADCacheSafeFreeObjectList(sMembersCount, &ppMembers);
    if (dwError && !pExpansionData->dwLastError)
    {
        pExpansionData->dwLastError = dwError;
    }
    goto cleanup;
}
Beispiel #4
0
DWORD
ADLdap_AddDomainLocalGroups(
    IN PAD_PROVIDER_CONTEXT pContext,
    IN PLSA_SECURITY_OBJECT pObject,
    IN OUT PLW_HASH_TABLE pGroupHash
    )
{
    DWORD dwError =  0;
    PLSA_DM_LDAP_CONNECTION pConn = NULL;
    PSTR szAttributeList[] = {
        AD_LDAP_OBJECTSID_TAG,
        NULL
    };
    PSTR pDomainDN = NULL;
    PSTR pszEscapedDN = NULL;
    // Do not free. This is owned by pConn
    HANDLE hDirectory = NULL;
    LDAPMessage* pMessage = NULL;
    // Do not free. This is owned by pConn
    LDAP* pLd = NULL;
    PSTR pGroupSid = NULL;
    PSTR pFilter = NULL;
    // Do not free
    LDAPMessage* pCurrentMessage = NULL;

    dwError = LsaDmLdapOpenDc(
                    pContext,
                    pContext->pState->pszDomainName,
                    &pConn);
    BAIL_ON_LSA_ERROR(dwError);
    
    dwError = LwLdapConvertDomainToDN(
                    pContext->pState->pszDomainName,
                    &pDomainDN);
    BAIL_ON_LSA_ERROR(dwError);

    dwError = LwLdapEscapeString(&pszEscapedDN, pObject->pszDN);
    BAIL_ON_LSA_ERROR(dwError);

    // groupType: 2147483652 = 0x80000004 = ( GROUP_TYPE_RESOURCE_GROUP |
    // GROUP_TYPE_SECURITY_ENABLED ) = domain local security group
    dwError = LwAllocateStringPrintf(
                    &pFilter,
                    "(&(|(member=%s)(member=CN=%s,CN=ForeignSecurityPrincipals,%s))(groupType=2147483652))",
                    pszEscapedDN,
                    pObject->pszObjectSid,
                    pDomainDN);
    BAIL_ON_LSA_ERROR(dwError);
 
    dwError = LsaDmLdapDirectorySearch(
                    pConn,
                    pDomainDN,
                    LDAP_SCOPE_SUBTREE,
                    pFilter,
                    szAttributeList,
                    &hDirectory,
                    &pMessage);
    BAIL_ON_LSA_ERROR(dwError);                   

    pLd = LwLdapGetSession(hDirectory);

    pCurrentMessage = ldap_first_entry(pLd, pMessage);
    while (pCurrentMessage)
    {
        LW_SAFE_FREE_STRING(pGroupSid);
        dwError = ADLdap_GetObjectSid(
                        hDirectory,
                        pCurrentMessage,
                        &pGroupSid);
        BAIL_ON_LSA_ERROR(dwError);

        if (!LwHashExists(pGroupHash, pGroupSid))
        {
            // Set the value of the hash entry so this string gets freed with
            // the hash.
            dwError = LwHashSetValue(pGroupHash, pGroupSid, pGroupSid);
            BAIL_ON_LSA_ERROR(dwError);

            pGroupSid = NULL;
        }

        pCurrentMessage = ldap_next_entry(pLd, pCurrentMessage);
    }

cleanup:
    LsaDmLdapClose(pConn);
    LW_SAFE_FREE_STRING(pszEscapedDN);
    LW_SAFE_FREE_STRING(pDomainDN);
    LW_SAFE_FREE_STRING(pFilter);
    LW_SAFE_FREE_STRING(pGroupSid);
    if (pMessage)
    {
        ldap_msgfree(pMessage);
    }
    return dwError;

error:
    goto cleanup;
}