//---------------------------------------------------------------------------; // // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1995 // // File: cdssrch.cxx // // Contents: Microsoft ADs LDAP Provider Generic Object // // // History: 03-02-97 ShankSh Created. // //---------------------------------------------------------------------------- #include "ldapc.hxx" #pragma hdrstop const int MAX_BYTES = 1048576; const int NO_LDAP_RESULT_HANDLES = 32; static BOOL IsValidPrefValue( ADS_SEARCHPREF_INFO SearchPref ); static HRESULT LdapValueToADsColumn( LPWSTR pszColumnName, DWORD dwSyntaxId, DWORD dwValues, VOID **lpValue, ADS_SEARCH_COLUMN * pColumn ); HRESULT UnicodeToUTF8String( LPCWSTR pUnicode, LPSTR *ppUTF8 ); HRESULT UTF8ToUnicodeString( LPCSTR pUTF8, LPWSTR *ppUnicode ); // // Sets the appropriate search preferences. // HRESULT ADsSetSearchPreference( IN PADS_SEARCHPREF_INFO pSearchPrefs, IN DWORD dwNumPrefs, OUT LDAP_SEARCH_PREF * pLdapPref, IN LPWSTR pszLDAPServer, IN LPWSTR pszLDAPDn, IN CCredentials& Credentials, IN DWORD dwPort ) { HRESULT hr = S_OK; BOOL fWarning = FALSE; DWORD i, j; BOOL fPagedSearch = FALSE, fSorting = TRUE, fVLV = FALSE, fAttribScoped = FALSE; DWORD dwSecDescType = ADSI_LDAPC_SECDESC_NONE; PADS_SORTKEY pSortKeyArray = NULL; DWORD dwSortKeyArrayLen = 0, nKeys = 0; BOOL fSetCaching = FALSE; // TRUE if user explicitly set a caching preference BOOL fSetScope = FALSE; // TRUE if user explicitly set a scope preference PADS_VLV pVLV = NULL; DWORD dwVLVLen = 0; LPSTR pUTF8Target = NULL; DWORD dwUTF8TargetLen = 0; LPWSTR pAttribScoped = NULL; DWORD dwSecurityMask; DWORD dwDirsyncFlag; DWORD dwExtendedDNOption; int iDirsyncFlagIndex = -1; if (!pSearchPrefs && dwNumPrefs > 0 || !pLdapPref) { RRETURN (E_ADS_BAD_PARAMETER); } for (i=0; i_fAsynchronous = pSearchPrefs[i].vValue.Boolean; break; case ADS_SEARCHPREF_ATTRIBTYPES_ONLY: pLdapPref->_fAttrsOnly = pSearchPrefs[i].vValue.Boolean; break; case ADS_SEARCHPREF_SIZE_LIMIT: pLdapPref->_dwSizeLimit = pSearchPrefs[i].vValue.Integer; break; case ADS_SEARCHPREF_TIME_LIMIT: pLdapPref->_dwTimeLimit = pSearchPrefs[i].vValue.Integer; break; case ADS_SEARCHPREF_TIMEOUT: pLdapPref->_timeout.tv_sec = pSearchPrefs[i].vValue.Integer; break; case ADS_SEARCHPREF_PAGESIZE: if (pLdapPref->_fDirSync) { BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER); } ReadPagingSupportedAttr( pszLDAPServer, &fPagedSearch, Credentials, dwPort ) ; if (fPagedSearch) { pLdapPref->_dwPageSize = pSearchPrefs[i].vValue.Integer; } else { pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF; fWarning = TRUE; } break; case ADS_SEARCHPREF_PAGED_TIME_LIMIT: ReadPagingSupportedAttr( pszLDAPServer, &fPagedSearch, Credentials, dwPort ) ; if (fPagedSearch) { pLdapPref->_dwPagedTimeLimit = pSearchPrefs[i].vValue.Integer; } else { pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF; fWarning = TRUE; } break; case ADS_SEARCHPREF_DEREF_ALIASES: pLdapPref->_dwDerefAliases = pSearchPrefs[i].vValue.Integer; break; case ADS_SEARCHPREF_SEARCH_SCOPE: // if doing a attribute-scoped query and user tries to set scope // to anything other than ADS_SCOPE_BASE, reject if (pLdapPref->_pAttribScoped && (pSearchPrefs[i].vValue.Integer != ADS_SCOPE_BASE)) { BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER); } switch (pSearchPrefs[i].vValue.Integer) { case ADS_SCOPE_SUBTREE: pLdapPref->_dwSearchScope = LDAP_SCOPE_SUBTREE; break; case ADS_SCOPE_ONELEVEL: pLdapPref->_dwSearchScope = LDAP_SCOPE_ONELEVEL; break; case ADS_SCOPE_BASE: pLdapPref->_dwSearchScope = LDAP_SCOPE_BASE; break; } fSetScope = TRUE; // set so if user later tries to do // attrib-scoped query, and user set scope // to other than ADS_SCOPE_BASE, can detect & reject break; case ADS_SEARCHPREF_CHASE_REFERRALS: switch (pSearchPrefs[i].vValue.Integer) { case ADS_CHASE_REFERRALS_NEVER: pLdapPref->_dwChaseReferrals = (DWORD) (DWORD_PTR)LDAP_OPT_OFF; break; case ADS_CHASE_REFERRALS_SUBORDINATE: pLdapPref->_dwChaseReferrals = LDAP_CHASE_SUBORDINATE_REFERRALS; break; case ADS_CHASE_REFERRALS_EXTERNAL: pLdapPref->_dwChaseReferrals = LDAP_CHASE_EXTERNAL_REFERRALS; break; case ADS_CHASE_REFERRALS_ALWAYS: pLdapPref->_dwChaseReferrals = (DWORD) (DWORD_PTR) LDAP_OPT_ON; break; } break; case ADS_SEARCHPREF_SORT_ON: ReadSortingSupportedAttr( pszLDAPServer, &fSorting, Credentials, dwPort ) ; if (!fSorting) { pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF; fWarning = TRUE; continue; } // // The value is actually a pointer to the LDAP Sort Key whose // structure is as defined in the sort control RFC extension. // pSortKeyArray = (PADS_SORTKEY) pSearchPrefs[i].vValue.ProviderSpecific.lpValue; dwSortKeyArrayLen = pSearchPrefs[i].vValue.ProviderSpecific.dwLength; if (!pSortKeyArray || !dwSortKeyArrayLen ) { continue; } if (dwSortKeyArrayLen % sizeof(ADS_SORTKEY) != 0 ) { // // The data given does not seem to contain a proper SortKey // structure // pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE; fWarning = TRUE; continue; } nKeys = dwSortKeyArrayLen / sizeof(ADS_SORTKEY); if (pLdapPref->_pSortKeys) { // // Free the previous one // FreeSortKeys(pLdapPref->_pSortKeys, pLdapPref->_nSortKeys); } pLdapPref->_pSortKeys = (PLDAPSortKey) AllocADsMem( sizeof(LDAPSortKey) * nKeys); if (!pLdapPref->_pSortKeys) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } for (j=0; j_pSortKeys[j].sk_attrtype = AllocADsStr(pSortKeyArray[j].pszAttrType); if(!pLdapPref->_pSortKeys[j].sk_attrtype && pSortKeyArray[j].pszAttrType) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } pLdapPref->_pSortKeys[j].sk_matchruleoid = pSortKeyArray[j].pszReserved; pLdapPref->_pSortKeys[j].sk_reverseorder = pSortKeyArray[j].fReverseorder; } pLdapPref->_nSortKeys = nKeys; break; case ADS_SEARCHPREF_CACHE_RESULTS: // if doing a VLV search and user tries to turn on caching, reject if (pLdapPref->_pVLVInfo && pSearchPrefs[i].vValue.Boolean) { BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER); } pLdapPref->_fCacheResults = pSearchPrefs[i].vValue.Boolean; fSetCaching = TRUE; // set so if we later determine user wants to // do a VLV search, we can reject if user tried // to explicitly turn on caching break; // // Like paged, setting this preference will mean that we use it // by default, it is not used. // case ADS_SEARCHPREF_DIRSYNC: if (pLdapPref->_dwPageSize) { BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER); } pLdapPref->_fDirSync = TRUE; // // Check if previous value is set and free if necessary. // if (pLdapPref->_pProvSpecific) { if (pLdapPref->_pProvSpecific->lpValue) { FreeADsMem(pLdapPref->_pProvSpecific->lpValue); pLdapPref->_pProvSpecific->lpValue = NULL; } FreeADsMem(pLdapPref->_pProvSpecific); pLdapPref->_pProvSpecific = NULL; } // // Copy over the info here. // pLdapPref->_pProvSpecific = (PADS_PROV_SPECIFIC) AllocADsMem(sizeof(ADS_PROV_SPECIFIC)); if (!pLdapPref->_pProvSpecific) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } pLdapPref->_pProvSpecific->dwLength = pSearchPrefs[i].vValue.ProviderSpecific.dwLength; // // If the octet string is anything other than NULL, // we need to copy it over. If it is NULL, then this is // the first time the control is being used. // if (pLdapPref->_pProvSpecific->dwLength > 0) { pLdapPref->_pProvSpecific->lpValue = (PBYTE)AllocADsMem(pLdapPref->_pProvSpecific->dwLength); if (!pLdapPref->_pProvSpecific->lpValue) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } memcpy( pLdapPref->_pProvSpecific->lpValue, pSearchPrefs[i].vValue.ProviderSpecific.lpValue, pLdapPref->_pProvSpecific->dwLength ); } break; case ADS_SEARCHPREF_TOMBSTONE : pLdapPref->_fTombStone = pSearchPrefs[i].vValue.Boolean; break; case ADS_SEARCHPREF_VLV: // If user tried to explicitly turn on caching, reject // Later on, we'll turn off caching if ( fSetCaching && pLdapPref->_fCacheResults) { BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER); } // test for server support of VLV ReadVLVSupportedAttr( pszLDAPServer, &fVLV, Credentials, dwPort ) ; if (!fVLV) { pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF; fWarning = TRUE; continue; } // basic sanity checks of user-supplied data pVLV = (PADS_VLV) pSearchPrefs[i].vValue.ProviderSpecific.lpValue; dwVLVLen = pSearchPrefs[i].vValue.ProviderSpecific.dwLength; if (!pVLV || !dwVLVLen ) { pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE; fWarning = TRUE; continue; } if (dwVLVLen != sizeof(ADS_VLV)) { // // The data given does not seem to contain a proper VLV // structure // pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE; fWarning = TRUE; continue; } // free the previous LDAPVLVInfo, if one exists (generally, it shouldn't) if (pLdapPref->_pVLVInfo) FreeLDAPVLVInfo(pLdapPref->_pVLVInfo); // Copy the user's VLV search preferences into a LDAPVLVInfo // Note that we copy the dwOffset and dwContentCount even if the user // wants to do a greaterThanOrEqual-type VLV search. This is because // we'll ignore those members if ldvlv_attrvalue != NULL. pLdapPref->_pVLVInfo = (PLDAPVLVInfo) AllocADsMem(sizeof(LDAPVLVInfo)); if (!pLdapPref->_pVLVInfo) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); pLdapPref->_pVLVInfo->ldvlv_version = LDAP_VLVINFO_VERSION; // 1 pLdapPref->_pVLVInfo->ldvlv_before_count = pVLV->dwBeforeCount; pLdapPref->_pVLVInfo->ldvlv_after_count = pVLV->dwAfterCount; pLdapPref->_pVLVInfo->ldvlv_offset = pVLV->dwOffset; pLdapPref->_pVLVInfo->ldvlv_count = pVLV->dwContentCount; pLdapPref->_pVLVInfo->ldvlv_attrvalue = NULL; pLdapPref->_pVLVInfo->ldvlv_context = NULL; pLdapPref->_pVLVInfo->ldvlv_extradata = NULL; // copy the greaterThanOrEqual attribute, if provided by the user if (pVLV->pszTarget) { pLdapPref->_pVLVInfo->ldvlv_attrvalue = (PBERVAL) AllocADsMem(sizeof(BERVAL)); if (!pLdapPref->_pVLVInfo->ldvlv_attrvalue) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); // convert Unicode to UDF-8 // important: do NOT include the NULL terminator in the LDAPVLVInfo.ldvlv_attrvalue hr = UnicodeToUTF8String(pVLV->pszTarget, &pUTF8Target); BAIL_ON_FAILURE(hr); // we want the number of bytes, not the number of MBCS characters dwUTF8TargetLen = strlen(pUTF8Target); pLdapPref->_pVLVInfo->ldvlv_attrvalue->bv_len = dwUTF8TargetLen; pLdapPref->_pVLVInfo->ldvlv_attrvalue->bv_val = (PCHAR) AllocADsMem(dwUTF8TargetLen); if (!pLdapPref->_pVLVInfo->ldvlv_attrvalue->bv_val) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); memcpy(pLdapPref->_pVLVInfo->ldvlv_attrvalue->bv_val, pUTF8Target, dwUTF8TargetLen); } // copy the context ID, if provided by the user if (pVLV->lpContextID && pVLV->dwContextIDLength) { pLdapPref->_pVLVInfo->ldvlv_context = (PBERVAL) AllocADsMem(sizeof(BERVAL)); if (pLdapPref->_pVLVInfo->ldvlv_context == NULL) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); pLdapPref->_pVLVInfo->ldvlv_context->bv_val = (PCHAR) AllocADsMem(pVLV->dwContextIDLength); if (pLdapPref->_pVLVInfo->ldvlv_context->bv_val == NULL) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); pLdapPref->_pVLVInfo->ldvlv_context->bv_len = pVLV->dwContextIDLength; memcpy(pLdapPref->_pVLVInfo->ldvlv_context->bv_val, pVLV->lpContextID, pVLV->dwContextIDLength); } // disable caching, since it's not supported in conjunction with VLV pLdapPref->_fCacheResults = FALSE; break; case ADS_SEARCHPREF_ATTRIBUTE_QUERY: // If user tried to explicitly set scope to other than "base", reject // Later on, we'll set it to base. if ( fSetScope && pLdapPref->_dwSearchScope != LDAP_SCOPE_BASE) { BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER); } // test for server support of attribute-scoped query ReadAttribScopedSupportedAttr( pszLDAPServer, &fAttribScoped, Credentials, dwPort ) ; if (!fAttribScoped) { pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF; fWarning = TRUE; continue; } // basic sanity checks of user-supplied data pAttribScoped = pSearchPrefs[i].vValue.CaseIgnoreString; if (!pAttribScoped) { pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE; fWarning = TRUE; continue; } // free the previous ADS_ATTRIBUTE_QUERY, if one exists (generally, it shouldn't) if (pLdapPref->_pAttribScoped) { FreeADsStr(pLdapPref->_pAttribScoped); pLdapPref->_pAttribScoped = NULL; } // copy the ADS_ATTRIBUTE_QUERY pLdapPref->_pAttribScoped = AllocADsStr(pAttribScoped); if (!(pLdapPref->_pAttribScoped)) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } // set search scope to base (only scope supported by attrib-scoped query) pLdapPref->_dwSearchScope = LDAP_SCOPE_BASE; break; case ADS_SEARCHPREF_SECURITY_MASK: // // test for server support of security descriptor control // ReadSecurityDescriptorControlType( pszLDAPServer, &dwSecDescType, Credentials, dwPort ); if (dwSecDescType != ADSI_LDAPC_SECDESC_NT) { pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF; fWarning = TRUE; continue; } // // sanity check of user supplied data // dwSecurityMask = pSearchPrefs[i].vValue.Integer; if (dwSecurityMask > (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION)) { pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE; fWarning = TRUE; continue; } // // enable the option // pLdapPref->_fSecurityDescriptorControl = TRUE; pLdapPref->_SecurityDescriptorMask = static_cast(dwSecurityMask); break; case ADS_SEARCHPREF_DIRSYNC_FLAG: // sanity check of user supplied data // dwDirsyncFlag = pSearchPrefs[i].vValue.Integer; if(dwDirsyncFlag & (~(LDAP_DIRSYNC_OBJECT_SECURITY | LDAP_DIRSYNC_ANCESTORS_FIRST_ORDER | LDAP_DIRSYNC_PUBLIC_DATA_ONLY | LDAP_DIRSYNC_INCREMENTAL_VALUES))) { pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE; fWarning = TRUE; continue; } // set the flag value pLdapPref->_dwDirSyncFlag = dwDirsyncFlag; iDirsyncFlagIndex = i; break; case ADS_SEARCHPREF_EXTENDED_DN: // sanity check of user supplied data // dwExtendedDNOption = pSearchPrefs[i].vValue.Integer; if(dwExtendedDNOption != 0 && dwExtendedDNOption != 1) { pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE; fWarning = TRUE; continue; } // set the option pLdapPref->_fExtendedDNControl = TRUE; pLdapPref->_dwExtendedDnOption = dwExtendedDNOption; break; default: pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF; fWarning = TRUE; continue; } } // if dirsyncflag is specified, but using dirsync control is not, then we should indicate error if(!pLdapPref->_fDirSync && iDirsyncFlagIndex != -1) { pSearchPrefs[iDirsyncFlagIndex].dwStatus = ADS_STATUS_INVALID_SEARCHPREF; fWarning = TRUE; } error: if (pUTF8Target) FreeADsMem(pUTF8Target); // // Need to return the hr if it was something like out of mem. // Most often though it will be either S_OK or s-error ocurred. // if (FAILED(hr)) { // // Free sort keys and dirsync data if applicable // if (pLdapPref->_pSortKeys) { FreeSortKeys(pLdapPref->_pSortKeys, pLdapPref->_nSortKeys); pLdapPref->_pSortKeys = NULL; pLdapPref->_nSortKeys = 0; } if (pLdapPref->_pProvSpecific) { if (pLdapPref->_pProvSpecific->lpValue) { FreeADsMem(pLdapPref->_pProvSpecific->lpValue); } FreeADsMem(pLdapPref->_pProvSpecific); pLdapPref->_pProvSpecific = NULL; } // // Free VLV information if applicable // if (pLdapPref->_pVLVInfo) { FreeLDAPVLVInfo(pLdapPref->_pVLVInfo); pLdapPref->_pVLVInfo = NULL; } // // Free attrib-scoped query if applicable // if (pLdapPref->_pAttribScoped) { FreeADsStr(pLdapPref->_pAttribScoped); pLdapPref->_pAttribScoped = NULL; } RRETURN(hr); } RRETURN (fWarning ? S_ADS_ERRORSOCCURRED : S_OK); } HRESULT ADsExecuteSearch( IN LDAP_SEARCH_PREF LdapPref, IN LPWSTR pszADsPath, IN LPWSTR pszLdapServer, IN LPWSTR pszLdapDn, IN LPWSTR pszSearchFilter, IN LPWSTR * pAttributeNames, IN DWORD dwNumberAttributes, OUT PADS_SEARCH_HANDLE phSearchHandle ) { PLDAP_SEARCHINFO phSearchInfo = NULL; LPWSTR szCurrAttr = NULL; DWORD dwAttrNamesLen = 0; HRESULT hr = S_OK; ULONG i, j; LPWSTR pszAttrNameBuffer = NULL, *ppszAttrs = NULL; OBJECTINFO ObjectInfo; POBJECTINFO pObjectInfo = &ObjectInfo; // // Initilize so that we wont end up freeing bad data. // memset(pObjectInfo, 0, sizeof(OBJECTINFO)); if (!phSearchHandle ) { RRETURN (E_ADS_BAD_PARAMETER); } // // Allocate search handle // phSearchInfo = (PLDAP_SEARCHINFO) AllocADsMem(sizeof(LDAP_SEARCHINFO)); if(!phSearchInfo) BAIL_ON_FAILURE (hr = E_OUTOFMEMORY); memset(phSearchInfo, 0, sizeof(LDAP_SEARCHINFO)); phSearchInfo->_pszADsPathContext = AllocADsStr(pszADsPath); if(!(phSearchInfo->_pszADsPathContext)) BAIL_ON_FAILURE (hr = E_OUTOFMEMORY); if (pszSearchFilter) { phSearchInfo->_pszSearchFilter = AllocADsStr(pszSearchFilter); } else { phSearchInfo->_pszSearchFilter = AllocADsStr(L"(objectClass=*)"); } if(!(phSearchInfo->_pszSearchFilter)) BAIL_ON_FAILURE (hr = E_OUTOFMEMORY); if (pszLdapServer) { phSearchInfo->_pszLdapServer = AllocADsStr(pszLdapServer); if (!phSearchInfo->_pszLdapServer) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } } if (pszLdapDn) { phSearchInfo->_pszBindContextDn = AllocADsStr(pszLdapDn); if(!(phSearchInfo->_pszBindContextDn)){ BAIL_ON_FAILURE (hr = E_OUTOFMEMORY); } } phSearchInfo->_fADsPathPresent = FALSE; phSearchInfo->_fADsPathReturned = FALSE; phSearchInfo->_fADsPathOnly = FALSE; phSearchInfo->_fDNPresent = FALSE; phSearchInfo->_fDNReturned = FALSE; if (dwNumberAttributes == -1) { // // Specifies returning all attributes // phSearchInfo->_ppszAttrs = NULL; phSearchInfo->_pszAttrNameBuffer = NULL; phSearchInfo->_fADsPathPresent = TRUE; if(LdapPref._fDirSync) { phSearchInfo->_fDNPresent = TRUE; } } else { ppszAttrs = (LPWSTR *) AllocADsMem( sizeof(LPWSTR) * (dwNumberAttributes + 1) ); if (!ppszAttrs) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); for (i = 0; i < dwNumberAttributes; i++) dwAttrNamesLen+= (wcslen(pAttributeNames[i]) + 1) * sizeof(WCHAR); pszAttrNameBuffer = (LPWSTR) AllocADsMem( dwAttrNamesLen ); if (!pszAttrNameBuffer) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); szCurrAttr = pszAttrNameBuffer; for (i = 0, j = 0; i < dwNumberAttributes; i++) { wcscpy(szCurrAttr, pAttributeNames[i]); ppszAttrs[j] = szCurrAttr; szCurrAttr += wcslen(ppszAttrs[j]) + 1; if(_wcsicmp(ppszAttrs[j], L"ADsPath") == 0) { // // This attribute need not be sent // phSearchInfo->_fADsPathPresent = TRUE; } else if(LdapPref._fDirSync && _wcsicmp(ppszAttrs[j], L"distinguishedName") == 0) { // // This attribute need not be sent // phSearchInfo->_fDNPresent = TRUE; } else { j++; } } // If the query requests only ADsPath, then set ppszAttrs[0] to some // attribute. Setting it to NULL results in all attributes being // returned, which is a huge performance hit. Instead, request only // the objectclass (guaranteed to be present on all LDAP servers). if (0 == j) { FreeADsMem(pszAttrNameBuffer); pszAttrNameBuffer = (LPWSTR) AllocADsStr(L"objectClass"); if(pszAttrNameBuffer == NULL) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } FreeADsMem(ppszAttrs); ppszAttrs = (LPWSTR *) AllocADsMem(sizeof(LPWSTR) * 2); if(ppszAttrs == NULL) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } ppszAttrs[0] = pszAttrNameBuffer; ppszAttrs[1] = NULL; phSearchInfo->_fADsPathOnly = TRUE; } else ppszAttrs[j] = NULL; phSearchInfo->_ppszAttrs = ppszAttrs; phSearchInfo->_pszAttrNameBuffer = pszAttrNameBuffer; } hr = ADsObject(pszADsPath, pObjectInfo); BAIL_ON_FAILURE(hr); phSearchInfo->_dwPort = pObjectInfo->PortNumber; phSearchInfo->_pConnection = NULL; phSearchInfo->_hPagedSearch = NULL; phSearchInfo->_pSearchResults = NULL; phSearchInfo->_cSearchResults = 0; phSearchInfo->_dwCurrResult = 0; phSearchInfo->_dwMaxResultGot = 0; phSearchInfo->_currMsgId = (DWORD) -1; phSearchInfo->_pCurrentRow = NULL; phSearchInfo->_pFirstAttr = NULL; phSearchInfo->_fLastResult = FALSE; phSearchInfo->_fLastPage = FALSE; phSearchInfo->_fBefFirstRow = TRUE; phSearchInfo->_hrLastSearch = S_OK; phSearchInfo->_fNonFatalErrors = FALSE; phSearchInfo->_fAbandon = FALSE; phSearchInfo->_dwVLVOffset = 0; phSearchInfo->_dwVLVCount = 0; phSearchInfo->_pVLVContextID = NULL; phSearchInfo->_pBerValAttribScoped = NULL; phSearchInfo->_pBerValExtendedDN = NULL; // // Copy the search preference structure and also make a copy of the memory // that the internal pointers point to. This can probably be done better by // an assignment operator. // phSearchInfo->_SearchPref = LdapPref; phSearchInfo->_SearchPref._pVLVInfo = NULL; phSearchInfo->_SearchPref._pAttribScoped = NULL; // sorting if (LdapPref._pSortKeys) { phSearchInfo->_SearchPref._pSortKeys = (PLDAPSortKey) AllocADsMem( sizeof(LDAPSortKey) * LdapPref._nSortKeys); if (!phSearchInfo->_SearchPref._pSortKeys) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } memcpy( phSearchInfo->_SearchPref._pSortKeys, LdapPref._pSortKeys, sizeof(LDAPSortKey) * LdapPref._nSortKeys ); // // We need to copy over all the attibutes. // for (i=0; i < LdapPref._nSortKeys; i++) { phSearchInfo->_SearchPref._pSortKeys[i].sk_attrtype = AllocADsStr( LdapPref._pSortKeys[i].sk_attrtype); if (!phSearchInfo->_SearchPref._pSortKeys[i].sk_attrtype) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } } } // VLV if (LdapPref._pVLVInfo) { hr = CopyLDAPVLVInfo(LdapPref._pVLVInfo, &(phSearchInfo->_SearchPref._pVLVInfo)); BAIL_ON_FAILURE(hr); } // Attribute-scoped query if (LdapPref._pAttribScoped) { phSearchInfo->_SearchPref._pAttribScoped = AllocADsStr(LdapPref._pAttribScoped); if (!(phSearchInfo->_SearchPref._pAttribScoped)) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } } *phSearchHandle = phSearchInfo; FreeObjectInfo(pObjectInfo); RRETURN(S_OK); error: FreeObjectInfo(pObjectInfo); if(phSearchInfo) { if (phSearchInfo->_pszLdapServer) { FreeADsStr(phSearchInfo->_pszLdapServer); } if(phSearchInfo->_pszBindContextDn) FreeADsStr(phSearchInfo->_pszBindContextDn); if(phSearchInfo->_pszADsPathContext) FreeADsStr(phSearchInfo->_pszADsPathContext); if(phSearchInfo->_pszSearchFilter) FreeADsStr(phSearchInfo->_pszSearchFilter); if(phSearchInfo->_ppszAttrs) FreeADsMem(phSearchInfo->_ppszAttrs); else if(ppszAttrs) FreeADsMem(ppszAttrs); if(phSearchInfo->_pszAttrNameBuffer) FreeADsMem(phSearchInfo->_pszAttrNameBuffer); else if(pszAttrNameBuffer) FreeADsMem(pszAttrNameBuffer); if (phSearchInfo->_SearchPref._pVLVInfo) { FreeLDAPVLVInfo(phSearchInfo->_SearchPref._pVLVInfo); } if (phSearchInfo->_SearchPref._pAttribScoped) { FreeADsStr(phSearchInfo->_SearchPref._pAttribScoped); } FreeADsMem(phSearchInfo); } RRETURN (hr); } HRESULT ADsAbandonSearch( IN ADS_SEARCH_HANDLE hSearchHandle ) { PLDAP_SEARCHINFO phSearchInfo = (PLDAP_SEARCHINFO) hSearchHandle; DWORD dwStatus = 0; HRESULT hr = S_OK; int ldaperr = 0; // If there is an outstanding message id, call LdapAbandon // if (phSearchInfo->_currMsgId != (DWORD) -1) { dwStatus = LdapAbandon( phSearchInfo->_pConnection, phSearchInfo->_currMsgId ); } // // Make sure that we don't do extra searches anymore. We only give back // whatever rows we have already received from the server // if(dwStatus != 0) { // the abandon call fails phSearchInfo->_fAbandon = FALSE; ldaperr = LdapGetLastError(); CheckAndSetExtendedError( phSearchInfo->_pConnection->LdapHandle, &hr, ldaperr); } else { phSearchInfo->_fAbandon = TRUE; } RRETURN(hr); } HRESULT ADsCloseSearchHandle ( IN ADS_SEARCH_HANDLE hSearchHandle ) { HRESULT hr = S_OK; PLDAP_SEARCHINFO phSearchInfo = (PLDAP_SEARCHINFO) hSearchHandle; DWORD i=0; if (!phSearchInfo) RRETURN (E_ADS_BAD_PARAMETER); if (phSearchInfo->_pszLdapServer) FreeADsStr(phSearchInfo->_pszLdapServer); if(phSearchInfo->_pszBindContextDn) FreeADsStr(phSearchInfo->_pszBindContextDn); if(phSearchInfo->_pszADsPathContext) FreeADsStr(phSearchInfo->_pszADsPathContext); if(phSearchInfo->_pszSearchFilter) FreeADsStr(phSearchInfo->_pszSearchFilter); if(phSearchInfo->_ppszAttrs) FreeADsMem(phSearchInfo->_ppszAttrs); if(phSearchInfo->_pszAttrNameBuffer) FreeADsMem(phSearchInfo->_pszAttrNameBuffer); if (phSearchInfo->_pSearchResults) { for (DWORD i=0; i <= phSearchInfo->_dwMaxResultGot; i++) { LdapMsgFree( phSearchInfo->_pSearchResults[i] ); } FreeADsMem(phSearchInfo->_pSearchResults); } if (phSearchInfo->_hPagedSearch) { LdapSearchAbandonPage( phSearchInfo->_pConnection, phSearchInfo->_hPagedSearch ); } // // Free ServerControls // if (phSearchInfo->_ServerControls) { // // This code assumes there are only VLV, sort, dirsync, // security descriptor, extended dn & attribute-scoped query controls. // If more controls are added, modify the code accordingly. // Nothing needs to be freed for the dirsync control for now. // Freeing the searchpref will take care of the controls data. // for (i=0; phSearchInfo->_ServerControls[i]; i++) { BOOL fSortControl = FALSE; BOOL fVLVControl = FALSE; BOOL fSecDescControl = FALSE; if (phSearchInfo->_ServerControls[i]->ldctl_oid) { // Compare with sort control if (wcscmp( phSearchInfo->_ServerControls[i]->ldctl_oid, LDAP_SERVER_SORT_OID_W ) == 0 ) { fSortControl = TRUE; } else { fSortControl = FALSE; } // Compare with VLV control if (wcscmp( phSearchInfo->_ServerControls[i]->ldctl_oid, LDAP_CONTROL_VLVREQUEST_W ) == 0 ) { fVLVControl = TRUE; } else { fVLVControl = FALSE; } // Compare with security descriptor control if (wcscmp( phSearchInfo->_ServerControls[i]->ldctl_oid, LDAP_SERVER_SD_FLAGS_OID_W ) == 0 ) { fSecDescControl = TRUE; } else { fSecDescControl = FALSE; } } // // Free the sort control if this is it. // if (fSortControl) { if (phSearchInfo->_ServerControls[i]->ldctl_oid != NULL) { ldap_memfree( phSearchInfo->_ServerControls[i]->ldctl_oid ); } if (phSearchInfo->_ServerControls[i]->ldctl_value.bv_val != NULL) { ldap_memfreeA( phSearchInfo->_ServerControls[i]->ldctl_value.bv_val ); } } // // Free the security descriptor control if this is it // if (fSecDescControl) { if (phSearchInfo->_ServerControls[i]->ldctl_value.bv_val != NULL) { FreeADsMem( phSearchInfo->_ServerControls[i]->ldctl_value.bv_val ); } } // // Need to free the control if sort or not. // Exception: VLV control is freed with LdapControlFree, // not with FreeADsMem // if (fVLVControl) { LdapControlFree( phSearchInfo->_ServerControls[i] ); } else { FreeADsMem( phSearchInfo->_ServerControls[i] ); } } FreeADsMem( phSearchInfo->_ServerControls ); } // // Free SearchPref data // FreeSortKeys( phSearchInfo->_SearchPref._pSortKeys, phSearchInfo->_SearchPref._nSortKeys ); FreeLDAPVLVInfo(phSearchInfo->_SearchPref._pVLVInfo); if (phSearchInfo->_SearchPref._pAttribScoped) FreeADsStr(phSearchInfo->_SearchPref._pAttribScoped); // // Free Dirsync control infromation. // if (phSearchInfo->_SearchPref._fDirSync) { if (phSearchInfo->_SearchPref._pProvSpecific) { // // Free the data if applicable. // if (phSearchInfo->_SearchPref._pProvSpecific->lpValue) { FreeADsMem(phSearchInfo->_SearchPref._pProvSpecific->lpValue); } // // Free the struct itself // FreeADsMem(phSearchInfo->_SearchPref._pProvSpecific); phSearchInfo->_SearchPref._pProvSpecific = NULL; } } if (phSearchInfo->_pVLVContextID) { if (phSearchInfo->_pVLVContextID->bv_val) { FreeADsMem(phSearchInfo->_pVLVContextID->bv_val); } FreeADsMem(phSearchInfo->_pVLVContextID); } if (phSearchInfo->_pBerVal) { ber_bvfree(phSearchInfo->_pBerVal); } if (phSearchInfo->_pBerValAttribScoped) { ber_bvfree(phSearchInfo->_pBerValAttribScoped); } if(phSearchInfo->_pBerValExtendedDN) { ber_bvfree(phSearchInfo->_pBerValExtendedDN); } if(phSearchInfo->_pConnection) LdapCloseObject( phSearchInfo->_pConnection ); FreeADsMem(phSearchInfo); RRETURN (hr); } HRESULT ADsGetFirstRow( IN ADS_SEARCH_HANDLE hSearchHandle, IN CCredentials& Credentials ) { HRESULT hr = S_OK; DWORD dwStatus = NO_ERROR, dwStatus2 = NO_ERROR; PLDAP_SEARCHINFO phSearchInfo = (PLDAP_SEARCHINFO) hSearchHandle; LDAP *ld = NULL; BOOL fNewOptionSet = FALSE; DWORD oldOption = 0; DWORD newOption = 0; if (!phSearchInfo) { RRETURN(E_ADS_BAD_PARAMETER); } // reset the value phSearchInfo->_fADsPathReturned = FALSE; phSearchInfo->_fDNReturned = FALSE; if(!phSearchInfo->_pConnection) { hr = LdapOpenObject( phSearchInfo->_pszLdapServer, phSearchInfo->_pszBindContextDn, &phSearchInfo->_pConnection, Credentials, phSearchInfo->_dwPort ); BAIL_ON_FAILURE(hr); // // Set the preferences like deref aliases, time limit and size limit // if (ld = phSearchInfo->_pConnection->LdapHandle) { ld->ld_deref = phSearchInfo->_SearchPref._dwDerefAliases; ld->ld_sizelimit = phSearchInfo->_SearchPref._dwSizeLimit; ld->ld_timelimit = phSearchInfo->_SearchPref._dwTimeLimit; } hr = AddSearchControls(phSearchInfo, Credentials); BAIL_ON_FAILURE(hr); } ld = phSearchInfo->_pConnection->LdapHandle; dwStatus = ldap_get_option( ld, LDAP_OPT_REFERRALS, &(oldOption) ); newOption = phSearchInfo->_SearchPref._dwChaseReferrals; dwStatus2 = ldap_set_option( ld, LDAP_OPT_REFERRALS, &(newOption) ); if (dwStatus == NO_ERROR && dwStatus2 == NO_ERROR) fNewOptionSet = TRUE; if(!phSearchInfo->_pSearchResults) { // // Get the results. This function uses various members of pSearchInfo // and returns the result in phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult] // which can be used to call LdapFirstEntry and LdapNextEntry // hr = ADsGetResults( phSearchInfo ); // // Update the VLV server response if applicable // if (phSearchInfo->_SearchPref._pVLVInfo && phSearchInfo->_pSearchResults && phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]) { HRESULT hrVLV = S_OK; hrVLV = StoreVLVInfo( phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult], phSearchInfo ); // // we only care if storing the cookie failed // if the search otherwise succeeded // if (FAILED(hrVLV) && SUCCEEDED(hr)) { hr = hrVLV; } } // // Update the Attribute-Scoped Query info if applicable // if (phSearchInfo->_SearchPref._pAttribScoped && phSearchInfo->_pSearchResults && phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]) { HRESULT hrASQ = S_OK; hrASQ = StoreAttribScopedInfo( phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult], phSearchInfo ); // // we only care if storing the info failed // if the search otherwise succeeded // if (FAILED(hrASQ) && SUCCEEDED(hr)) { hr = hrASQ; } } // // Update the dirsync control cookie if applicable. // if (phSearchInfo->_SearchPref._fDirSync && phSearchInfo->_pSearchResults && phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]) { // // Store the cookie info in searchprefs. // StoreDirSyncCookie( phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult], phSearchInfo ); while (hr == S_ADS_NOMORE_ROWS) { // // Try and get more results - this will handle the // case of the DirSync cookie indicating more rows // correctly. // hr = ADsGetMoreResultsDirSync( phSearchInfo, Credentials ); BAIL_ON_FAILURE(hr); } } if (FAILED(hr) || hr == S_ADS_NOMORE_ROWS) { goto error; } } // // Need to set the cur result to 0 as it maybe a case // where we are now going back to the top of a multiple // page search. This will make no difference if the cache // is turned off. // phSearchInfo->_dwCurrResult = 0; hr = LdapFirstEntry( phSearchInfo->_pConnection, phSearchInfo->_pSearchResults[0], &phSearchInfo->_pCurrentRow ); BAIL_ON_FAILURE(hr); if(phSearchInfo->_pCurrentRow) { phSearchInfo->_pFirstAttr = NULL; phSearchInfo->_fBefFirstRow = FALSE; hr = S_OK; } else { hr = S_ADS_NOMORE_ROWS; // // Might be DirSync case where we need to try fetch // more results. // if (phSearchInfo->_SearchPref._fDirSync && phSearchInfo->_fMoreDirSync ) { // // Try and get more results - this will handle the // case of the DirSync cookie indicating more rows // correctly. // hr = ADsGetMoreResultsDirSync( phSearchInfo, Credentials ); BAIL_ON_FAILURE(hr); } } error: if (ld && fNewOptionSet) { ldap_set_option( ld, LDAP_OPT_REFERRALS, &(oldOption) ); } // // When there is no more rows to be returned, return whatever error // that was returned from the last search // if (hr == S_ADS_NOMORE_ROWS) { if (phSearchInfo->_hrLastSearch != S_OK) { RRETURN(phSearchInfo->_hrLastSearch); } else if (phSearchInfo->_fNonFatalErrors) { RRETURN(S_ADS_ERRORSOCCURRED); } else { RRETURN(hr); } } else { RRETURN(hr); } } HRESULT ADsGetNextRow( IN ADS_SEARCH_HANDLE hSearchHandle, IN CCredentials& Credentials ) { HRESULT hr = S_OK; DWORD dwStatus = NO_ERROR, dwStatus2 = NO_ERROR; PLDAP_SEARCHINFO phSearchInfo = (PLDAP_SEARCHINFO) hSearchHandle; LDAP *ld = NULL; BOOL fNewOptionSet = FALSE; DWORD oldOption = 0; DWORD newOption = 0; if (!phSearchInfo) { RRETURN(E_ADS_BAD_PARAMETER); } // reset the value phSearchInfo->_fADsPathReturned = FALSE; phSearchInfo->_fDNReturned = FALSE; if(!phSearchInfo->_pConnection) { hr = LdapOpenObject( phSearchInfo->_pszLdapServer, phSearchInfo->_pszBindContextDn, &phSearchInfo->_pConnection, Credentials, phSearchInfo->_dwPort ); BAIL_ON_FAILURE(hr); // // Set the preferences like deref aliases, time limit and size limit // if (ld = phSearchInfo->_pConnection->LdapHandle) { ld->ld_deref = phSearchInfo->_SearchPref._dwDerefAliases; ld->ld_sizelimit = phSearchInfo->_SearchPref._dwSizeLimit; ld->ld_timelimit = phSearchInfo->_SearchPref._dwTimeLimit; } hr = AddSearchControls(phSearchInfo, Credentials); BAIL_ON_FAILURE(hr); } ld = phSearchInfo->_pConnection->LdapHandle; dwStatus = ldap_get_option( ld, LDAP_OPT_REFERRALS, &(oldOption) ); newOption = phSearchInfo->_SearchPref._dwChaseReferrals; dwStatus2 = ldap_set_option( ld, LDAP_OPT_REFERRALS, &(newOption) ); if (dwStatus == NO_ERROR && dwStatus2 == NO_ERROR) fNewOptionSet = TRUE; if(!phSearchInfo->_pSearchResults) { // // Get the results. This function uses various members of pSearchInfo // and returns the result in phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult] // which can be used to call LdapFirstEntry and LdapNextEntry // hr = ADsGetResults( phSearchInfo ); // // Update the dirsync control cookie if applicable. // if (phSearchInfo->_SearchPref._fDirSync && phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]) { // // Store the cookie info in searchprefs. // StoreDirSyncCookie( phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult], phSearchInfo ); } // // Update the VLV server response if applicable // if (phSearchInfo->_SearchPref._pVLVInfo && phSearchInfo->_pSearchResults && phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]) { HRESULT hrVLV = S_OK; hrVLV = StoreVLVInfo( phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult], phSearchInfo ); // // we only care if storing the cookie failed if the search // otherwise succeeded // if (FAILED(hrVLV) && SUCCEEDED(hr)) { hr = hrVLV; } } // // Update the Attribute-Scoped Query info if applicable // if (phSearchInfo->_SearchPref._pAttribScoped && phSearchInfo->_pSearchResults && phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]) { HRESULT hrASQ = S_OK; hrASQ = StoreAttribScopedInfo( phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult], phSearchInfo ); // // we only care if storing the info failed // if the search otherwise succeeded // if (FAILED(hrASQ) && SUCCEEDED(hr)) { hr = hrASQ; } } if (hr == S_ADS_NOMORE_ROWS) { // // Try and get more results - this will handle the // case of the DirSync cookie indicating more rows // correctly. // hr = ADsGetMoreResultsDirSync( phSearchInfo, Credentials ); BAIL_ON_FAILURE(hr); } if (FAILED(hr) || hr == S_ADS_NOMORE_ROWS) { goto error; } } // // If the current row has not been obtained, get it now. Need to // distinguish between the case where we are after the end of the result // from the case where we are before the beginning of the result. In // both cases _pCurrentRow is NULL, but _fBefFirstRow is TRUE only in // the latter case. // if(!phSearchInfo->_pCurrentRow) { if(phSearchInfo->_fBefFirstRow) { // // Call the ldap specific function to get the first row. // hr = LdapFirstEntry( phSearchInfo->_pConnection, phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult], &phSearchInfo->_pCurrentRow ); } } else { // // Call the ldap specific function to get the next row // hr = LdapNextEntry( phSearchInfo->_pConnection, phSearchInfo->_pCurrentRow, &phSearchInfo->_pCurrentRow ); } if (!phSearchInfo->_pCurrentRow && (phSearchInfo->_dwCurrResult < phSearchInfo->_dwMaxResultGot)) { // // In this case we need to proceed to the next result in memory // hr = S_OK; while (!phSearchInfo->_pCurrentRow && phSearchInfo->_dwCurrResult < phSearchInfo->_dwMaxResultGot && SUCCEEDED(hr)) { // // With Dirsync we may have results that do not have // any entries in them, but the next one may. // phSearchInfo->_dwCurrResult++; hr = LdapFirstEntry( phSearchInfo->_pConnection, phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult], &phSearchInfo->_pCurrentRow ); } } else if (!phSearchInfo->_pCurrentRow && (!phSearchInfo->_fLastResult || !phSearchInfo->_fLastPage || phSearchInfo->_fMoreDirSync ) ) { // // Now if both lastResult and page are true, we need to call // ADsGetMoreResultsDirSync. This is the unusual case. // if (phSearchInfo->_fLastResult && phSearchInfo->_fLastPage) { hr = ADsGetMoreResultsDirSync( phSearchInfo, Credentials ); } else { // // This means that there are more results to be obtained // although the current result has reached its end. // Call the function to get more results in // phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult] // It will increment _dwCurrResult and reallocate if needed. // hr = ADsGetMoreResults( phSearchInfo ); } // // In async searches, we will know if we have to call // ADsGetMoreResultsAsync only now. So recheck. // if (hr == S_ADS_NOMORE_ROWS && phSearchInfo->_SearchPref._fAsynchronous ) { if (phSearchInfo->_fLastResult && phSearchInfo->_fLastPage) { hr = ADsGetMoreResultsDirSync( phSearchInfo, Credentials ); } } // // Update the dirsync control cookie if applicable. // if (phSearchInfo->_SearchPref._fDirSync && phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]) { // // Store the cookie info in searchprefs. // StoreDirSyncCookie( phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult], phSearchInfo ); } // // Update the Attribute-Scoped Query info if applicable // if (phSearchInfo->_SearchPref._pAttribScoped && phSearchInfo->_pSearchResults && phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]) { HRESULT hrASQ = S_OK; hrASQ = StoreAttribScopedInfo( phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult], phSearchInfo ); // // we only care if storing the info failed // if the search otherwise succeeded // if (FAILED(hrASQ) && SUCCEEDED(hr)) { hr = hrASQ; } } if (FAILED(hr) || hr == S_ADS_NOMORE_ROWS) { goto error; } hr = LdapFirstEntry( phSearchInfo->_pConnection, phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult], &phSearchInfo->_pCurrentRow ); if (!phSearchInfo->_pCurrentRow) { // // This means that we can possibly have more results // but this time we did not get any - not yet a NULL // cookie on a paged search that is. // ADsSetLastError( ERROR_MORE_DATA, L"Calling GetNextRow can potentially return more results.", L"LDAP Provider" ); } } BAIL_ON_FAILURE(hr); if(phSearchInfo->_pCurrentRow) { phSearchInfo->_pFirstAttr = NULL; phSearchInfo->_fBefFirstRow = FALSE; hr = S_OK; } else { hr = S_ADS_NOMORE_ROWS; // // Might be DirSync case where we need to try fetch // more results. // if (phSearchInfo->_SearchPref._fDirSync && phSearchInfo->_fMoreDirSync ) { // // Try and get more results - this will handle the // case of the DirSync cookie indicating more rows // correctly. // hr = ADsGetMoreResultsDirSync( phSearchInfo, Credentials ); BAIL_ON_FAILURE(hr); } } error: if (ld && fNewOptionSet) { ldap_set_option( ld, LDAP_OPT_REFERRALS, &(oldOption) ); } // // When there is no more rows to be returned, return whatever error // that was returned from the last search // if (hr == S_ADS_NOMORE_ROWS) { if (phSearchInfo->_hrLastSearch != S_OK) { RRETURN(phSearchInfo->_hrLastSearch); } else if (phSearchInfo->_fNonFatalErrors) { RRETURN(S_ADS_ERRORSOCCURRED); } else { RRETURN(hr); } } else { RRETURN(hr); } } // // Function to get the results by performing the appropriate search depending // on the preferences; Paged Results, Sorting, Synchronous, Asynchrnous or // Timed Synchronous // HRESULT ADsGetResults( IN PLDAP_SEARCHINFO phSearchInfo ) { HRESULT hr = S_OK; DWORD dwError; WCHAR pszErrorBuf[MAX_PATH], pszNameBuf[MAX_PATH]; ULONG totalCount; int resType; ADsAssert(phSearchInfo); // // If abandon has been called, we don't get more results. // if (phSearchInfo->_fAbandon) { RRETURN(S_ADS_NOMORE_ROWS); } if(!phSearchInfo->_pSearchResults) { // // Allocate an array of handles to Search Results // phSearchInfo->_pSearchResults = (LDAPMessage **) AllocADsMem( sizeof(LDAPMessage *) * NO_LDAP_RESULT_HANDLES); if(!phSearchInfo->_pSearchResults) { hr = E_OUTOFMEMORY; goto error; } phSearchInfo->_dwCurrResult = 0; phSearchInfo->_cSearchResults = NO_LDAP_RESULT_HANDLES; // // Should also set the cur max to 0; // phSearchInfo->_dwMaxResultGot = 0; } // Initialize Result to NULL phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult] = NULL; // // Call the ldap specific search function // if (phSearchInfo->_SearchPref._dwPageSize != 0) { // // Paged results // if(!phSearchInfo->_hPagedSearch ) { hr = LdapSearchInitPage( phSearchInfo->_pConnection, phSearchInfo->_pszBindContextDn, phSearchInfo->_SearchPref._dwSearchScope, phSearchInfo->_pszSearchFilter, phSearchInfo->_ppszAttrs, phSearchInfo->_SearchPref._fAttrsOnly, phSearchInfo->_ServerControls, phSearchInfo->_ClientControls, phSearchInfo->_SearchPref._dwPagedTimeLimit, phSearchInfo->_SearchPref._dwSizeLimit, NULL, &phSearchInfo->_hPagedSearch ); BAIL_ON_FAILURE(hr); } if ( phSearchInfo->_SearchPref._fAsynchronous ) { hr = LdapGetNextPage( phSearchInfo->_pConnection, phSearchInfo->_hPagedSearch, phSearchInfo->_SearchPref._dwPageSize, (ULONG *)&phSearchInfo->_currMsgId ); if (FAILED(hr)) { if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_RESULTS_RETURNED)) { phSearchInfo->_fLastPage = TRUE; RRETURN(S_ADS_NOMORE_ROWS); } else { BAIL_ON_FAILURE(hr); } } // // Wait for one page worth of results to get back. // hr = LdapResult( phSearchInfo->_pConnection, phSearchInfo->_currMsgId, LDAP_MSG_ALL, phSearchInfo->_SearchPref._timeout.tv_sec ? &phSearchInfo->_SearchPref._timeout : NULL, &phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult], &resType ); if (FAILED(hr)) { if ((hr == HRESULT_FROM_WIN32(ERROR_DS_INVALID_DN_SYNTAX)) || (hr == HRESULT_FROM_WIN32(ERROR_DS_NAMING_VIOLATION)) || (hr == HRESULT_FROM_WIN32(ERROR_DS_OBJ_CLASS_VIOLATION)) || (hr == HRESULT_FROM_WIN32(ERROR_DS_FILTER_UNKNOWN)) || (hr == HRESULT_FROM_WIN32(ERROR_DS_PARAM_ERROR)) || (hr == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER))) { phSearchInfo->_fLastResult = TRUE; RRETURN(S_ADS_NOMORE_ROWS); } else { BAIL_ON_FAILURE(hr); } } hr = LdapGetPagedCount( phSearchInfo->_pConnection, phSearchInfo->_hPagedSearch, &totalCount, phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult] ); if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_RESULTS_RETURNED)) { hr = S_OK; } // // if hr failed, we will do the corresponding according to whether there is any result returned in our mechanism later // } else { hr = LdapGetNextPageS( phSearchInfo->_pConnection, phSearchInfo->_hPagedSearch, phSearchInfo->_SearchPref._timeout.tv_sec ? &phSearchInfo->_SearchPref._timeout : NULL, phSearchInfo->_SearchPref._dwPageSize, &totalCount, &phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult] ); if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_RESULTS_RETURNED)) { phSearchInfo->_fLastPage = TRUE; RRETURN(S_ADS_NOMORE_ROWS); } // // if hr failed, we will do the corresponding according to whether there is any result returned in our mechanism later // phSearchInfo->_fLastResult = TRUE; } } else if (phSearchInfo->_SearchPref._fAsynchronous) { hr = LdapSearchExt( phSearchInfo->_pConnection, phSearchInfo->_pszBindContextDn, phSearchInfo->_SearchPref._dwSearchScope, phSearchInfo->_pszSearchFilter, phSearchInfo->_ppszAttrs, phSearchInfo->_SearchPref._fAttrsOnly, phSearchInfo->_ServerControls, phSearchInfo->_ClientControls, phSearchInfo->_SearchPref._dwPagedTimeLimit, phSearchInfo->_SearchPref._dwSizeLimit, &phSearchInfo->_currMsgId ); BAIL_ON_FAILURE(hr); // // Wait for atleast one result // hr = LdapResult( phSearchInfo->_pConnection, phSearchInfo->_currMsgId, LDAP_MSG_RECEIVED, phSearchInfo->_SearchPref._timeout.tv_sec ? &phSearchInfo->_SearchPref._timeout : NULL, &phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult], &resType ); if ((hr == HRESULT_FROM_WIN32(ERROR_DS_INVALID_DN_SYNTAX)) || (hr == HRESULT_FROM_WIN32(ERROR_DS_NAMING_VIOLATION)) || (hr == HRESULT_FROM_WIN32(ERROR_DS_OBJ_CLASS_VIOLATION)) || (hr == HRESULT_FROM_WIN32(ERROR_DS_FILTER_UNKNOWN)) || (hr == HRESULT_FROM_WIN32(ERROR_DS_PARAM_ERROR)) || (hr == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER))) { phSearchInfo->_fLastResult = TRUE; RRETURN(S_ADS_NOMORE_ROWS); } // // if hr failed, we will do the corresponding according to whether there is any result returned in our mechanism later // phSearchInfo->_fLastPage = TRUE; } else if (phSearchInfo->_SearchPref._timeout.tv_sec != 0) { hr = LdapSearchExtS( phSearchInfo->_pConnection, phSearchInfo->_pszBindContextDn, phSearchInfo->_SearchPref._dwSearchScope, phSearchInfo->_pszSearchFilter, phSearchInfo->_ppszAttrs, phSearchInfo->_SearchPref._fAttrsOnly, phSearchInfo->_ServerControls, phSearchInfo->_ClientControls, &phSearchInfo->_SearchPref._timeout, phSearchInfo->_SearchPref._dwSizeLimit, &phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult] ); phSearchInfo->_fLastResult = TRUE; phSearchInfo->_fLastPage = TRUE; } else { hr = LdapSearchExtS( phSearchInfo->_pConnection, phSearchInfo->_pszBindContextDn, phSearchInfo->_SearchPref._dwSearchScope, phSearchInfo->_pszSearchFilter, phSearchInfo->_ppszAttrs, phSearchInfo->_SearchPref._fAttrsOnly, phSearchInfo->_ServerControls, phSearchInfo->_ClientControls, NULL, phSearchInfo->_SearchPref._dwSizeLimit, &phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult] ); phSearchInfo->_fLastResult = TRUE; phSearchInfo->_fLastPage = TRUE; } // // Only if there are zero rows returned, return the error, // otherwise, store the error and return when GetNextRow is // called for the last time // if (FAILED(hr) && (LdapCountEntries( phSearchInfo->_pConnection, phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]) == 0)) { BAIL_ON_FAILURE(hr); } else { phSearchInfo->_hrLastSearch = hr; hr = S_OK; } phSearchInfo->_pCurrentRow = NULL; error: RRETURN(hr); } // // For Asynchronous or paged searches, more results need to be obtained, once // the current result set is exhausted. This function gets the next result set // if one is available. In the case of paged results, this might translate to // getting the next page. // HRESULT ADsGetMoreResults( IN PLDAP_SEARCHINFO phSearchInfo ) { HRESULT hr = S_OK; DWORD dwError; LPWSTR pszLDAPPath; WCHAR pszErrorBuf[MAX_PATH], pszNameBuf[MAX_PATH]; ULONG totalCount; int resType; LDAPMessage **pTemp = NULL; ADsAssert(phSearchInfo); // // If abandon has been called, we don't get more results. // if (phSearchInfo->_fAbandon) { RRETURN(S_ADS_NOMORE_ROWS); } if (phSearchInfo->_fLastResult && phSearchInfo->_fLastPage) RRETURN (S_ADS_NOMORE_ROWS); if (phSearchInfo->_fLastResult == FALSE) { // // if we need to cache the results, then we save the result in the // phSearchInfo->_pSearchResults array. If we don't need to cache it, // release the result and save it in the same place. if ( phSearchInfo->_SearchPref._fCacheResults ) { ADsAssert(phSearchInfo->_dwCurrResult == phSearchInfo->_dwMaxResultGot); phSearchInfo->_dwCurrResult++; phSearchInfo->_dwMaxResultGot++; if (phSearchInfo->_dwCurrResult >= phSearchInfo->_cSearchResults) { // // Need to allocate more memory for handles // pTemp = (LDAPMessage **) ReallocADsMem( (void *) phSearchInfo->_pSearchResults, sizeof(LDAPMessage *) * phSearchInfo->_cSearchResults, sizeof(LDAPMessage *) * (phSearchInfo->_cSearchResults + NO_LDAP_RESULT_HANDLES)); if(!pTemp) { hr = E_OUTOFMEMORY; phSearchInfo->_dwCurrResult--; phSearchInfo->_dwMaxResultGot--; goto error; } phSearchInfo->_pSearchResults = pTemp; pTemp = NULL; phSearchInfo->_cSearchResults += NO_LDAP_RESULT_HANDLES; } } else { // // Release and use the same space to store the next result. // LdapMsgFree(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]); } // Initialize Result to NULL phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult] = NULL; hr = LdapResult( phSearchInfo->_pConnection, phSearchInfo->_currMsgId, LDAP_MSG_RECEIVED, phSearchInfo->_SearchPref._timeout.tv_sec ? &phSearchInfo->_SearchPref._timeout : NULL, &phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult], &resType ); if ((hr == HRESULT_FROM_WIN32(ERROR_DS_INVALID_DN_SYNTAX)) || (hr == HRESULT_FROM_WIN32(ERROR_DS_NAMING_VIOLATION)) || (hr == HRESULT_FROM_WIN32(ERROR_DS_OBJ_CLASS_VIOLATION)) || (hr == HRESULT_FROM_WIN32(ERROR_DS_FILTER_UNKNOWN)) || (hr == HRESULT_FROM_WIN32(ERROR_DS_PARAM_ERROR)) || (hr == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER))) { phSearchInfo->_fLastResult = TRUE; } else { phSearchInfo->_hrLastSearch = hr; hr = S_OK; RRETURN(hr); } } // // The last result has been reached. Check if we need to look for further // pages // if ( phSearchInfo->_fLastPage == FALSE) { // // if we need to cache the results, then we save the result in the // phSearchInfo->_pSearchResults array. If we don't need to cache it, // release the result and save it in the same place. if ( phSearchInfo->_SearchPref._fCacheResults ) { ADsAssert(phSearchInfo->_dwCurrResult == phSearchInfo->_dwMaxResultGot); phSearchInfo->_dwCurrResult++; phSearchInfo->_dwMaxResultGot++; if (phSearchInfo->_dwCurrResult >= phSearchInfo->_cSearchResults) { // // Need to allocate more memory for handles // pTemp = (LDAPMessage **) ReallocADsMem( (void *) phSearchInfo->_pSearchResults, sizeof(LDAPMessage *) * phSearchInfo->_cSearchResults, sizeof(LDAPMessage *) * (phSearchInfo->_cSearchResults + NO_LDAP_RESULT_HANDLES)); if(!pTemp) { hr = E_OUTOFMEMORY; goto error; } phSearchInfo->_pSearchResults = pTemp; pTemp = NULL; phSearchInfo->_cSearchResults += NO_LDAP_RESULT_HANDLES; } } else { // // Release and use the same space to store the next result. // LdapMsgFree(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]); } // Initialize Result to NULL phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult] = NULL; if ( phSearchInfo->_SearchPref._fAsynchronous ) { hr = LdapGetNextPage( phSearchInfo->_pConnection, phSearchInfo->_hPagedSearch, phSearchInfo->_SearchPref._dwPageSize, (ULONG *) &phSearchInfo->_currMsgId ); if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_RESULTS_RETURNED)) { phSearchInfo->_fLastPage = TRUE; if (phSearchInfo->_SearchPref._fCacheResults) { phSearchInfo->_dwCurrResult--; phSearchInfo->_dwMaxResultGot--; } RRETURN(S_ADS_NOMORE_ROWS); } BAIL_ON_FAILURE(hr); // // Wait for one page worth of results to get back. // hr = LdapResult( phSearchInfo->_pConnection, phSearchInfo->_currMsgId, LDAP_MSG_ALL, phSearchInfo->_SearchPref._timeout.tv_sec ? &phSearchInfo->_SearchPref._timeout : NULL, &phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult], &resType ); phSearchInfo->_fLastResult = FALSE; if ((hr == HRESULT_FROM_WIN32(ERROR_DS_INVALID_DN_SYNTAX)) || (hr == HRESULT_FROM_WIN32(ERROR_DS_NAMING_VIOLATION)) || (hr == HRESULT_FROM_WIN32(ERROR_DS_OBJ_CLASS_VIOLATION)) || (hr == HRESULT_FROM_WIN32(ERROR_DS_FILTER_UNKNOWN)) || (hr == HRESULT_FROM_WIN32(ERROR_DS_PARAM_ERROR)) || (hr == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER))) { phSearchInfo->_fLastResult = TRUE; RRETURN(S_ADS_NOMORE_ROWS); } BAIL_ON_FAILURE(hr); hr = LdapGetPagedCount( phSearchInfo->_pConnection, phSearchInfo->_hPagedSearch, &totalCount, phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult] ); if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_RESULTS_RETURNED)) { hr = S_OK; } BAIL_ON_FAILURE(hr); } else { hr = LdapGetNextPageS( phSearchInfo->_pConnection, phSearchInfo->_hPagedSearch, phSearchInfo->_SearchPref._timeout.tv_sec ? &phSearchInfo->_SearchPref._timeout : NULL, phSearchInfo->_SearchPref._dwPageSize, &totalCount, &phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult] ); if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_RESULTS_RETURNED)) { // // Since we hit the last page we need to get the // count of the max and currResults down by one. // if (phSearchInfo->_SearchPref._fCacheResults) { phSearchInfo->_dwCurrResult--; phSearchInfo->_dwMaxResultGot--; } phSearchInfo->_fLastPage = TRUE; RRETURN(S_ADS_NOMORE_ROWS); } BAIL_ON_FAILURE(hr); } RRETURN(S_OK); } // // If we came here, we have reached the end // hr = S_ADS_NOMORE_ROWS; error: RRETURN(hr); } HRESULT ADsGetPreviousRow( IN ADS_SEARCH_HANDLE hSearchHandle, IN CCredentials& Credentials ) { PLDAP_SEARCHINFO phSearchInfo = (PLDAP_SEARCHINFO) hSearchHandle; LDAPMessage *pTmpRow, *pTargetRow, *pPrevRow = NULL; DWORD dwOrigCurrResult; HRESULT hr; if (!phSearchInfo) { RRETURN(E_ADS_BAD_PARAMETER); } if(!phSearchInfo->_pConnection) { // cannot ask for previous row if connection not established RRETURN(E_ADS_BAD_PARAMETER); } if(!phSearchInfo->_pSearchResults) { // cannot ask for previous row if no results have been obtained RRETURN(E_ADS_BAD_PARAMETER); } // save value in case we need to restore later dwOrigCurrResult = phSearchInfo->_dwCurrResult; if(NULL == phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]) // we are at the end of the entire search result list { ADsAssert(!phSearchInfo->_pCurrentRow); if(phSearchInfo->_dwCurrResult > 0) // we need to get the last entry of the previous result phSearchInfo->_dwCurrResult--; else { phSearchInfo->_fBefFirstRow = TRUE; RRETURN(S_ADS_NOMORE_ROWS); } } ADsAssert(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]); hr = LdapFirstEntry(phSearchInfo->_pConnection, phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult], &pTmpRow); BAIL_ON_FAILURE(hr); // row whose predecessor we are looking for (this may be NULL) pTargetRow = phSearchInfo->_pCurrentRow; if(pTmpRow == pTargetRow) // we are at the first row of the current result { if(phSearchInfo->_dwCurrResult > 0) { // we need to get the last entry of the previous result phSearchInfo->_dwCurrResult--; pTargetRow = NULL; hr = LdapFirstEntry(phSearchInfo->_pConnection, phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult], &pTmpRow); BAIL_ON_FAILURE(hr); } else { phSearchInfo->_pCurrentRow = NULL; phSearchInfo->_fBefFirstRow = TRUE; RRETURN(S_ADS_NOMORE_ROWS); } } while(pTmpRow != pTargetRow) { pPrevRow = pTmpRow; hr = LdapNextEntry(phSearchInfo->_pConnection, pTmpRow, &pTmpRow); BAIL_ON_FAILURE(hr); } ADsAssert(pPrevRow); phSearchInfo->_pCurrentRow = pPrevRow; phSearchInfo->_pFirstAttr = NULL; RRETURN(S_OK); error: phSearchInfo->_dwCurrResult = dwOrigCurrResult; RRETURN(hr); } HRESULT ADsGetColumn( IN ADS_SEARCH_HANDLE hSearchHandle, IN LPWSTR pszColumnName, IN CCredentials& Credentials, DWORD dwPort, OUT PADS_SEARCH_COLUMN pColumn ) { PLDAP_SEARCHINFO phSearchInfo = (PLDAP_SEARCHINFO) hSearchHandle; VOID **ppValue = NULL; struct berval **ppBerValue = NULL; WCHAR **ppStrValue = NULL; int cValueCount; HRESULT hr = S_OK; DWORD dwStatus; LPWSTR pszDn = NULL; LPWSTR pszADsPathName = NULL; DWORD dwSyntaxId; DWORD dwError; WCHAR pszErrorBuf[MAX_PATH], pszNameBuf[MAX_PATH]; PADS_VLV pVLV = NULL; LPWSTR pszTempDN = NULL; if( !pColumn || !phSearchInfo || !phSearchInfo->_pSearchResults ) RRETURN (E_ADS_BAD_PARAMETER); pColumn->pszAttrName = NULL; pColumn->dwADsType = ADSTYPE_INVALID; pColumn->pADsValues = NULL; pColumn->dwNumValues = 0; pColumn->hReserved = NULL; if(!phSearchInfo->_pConnection) RRETURN (E_ADS_BAD_PARAMETER); if (!phSearchInfo->_pCurrentRow && _wcsicmp(pszColumnName, ADS_DIRSYNC_COOKIE) && _wcsicmp(pszColumnName, ADS_VLV_RESPONSE)) { // // Current row is not valid and you are not asking for the // dirsync cookie - so we will fail. // RRETURN(E_ADS_BAD_PARAMETER); } pColumn->pszAttrName = AllocADsStr(pszColumnName); if (!pColumn->pszAttrName) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); if(!_wcsicmp (pszColumnName, L"ADsPath")) { // // Get the DN of the entry. // hr = LdapGetDn( phSearchInfo->_pConnection, phSearchInfo->_pCurrentRow, &pszDn ); BAIL_ON_FAILURE(hr); // if extended_dn control is used, we need to get the normal dn format out for ADsPath if(phSearchInfo->_SearchPref._fExtendedDNControl) { hr = HelpGetNormalDN(pszDn, &pszTempDN); BAIL_ON_FAILURE(hr); } else { pszTempDN = pszDn; } // // Build the ADsPath // hr = BuildADsPathFromLDAPPath( phSearchInfo->_pszADsPathContext, pszTempDN, &pszADsPathName ); BAIL_ON_FAILURE(hr); LdapMemFree(pszDn); pszDn = NULL; pColumn->pADsValues = (PADSVALUE) AllocADsMem(sizeof(ADSVALUE)); if (!pColumn->pADsValues) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); pColumn->dwADsType = ADSTYPE_CASE_IGNORE_STRING; pColumn->dwNumValues = 1; pColumn->pADsValues[0].dwType = ADSTYPE_CASE_IGNORE_STRING; pColumn->pADsValues[0].CaseIgnoreString = AllocADsStr(pszADsPathName); if (!pColumn->pADsValues[0].CaseIgnoreString) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); FreeADsMem(pszADsPathName); RRETURN(S_OK); } else if (phSearchInfo->_SearchPref._fDirSync) { // // See if we need to return the DistinguishedName // if(phSearchInfo->_fDNPresent && !_wcsicmp(pszColumnName, L"distinguishedName")) { // // Get the DN of the entry. // hr = LdapGetDn( phSearchInfo->_pConnection, phSearchInfo->_pCurrentRow, &pszDn ); BAIL_ON_FAILURE(hr); pColumn->pADsValues = (PADSVALUE) AllocADsMem(sizeof(ADSVALUE)); if (!pColumn->pADsValues) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); pColumn->dwADsType = ADSTYPE_DN_STRING; pColumn->dwNumValues = 1; pColumn->pADsValues[0].dwType = ADSTYPE_DN_STRING; pColumn->pADsValues[0].CaseIgnoreString = AllocADsStr(pszDn); if (!pColumn->pADsValues[0].CaseIgnoreString) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); LdapMemFree(pszDn); RRETURN(S_OK); } // // See if we need to return the dirsync control info. // if (!_wcsicmp (pszColumnName, ADS_DIRSYNC_COOKIE)) { pColumn->pADsValues = (PADSVALUE) AllocADsMem(sizeof(ADSVALUE)); if (!pColumn->pADsValues) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); pColumn->dwADsType = ADSTYPE_PROV_SPECIFIC; pColumn->dwNumValues = 1; pColumn->pADsValues[0].dwType = ADSTYPE_PROV_SPECIFIC; // // Copy the control over if appropriate if not we will // return NULL or empty data for the result. // if (phSearchInfo->_SearchPref._pProvSpecific->lpValue) { pColumn->pADsValues[0].ProviderSpecific.dwLength = phSearchInfo->_SearchPref._pProvSpecific->dwLength; pColumn->pADsValues[0].ProviderSpecific.lpValue = (LPBYTE) AllocADsMem( pColumn->pADsValues[0].ProviderSpecific.dwLength ); if (!pColumn->pADsValues[0].ProviderSpecific.lpValue) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } memcpy( pColumn->pADsValues[0].ProviderSpecific.lpValue, phSearchInfo->_SearchPref._pProvSpecific->lpValue, phSearchInfo->_SearchPref._pProvSpecific->dwLength ); } RRETURN(S_OK); } // if DirSyncControlStruct is being asked for. } // if dirsync set. else if (phSearchInfo->_SearchPref._pVLVInfo) { // // See if we need to return the VLV control info. // if (!_wcsicmp (pszColumnName, ADS_VLV_RESPONSE)) { pColumn->pADsValues = (PADSVALUE) AllocADsMem(sizeof(ADSVALUE)); if (!pColumn->pADsValues) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); pColumn->dwADsType = ADSTYPE_PROV_SPECIFIC; pColumn->dwNumValues = 1; pColumn->pADsValues[0].dwType = ADSTYPE_PROV_SPECIFIC; pColumn->pADsValues[0].ProviderSpecific.dwLength = sizeof(ADS_VLV); pColumn->pADsValues[0].ProviderSpecific.lpValue = (LPBYTE) AllocADsMem(sizeof(ADS_VLV)); if (!pColumn->pADsValues[0].ProviderSpecific.lpValue) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); // copy the VLV data into the ADS_VLV pVLV = (PADS_VLV) pColumn->pADsValues[0].ProviderSpecific.lpValue; pVLV->dwBeforeCount = 0; pVLV->dwAfterCount = 0; pVLV->dwOffset = phSearchInfo->_dwVLVOffset; pVLV->dwContentCount = phSearchInfo->_dwVLVCount; pVLV->pszTarget = NULL; // copy the VLV context ID, if available pVLV->lpContextID = NULL; pVLV->dwContextIDLength = 0; if (phSearchInfo->_pVLVContextID && phSearchInfo->_pVLVContextID->bv_len) { pVLV->lpContextID = (LPBYTE) AllocADsMem(phSearchInfo->_pVLVContextID->bv_len); if (!pVLV->lpContextID) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); pVLV->dwContextIDLength = phSearchInfo->_pVLVContextID->bv_len; memcpy(pVLV->lpContextID, phSearchInfo->_pVLVContextID->bv_val, phSearchInfo->_pVLVContextID->bv_len); } RRETURN(S_OK); } // if VLV response is being asked for } // if VLV set if (phSearchInfo->_fADsPathOnly) { // // Only ADsPath attribute requested in the search, // so don't return any other column values. // RRETURN (E_ADS_COLUMN_NOT_SET); } if (phSearchInfo->_SearchPref._fAttrsOnly) { // // Only Names got. So, don't return any values // RRETURN (S_OK); } // // Call the helper function to get the LDAP specific type // hr = LdapGetSyntaxOfAttributeOnServer( phSearchInfo->_pszLdapServer, pszColumnName, &dwSyntaxId, Credentials, dwPort ); if (hr == E_ADS_CANT_CONVERT_DATATYPE) { // // This means that the server didn't give back the schema and we don't // have it in the default schema. Return an octet blob. // dwSyntaxId = LDAPTYPE_OCTETSTRING; hr = S_OK; } if (hr == E_ADS_PROPERTY_NOT_FOUND) { // // Not on the server, we will return as provider specific. // LDAPTYPE_UNKNOWN will be mapped to ADSTYPE_PROVIDER_SPECIFIC // when we build the ADsColumn. // dwSyntaxId = LDAPTYPE_UNKNOWN; hr = S_OK; } BAIL_ON_FAILURE(hr); // // Now get the data // switch ( dwSyntaxId ) { case LDAPTYPE_CERTIFICATE: case LDAPTYPE_CERTIFICATELIST: case LDAPTYPE_CERTIFICATEPAIR: case LDAPTYPE_PASSWORD: case LDAPTYPE_TELETEXTERMINALIDENTIFIER: case LDAPTYPE_AUDIO: case LDAPTYPE_JPEG: case LDAPTYPE_FAX: case LDAPTYPE_OCTETSTRING: case LDAPTYPE_SECURITY_DESCRIPTOR: case LDAPTYPE_UNKNOWN: hr = LdapGetValuesLen( phSearchInfo->_pConnection, phSearchInfo->_pCurrentRow, pszColumnName, &ppBerValue, &cValueCount ); ppValue = (VOID **) ppBerValue; break; default: hr = LdapGetValues( phSearchInfo->_pConnection, phSearchInfo->_pCurrentRow, pszColumnName, &ppStrValue, &cValueCount ); ppValue = (VOID **) ppStrValue; break; } if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_ATTRIBUTE_OR_VALUE)) { hr=E_ADS_COLUMN_NOT_SET; } BAIL_ON_FAILURE(hr); hr = LdapValueToADsColumn( pszColumnName, dwSyntaxId, cValueCount, ppValue, pColumn ); BAIL_ON_FAILURE(hr); RRETURN(S_OK); error: ADsFreeColumn(pColumn); if (pszADsPathName) FreeADsMem(pszADsPathName); if(pszDn) { LdapMemFree(pszDn); } RRETURN (hr); } HRESULT ADsGetNextColumnName( IN ADS_SEARCH_HANDLE hSearchHandle, OUT LPWSTR * ppszColumnName ) { HRESULT hr = S_OK; PLDAP_SEARCHINFO phSearchInfo = (PLDAP_SEARCHINFO) hSearchHandle; DWORD dwStatus, dwError; WCHAR pszErrorBuf[MAX_PATH], pszNameBuf[MAX_PATH]; if( !phSearchInfo || !phSearchInfo->_pSearchResults || !ppszColumnName) RRETURN (E_ADS_BAD_PARAMETER); *ppszColumnName = NULL; if (!phSearchInfo->_fADsPathOnly) { if (!phSearchInfo->_pFirstAttr) hr = LdapFirstAttribute( phSearchInfo->_pConnection, phSearchInfo->_pCurrentRow, &phSearchInfo->_pFirstAttr, ppszColumnName ); else hr = LdapNextAttribute( phSearchInfo->_pConnection, phSearchInfo->_pCurrentRow, phSearchInfo->_pFirstAttr, ppszColumnName ); BAIL_ON_FAILURE(hr); } if (*ppszColumnName) { // Nothing to do in this case. } else if ( phSearchInfo->_fDNPresent || phSearchInfo->_fADsPathPresent) { if(phSearchInfo->_fDNPresent) { if(!phSearchInfo->_fDNReturned) { *ppszColumnName = AllocADsStr(L"distinguishedName"); if(!*ppszColumnName) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } phSearchInfo->_fDNReturned = TRUE; // got the column name, just return hr = S_OK; return hr; } else { // just set hr equal to no more column here hr = S_ADS_NOMORE_COLUMNS; } } // // If ADsPath was specified return it as the last column // if(phSearchInfo->_fADsPathPresent) { if (!phSearchInfo->_fADsPathReturned) { *ppszColumnName = AllocADsStr(L"ADsPath"); if(!*ppszColumnName) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } phSearchInfo->_fADsPathReturned = TRUE; hr = S_OK; } else { hr = S_ADS_NOMORE_COLUMNS; } } } else { hr = S_ADS_NOMORE_COLUMNS; } error: RRETURN (hr); } HRESULT ADsFreeColumn( IN PADS_SEARCH_COLUMN pColumn ) { HRESULT hr = S_OK; if(!pColumn) RRETURN (E_ADS_BAD_PARAMETER); switch(pColumn->dwADsType) { case ADSTYPE_OCTET_STRING: case ADSTYPE_NT_SECURITY_DESCRIPTOR: case ADSTYPE_PROV_SPECIFIC: // // Call the LDAP free value routine if not DirSyncControl // or VLV // if (pColumn->pszAttrName && !_wcsicmp(ADS_VLV_RESPONSE, pColumn->pszAttrName)) { // // VLV, so free the ADS_VLV and its members // if (pColumn->pADsValues && pColumn->pADsValues[0].ProviderSpecific.lpValue) { if (((PADS_VLV)(pColumn->pADsValues[0].ProviderSpecific.lpValue))->lpContextID) { FreeADsMem(((PADS_VLV)(pColumn->pADsValues[0].ProviderSpecific.lpValue))->lpContextID); } FreeADsMem(pColumn->pADsValues[0].ProviderSpecific.lpValue); } } else if (pColumn->pszAttrName && _wcsicmp(ADS_DIRSYNC_COOKIE, pColumn->pszAttrName) ) { LdapValueFreeLen((struct berval **)pColumn->hReserved); pColumn->hReserved = NULL; } else { // // DirSyncControlStruct - so we free the ADsValue. // if (pColumn->pADsValues[0].ProviderSpecific.lpValue) { FreeADsMem(pColumn->pADsValues[0].ProviderSpecific.lpValue); } } break; case ADSTYPE_CASE_IGNORE_STRING: case ADSTYPE_NUMERIC_STRING: case ADSTYPE_PRINTABLE_STRING: case ADSTYPE_DN_STRING: case ADSTYPE_CASE_EXACT_STRING: if(!pColumn->hReserved) { // // The column just contains a DN. // FreeADsMem(pColumn->pADsValues[0].CaseIgnoreString); } else { LdapValueFree( (WCHAR **)pColumn->hReserved); pColumn->hReserved = NULL; } break; case ADSTYPE_INTEGER: case ADSTYPE_LARGE_INTEGER: case ADSTYPE_BOOLEAN: case ADSTYPE_UTC_TIME: // Nothing to free break; case ADSTYPE_DN_WITH_BINARY: case ADSTYPE_DN_WITH_STRING: AdsTypeFreeAdsObjects( pColumn->pADsValues, pColumn->dwNumValues ); // // Do not want to free this twice // pColumn->pADsValues = NULL; break; case ADSTYPE_INVALID: // // This comes from the result of search by setting _SearchPref._fAttrsOnly // nothing need to be done // break; default: // unknown type; hr = E_ADS_BAD_PARAMETER; } if (pColumn->pszAttrName) FreeADsStr(pColumn->pszAttrName); if (pColumn->pADsValues) { FreeADsMem(pColumn->pADsValues); pColumn->pADsValues = NULL; } RRETURN(hr); } BOOL IsValidPrefValue( ADS_SEARCHPREF_INFO SearchPref ) { switch(SearchPref.dwSearchPref) { case ADS_SEARCHPREF_ASYNCHRONOUS: case ADS_SEARCHPREF_ATTRIBTYPES_ONLY: case ADS_SEARCHPREF_CACHE_RESULTS: case ADS_SEARCHPREF_TOMBSTONE: if (SearchPref.vValue.dwType != ADSTYPE_BOOLEAN) return FALSE; break; case ADS_SEARCHPREF_DEREF_ALIASES: case ADS_SEARCHPREF_SIZE_LIMIT: case ADS_SEARCHPREF_TIME_LIMIT: case ADS_SEARCHPREF_SEARCH_SCOPE: case ADS_SEARCHPREF_TIMEOUT: case ADS_SEARCHPREF_PAGESIZE: case ADS_SEARCHPREF_PAGED_TIME_LIMIT: case ADS_SEARCHPREF_CHASE_REFERRALS: if (SearchPref.vValue.dwType != ADSTYPE_INTEGER) return FALSE; break; case ADS_SEARCHPREF_SORT_ON: if (SearchPref.vValue.dwType != ADSTYPE_PROV_SPECIFIC) return FALSE; break; case ADS_SEARCHPREF_DIRSYNC: if (SearchPref.vValue.dwType != ADSTYPE_PROV_SPECIFIC) return FALSE; break; case ADS_SEARCHPREF_VLV: if (SearchPref.vValue.dwType != ADSTYPE_PROV_SPECIFIC) return FALSE; break; case ADS_SEARCHPREF_ATTRIBUTE_QUERY: if (SearchPref.vValue.dwType != ADSTYPE_CASE_IGNORE_STRING) return FALSE; break; case ADS_SEARCHPREF_SECURITY_MASK: if (SearchPref.vValue.dwType != ADSTYPE_INTEGER) return FALSE; break; case ADS_SEARCHPREF_DIRSYNC_FLAG: if(SearchPref.vValue.dwType != ADSTYPE_INTEGER) return FALSE; break; case ADS_SEARCHPREF_EXTENDED_DN: if(SearchPref.vValue.dwType != ADSTYPE_INTEGER) return FALSE; break; default: return FALSE; } return TRUE; } HRESULT LdapValueToADsColumn( LPWSTR pszColumnName, DWORD dwSyntaxId, DWORD dwValues, VOID **ppValue, ADS_SEARCH_COLUMN * pColumn ) { HRESULT hr = S_OK; DWORD i, j; if(!pszColumnName || !pColumn) RRETURN(E_ADS_BAD_PARAMETER); pColumn->hReserved = (HANDLE) ppValue; pColumn->dwNumValues = dwValues; if (dwValues < 1) { // // Need to set the ADsValue struct to NULL as it does // not make sense to return any ADsValues // pColumn->pADsValues = NULL; } else { pColumn->pADsValues = (PADSVALUE) AllocADsMem( sizeof(ADSVALUE) * dwValues ); if (!pColumn->pADsValues) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } pColumn->dwADsType = MapLDAPTypeToADSType(dwSyntaxId); switch (dwSyntaxId) { case LDAPTYPE_BITSTRING: case LDAPTYPE_PRINTABLESTRING: case LDAPTYPE_DIRECTORYSTRING: case LDAPTYPE_COUNTRYSTRING: case LDAPTYPE_DN: case LDAPTYPE_NUMERICSTRING: case LDAPTYPE_IA5STRING: case LDAPTYPE_CASEIGNORESTRING: case LDAPTYPE_OID: case LDAPTYPE_TELEPHONENUMBER: case LDAPTYPE_ATTRIBUTETYPEDESCRIPTION: case LDAPTYPE_OBJECTCLASSDESCRIPTION: case LDAPTYPE_DELIVERYMETHOD: case LDAPTYPE_ENHANCEDGUIDE: case LDAPTYPE_FACSIMILETELEPHONENUMBER: case LDAPTYPE_GUIDE: case LDAPTYPE_NAMEANDOPTIONALUID: case LDAPTYPE_POSTALADDRESS: case LDAPTYPE_PRESENTATIONADDRESS: case LDAPTYPE_TELEXNUMBER: case LDAPTYPE_DSAQUALITYSYNTAX: case LDAPTYPE_DATAQUALITYSYNTAX: case LDAPTYPE_MAILPREFERENCE: case LDAPTYPE_OTHERMAILBOX: case LDAPTYPE_ACCESSPOINTDN: case LDAPTYPE_ORNAME: case LDAPTYPE_ORADDRESS: for (i=0; i < dwValues; i++) { pColumn->pADsValues[i].dwType = pColumn->dwADsType; pColumn->pADsValues[i].CaseIgnoreString = (LPWSTR) ppValue[i]; } break; case LDAPTYPE_CASEEXACTSTRING: for (i=0; i < dwValues; i++) { pColumn->pADsValues[i].dwType = pColumn->dwADsType; pColumn->pADsValues[i].CaseExactString = (LPWSTR) ppValue[i]; } break; case LDAPTYPE_UTCTIME: for (i=0; i < dwValues; i++) { SYSTEMTIME st; hr = UTCTimeStringToUTCTime((LPWSTR)ppValue[i], &st); BAIL_ON_FAILURE(hr); pColumn->pADsValues[i].dwType = pColumn->dwADsType; pColumn->pADsValues[i].UTCTime = st; } LdapValueFree((WCHAR **)pColumn->hReserved); pColumn->hReserved = NULL; break; case LDAPTYPE_GENERALIZEDTIME: for (i=0; i < dwValues; i++) { SYSTEMTIME st; hr = GenTimeStringToUTCTime((LPWSTR)ppValue[i], &st); BAIL_ON_FAILURE(hr); pColumn->pADsValues[i].dwType = pColumn->dwADsType; pColumn->pADsValues[i].UTCTime = st; } LdapValueFree((WCHAR **)pColumn->hReserved); pColumn->hReserved = NULL; break; case LDAPTYPE_CERTIFICATE: case LDAPTYPE_CERTIFICATELIST: case LDAPTYPE_CERTIFICATEPAIR: case LDAPTYPE_PASSWORD: case LDAPTYPE_TELETEXTERMINALIDENTIFIER: case LDAPTYPE_AUDIO: case LDAPTYPE_JPEG: case LDAPTYPE_FAX: case LDAPTYPE_OCTETSTRING: case LDAPTYPE_SECURITY_DESCRIPTOR: for (i=0; i < dwValues; i++) { pColumn->pADsValues[i].dwType = pColumn->dwADsType; pColumn->pADsValues[i].OctetString.dwLength = ((struct berval **)ppValue)[i]->bv_len; pColumn->pADsValues[i].OctetString.lpValue = (LPBYTE) ((struct berval **) ppValue)[i]->bv_val; } break; case LDAPTYPE_BOOLEAN: for (i=0; i < dwValues; i++) { pColumn->pADsValues[i].dwType = pColumn->dwADsType; if ( _wcsicmp( (WCHAR *) ppValue[i], L"TRUE") == 0 ) { pColumn->pADsValues[i].Boolean = TRUE; } else if ( _wcsicmp( (WCHAR *) ppValue[i], L"FALSE") == 0 ) { pColumn->pADsValues[i].Boolean = FALSE; } else { BAIL_ON_FAILURE(hr = E_ADS_CANT_CONVERT_DATATYPE); } } LdapValueFree((WCHAR **)pColumn->hReserved); pColumn->hReserved = NULL; break; case LDAPTYPE_INTEGER: for (i=0; i < dwValues; i++) { pColumn->pADsValues[i].dwType = pColumn->dwADsType; pColumn->pADsValues[i].Integer = _wtol((WCHAR *) ppValue[i]); } LdapValueFree((WCHAR **)pColumn->hReserved); pColumn->hReserved = NULL; break; case LDAPTYPE_INTEGER8: for (i=0; i < dwValues; i++) { pColumn->pADsValues[i].dwType = pColumn->dwADsType; swscanf ((WCHAR *) ppValue[i], L"%I64d", &pColumn->pADsValues[i].LargeInteger); } LdapValueFree((WCHAR **)pColumn->hReserved); pColumn->hReserved = NULL; break; case LDAPTYPE_DNWITHBINARY: for (i=0; i < dwValues; i++) { hr = LdapDNWithBinToAdsTypeHelper( (LPWSTR) ppValue[i], &pColumn->pADsValues[i] ); BAIL_ON_FAILURE(hr); } LdapValueFree((WCHAR **)pColumn->hReserved); pColumn->hReserved = NULL; break; case LDAPTYPE_DNWITHSTRING: for (i=0; i < dwValues; i++) { hr = LdapDNWithStrToAdsTypeHelper( (LPWSTR) ppValue[i], &pColumn->pADsValues[i] ); BAIL_ON_FAILURE(hr); } LdapValueFree((WCHAR **)pColumn->hReserved); pColumn->hReserved = NULL; break; default: pColumn->dwADsType = ADSTYPE_PROV_SPECIFIC; for (i=0; i < dwValues; i++) { pColumn->pADsValues[i].dwType = ADSTYPE_PROV_SPECIFIC; pColumn->pADsValues[i].ProviderSpecific.dwLength = ((struct berval **)ppValue)[i]->bv_len; pColumn->pADsValues[i].ProviderSpecific.lpValue = (LPBYTE) ((struct berval **) ppValue)[i]->bv_val; } break; } RRETURN(hr); error: if (pColumn->pADsValues) { FreeADsMem(pColumn->pADsValues); pColumn->pADsValues = NULL; pColumn->dwNumValues = 0; } RRETURN(hr); } // // To add the server controls. The controls will be set internally in the // handle. Right now, we support sort, dirsync and domain scope controls. // HRESULT AddSearchControls( PLDAP_SEARCHINFO phSearchInfo, CCredentials& Credentials ) { HRESULT hr = S_OK; PLDAPSortKey *ppSortKeys = NULL; PLDAPControl pSortControl = NULL, *ppServerControls = NULL; PLDAPControl pDirSyncControl = NULL; PLDAPControl pDomCtrl = NULL; PLDAPControl pTombStoneCtrl = NULL; PLDAPControl pVLVControl = NULL; PLDAPControl pAttribScopedCtrl = NULL; PLDAPControl pSecurityDescCtrl = NULL; PLDAPControl pExtendedCtrl = NULL; PBERVAL pBerVal = NULL; DWORD nKeys=0, i=0; DWORD dwControls = 0; DWORD dwCurControl = 0; BOOL fDomainScopeControl = FALSE; BOOL fTombStone = FALSE; BYTE * pbSecDescValue = NULL; if (phSearchInfo->_SearchPref._pSortKeys) { dwControls++; } if (phSearchInfo->_SearchPref._fDirSync) { dwControls++; } if (phSearchInfo->_SearchPref._fTombStone) { dwControls++; fTombStone = TRUE; } if (phSearchInfo->_SearchPref._pVLVInfo) { dwControls++; } if (phSearchInfo->_SearchPref._pAttribScoped) { dwControls++; } if (phSearchInfo->_SearchPref._fSecurityDescriptorControl) { dwControls++; } if(phSearchInfo->_SearchPref._fExtendedDNControl) { dwControls++; } if (phSearchInfo->_SearchPref._dwChaseReferrals == LDAP_CHASE_EXTERNAL_REFERRALS || phSearchInfo->_SearchPref._dwChaseReferrals == (DWORD)(DWORD_PTR)LDAP_OPT_OFF) { // // Try and see if we can add the additional ADControl. // hr = ReadDomScopeSupportedAttr( phSearchInfo->_pszLdapServer, &fDomainScopeControl, Credentials, phSearchInfo->_dwPort ); if (FAILED(hr)) { hr = S_OK; fDomainScopeControl = FALSE; } else if (fDomainScopeControl == TRUE) { dwControls++; } } if (!dwControls) { RRETURN(S_OK); } ADsAssert(phSearchInfo); if (phSearchInfo->_ServerControls) { while (phSearchInfo->_ServerControls[i]) { // // Free the pre-existing controls in preparation for adding in a new // batch. // // The algorithm is: // If this is the VLV control, free it with LdapControlFree // All other controls are freed with FreeADsMem // The sort & security descriptor controls also have additional // memory associated with them that must be freed here. // (some other controls, like ASQ, extended dn or DirSync, also have additonal // memory that must be freed, but this memory is tracked via // _ldap_searchinfo and the freeing is done when we actually // process adding the new control below) // // // If this is the VLV control, need to free it // using LdapControlFree // if ((phSearchInfo->_ServerControls[i]->ldctl_oid) && (wcscmp( phSearchInfo->_ServerControls[i]->ldctl_oid, LDAP_CONTROL_VLVREQUEST_W ) == 0)) { LdapControlFree(phSearchInfo->_ServerControls[i]); } else { // // If this is the sort or security descriptor control, we // need to free some additional stuff. // if ((phSearchInfo->_ServerControls[i]->ldctl_oid) && (wcscmp( phSearchInfo->_ServerControls[i]->ldctl_oid, LDAP_SERVER_SORT_OID_W ) == 0) ) { // // This is a sort control // if (phSearchInfo->_ServerControls[i]->ldctl_oid) { ldap_memfree(phSearchInfo->_ServerControls[i]->ldctl_oid); } if (phSearchInfo->_ServerControls[i]->ldctl_value.bv_val) { ldap_memfreeA( phSearchInfo->_ServerControls[i]->ldctl_value.bv_val ); } } else if ((phSearchInfo->_ServerControls[i]->ldctl_oid) && (wcscmp(phSearchInfo->_ServerControls[i]->ldctl_oid, LDAP_SERVER_SD_FLAGS_OID_W) == 0)) { // // This is a security descriptor control // if (phSearchInfo->_ServerControls[i]->ldctl_value.bv_val) { FreeADsMem(phSearchInfo->_ServerControls[i]->ldctl_value.bv_val); } } // free the control (for any control except VLV, which // we already freed above) FreeADsMem(phSearchInfo->_ServerControls[i]); } i++; } FreeADsMem(phSearchInfo->_ServerControls); phSearchInfo->_ServerControls = NULL; } nKeys = phSearchInfo->_SearchPref._nSortKeys; // // One more than our dwControls is the number we need. // ppServerControls = (PLDAPControl *) AllocADsMem( sizeof(PLDAPControl) * (dwControls+1) ); if (!ppServerControls) { RRETURN(E_OUTOFMEMORY); } // // Process the VLV control // if (phSearchInfo->_SearchPref._pVLVInfo) { hr = LdapCreateVLVControl(phSearchInfo->_pConnection, phSearchInfo->_SearchPref._pVLVInfo, TRUE, &pVLVControl ); BAIL_ON_FAILURE(hr); ppServerControls[dwCurControl++] = pVLVControl; } // // Process the sort control. // if (phSearchInfo->_SearchPref._pSortKeys) { ppSortKeys = (PLDAPSortKey *) AllocADsMem( sizeof(PLDAPSortKey) * (nKeys+1) ); if (!ppSortKeys) { RRETURN(E_OUTOFMEMORY); } pSortControl = (LDAPControl *) AllocADsMem(sizeof(LDAPControl)); if (!pSortControl) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } for (i=0; i_SearchPref._pSortKeys[i]); } ppSortKeys[nKeys] = NULL; hr = LdapEncodeSortControl( phSearchInfo->_pConnection, ppSortKeys, pSortControl, TRUE ); BAIL_ON_FAILURE(hr); ppServerControls[dwCurControl++] = pSortControl; if (ppSortKeys) { FreeADsMem(ppSortKeys); } } // // Handle the dirsync control if applicable // if (phSearchInfo->_SearchPref._fDirSync) { pDirSyncControl = (LDAPControl *) AllocADsMem(sizeof(LDAPControl)); if (!pDirSyncControl) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } hr = BerEncodeReplicationCookie( phSearchInfo->_SearchPref._pProvSpecific->lpValue, phSearchInfo->_SearchPref._pProvSpecific->dwLength, &pBerVal, phSearchInfo->_SearchPref._dwDirSyncFlag ); BAIL_ON_FAILURE(hr); pDirSyncControl->ldctl_oid = LDAP_SERVER_DIRSYNC_OID_W; pDirSyncControl->ldctl_value.bv_len = pBerVal->bv_len; pDirSyncControl->ldctl_value.bv_val = (PCHAR) pBerVal->bv_val; pDirSyncControl->ldctl_iscritical = TRUE; // // Clear the info in the search handle if applicable // if (phSearchInfo->_pBerVal) { ber_bvfree(phSearchInfo->_pBerVal); } phSearchInfo->_pBerVal = pBerVal; ppServerControls[dwCurControl++] = pDirSyncControl; } // // Process the DomainScope control if applicable // if (fDomainScopeControl) { pDomCtrl = (LDAPControl *) AllocADsMem(sizeof(LDAPControl)); if (!pDomCtrl) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } pDomCtrl->ldctl_oid = LDAP_SERVER_DOMAIN_SCOPE_OID_W; pDomCtrl->ldctl_value.bv_len = 0; pDomCtrl->ldctl_value.bv_val = NULL; pDomCtrl->ldctl_iscritical = FALSE; ppServerControls[dwCurControl++] = pDomCtrl; } // // Process the tombstone control if applicable // if (fTombStone) { pTombStoneCtrl = (LDAPControl *) AllocADsMem(sizeof(LDAPControl)); if (!pTombStoneCtrl) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } pTombStoneCtrl->ldctl_oid = LDAP_SERVER_SHOW_DELETED_OID_W; pTombStoneCtrl->ldctl_value.bv_len = 0; pTombStoneCtrl->ldctl_value.bv_val = NULL; pTombStoneCtrl->ldctl_iscritical = TRUE; ppServerControls[dwCurControl++] = pTombStoneCtrl; } // // Process the attribute scoped query control // if (phSearchInfo->_SearchPref._pAttribScoped) { pAttribScopedCtrl = (LDAPControl *) AllocADsMem(sizeof(LDAPControl)); if (!pAttribScopedCtrl) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } hr = BerEncodeAttribScopedControlValue(phSearchInfo->_SearchPref._pAttribScoped, &pBerVal); BAIL_ON_FAILURE(hr); pAttribScopedCtrl->ldctl_oid = LDAP_SERVER_ASQ_OID_W; pAttribScopedCtrl->ldctl_value.bv_len = pBerVal->bv_len; pAttribScopedCtrl->ldctl_value.bv_val = pBerVal->bv_val; pAttribScopedCtrl->ldctl_iscritical = TRUE; // // Clear the info in the search handle if applicable // if (phSearchInfo->_pBerValAttribScoped) { ber_bvfree(phSearchInfo->_pBerValAttribScoped); } phSearchInfo->_pBerValAttribScoped = pBerVal; ppServerControls[dwCurControl++] = pAttribScopedCtrl; } // // Process the security descriptor control // if (phSearchInfo->_SearchPref._fSecurityDescriptorControl) { pSecurityDescCtrl = (LDAPControl *) AllocADsMem(sizeof(LDAPControl)); if (!pSecurityDescCtrl) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } pbSecDescValue = (BYTE *) AllocADsMem(5); if (!pbSecDescValue) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } ZeroMemory(pbSecDescValue, 5); pbSecDescValue[0] = 0x30; // Start sequence tag pbSecDescValue[1] = 0x03; // Length in bytes of following pbSecDescValue[2] = 0x02; // Actual value this and next 2 pbSecDescValue[3] = 0x01; pbSecDescValue[4] = (BYTE) ((ULONG)phSearchInfo->_SearchPref._SecurityDescriptorMask); pSecurityDescCtrl->ldctl_oid = LDAP_SERVER_SD_FLAGS_OID_W; pSecurityDescCtrl->ldctl_value.bv_len = 5; pSecurityDescCtrl->ldctl_value.bv_val = (PCHAR) pbSecDescValue; pSecurityDescCtrl->ldctl_iscritical = TRUE; ppServerControls[dwCurControl++] = pSecurityDescCtrl; } // process the extended dn control if(phSearchInfo->_SearchPref._fExtendedDNControl) { pExtendedCtrl = (LDAPControl *) AllocADsMem(sizeof(LDAPControl)); if(!pExtendedCtrl) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } hr = BerEncodeExtendedDNControlValue(phSearchInfo->_SearchPref._dwExtendedDnOption, &pBerVal); BAIL_ON_FAILURE(hr); pExtendedCtrl->ldctl_oid = LDAP_SERVER_EXTENDED_DN_OID_W; pExtendedCtrl->ldctl_value.bv_len = pBerVal->bv_len; pExtendedCtrl->ldctl_value.bv_val = pBerVal->bv_val; pExtendedCtrl->ldctl_iscritical = TRUE; // // Clear the info in the search handle if applicable // if(phSearchInfo->_pBerValExtendedDN) { ber_bvfree(phSearchInfo->_pBerValExtendedDN); } phSearchInfo->_pBerValExtendedDN = pBerVal; ppServerControls[dwCurControl++] = pExtendedCtrl; } ppServerControls[dwControls] = NULL; phSearchInfo->_ServerControls = ppServerControls; RRETURN(S_OK); error: if (ppServerControls) { FreeADsMem(ppServerControls); } if (pSortControl) { FreeADsMem(pSortControl); } if (pDirSyncControl) { FreeADsMem(pSortControl); } if (pDomCtrl) { FreeADsMem(pDomCtrl); } if (pTombStoneCtrl) { FreeADsMem(pTombStoneCtrl); } if (pAttribScopedCtrl) { FreeADsMem(pAttribScopedCtrl); } if (pVLVControl) { LdapControlFree(pVLVControl); } if (pSecurityDescCtrl) { FreeADsMem(pSecurityDescCtrl); } if (ppSortKeys) { FreeADsMem(ppSortKeys); } if (pbSecDescValue) { FreeADsMem(pbSecDescValue); } if(pExtendedCtrl) { FreeADsMem(pExtendedCtrl); } RRETURN(hr); } void FreeSortKeys( IN PLDAPSortKey pSortKeys, IN DWORD dwSortKeys ) { for (DWORD i=0; i < dwSortKeys; i++) { if (pSortKeys[i].sk_attrtype) { FreeADsStr(pSortKeys[i].sk_attrtype); } } if (pSortKeys) { FreeADsMem(pSortKeys); } } // // Copy a LDAPVLVInfo (and the data it points to) from // *pVLVInfoSource to **ppVLVInfoTarget. // // Note that pVLVInfoSource->ldvlv_extradata is not copied, // and is set to NULL in **ppVLVInfoTarget. If the caller // uses this for anything, copying it is the caller's // responsibility. // HRESULT CopyLDAPVLVInfo( PLDAPVLVInfo pVLVInfoSource, PLDAPVLVInfo *ppVLVInfoTarget ) { HRESULT hr = S_OK; PLDAPVLVInfo pVLVInfo = NULL; if (!pVLVInfoSource || !ppVLVInfoTarget) BAIL_ON_FAILURE(hr = E_INVALIDARG); *ppVLVInfoTarget = NULL; pVLVInfo = (PLDAPVLVInfo) AllocADsMem(sizeof(LDAPVLVInfo)); if (!pVLVInfo) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); // copy the non-pointer members *pVLVInfo = *pVLVInfoSource; pVLVInfo->ldvlv_attrvalue = NULL; pVLVInfo->ldvlv_context = NULL; pVLVInfo->ldvlv_extradata = NULL; // copy the pointer members if (pVLVInfoSource->ldvlv_attrvalue) { pVLVInfo->ldvlv_attrvalue = (PBERVAL) AllocADsMem(sizeof(BERVAL)); if (!pVLVInfo->ldvlv_attrvalue) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); pVLVInfo->ldvlv_attrvalue->bv_len = pVLVInfoSource->ldvlv_attrvalue->bv_len; pVLVInfo->ldvlv_attrvalue->bv_val = (PCHAR) AllocADsMem(pVLVInfo->ldvlv_attrvalue->bv_len); if (!pVLVInfo->ldvlv_attrvalue->bv_val) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); memcpy(pVLVInfo->ldvlv_attrvalue->bv_val, pVLVInfoSource->ldvlv_attrvalue->bv_val, pVLVInfo->ldvlv_attrvalue->bv_len); } if (pVLVInfoSource->ldvlv_context) { pVLVInfo->ldvlv_context = (PBERVAL) AllocADsMem(sizeof(BERVAL)); if (!pVLVInfo->ldvlv_context) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); pVLVInfo->ldvlv_context->bv_len = pVLVInfoSource->ldvlv_context->bv_len; pVLVInfo->ldvlv_context->bv_val = (PCHAR) AllocADsMem(pVLVInfo->ldvlv_context->bv_len); if (!pVLVInfo->ldvlv_context->bv_val) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); memcpy(pVLVInfo->ldvlv_context->bv_val, pVLVInfoSource->ldvlv_context->bv_val, pVLVInfo->ldvlv_context->bv_len); } *ppVLVInfoTarget = pVLVInfo; RRETURN(hr); error: FreeLDAPVLVInfo(pVLVInfo); RRETURN(hr); } // // Free a LDAPVLVInfo (and the data it points to) // // Note that pVLVInfoSource->ldvlv_extradata is not freed. // If the caller uses this for anything, freeing it before // calling this function is the caller's responsibility. // void FreeLDAPVLVInfo( IN PLDAPVLVInfo pVLVInfo ) { if (pVLVInfo) { if (pVLVInfo->ldvlv_attrvalue) { if (pVLVInfo->ldvlv_attrvalue->bv_val) { FreeADsMem(pVLVInfo->ldvlv_attrvalue->bv_val); } FreeADsMem(pVLVInfo->ldvlv_attrvalue); } if (pVLVInfo->ldvlv_context) { if (pVLVInfo->ldvlv_context->bv_val) { FreeADsMem(pVLVInfo->ldvlv_context->bv_val); } FreeADsMem(pVLVInfo->ldvlv_context); } FreeADsMem(pVLVInfo); } } HRESULT StoreVLVInfo( LDAPMessage *pLDAPMsg, PLDAP_SEARCHINFO phSearchInfo ) { HRESULT hr = S_OK; PLDAPControl *ppServerControls = NULL; ULONG ulTarget = 0; ULONG ulCount = 0; PBERVAL pContextID = NULL; PBERVAL pContextIDCopy = NULL; if (!pLDAPMsg) { RRETURN(S_OK); } // // Retrieve the server controls // hr = LdapParseResult( phSearchInfo->_pConnection, pLDAPMsg, NULL, // ret code NULL, // matched dn's NULL, // err msg's NULL, // referrals &ppServerControls, FALSE // freeIt ); BAIL_ON_FAILURE(hr); if (!ppServerControls) { // // Could not get the control // BAIL_ON_FAILURE(hr = E_ADS_PROPERTY_NOT_FOUND); } // // Parse the VLV response control // hr = LdapParseVLVControl( phSearchInfo->_pConnection, ppServerControls, &ulTarget, &ulCount, &pContextID ); BAIL_ON_FAILURE(hr); // // Copy the new context ID, if one was returned by the server // if (pContextID && pContextID->bv_val && pContextID->bv_len) { pContextIDCopy = (PBERVAL) AllocADsMem(sizeof(BERVAL)); if (!pContextIDCopy) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); pContextIDCopy->bv_len = pContextID->bv_len; pContextIDCopy->bv_val = (PCHAR) AllocADsMem(pContextID->bv_len); if (!pContextIDCopy->bv_val) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); memcpy(pContextIDCopy->bv_val, pContextID->bv_val, pContextID->bv_len); } // // Copy VLV response control info into the _ldap_searchinfo // If the server did not return context ID, pContextIDCopy == NULL. // phSearchInfo->_dwVLVOffset = ulTarget; phSearchInfo->_dwVLVCount = ulCount; // free the previous context ID if (phSearchInfo->_pVLVContextID) { if (phSearchInfo->_pVLVContextID->bv_val) { FreeADsMem(phSearchInfo->_pVLVContextID->bv_val); } FreeADsMem(phSearchInfo->_pVLVContextID); } phSearchInfo->_pVLVContextID = pContextIDCopy; error : if (pContextID) BerBvFree(pContextID); if (ppServerControls) { ldap_controls_free(ppServerControls); } if (FAILED(hr)) { if (pContextIDCopy) { if (pContextIDCopy->bv_val) { FreeADsMem(pContextIDCopy->bv_val); } FreeADsMem(pContextIDCopy); } } RRETURN(hr); } HRESULT StoreAttribScopedInfo( LDAPMessage *pLDAPMsg, PLDAP_SEARCHINFO phSearchInfo ) { HRESULT hr = S_OK; PLDAPControl *ppServerControls = NULL; DWORD dwCtr = 0; BERVAL berVal; BerElement *pBer = NULL; int retval = LDAP_SUCCESS; if (!pLDAPMsg) { RRETURN(S_OK); } hr = LdapParseResult( phSearchInfo->_pConnection, pLDAPMsg, NULL, // ret code NULL, // matched dn's NULL, // err msg's NULL, // referrals &ppServerControls, FALSE // freeIt ); BAIL_ON_FAILURE(hr); // // See if the ASQ control is in there. // while (ppServerControls && ppServerControls[dwCtr] && wcscmp( ppServerControls[dwCtr]->ldctl_oid, LDAP_SERVER_ASQ_OID_W ) != 0) { dwCtr++; } if (!ppServerControls || !ppServerControls[dwCtr]) { // // Could not get the control // BAIL_ON_FAILURE(hr = E_ADS_PROPERTY_NOT_FOUND); } // // Get the info we need. // berVal.bv_len = ppServerControls[dwCtr]->ldctl_value.bv_len; berVal.bv_val = ppServerControls[dwCtr]->ldctl_value.bv_val; pBer = ber_init(&berVal); if (ber_scanf(pBer, "{e}", &retval) != NO_ERROR) { BAIL_ON_FAILURE(hr = E_FAIL); } // // Test for non-fatal error codes // if (retval == LDAP_AFFECTS_MULTIPLE_DSAS) phSearchInfo->_fNonFatalErrors = TRUE; error : if (ppServerControls) { ldap_controls_free(ppServerControls); } if (pBer) { ber_free(pBer, 1); } RRETURN(hr); } HRESULT StoreDirSyncCookie( LDAPMessage *pLDAPMsg, PLDAP_SEARCHINFO phSearchInfo ) { HRESULT hr = S_OK; PADS_PROV_SPECIFIC pProvSpecific = NULL; PLDAPControl *ppServerControls = NULL; DWORD dwCtr = 0; BERVAL berVal; BerElement *pBer = NULL; PBERVAL pBerVal = NULL; DWORD dwSize; BOOL fMoreData = FALSE; if (!pLDAPMsg) { RRETURN(S_OK); } phSearchInfo->_fMoreDirSync = FALSE; // // Build the new value and then assign it to the searchpref // information. That way, if there are errors we wont loose // the last cookie. // hr = LdapParseResult( phSearchInfo->_pConnection, pLDAPMsg, NULL, // ret code NULL, // matched dn's NULL, // err msg's NULL, // referrals &ppServerControls, FALSE // freeIt ); BAIL_ON_FAILURE(hr); // // See if the dirsync control is in there. // while (ppServerControls && ppServerControls[dwCtr] && wcscmp( ppServerControls[dwCtr]->ldctl_oid, LDAP_SERVER_DIRSYNC_OID_W ) != 0) { dwCtr++; } if (!ppServerControls || !ppServerControls[dwCtr]) { // // Could not get the control // BAIL_ON_FAILURE(hr = E_ADS_PROPERTY_NOT_FOUND); } // // Get the info we need. // berVal.bv_len = ppServerControls[dwCtr]->ldctl_value.bv_len; berVal.bv_val = ppServerControls[dwCtr]->ldctl_value.bv_val; pBer = ber_init(&berVal); ber_scanf(pBer, "{iiO}", &fMoreData, &dwSize, &pBerVal); phSearchInfo->_fMoreDirSync = fMoreData; pProvSpecific = (PADS_PROV_SPECIFIC) AllocADsMem(sizeof(ADS_PROV_SPECIFIC)); if (!pProvSpecific) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } pProvSpecific->lpValue = (LPBYTE) AllocADsMem(pBerVal->bv_len); if (!pProvSpecific->lpValue) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } pProvSpecific->dwLength = pBerVal->bv_len; memcpy(pProvSpecific->lpValue, (LPBYTE) pBerVal->bv_val, pBerVal->bv_len); // // At this point it is safe to clear the Info on the dirsync control // if (phSearchInfo->_SearchPref._pProvSpecific) { if (phSearchInfo->_SearchPref._pProvSpecific->lpValue) { FreeADsMem(phSearchInfo->_SearchPref._pProvSpecific->lpValue); } FreeADsMem(phSearchInfo->_SearchPref._pProvSpecific); } phSearchInfo->_SearchPref._pProvSpecific = pProvSpecific; error : if (ppServerControls) { ldap_controls_free(ppServerControls); } if (FAILED(hr)) { // // Handle the Provider Specific struct if applicable. // if (pProvSpecific) { if (pProvSpecific->lpValue) { FreeADsMem(pProvSpecific->lpValue); } FreeADsMem(pProvSpecific); } } if (pBerVal) { ber_bvfree(pBerVal); } if (pBer) { ber_free(pBer, 1); } RRETURN(hr); } HRESULT BerEncodeReplicationCookie( PBYTE pCookie, DWORD dwLen, PBERVAL *ppBerVal, DWORD dwFlag ) { HRESULT hr = E_FAIL; BerElement *pBer = NULL; pBer = ber_alloc_t(LBER_USE_DER); if (!pBer) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } // // flag - set to zero, so order of parent & child objects is not important // if (ber_printf(pBer, "{iio}", dwFlag, MAX_BYTES, pCookie, dwLen) == -1) { BAIL_ON_FAILURE(hr = E_FAIL); } // // Pull data from the BerElement into a BERVAL struct. // Caller needs to free ppBerVal. // if (ber_flatten(pBer, ppBerVal) != 0) { BAIL_ON_FAILURE(hr = E_FAIL); } hr = S_OK; error: if (pBer) { ber_free(pBer,1); } return hr; } HRESULT BerEncodeAttribScopedControlValue( LPCWSTR pAttribScoped, PBERVAL *ppBerVal ) { HRESULT hr = S_OK; BerElement *pBer = NULL; LPSTR pszAttribute = NULL; pBer = ber_alloc_t(LBER_USE_DER); if (!pBer) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } // // Translate the Unicode strings to UTF-8 // hr = UnicodeToUTF8String(pAttribScoped, &pszAttribute); BAIL_ON_FAILURE(hr); // // BER-encode the attributeScopedQueryRequestControlValue // if (ber_printf(pBer, "{s}", pszAttribute) == -1) { BAIL_ON_FAILURE(hr = E_FAIL); } // // Pull data from the BerElement into a BERVAL struct. // Caller needs to free ppBerVal. // if (ber_flatten(pBer, ppBerVal) != 0) { BAIL_ON_FAILURE(hr = E_FAIL); } error: if (pBer) { ber_free(pBer,1); } if (pszAttribute) FreeADsMem(pszAttribute); return hr; } HRESULT BerEncodeExtendedDNControlValue( DWORD dwOption, PBERVAL *ppBerVal ) { HRESULT hr = S_OK; BerElement *pBer = NULL; pBer = ber_alloc_t(LBER_USE_DER); if (!pBer) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } // // BER-encode the extendeddncontrolvalue // if (ber_printf(pBer, "{i}", dwOption) == -1) { BAIL_ON_FAILURE(hr = E_FAIL); } // // Pull data from the BerElement into a BERVAL struct. // Caller needs to free ppBerVal. // if (ber_flatten(pBer, ppBerVal) != 0) { BAIL_ON_FAILURE(hr = E_FAIL); } error: if (pBer) { ber_free(pBer,1); } return hr; } HRESULT BerEncodingQuotaControl( PBYTE pSid, DWORD dwSidLength, PBERVAL *ppBerVal ) { HRESULT hr = E_FAIL; BerElement *pBer = NULL; pBer = ber_alloc_t(LBER_USE_DER); if (!pBer) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } if (ber_printf(pBer, "{o}", pSid, dwSidLength) == -1) { BAIL_ON_FAILURE(hr = E_FAIL); } // // Pull data from the BerElement into a BERVAL struct. // Caller needs to free ppBerVal. // if (ber_flatten(pBer, ppBerVal) != 0) { BAIL_ON_FAILURE(hr = E_FAIL); } hr = S_OK; error: if (pBer) { ber_free(pBer,1); } return hr; } // // This is called only by ADsGetMoreResultsDirSync. // HRESULT ADsGetMoreResultsDirSyncHelper( IN PLDAP_SEARCHINFO phSearchInfo, CCredentials& Credentials ) { HRESULT hr = S_OK; DWORD dwError; LPWSTR pszLDAPPath; WCHAR pszErrorBuf[MAX_PATH], pszNameBuf[MAX_PATH]; ULONG totalCount; int resType; LDAPMessage **pTemp = NULL; ADsAssert(phSearchInfo); // // If the searchpref is not dirsync, abandon has been called // or if the cookie indicated that there is no more data then // we should return right away. // if (!phSearchInfo->_SearchPref._fDirSync || phSearchInfo->_fAbandon || !phSearchInfo->_fMoreDirSync) { RRETURN(S_ADS_NOMORE_ROWS); } // // We need to update the controls // hr = AddSearchControls( phSearchInfo, Credentials ); BAIL_ON_FAILURE(hr); // // Need to allocate more messages in the buffer // if ( phSearchInfo->_SearchPref._fCacheResults ) { ADsAssert(phSearchInfo->_dwCurrResult == phSearchInfo->_dwMaxResultGot); phSearchInfo->_dwCurrResult++; phSearchInfo->_dwMaxResultGot++; if (phSearchInfo->_dwCurrResult >= phSearchInfo->_cSearchResults) { // // Need to allocate more memory for handles // pTemp = (LDAPMessage **) ReallocADsMem( (void *) phSearchInfo->_pSearchResults, sizeof(LDAPMessage *) * phSearchInfo->_cSearchResults, sizeof(LDAPMessage *) * (phSearchInfo->_cSearchResults + NO_LDAP_RESULT_HANDLES)); if(!pTemp) { hr = E_OUTOFMEMORY; phSearchInfo->_dwCurrResult--; phSearchInfo->_dwMaxResultGot--; goto error; } phSearchInfo->_pSearchResults = pTemp; pTemp = NULL; phSearchInfo->_cSearchResults += NO_LDAP_RESULT_HANDLES; } } else { // // Release and use the same space to store the next result. // LdapMsgFree(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]); } // // Async and sync searches need to be handled differently. // if (phSearchInfo->_SearchPref._fAsynchronous) { // // Asynchronous search. // hr = LdapSearchExt( phSearchInfo->_pConnection, phSearchInfo->_pszBindContextDn, phSearchInfo->_SearchPref._dwSearchScope, phSearchInfo->_pszSearchFilter, phSearchInfo->_ppszAttrs, phSearchInfo->_SearchPref._fAttrsOnly, phSearchInfo->_ServerControls, phSearchInfo->_ClientControls, phSearchInfo->_SearchPref._dwPagedTimeLimit, phSearchInfo->_SearchPref._dwSizeLimit, &phSearchInfo->_currMsgId ); BAIL_ON_FAILURE(hr); phSearchInfo->_fLastResult = FALSE; // // Wait for atleast one result // hr = LdapResult( phSearchInfo->_pConnection, phSearchInfo->_currMsgId, LDAP_MSG_RECEIVED, phSearchInfo->_SearchPref._timeout.tv_sec ? &phSearchInfo->_SearchPref._timeout : NULL, &phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult], &resType ); if ((hr == HRESULT_FROM_WIN32(ERROR_DS_INVALID_DN_SYNTAX)) || (hr == HRESULT_FROM_WIN32(ERROR_DS_NAMING_VIOLATION)) || (hr == HRESULT_FROM_WIN32(ERROR_DS_OBJ_CLASS_VIOLATION)) || (hr == HRESULT_FROM_WIN32(ERROR_DS_FILTER_UNKNOWN)) || (hr == HRESULT_FROM_WIN32(ERROR_DS_PARAM_ERROR)) || (hr == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER))) { phSearchInfo->_fLastResult = TRUE; RRETURN(S_ADS_NOMORE_ROWS); } else { // // Only if there are zero rows returned, return the error, // otherwise, store the error and return when GetNextRow is // called for the last time // if (FAILED(hr) && (LdapCountEntries( phSearchInfo->_pConnection, phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]) == 0)) { BAIL_ON_FAILURE(hr); } else { phSearchInfo->_hrLastSearch = hr; hr = S_OK; } } phSearchInfo->_fLastPage = TRUE; } else { // // Synchronous search // hr = LdapSearchExtS( phSearchInfo->_pConnection, phSearchInfo->_pszBindContextDn, phSearchInfo->_SearchPref._dwSearchScope, phSearchInfo->_pszSearchFilter, phSearchInfo->_ppszAttrs, phSearchInfo->_SearchPref._fAttrsOnly, phSearchInfo->_ServerControls, phSearchInfo->_ClientControls, (phSearchInfo->_SearchPref._timeout.tv_sec == 0) ? NULL : &phSearchInfo->_SearchPref._timeout, phSearchInfo->_SearchPref._dwSizeLimit, &phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult] ); phSearchInfo->_fLastResult = TRUE; phSearchInfo->_fLastPage = TRUE; } // // Only if there are zero rows returned, return the error, // otherwise, store the error and return when GetNextRow is // called for the last time // if (FAILED(hr) && (LdapCountEntries( phSearchInfo->_pConnection, phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]) == 0)) { BAIL_ON_FAILURE(hr); } else { phSearchInfo->_hrLastSearch = hr; hr = S_OK; } error: RRETURN(hr); } // // This function is very similar to GetMoreResults except that // it will issue a new search if applicable for the dirsync control. // HRESULT ADsGetMoreResultsDirSync( IN PLDAP_SEARCHINFO phSearchInfo, CCredentials& Credentials ) { HRESULT hr = S_OK; BOOL fTryAndGetResults = TRUE; // // If the searchpref is not dirsync, abandon has been called // or if the cookie indicated that there is no more data then // we should return right away. // if (!phSearchInfo->_SearchPref._fDirSync || phSearchInfo->_fAbandon || !phSearchInfo->_fMoreDirSync) { RRETURN(S_ADS_NOMORE_ROWS); } while (fTryAndGetResults) { fTryAndGetResults = FALSE; hr = ADsGetMoreResultsDirSyncHelper( phSearchInfo, Credentials ); BAIL_ON_FAILURE(hr); StoreDirSyncCookie( phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult], phSearchInfo ); if (hr == S_ADS_NOMORE_ROWS && phSearchInfo->_fMoreDirSync) { fTryAndGetResults = TRUE; } // // Now we want to see if the first row was valid. We could // get back an entry but then not have any rows, just a cookie // if (!fTryAndGetResults) { hr = LdapFirstEntry( phSearchInfo->_pConnection, phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult], &phSearchInfo->_pCurrentRow ); BAIL_ON_FAILURE(hr); if(phSearchInfo->_pCurrentRow) { phSearchInfo->_pFirstAttr = NULL; phSearchInfo->_fBefFirstRow = FALSE; hr = S_OK; } else { hr = S_ADS_NOMORE_ROWS; if (phSearchInfo->_fMoreDirSync) { fTryAndGetResults = TRUE; } } } // if !Try and get more results. } // while try and get more results. error : RRETURN(hr); } //+--------------------------------------------------------------------------- // Function: LdapInitializeSearchPreferences - Exported helper routine. // // Synopsis: Initializes the search preferences struc to the default values. // With this function we can isolate the code in one place. // // Arguments: pSearchPrefs - Ptr to search prefs being initialized. // fCacheResults - The cache results pref is set to this. // // Returns: N/A. // // Modifies: pSearchPrefs. // //---------------------------------------------------------------------------- void LdapInitializeSearchPreferences( LDAP_SEARCH_PREF *pSearchPrefs, BOOL fCacheResults ) { ADsAssert(pSearchPrefs); pSearchPrefs->_fAsynchronous = FALSE; pSearchPrefs->_dwDerefAliases = FALSE; pSearchPrefs->_dwSizeLimit = 0; pSearchPrefs->_dwTimeLimit = 0; pSearchPrefs->_fAttrsOnly = FALSE; pSearchPrefs->_dwSearchScope = LDAP_SCOPE_SUBTREE; pSearchPrefs->_timeout.tv_sec = 0; pSearchPrefs->_timeout.tv_usec = 0; pSearchPrefs->_dwPageSize = 0; pSearchPrefs->_dwPagedTimeLimit = 0; pSearchPrefs->_dwChaseReferrals = ADS_CHASE_REFERRALS_EXTERNAL; pSearchPrefs->_pSortKeys = NULL; pSearchPrefs->_nSortKeys = 0; pSearchPrefs->_fDirSync = FALSE; pSearchPrefs->_pProvSpecific = NULL; pSearchPrefs->_fTombStone = FALSE; pSearchPrefs->_fCacheResults = fCacheResults; pSearchPrefs->_pVLVInfo = NULL; pSearchPrefs->_pAttribScoped = NULL; pSearchPrefs->_fSecurityDescriptorControl = FALSE; pSearchPrefs->_dwDirSyncFlag = 0; pSearchPrefs->_fExtendedDNControl = FALSE; } HRESULT HelpGetNormalDN( LPWSTR pszDn, LPWSTR* ppszTempDn ) { WCHAR* pszChr = NULL; // the extended dn format is ;;distinguishedName. is optional part pszChr = wcschr(pszDn, L';'); // part is always present ADsAssert(pszChr); if(!pszChr) { return E_FAIL; } if(pszChr[1] == '<') { // means part is present pszDn = pszChr + 1; pszChr = wcschr(pszDn, L';'); ADsAssert(pszChr); if(!pszChr) { return E_FAIL; } } *ppszTempDn = pszChr + 1; return S_OK; } //+--------------------------------------------------------------------------- // Function: ADsHelperGetCurrentRowMessage - used for Umi Search support. // // Synopsis: This returns the current row and the handle of the search. // Neither are refCounted but this should not matter cause these // will no longer be in use by the caller beyond the scope of // the search (before the search is "closed", the handle and // message that are got from this search will no longer be in // use). // // Arguments: hSearchHandle - Handle to the search. // ppAdsLdp - Pointer to hold returned lda handle. // ppLdapMsg - Pointer to hold the current "rows" msg. // // Returns: S_OK or any appropriate error code. // // Modifies: ppAdsLdp and ppLdapMsg if successful. // //---------------------------------------------------------------------------- HRESULT ADsHelperGetCurrentRowMessage( IN ADS_SEARCH_HANDLE hSearchHandle, OUT PADSLDP *ppAdsLdp, OUT LDAPMessage **ppLdapMsg ) { HRESULT hr = S_OK; PLDAP_SEARCHINFO phSearchInfo = (PLDAP_SEARCHINFO) hSearchHandle; if( !phSearchInfo || !phSearchInfo->_pSearchResults) { RRETURN (E_ADS_BAD_PARAMETER); } if (!phSearchInfo->_pConnection || !phSearchInfo->_pCurrentRow) { // // Dont have the info we need // RRETURN(E_FAIL); } else { // // We have the handle and the row we need. // *ppAdsLdp = phSearchInfo->_pConnection; *ppLdapMsg = phSearchInfo->_pCurrentRow; } RRETURN(hr); }