DWORD AD_GroupExpansionDataCreate( OUT PLSA_AD_GROUP_EXPANSION_DATA* ppExpansionData, IN DWORD dwMaxDepth ) { DWORD dwError = 0; PLSA_AD_GROUP_EXPANSION_DATA pExpansionData = NULL; const size_t sNumberOfBuckets = 20; dwError = LwAllocateMemory( sizeof(*pExpansionData), (PVOID*) &pExpansionData); BAIL_ON_LSA_ERROR(dwError); dwError = LwHashCreate( sNumberOfBuckets, AD_CompareObjectSids, AD_HashObjectSid, NULL, NULL, &pExpansionData->pGroupsToExpand); BAIL_ON_LSA_ERROR(dwError); dwError = LwHashCreate( sNumberOfBuckets, AD_CompareObjectSids, AD_HashObjectSid, NULL, NULL, &pExpansionData->pExpandedGroups); BAIL_ON_LSA_ERROR(dwError); dwError = LwHashCreate( sNumberOfBuckets, AD_CompareObjectSids, AD_HashObjectSid, NULL, NULL, &pExpansionData->pUsers); BAIL_ON_LSA_ERROR(dwError); pExpansionData->dwMaxDepth = dwMaxDepth; *ppExpansionData = pExpansionData; cleanup: return dwError; error: *ppExpansionData = NULL; AD_GroupExpansionDataDestroy(pExpansionData); goto cleanup; }
DWORD AD_AddAllowedMember( IN PLSA_AD_PROVIDER_STATE pState, IN PCSTR pszSID, IN PSTR pszMember, IN OUT PLW_HASH_TABLE *ppAllowedMemberList ) { DWORD dwError = 0; BOOLEAN bInLock = FALSE; PSTR pszValue = NULL; PSTR pszSIDCopy = NULL; PSTR pszMemberCopy = NULL; PLW_HASH_TABLE pAllowedMemberList = *ppAllowedMemberList; ENTER_AD_CONFIG_RW_WRITER_LOCK(bInLock, pState); if (!pState->pAllowedSIDs) { dwError = LwHashCreate( 11, LwHashCaselessStringCompare, LwHashCaselessStringHash, AD_FreeHashStringKeyValue, AD_CopyHashStringKeyValue, &pState->pAllowedSIDs); BAIL_ON_LSA_ERROR(dwError); } if (!pAllowedMemberList) { dwError = LwHashCreate( 11, LwHashCaselessStringCompare, LwHashCaselessStringHash, AD_FreeHashStringKeyValue, AD_CopyHashStringKeyValue, &pAllowedMemberList); BAIL_ON_LSA_ERROR(dwError); } dwError = LwAllocateString( pszSID, &pszSIDCopy); BAIL_ON_LSA_ERROR(dwError); dwError = LwAllocateString( pszMember, &pszMemberCopy); BAIL_ON_LSA_ERROR(dwError); dwError = LwHashSetValue( pAllowedMemberList, pszSIDCopy, pszMemberCopy); BAIL_ON_LSA_ERROR(dwError); pszSIDCopy = NULL; pszMemberCopy = NULL; if ( AD_IsInMembersList_InLock(pState, pszMember) ) { dwError = LwHashGetValue( pState->pAllowedSIDs, pszSID, (PVOID*)&pszValue); if (dwError == ERROR_NOT_FOUND) { dwError = LwAllocateString( pszSID, &pszSIDCopy); BAIL_ON_LSA_ERROR(dwError); dwError = LwAllocateString( pszMember, &pszMemberCopy); BAIL_ON_LSA_ERROR(dwError); dwError = LwHashSetValue( pState->pAllowedSIDs, pszSIDCopy, pszMemberCopy); BAIL_ON_LSA_ERROR(dwError); pszSIDCopy = NULL; pszMemberCopy = NULL; } AD_DeleteFromMembersList_InLock(pState, pszMember); } *ppAllowedMemberList = pAllowedMemberList; cleanup: LW_SAFE_FREE_STRING(pszSIDCopy); LW_SAFE_FREE_STRING(pszMemberCopy); LEAVE_AD_CONFIG_RW_WRITER_LOCK(bInLock, pState); return dwError; error: if ( ! *ppAllowedMemberList ) { LwHashSafeFree(&pAllowedMemberList); } goto cleanup; }
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; }
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; }
DWORD UmnSrvUpdateADAccounts( HANDLE hLsass, PLW_EVENTLOG_CONNECTION pEventlog, HANDLE hReg, HKEY hParameters, long long PreviousRun, long long Now ) { DWORD dwError = 0; PSTR pMemberList = NULL; PCSTR pIter = NULL; PSTR pMember = NULL; PLW_HASH_TABLE pUsers = NULL; LWREG_CONFIG_ITEM ADConfigDescription[] = { { "RequireMembershipOf", TRUE, LwRegTypeMultiString, 0, MAXDWORD, NULL, &pMemberList, NULL }, }; PLSASTATUS pLsaStatus = NULL; // Do not free PSTR pDomain = NULL; // Do not free PSTR pCell = NULL; PLSA_SECURITY_OBJECT pAllUsers = NULL; DWORD i = 0; dwError = LwHashCreate( 100, LwHashStringCompare, LwHashStringHash, UmnSrvHashFreeObjectValue, NULL, &pUsers); BAIL_ON_UMN_ERROR(dwError); dwError = RegProcessConfig( AD_PROVIDER_REGKEY, AD_PROVIDER_POLICY_REGKEY, ADConfigDescription, sizeof(ADConfigDescription)/sizeof(ADConfigDescription[0])); BAIL_ON_UMN_ERROR(dwError); if (pMemberList && pMemberList[0]) { pIter = pMemberList; while (*pIter != 0) { dwError = LwStrDupOrNull( pIter, &pMember); BAIL_ON_UMN_ERROR(dwError); LwStripWhitespace( pMember, TRUE, TRUE); dwError = UmnSrvAddUsersFromMembership( hLsass, pUsers, pMember); BAIL_ON_UMN_ERROR(dwError); pIter += strlen(pIter) + 1; } } else { dwError = LsaGetStatus2( hLsass, NULL, &pLsaStatus); BAIL_ON_UMN_ERROR(dwError); for (i = 0; i < pLsaStatus->dwCount; i++) { if (pLsaStatus->pAuthProviderStatusList[i].pszDomain) { pDomain = pLsaStatus->pAuthProviderStatusList[i].pszDomain; } if (pLsaStatus->pAuthProviderStatusList[i].pszCell) { pCell = pLsaStatus->pAuthProviderStatusList[i].pszCell; } } if (pDomain || pCell) { dwError = LwAllocateMemory( sizeof(*pAllUsers), (PVOID*)&pAllUsers); BAIL_ON_UMN_ERROR(dwError); dwError = LwAllocateString( "S-INVALID", &pAllUsers->pszObjectSid); BAIL_ON_UMN_ERROR(dwError); pAllUsers->enabled = TRUE; pAllUsers->bIsLocal = FALSE; dwError = LwAllocateString( "AllDomains", &pAllUsers->pszNetbiosDomainName); BAIL_ON_UMN_ERROR(dwError); dwError = LwAllocateString( "AllUsers", &pAllUsers->pszSamAccountName); BAIL_ON_UMN_ERROR(dwError); pAllUsers->type = LSA_OBJECT_TYPE_USER; dwError = LwAllocateString( "S-INVALID", &pAllUsers->userInfo.pszPrimaryGroupSid); BAIL_ON_UMN_ERROR(dwError); dwError = LwAllocateString( "All Users", &pAllUsers->userInfo.pszUnixName); BAIL_ON_UMN_ERROR(dwError); dwError = LwAllocateString( "All Users", &pAllUsers->userInfo.pszGecos); BAIL_ON_UMN_ERROR(dwError); dwError = LwAllocateString( "", &pAllUsers->userInfo.pszShell); BAIL_ON_UMN_ERROR(dwError); dwError = LwAllocateString( "", &pAllUsers->userInfo.pszHomedir); BAIL_ON_UMN_ERROR(dwError); if (pCell) { dwError = LwAllocateStringPrintf( &pAllUsers->userInfo.pszDisplayName, "All Users in cell %s", pCell); BAIL_ON_UMN_ERROR(dwError); } else { dwError = LwAllocateStringPrintf( &pAllUsers->userInfo.pszDisplayName, "All Users accessible from domain %s", pDomain); BAIL_ON_UMN_ERROR(dwError); } dwError = LwHashSetValue( pUsers, pAllUsers->pszObjectSid, pAllUsers); BAIL_ON_UMN_ERROR(dwError); pAllUsers = NULL; } } dwError = UmnSrvUpdateADAccountsByHash( hLsass, pEventlog, hReg, hParameters, pUsers, PreviousRun, Now); BAIL_ON_UMN_ERROR(dwError); cleanup: if (pLsaStatus) { LsaFreeStatus(pLsaStatus); } LW_SAFE_FREE_STRING(pMemberList); LW_SAFE_FREE_STRING(pMember); LwHashSafeFree(&pUsers); if (pAllUsers) { LsaFreeSecurityObject(pAllUsers); } return dwError; error: goto cleanup; }
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; }