static DWORD LsaAdBatchGatherUnprovisionedMode( IN OUT PLSA_AD_BATCH_ITEM pItem, IN HANDLE hDirectory, IN LDAPMessage* pMessage ) { DWORD dwError = 0; switch (pItem->ObjectType) { case LSA_AD_BATCH_OBJECT_TYPE_USER: dwError = LsaAdBatchGatherUnprovisionedModeUser( pItem, hDirectory, pMessage); BAIL_ON_LSA_ERROR(dwError); break; case LSA_AD_BATCH_OBJECT_TYPE_GROUP: // Nothing special for groups. break; default: LSA_ASSERT(FALSE); dwError = LW_ERROR_INTERNAL; BAIL_ON_LSA_ERROR(dwError); } cleanup: return dwError; error: goto cleanup; }
static DWORD LsaUnjoinDomain( IN PCWSTR pwszDnsDomainName, IN PCWSTR pwszMachineSamAccountName, IN OPTIONAL PCWSTR pwszUserName, IN OPTIONAL PCWSTR pwszUserDomain, IN OPTIONAL PCWSTR pwszUserPassword, IN DWORD dwUnjoinFlags ) { DWORD dwError = ERROR_SUCCESS; NTSTATUS ntStatus = STATUS_SUCCESS; PWSTR pwszDCName = NULL; PIO_CREDS pCreds = NULL; dwError = LsaGetRwDcName(pwszDnsDomainName, FALSE, &pwszDCName); BAIL_ON_LSA_ERROR(dwError); /* disable the account only if requested */ if (dwUnjoinFlags & LSAJOIN_ACCT_DELETE) { if (pwszUserName && pwszUserPassword) { ntStatus = LwIoCreatePlainCredsW(pwszUserName, pwszUserDomain, pwszUserPassword, &pCreds); dwError = LwNtStatusToWin32Error(ntStatus); BAIL_ON_LSA_ERROR(dwError); } else { ntStatus = LwIoGetActiveCreds(NULL, &pCreds); dwError = LwNtStatusToWin32Error(ntStatus); BAIL_ON_LSA_ERROR(dwError); } ntStatus = LsaDisableMachineAccount(pwszDCName, pCreds, pwszMachineSamAccountName); dwError = LwNtStatusToWin32Error(ntStatus); BAIL_ON_LSA_ERROR(dwError); } error: LSA_ASSERT(!ntStatus || dwError); LW_SAFE_FREE_MEMORY(pwszDCName); if (pCreds) { LwIoDeleteCreds(pCreds); } return dwError; }
static DWORD AD_ConvertMultiStringToStringArray( IN PCSTR pszMultiString, OUT PSTR** pppszStringArray, OUT PDWORD pdwCount ) { DWORD dwError = 0; PSTR* ppszStringArray = NULL; DWORD dwCount = 0; PCSTR pszIter = NULL; DWORD dwIndex = 0; dwCount = 0; for (pszIter = pszMultiString; pszIter && *pszIter; pszIter += strlen(pszIter) + 1) { dwCount++; } if (dwCount) { dwError = LwAllocateMemory( dwCount * sizeof(*ppszStringArray), OUT_PPVOID(&ppszStringArray)); BAIL_ON_LSA_ERROR(dwError); } dwIndex = 0; for (pszIter = pszMultiString; pszIter && *pszIter; pszIter += strlen(pszIter) + 1) { dwError = LwAllocateString(pszIter, &ppszStringArray[dwIndex]); BAIL_ON_LSA_ERROR(dwError); dwIndex++; } LSA_ASSERT(dwIndex == dwCount); cleanup: *pppszStringArray = ppszStringArray; *pdwCount = dwCount; return dwError; error: LwFreeStringArray(ppszStringArray, dwCount); ppszStringArray = NULL; dwCount = 0; goto cleanup; }
DWORD LsaAdBatchGatherPseudoObjectSidFromGc( IN PAD_PROVIDER_DATA pProviderData, IN OUT PLSA_AD_BATCH_ITEM pItem, IN LSA_AD_BATCH_OBJECT_TYPE ObjectType, IN OPTIONAL DWORD dwKeywordValuesCount, IN OPTIONAL PSTR* ppszKeywordValues, IN HANDLE hDirectory, IN LDAPMessage* pMessage ) { DWORD dwError = 0; LSA_ASSERT(LSA_IS_XOR(LsaAdBatchIsDefaultSchemaMode(pProviderData), ppszKeywordValues)); LSA_ASSERT(!IsSetFlag(pItem->Flags, LSA_AD_BATCH_ITEM_FLAG_HAVE_PSEUDO)); dwError = LsaAdBatchGatherObjectType(pItem, ObjectType); BAIL_ON_LSA_ERROR(dwError); if (!pItem->pszSid) { dwError = LsaAdBatchGatherPseudoSid( &pItem->pszSid, pProviderData, dwKeywordValuesCount, ppszKeywordValues, hDirectory, pMessage); BAIL_ON_LSA_ERROR(dwError); } cleanup: return dwError; error: SetFlag(pItem->Flags, LSA_AD_BATCH_ITEM_FLAG_ERROR); goto cleanup; }
DWORD LsaAdBatchMarshalList( IN PLSA_AD_PROVIDER_STATE pState, IN PCSTR pszDnsDomainName, IN PCSTR pszNetbiosDomainName, IN OUT PLSA_LIST_LINKS pBatchItemList, IN DWORD dwAvailableCount, OUT PLSA_SECURITY_OBJECT* ppObjects, OUT PDWORD pdwUsedCount ) { DWORD dwError = 0; PLSA_LIST_LINKS pLinks = NULL; DWORD dwIndex = 0; for (pLinks = pBatchItemList->Next; pLinks != pBatchItemList; pLinks = pLinks->Next) { PLSA_AD_BATCH_ITEM pItem = LW_STRUCT_FROM_FIELD(pLinks, LSA_AD_BATCH_ITEM, BatchItemListLinks); if (dwIndex >= dwAvailableCount) { LSA_ASSERT(FALSE); dwError = LW_ERROR_INTERNAL; BAIL_ON_LSA_ERROR(dwError); } dwError = LsaAdBatchMarshal( pState, pszDnsDomainName, pszNetbiosDomainName, pItem, &ppObjects[dwIndex]); BAIL_ON_LSA_ERROR(dwError); if (ppObjects[dwIndex]) { dwIndex++; } } cleanup: *pdwUsedCount = dwIndex; return dwError; error: goto cleanup; }
static DWORD LsaAdBatchGatherPseudoSid( OUT PSTR* ppszSid, IN PAD_PROVIDER_DATA pProviderData, IN OPTIONAL DWORD dwKeywordValuesCount, IN OPTIONAL PSTR* ppszKeywordValues, IN HANDLE hDirectory, IN LDAPMessage* pMessage ) { DWORD dwError = 0; PSTR pszSid = NULL; if (LsaAdBatchIsDefaultSchemaMode(pProviderData)) { dwError = ADLdap_GetObjectSid(hDirectory, pMessage, &pszSid); BAIL_ON_LSA_ERROR(dwError); } else { PCSTR pszSidFromKeywords = NULL; LSA_ASSERT(ppszKeywordValues); pszSidFromKeywords = LsaAdBatchFindKeywordAttributeStatic( dwKeywordValuesCount, ppszKeywordValues, AD_LDAP_BACKLINK_PSEUDO_TAG); if (LW_IS_NULL_OR_EMPTY_STR(pszSidFromKeywords)) { dwError = LW_ERROR_INVALID_SID; BAIL_ON_LSA_ERROR(dwError); } dwError = LwAllocateString(pszSidFromKeywords, &pszSid); BAIL_ON_LSA_ERROR(dwError); } cleanup: *ppszSid = pszSid; return dwError; error: LW_SAFE_FREE_STRING(pszSid); goto cleanup; }
static DWORD LsaAdBatchGatherNonSchemaMode( IN OUT PLSA_AD_BATCH_ITEM pItem, IN DWORD dwKeywordValuesCount, IN PSTR* ppszKeywordValues ) { DWORD dwError = 0; switch (pItem->ObjectType) { case LSA_AD_BATCH_OBJECT_TYPE_USER: dwError = LsaAdBatchGatherNonSchemaModeUser( pItem, dwKeywordValuesCount, ppszKeywordValues); BAIL_ON_LSA_ERROR(dwError); break; case LSA_AD_BATCH_OBJECT_TYPE_GROUP: dwError = LsaAdBatchGatherNonSchemaModeGroup( pItem, dwKeywordValuesCount, ppszKeywordValues); BAIL_ON_LSA_ERROR(dwError); break; default: LSA_ASSERT(FALSE); dwError = LW_ERROR_INTERNAL; BAIL_ON_LSA_ERROR(dwError); } cleanup: 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; }
static DWORD LsaPcachepLoadPasswordInfoInLock( IN LSA_MACHINEPWD_CACHE_HANDLE pPcache ) { DWORD dwError = 0; PLSA_MACHINE_PASSWORD_INFO_A pPasswordInfoA = NULL; PLSA_MACHINE_PASSWORD_INFO_W pPasswordInfoW = NULL; LSA_ASSERT(!pPcache->bIsLoaded); LSA_ASSERT(!pPcache->pEntry); // // Read information from LSA Pstore // dwError = LsaPstoreGetPasswordInfoA( pPcache->pszDomainName, &pPasswordInfoA); BAIL_ON_LSA_ERROR(dwError); dwError = LsaPstoreGetPasswordInfoW( pPcache->pwszDomainName, &pPasswordInfoW); BAIL_ON_LSA_ERROR(dwError); LSA_ASSERT(pPasswordInfoA->Account.KeyVersionNumber == pPasswordInfoW->Account.KeyVersionNumber); LSA_ASSERT(pPasswordInfoA->Account.LastChangeTime == pPasswordInfoW->Account.LastChangeTime); // // Stash information from LSA Pstore // dwError = LwAllocateMemory( sizeof(*pPcache->pEntry), OUT_PPVOID(&pPcache->pEntry)); BAIL_ON_LSA_ERROR(dwError); pPcache->pEntry->RefCount = 1; dwError = LsaImplFillMachinePasswordInfoA( pPasswordInfoA, &pPcache->pEntry->PasswordInfoA); BAIL_ON_LSA_ERROR(dwError); dwError = LsaImplFillMachinePasswordInfoW( pPasswordInfoW, &pPcache->pEntry->PasswordInfoW); BAIL_ON_LSA_ERROR(dwError); pPcache->bIsLoaded = TRUE; error: if (dwError) { LsaPcachepClearPasswordInfoInLock(pPcache); } if (pPasswordInfoW) { LsaPstoreFreePasswordInfoW(pPasswordInfoW); } if (pPasswordInfoA) { LsaPstoreFreePasswordInfoA(pPasswordInfoA); } return dwError; }
DWORD LsaAdBatchBuildQueryForRpc( IN PCSTR pszNetbiosDomainName, IN LSA_AD_BATCH_QUERY_TYPE QueryType, // List of PLSA_AD_BATCH_ITEM IN PLSA_LIST_LINKS pFirstLinks, IN PLSA_LIST_LINKS pEndLinks, OUT PLSA_LIST_LINKS* ppNextLinks, IN DWORD dwMaxQueryCount, OUT PDWORD pdwQueryCount, OUT PSTR** pppszQueryList ) { DWORD dwError = 0; PLSA_LIST_LINKS pLinks = NULL; PSTR* ppszQueryList = NULL; PLSA_LIST_LINKS pLastLinks = pFirstLinks; DWORD dwQueryCount = 0; DWORD dwSavedQueryCount = 0; pLinks = pFirstLinks; for (pLinks = pFirstLinks; pLinks != pEndLinks; pLinks = pLinks->Next) { PLSA_AD_BATCH_ITEM pBatchItem = LW_STRUCT_FROM_FIELD(pLinks, LSA_AD_BATCH_ITEM, BatchItemListLinks); PCSTR pszQueryTerm = NULL; switch (QueryType) { case LSA_AD_BATCH_QUERY_TYPE_BY_SID: { if (pBatchItem->pszSid) { pszQueryTerm = pBatchItem->pszSid; } else if (QueryType == pBatchItem->QueryTerm.Type) { pszQueryTerm = pBatchItem->QueryTerm.pszString; } break; } case LSA_AD_BATCH_QUERY_TYPE_BY_NT4: { if (pBatchItem->pszSamAccountName) { pszQueryTerm = pBatchItem->pszSamAccountName; } else if (QueryType == pBatchItem->QueryTerm.Type) { pszQueryTerm = pBatchItem->QueryTerm.pszString; } break; } default: LSA_ASSERT(FALSE); dwError = LW_ERROR_INTERNAL; BAIL_ON_LSA_ERROR(dwError); } if (!LW_IS_NULL_OR_EMPTY_STR(pszQueryTerm)) { DWORD dwNewQueryCount = dwQueryCount + 1; if (dwMaxQueryCount && (dwNewQueryCount > dwMaxQueryCount)) { break; } dwQueryCount = dwNewQueryCount; } } pLastLinks = pLinks; dwSavedQueryCount = dwQueryCount; if (dwQueryCount < 1) { goto cleanup; } dwError = LwAllocateMemory(dwQueryCount*sizeof(*ppszQueryList), (PVOID*)&ppszQueryList); BAIL_ON_LSA_ERROR(dwError); dwQueryCount = 0; // Loop until we reach last links. for (pLinks = pFirstLinks; pLinks != pLastLinks; pLinks = pLinks->Next) { PLSA_AD_BATCH_ITEM pBatchItem = LW_STRUCT_FROM_FIELD(pLinks, LSA_AD_BATCH_ITEM, BatchItemListLinks); if (IsSetFlag(pBatchItem->Flags, LSA_AD_BATCH_ITEM_FLAG_ALLOCATED_MATCH_TERM)) { LW_SAFE_FREE_STRING(pBatchItem->pszQueryMatchTerm); ClearFlag(pBatchItem->Flags, LSA_AD_BATCH_ITEM_FLAG_ALLOCATED_MATCH_TERM); } switch (QueryType) { case LSA_AD_BATCH_QUERY_TYPE_BY_SID: { PCSTR pszUseSid = NULL; if (pBatchItem->pszSid) { pszUseSid = pBatchItem->pszSid; } else if (QueryType == pBatchItem->QueryTerm.Type) { pszUseSid = pBatchItem->QueryTerm.pszString; } // We might not have a SID if we failed to find a pseudo. if (pszUseSid) { dwError = LwAllocateString(pszUseSid, &ppszQueryList[dwQueryCount++]); BAIL_ON_LSA_ERROR(dwError); pBatchItem->pszQueryMatchTerm = (PSTR)pszUseSid; } break; } case LSA_AD_BATCH_QUERY_TYPE_BY_NT4: { PCSTR pszUseSamAccountName = NULL; if (pBatchItem->pszSamAccountName) { pszUseSamAccountName = pBatchItem->pszSamAccountName; } else if (QueryType == pBatchItem->QueryTerm.Type) { pszUseSamAccountName = pBatchItem->QueryTerm.pszString; } if (pszUseSamAccountName) { dwError = LwAllocateStringPrintf( &ppszQueryList[dwQueryCount++], "%s\\%s", pszNetbiosDomainName, pszUseSamAccountName); BAIL_ON_LSA_ERROR(dwError); pBatchItem->pszQueryMatchTerm = (PSTR)pszUseSamAccountName; } break; } default: LSA_ASSERT(FALSE); dwError = LW_ERROR_INTERNAL; BAIL_ON_LSA_ERROR(dwError); } } assert(dwSavedQueryCount == dwQueryCount); cleanup: // We handle error here instead of error label // because there is a goto cleanup above. if (dwError) { LwFreeStringArray(ppszQueryList, dwSavedQueryCount); ppszQueryList = NULL; dwQueryCount = 0; dwSavedQueryCount = 0; pLastLinks = pFirstLinks; } *pppszQueryList = ppszQueryList; *pdwQueryCount = dwQueryCount; *ppNextLinks = pLastLinks; return dwError; error: // Do not actually handle any errors here. goto cleanup; }
static DWORD LsaAdBatchBuilderBatchItemGetAttributeValue( IN PAD_PROVIDER_DATA pProviderData, IN PVOID pCallbackContext, IN PVOID pItem, OUT PCSTR* ppszValue, OUT PVOID* ppFreeValueContext ) { DWORD dwError = 0; PLSA_AD_BATCH_BUILDER_BATCH_ITEM_CONTEXT pContext = (PLSA_AD_BATCH_BUILDER_BATCH_ITEM_CONTEXT)pCallbackContext; LSA_AD_BATCH_QUERY_TYPE QueryType = pContext->QueryType; BOOLEAN bIsForRealObject = pContext->bIsForRealObject; PLSA_LIST_LINKS pLinks = (PLSA_LIST_LINKS)pItem; PLSA_AD_BATCH_ITEM pBatchItem = LW_STRUCT_FROM_FIELD(pLinks, LSA_AD_BATCH_ITEM, BatchItemListLinks); PSTR pszValueToEscape = NULL; PSTR pszValueToHex = NULL; PSTR pszValue = NULL; PVOID pFreeValueContext = NULL; // Free this on error only. PSTR pszMatchTerm = NULL; PSTR pszAllocatedMatchTermValue = NULL; BOOLEAN bHaveReal = IsSetFlag(pBatchItem->Flags, LSA_AD_BATCH_ITEM_FLAG_HAVE_REAL); BOOLEAN bHavePseudo = IsSetFlag(pBatchItem->Flags, LSA_AD_BATCH_ITEM_FLAG_HAVE_PSEUDO); if (IsSetFlag(pBatchItem->Flags, LSA_AD_BATCH_ITEM_FLAG_ALLOCATED_MATCH_TERM)) { LW_SAFE_FREE_STRING(pBatchItem->pszQueryMatchTerm); ClearFlag(pBatchItem->Flags, LSA_AD_BATCH_ITEM_FLAG_ALLOCATED_MATCH_TERM); } if ((bIsForRealObject && bHaveReal) || (!bIsForRealObject && bHavePseudo)) { // This can only happen in the linked cells case, but even // that should go away in the future as we just keep an // unresolved batch items list. LSA_ASSERT(!bIsForRealObject && (pProviderData->dwDirectoryMode == CELL_MODE)); goto cleanup; } switch (QueryType) { case LSA_AD_BATCH_QUERY_TYPE_BY_DN: // Must be looking for real object LSA_ASSERT(bIsForRealObject); LSA_ASSERT(QueryType == pBatchItem->QueryTerm.Type); pszValueToEscape = (PSTR)pBatchItem->QueryTerm.pszString; LSA_ASSERT(pszValueToEscape); break; case LSA_AD_BATCH_QUERY_TYPE_BY_SID: if (pBatchItem->pszSid) { // This is case where we already got the SID by resolving // the pseudo object by id/alias. pszValue = pBatchItem->pszSid; } else if (QueryType == pBatchItem->QueryTerm.Type) { // This is the case where the original query was // a query by SID. pszValue = (PSTR)pBatchItem->QueryTerm.pszString; LSA_ASSERT(pszValue); } // Will be NULL if we cannot find a SID for which to query. // This can happen if this batch item is for an object // that we did not find real but are trying to look up pseudo. // In that case, we have NULL and will just skip it. // If we have a SID string, make sure it looks like a SID. // Note that we must do some sanity checking to make sure // that the string does not need escaping since we are // not setting pszValueToEscape. (The SID check takes // care of that.) if (pszValue && !LsaAdBatchHasValidCharsForSid(pszValue)) { LSA_ASSERT(FALSE); dwError = LW_ERROR_INTERNAL; BAIL_ON_LSA_ERROR(dwError); } if (bIsForRealObject) { // "S-"-style SID string are only handled starting with // Windows 2003. So an LDAP hex-formatted SID string // is needed to handle Windows 2000. pszValueToHex = pszValue; pszValue = NULL; } break; case LSA_AD_BATCH_QUERY_TYPE_BY_NT4: LSA_ASSERT(bIsForRealObject); if (pBatchItem->pszSamAccountName) { // Unprovisioned id/alias case where id mapper returned // a SAM account name (and domain name) but no SID. pszValueToEscape = pBatchItem->pszSamAccountName; // However, we currently do not have this sort of id mapper // support, so we LSA_ASSERT(FALSE) for now. LSA_ASSERT(FALSE); } else if (QueryType == pBatchItem->QueryTerm.Type) { pszValueToEscape = (PSTR)pBatchItem->QueryTerm.pszString; LSA_ASSERT(pszValueToEscape); } break; case LSA_AD_BATCH_QUERY_TYPE_BY_UID: case LSA_AD_BATCH_QUERY_TYPE_BY_GID: LSA_ASSERT(!bIsForRealObject); LSA_ASSERT(QueryType == pBatchItem->QueryTerm.Type); dwError = LwAllocateStringPrintf( &pszAllocatedMatchTermValue, "%u", (unsigned int)pBatchItem->QueryTerm.dwId); BAIL_ON_LSA_ERROR(dwError); pszValue = pszAllocatedMatchTermValue; // Note: It is ok to set this here because it is ok for // this flag to be set if the match term field in the // batch item is still NULL (i.e., if we fail later in // this function). SetFlag(pBatchItem->Flags, LSA_AD_BATCH_ITEM_FLAG_ALLOCATED_MATCH_TERM); break; case LSA_AD_BATCH_QUERY_TYPE_BY_USER_ALIAS: case LSA_AD_BATCH_QUERY_TYPE_BY_GROUP_ALIAS: LSA_ASSERT(!bIsForRealObject); LSA_ASSERT(QueryType == pBatchItem->QueryTerm.Type); pszValueToEscape = (PSTR)pBatchItem->QueryTerm.pszString; LSA_ASSERT(pszValueToEscape); break; default: dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } LSA_ASSERT(!pszMatchTerm); LSA_ASSERT(!(pszValueToEscape && pszValueToHex)); if (pszValueToEscape) { LSA_ASSERT(!pszValue); dwError = LwLdapEscapeString(&pszValue, pszValueToEscape); BAIL_ON_LSA_ERROR(dwError); pszMatchTerm = pszValueToEscape; pFreeValueContext = pszValue; } else if (pszValueToHex) { LSA_ASSERT(!pszValue); dwError = LsaSidStrToLdapFormatHexStr(pszValueToHex, &pszValue); BAIL_ON_LSA_ERROR(dwError); pszMatchTerm = pszValueToHex; pFreeValueContext = pszValue; } else { pszMatchTerm = pszValue; } cleanup: // Note that the match value can be different from the value, // which we may need to escape or hex. pBatchItem->pszQueryMatchTerm = pszMatchTerm; *ppszValue = pszValue; *ppFreeValueContext = pFreeValueContext; return dwError; error: // assing output in cleanup in case of goto cleanup in function. pszValueToEscape = NULL; pszValue = NULL; LW_SAFE_FREE_STRING(pFreeValueContext); LW_SAFE_FREE_STRING(pszAllocatedMatchTermValue); goto cleanup; }
static DWORD LsaAdBatchBuildQueryForPseudoInternal( IN PAD_PROVIDER_DATA pProviderData, IN BOOLEAN bIsSchemaMode, IN OPTIONAL PDWORD pdwDirectoryMode, IN LSA_AD_BATCH_QUERY_TYPE QueryType, // List of PLSA_AD_BATCH_ITEM IN PLSA_LIST_LINKS pFirstLinks, IN PLSA_LIST_LINKS pEndLinks, OUT PLSA_LIST_LINKS* ppNextLinks, IN DWORD dwMaxQuerySize, IN DWORD dwMaxQueryCount, OUT PDWORD pdwQueryCount, OUT PSTR* ppszQuery ) { DWORD dwError = 0; PLSA_LIST_LINKS pNextLinks = NULL; DWORD dwQueryCount = 0; PSTR pszQuery = NULL; PCSTR pszAttributeName = NULL; PCSTR pszPrefix = NULL; PCSTR pszSuffix = NULL; LSA_AD_BATCH_BUILDER_BATCH_ITEM_CONTEXT context = { 0 }; pszAttributeName = LsaAdBatchBuilderGetPseudoQueryAttributeInternal( pdwDirectoryMode, bIsSchemaMode, QueryType); if (!pszAttributeName) { LSA_ASSERT(FALSE); dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } pszPrefix = LsaAdBatchBuilderGetPseudoQueryPrefixInternal( pProviderData, pdwDirectoryMode, bIsSchemaMode, QueryType, LsaAdBatchGetObjectTypeFromQueryType(QueryType), &pszSuffix); if (!pszPrefix || !pszSuffix) { LSA_ASSERT(FALSE); dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } context.QueryType = QueryType; context.bIsForRealObject = FALSE; dwError = LsaAdBatchBuilderCreateQuery( pProviderData, pszPrefix, pszSuffix, pszAttributeName, pFirstLinks, pEndLinks, (PVOID*)&pNextLinks, &context, LsaAdBatchBuilderBatchItemGetAttributeValue, LsaAdBatchBuilderGenericFreeValueContext, LsaAdBatchBuilderBatchItemNextItem, dwMaxQuerySize, dwMaxQueryCount, &dwQueryCount, &pszQuery); BAIL_ON_LSA_ERROR(dwError); cleanup: *ppNextLinks = pNextLinks; *pdwQueryCount = dwQueryCount; *ppszQuery = pszQuery; return dwError; error: // set output on cleanup pNextLinks = pFirstLinks; dwQueryCount = 0; LW_SAFE_FREE_STRING(pszQuery); goto cleanup; }
DWORD AD_BuildHomeDirFromTemplate( PLSA_AD_PROVIDER_STATE pState, PCSTR pszHomedirTemplate, PCSTR pszNetBIOSDomainName, PCSTR pszSamAccountName, PSTR* ppszHomedir ) { DWORD dwError = 0; PSTR pszHomedirPrefix = NULL; PSTR pszHomedir = NULL; DWORD dwOffset = 0; PCSTR pszIterTemplate = pszHomedirTemplate; DWORD dwBytesAllocated = 0; DWORD dwNetBIOSDomainNameLength = 0; DWORD dwSamAccountNameLength = 0; DWORD dwHomedirPrefixLength = 0; PSTR pszHostName = NULL; DWORD dwHostNameLength = 0; CHAR szEscapedPercent[2] = "%"; DWORD dwEscapedPercentLength = 0; BAIL_ON_INVALID_STRING(pszHomedirTemplate); BAIL_ON_INVALID_STRING(pszNetBIOSDomainName); BAIL_ON_INVALID_STRING(pszSamAccountName); if (strstr(pszHomedirTemplate, "%H")) { dwError = AD_GetHomedirPrefixPath(pState, &pszHomedirPrefix); BAIL_ON_LSA_ERROR(dwError); BAIL_ON_INVALID_STRING(pszHomedirPrefix); dwHomedirPrefixLength = strlen(pszHomedirPrefix); } if (strstr(pszHomedirTemplate, "%L")) { dwError = LsaDnsGetHostInfo(&pszHostName); BAIL_ON_LSA_ERROR(dwError); BAIL_ON_INVALID_STRING(pszHostName); dwHostNameLength = strlen(pszHostName); } if (strstr(pszHomedirTemplate, "%%")) { dwEscapedPercentLength = strlen(szEscapedPercent); } dwNetBIOSDomainNameLength = strlen(pszNetBIOSDomainName); dwSamAccountNameLength = strlen(pszSamAccountName); // Handle common case where we might use all replacements. dwBytesAllocated = (strlen(pszHomedirTemplate) + dwNetBIOSDomainNameLength + dwSamAccountNameLength + dwHomedirPrefixLength + dwHostNameLength + dwEscapedPercentLength + 1); dwError = LwAllocateMemory( sizeof(CHAR) * dwBytesAllocated, (PVOID*)&pszHomedir); BAIL_ON_LSA_ERROR(dwError); while (pszIterTemplate[0]) { // Do not count the terminating NULL as "available". DWORD dwBytesRemaining = dwBytesAllocated - dwOffset - 1; PCSTR pszInsert = NULL; DWORD dwInsertLength = 0; BOOLEAN bNeedUpper = FALSE; BOOLEAN bNeedLower = FALSE; LSA_ASSERT(dwOffset < dwBytesAllocated); if (pszIterTemplate[0] == '%') { switch (pszIterTemplate[1]) { case 'D': pszInsert = pszNetBIOSDomainName; dwInsertLength = dwNetBIOSDomainNameLength; bNeedUpper = TRUE; break; case 'U': pszInsert = pszSamAccountName; dwInsertLength = dwSamAccountNameLength; bNeedLower = TRUE; break; case 'H': pszInsert = pszHomedirPrefix; dwInsertLength = dwHomedirPrefixLength; break; case 'L': pszInsert = pszHostName; dwInsertLength = dwHostNameLength; break; case '%': pszInsert = szEscapedPercent; dwInsertLength = dwEscapedPercentLength; break; default: dwError = LW_ERROR_INVALID_HOMEDIR_TEMPLATE; BAIL_ON_LSA_ERROR(dwError); } LSA_ASSERT(!(bNeedUpper && bNeedLower)); pszIterTemplate += 2; } else { PCSTR pszEnd = strchr(pszIterTemplate, '%'); if (!pszEnd) { dwInsertLength = strlen(pszIterTemplate); } else { dwInsertLength = pszEnd - pszIterTemplate; } pszInsert = pszIterTemplate; pszIterTemplate += dwInsertLength; } if (dwBytesRemaining < dwInsertLength) { // We will increment by at least a minimum amount. DWORD dwAllocate = LSA_MAX(dwInsertLength - dwBytesRemaining, 64); PSTR pszNewHomedir = NULL; dwError = LwReallocMemory( pszHomedir, (PVOID*)&pszNewHomedir, dwBytesAllocated + dwAllocate); BAIL_ON_LSA_ERROR(dwError); pszHomedir = pszNewHomedir; dwBytesAllocated += dwAllocate; } memcpy(pszHomedir + dwOffset, pszInsert, dwInsertLength); if (bNeedUpper) { LwStrnToUpper(pszHomedir + dwOffset, dwInsertLength); } else if (bNeedLower) { LwStrnToLower(pszHomedir + dwOffset, dwInsertLength); } dwOffset += dwInsertLength; } // We should still have enough room for NULL. LSA_ASSERT(dwOffset < dwBytesAllocated); pszHomedir[dwOffset] = 0; dwOffset++; *ppszHomedir = pszHomedir; cleanup: LW_SAFE_FREE_STRING(pszHomedirPrefix); LW_SAFE_FREE_STRING(pszHostName); return dwError; error: *ppszHomedir = NULL; LW_SAFE_FREE_MEMORY(pszHomedir); goto cleanup; }
static DWORD AD_GetComputerDn( IN OPTIONAL PCSTR pszDnsDomainName, OUT PSTR* ppszComputerDn ) { DWORD dwError = 0; PSTR pszComputerDn = NULL; PLSA_MACHINE_PASSWORD_INFO_A pPasswordInfo = NULL; PSTR pszUserPrincipalName = NULL; PCSTR pszKrb5CachePath = "MEMORY:lsass_get_computer_dn"; PSTR pszPreviousKrb5CachePath = NULL; HANDLE hDirectory = NULL; // Lock to protect the cache: static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; BOOLEAN isLocked = FALSE; BOOLEAN needDestroyCache = FALSE; // // In the future, if we have cached DN information in the domain state, // we will use that. However, since that does not currently exist, // we will fetch it directly. // // Since this code should work regardless of the internal state, // we will need to use a private memory cache to establish credentials. // dwError = AD_GetMachinePasswordInfoA(pszDnsDomainName, &pPasswordInfo); BAIL_ON_LSA_ERROR(dwError); dwError = LwAllocateStringPrintf( &pszUserPrincipalName, "%s@%s", pPasswordInfo->Account.SamAccountName, pPasswordInfo->Account.DnsDomainName); BAIL_ON_LSA_ERROR(dwError); dwError = LwMapErrnoToLwError(pthread_mutex_lock(&mutex)); BAIL_ON_LSA_ERROR(dwError); isLocked = TRUE; dwError = LwKrb5InitializeCredentials( pszUserPrincipalName, pPasswordInfo->Password, pszKrb5CachePath, NULL); BAIL_ON_LSA_ERROR(dwError); needDestroyCache = TRUE; dwError = LwKrb5SetThreadDefaultCachePath(pszKrb5CachePath, &pszPreviousKrb5CachePath); BAIL_ON_LSA_ERROR(dwError); dwError = LsaLdapOpenDirectoryDomain( pPasswordInfo->Account.DnsDomainName, NULL, 0, &hDirectory); BAIL_ON_LSA_ERROR(dwError); dwError = AD_RawFindComputerDn( hDirectory, pPasswordInfo->Account.DnsDomainName, pPasswordInfo->Account.SamAccountName, &pszComputerDn); BAIL_ON_LSA_ERROR(dwError); error: if (dwError) { LW_SAFE_FREE_STRING(pszComputerDn); } if (needDestroyCache) { LwKrb5DestroyCache(pszKrb5CachePath); } if (pszPreviousKrb5CachePath) { LwKrb5SetThreadDefaultCachePath(pszPreviousKrb5CachePath, NULL); } if (isLocked) { int localError = pthread_mutex_unlock(&mutex); LSA_ASSERT(!localError); } LsaSrvFreeMachinePasswordInfoA(pPasswordInfo); LW_SAFE_FREE_STRING(pszUserPrincipalName); LW_SAFE_FREE_STRING(pszPreviousKrb5CachePath); if (hDirectory) { LwLdapCloseDirectory(hDirectory); } *ppszComputerDn = pszComputerDn; return dwError; }
static DWORD LsaAdBatchGatherRealUser( IN OUT PLSA_AD_BATCH_ITEM pItem, IN HANDLE hDirectory, IN LDAPMessage* pMessage ) { DWORD dwError = 0; dwError = LwLdapGetUInt32( hDirectory, pMessage, AD_LDAP_PRIMEGID_TAG, &pItem->UserInfo.dwPrimaryGroupRid); BAIL_ON_LSA_ERROR(dwError); LSA_ASSERT(!pItem->UserInfo.pszUserPrincipalName); dwError = LwLdapGetString( hDirectory, pMessage, AD_LDAP_UPN_TAG, &pItem->UserInfo.pszUserPrincipalName); BAIL_ON_LSA_ERROR(dwError); if (pItem->UserInfo.pszUserPrincipalName) { // Do not touch the non-realm part, just the realm part // to make sure the realm conforms to spec. LsaPrincipalRealmToUpper(pItem->UserInfo.pszUserPrincipalName); } dwError = LwLdapGetUInt32( hDirectory, pMessage, AD_LDAP_USER_CTRL_TAG, &pItem->UserInfo.UserAccountControl); if (dwError == LW_ERROR_INVALID_LDAP_ATTR_VALUE) { LSA_LOG_VERBOSE( "User %s has an invalid value for the userAccountControl" " attribute. Please check that it is set and that the " "machine account has permission to read it. Assuming 0x%x", pItem->pszSid, LSA_AD_UF_DEFAULT); pItem->UserInfo.UserAccountControl = LSA_AD_UF_DEFAULT; dwError = 0; } BAIL_ON_LSA_ERROR(dwError); dwError = LwLdapGetUInt64( hDirectory, pMessage, AD_LDAP_ACCOUT_EXP_TAG, &pItem->UserInfo.AccountExpires); if (dwError == LW_ERROR_INVALID_LDAP_ATTR_VALUE) { LSA_LOG_VERBOSE( "User %s has an invalid value for the accountExpires" " attribute. Please check that it is set and that the " "machine account has permission to read it.", pItem->pszSid); pItem->UserInfo.AccountExpires = 0; dwError = 0; } BAIL_ON_LSA_ERROR(dwError); dwError = LwLdapGetUInt64( hDirectory, pMessage, AD_LDAP_PWD_LASTSET_TAG, &pItem->UserInfo.PasswordLastSet); if (dwError == LW_ERROR_INVALID_LDAP_ATTR_VALUE) { LSA_LOG_VERBOSE( "User %s has an invalid value for the passwordLastSet" " attribute. Please check that it is set and that the " "machine account has permission to read it.", pItem->pszSid); dwError = ADGetCurrentNtTime(&pItem->UserInfo.PasswordLastSet); } BAIL_ON_LSA_ERROR(dwError); LSA_ASSERT(!pItem->UserInfo.pszDisplayName); dwError = LwLdapGetString( hDirectory, pMessage, AD_LDAP_DISPLAY_NAME_TAG, &pItem->UserInfo.pszDisplayName); BAIL_ON_LSA_ERROR(dwError); dwError = LwLdapGetString( hDirectory, pMessage, AD_LDAP_WINDOWSHOMEFOLDER_TAG, &pItem->UserInfo.pszWindowsHomeFolder); BAIL_ON_LSA_ERROR(dwError); SetFlag(pItem->Flags, LSA_AD_BATCH_ITEM_FLAG_ACCOUNT_INFO_KNOWN); cleanup: return dwError; error: goto cleanup; }
DWORD LsaAdBatchMarshal( IN PLSA_AD_PROVIDER_STATE pState, IN PCSTR pszDnsDomainName, IN PCSTR pszNetbiosDomainName, IN OUT PLSA_AD_BATCH_ITEM pItem, OUT PLSA_SECURITY_OBJECT* ppObject ) { DWORD dwError = 0; PAD_PROVIDER_DATA pProviderData = pState->pProviderData; PLSA_SECURITY_OBJECT pObject = NULL; // To marshal, the following conditions to be satisfied: // // 1) Object must have user or group type. // 2) Object must have real information. if ((LSA_AD_BATCH_OBJECT_TYPE_UNDEFINED == pItem->ObjectType) || !IsSetFlag(pItem->Flags, LSA_AD_BATCH_ITEM_FLAG_HAVE_REAL)) { PCSTR pszType = NULL; BOOLEAN bIsString = FALSE; PCSTR pszString = NULL; DWORD dwId = 0; LsaAdBatchQueryTermDebugInfo( &pItem->QueryTerm, &pszType, &bIsString, &pszString, &dwId); if (bIsString) { LSA_LOG_VERBOSE("Did not find object by %s '%s'", pszType, pszString); } else { LSA_LOG_VERBOSE("Did not find object by %s %u", pszType, dwId); } dwError = 0; goto cleanup; } if (!IsSetFlag(pItem->Flags, LSA_AD_BATCH_ITEM_FLAG_HAVE_PSEUDO) && !LsaAdBatchIsUnprovisionedMode(pProviderData)) { SetFlag(pItem->Flags, LSA_AD_BATCH_ITEM_FLAG_DISABLED); } #if 0 // Disable in svn commit r45217 // Fix regression that could cause NULL objects to be returned by LsaEnumObjects(): // Don't filter out disabled objects when enumerating in the AD provider - If we // ever do filter out objects, don't leave NULLs in the array // // This code also has to be disabled for to support returning non-provisioned objects // (computers, users, ...) that need an access token for use in Likewise-CIFS if (IsSetFlag(pItem->Flags, LSA_AD_BATCH_ITEM_FLAG_DISABLED) && (pItem->ObjectType != LSA_AD_BATCH_OBJECT_TYPE_GROUP)) { // Skip any disabled non-groups. LSA_LOG_VERBOSE("Skipping disabled object (sid = %s, name = %s\\%s)", LSA_SAFE_LOG_STRING(pItem->pszSid), LSA_SAFE_LOG_STRING(pszNetbiosDomainName), LSA_SAFE_LOG_STRING(pItem->pszSamAccountName)); dwError = 0; goto cleanup; } #endif dwError = LwAllocateMemory(sizeof(*pObject), (PVOID*)&pObject); BAIL_ON_LSA_ERROR(dwError); pObject->version.qwDbId = -1; pObject->enabled = !IsSetFlag(pItem->Flags, LSA_AD_BATCH_ITEM_FLAG_DISABLED); // Transfer the data LSA_XFER_STRING(pItem->pszSid, pObject->pszObjectSid); LSA_XFER_STRING(pItem->pszSamAccountName, pObject->pszSamAccountName); LSA_XFER_STRING(pItem->pszDn, pObject->pszDN); dwError = LwAllocateString( pszNetbiosDomainName, &pObject->pszNetbiosDomainName); BAIL_ON_LSA_ERROR(dwError); switch (pItem->ObjectType) { case LSA_AD_BATCH_OBJECT_TYPE_USER: pObject->type = LSA_OBJECT_TYPE_USER; dwError = LsaAdBatchMarshalUserInfo( pState, &pItem->UserInfo, &pObject->userInfo, pszDnsDomainName, pObject->pszNetbiosDomainName, pObject->pszSamAccountName, pObject->pszObjectSid); BAIL_ON_LSA_ERROR(dwError); pObject->userInfo.bIsAccountInfoKnown = IsSetFlag(pItem->Flags, LSA_AD_BATCH_ITEM_FLAG_ACCOUNT_INFO_KNOWN); break; case LSA_AD_BATCH_OBJECT_TYPE_GROUP: pObject->type = LSA_OBJECT_TYPE_GROUP; dwError = LsaAdBatchMarshalGroupInfo( pProviderData, &pItem->GroupInfo, &pObject->groupInfo, pszDnsDomainName, pObject->pszNetbiosDomainName, pObject->pszSamAccountName, pObject->pszObjectSid); BAIL_ON_LSA_ERROR(dwError); break; default: LSA_ASSERT(FALSE); dwError = LW_ERROR_INTERNAL; BAIL_ON_LSA_ERROR(dwError); } cleanup: *ppObject = pObject; return dwError; error: if (pObject) { ADCacheSafeFreeObject(&pObject); } goto cleanup; }
DWORD LsaAdBatchGatherPseudoObject( IN PAD_PROVIDER_DATA pProviderData, IN OUT PLSA_AD_BATCH_ITEM pItem, IN LSA_AD_BATCH_OBJECT_TYPE ObjectType, IN BOOLEAN bIsSchemaMode, IN OPTIONAL DWORD dwKeywordValuesCount, IN OPTIONAL PSTR* ppszKeywordValues, IN HANDLE hDirectory, IN LDAPMessage* pMessage ) { DWORD dwError = 0; PSTR pszComparePseudoDn = NULL; LSA_ASSERT(LSA_IS_XOR(LsaAdBatchIsDefaultSchemaMode(pProviderData), ppszKeywordValues)); SetFlag(pItem->Flags, LSA_AD_BATCH_ITEM_FLAG_HAVE_PSEUDO); dwError = LsaAdBatchGatherObjectType(pItem, ObjectType); BAIL_ON_LSA_ERROR(dwError); if (!pItem->pszSid) { dwError = LsaAdBatchGatherPseudoSid( &pItem->pszSid, pProviderData, dwKeywordValuesCount, ppszKeywordValues, hDirectory, pMessage); BAIL_ON_LSA_ERROR(dwError); } if (!pItem->pszPseudoDn) { dwError = LwLdapGetString( hDirectory, pMessage, AD_LDAP_DN_TAG, &pItem->pszPseudoDn); BAIL_ON_LSA_ERROR(dwError); if (LW_IS_NULL_OR_EMPTY_STR(pItem->pszPseudoDn)) { dwError = LW_ERROR_DATA_ERROR; BAIL_ON_LSA_ERROR(dwError); } } pItem->FoundPseudoCount++; if (pItem->FoundPseudoCount > 1) { dwError = LwLdapGetString( hDirectory, pMessage, AD_LDAP_DN_TAG, &pszComparePseudoDn); BAIL_ON_LSA_ERROR(dwError); LSA_LOG_WARNING("Found pseudo object %s that conflicts with pseudo object %s for SID %s", LSA_SAFE_LOG_STRING(pItem->pszPseudoDn), LSA_SAFE_LOG_STRING(pszComparePseudoDn), LSA_SAFE_LOG_STRING(pItem->pszSid)); dwError = LW_ERROR_DUPLICATE_USER_OR_GROUP; BAIL_ON_LSA_ERROR(dwError); } if (bIsSchemaMode) { dwError = LsaAdBatchGatherSchemaMode( pItem, hDirectory, pMessage); BAIL_ON_LSA_ERROR(dwError); // In default Schema mode, originally the following portion of code tries to gather real use information // using 'pMessage' obtained during pseudo objects lookup // However, a GC search is used on pseudo objects lookup, // Some of the attributes, such as user-specific attributes, i.e. 'accountExpires' etc. // are not available in GC. We still need to look up real objects in that particular domain for those missing attributes // Hence, we do not gather real object information until we actually do a real object lookup later on. #if 0 if (LsaAdBatchIsDefaultSchemaMode() && !IsSetFlag(pItem->Flags, LSA_AD_BATCH_ITEM_FLAG_HAVE_REAL)) { dwError = LsaAdBatchGatherRealObject( pItem, ObjectType, NULL, hDirectory, pMessage); BAIL_ON_LSA_ERROR(dwError); } #endif } else { dwError = LsaAdBatchGatherNonSchemaMode( pItem, dwKeywordValuesCount, ppszKeywordValues); BAIL_ON_LSA_ERROR(dwError); } cleanup: LW_SAFE_FREE_STRING(pszComparePseudoDn); return dwError; error: SetFlag(pItem->Flags, LSA_AD_BATCH_ITEM_FLAG_ERROR); goto cleanup; }
DWORD LsaAdBatchGatherRealObjectInternal( IN PAD_PROVIDER_DATA pProviderData, IN OUT PLSA_AD_BATCH_ITEM pItem, IN OPTIONAL PDWORD pdwDirectoryMode, IN OPTIONAL ADConfigurationMode* pAdMode, IN LSA_AD_BATCH_OBJECT_TYPE ObjectType, IN OUT OPTIONAL PSTR* ppszSid, IN HANDLE hDirectory, IN LDAPMessage* pMessage ) { DWORD dwError = 0; DWORD dwDirectoryMode = pdwDirectoryMode == NULL ? pProviderData->dwDirectoryMode : *pdwDirectoryMode; ADConfigurationMode adMode = pAdMode == NULL ? pProviderData->adConfigurationMode : *pAdMode; SetFlag(pItem->Flags, LSA_AD_BATCH_ITEM_FLAG_HAVE_REAL); dwError = LsaAdBatchGatherObjectType(pItem, ObjectType); BAIL_ON_LSA_ERROR(dwError); if (!pItem->pszSid) { if (ppszSid) { LSA_XFER_STRING(*ppszSid, pItem->pszSid); } else { dwError = ADLdap_GetObjectSid(hDirectory, pMessage, &pItem->pszSid); BAIL_ON_LSA_ERROR(dwError); } } if (LW_IS_NULL_OR_EMPTY_STR(pItem->pszSid)) { dwError = LW_ERROR_DATA_ERROR; BAIL_ON_LSA_ERROR(dwError); } LSA_ASSERT(!pItem->pszSamAccountName); dwError = LwLdapGetString( hDirectory, pMessage, AD_LDAP_SAM_NAME_TAG, &pItem->pszSamAccountName); BAIL_ON_LSA_ERROR(dwError); if (LW_IS_NULL_OR_EMPTY_STR(pItem->pszSamAccountName)) { dwError = LW_ERROR_DATA_ERROR; BAIL_ON_LSA_ERROR(dwError); } LSA_ASSERT(!pItem->pszDn); dwError = LwLdapGetString( hDirectory, pMessage, AD_LDAP_DN_TAG, &pItem->pszDn); BAIL_ON_LSA_ERROR(dwError); if (LW_IS_NULL_OR_EMPTY_STR(pItem->pszDn)) { dwError = LW_ERROR_DATA_ERROR; BAIL_ON_LSA_ERROR(dwError); } // Handle cases where real contains pseudo. if (DEFAULT_MODE == dwDirectoryMode && SchemaMode == adMode) { // But only if we are not being called by a pseudo // lookup for default schema mode. if (!IsSetFlag(pItem->Flags, LSA_AD_BATCH_ITEM_FLAG_HAVE_PSEUDO)) { SetFlag(pItem->Flags, LSA_AD_BATCH_ITEM_FLAG_HAVE_PSEUDO); dwError = LsaAdBatchGatherSchemaMode( pItem, hDirectory, pMessage); BAIL_ON_LSA_ERROR(dwError); } } else if (UNPROVISIONED_MODE == dwDirectoryMode) { dwError = LsaAdBatchGatherUnprovisionedMode( pItem, hDirectory, pMessage); BAIL_ON_LSA_ERROR(dwError); } // User object has some AD-specific fields. if (LSA_AD_BATCH_OBJECT_TYPE_USER == pItem->ObjectType) { dwError = LsaAdBatchGatherRealUser( pItem, hDirectory, pMessage); BAIL_ON_LSA_ERROR(dwError); } cleanup: return dwError; error: SetFlag(pItem->Flags, LSA_AD_BATCH_ITEM_FLAG_ERROR); goto cleanup; }