IDirectorySearch::GetFirstRow returns wrong error code.

EDN Admin

Well-known member
Joined
Aug 7, 2010
Messages
12,794
Location
In the Machine
Hi,
Ive a code block that checks if a given user exists in Active Directory DC, if yes, then it checks if it is member of Domain Admin group. Here is the codeBOOLEAN
GetUserLdapPath(
IADsContainer* pContainer,
const WCHAR *pcwszUsername,
WCHAR *pwszLdapPath,
DWORD dwcchLdapPathSize,
DWORD *pdwError
)
{
VARIANT var;
ULONG lFetch;
IADs *pADs = NULL;
HRESULT hr = E_FAIL;
HRESULT hrGC = S_OK;
IUnknown *pUnk = NULL;
IDispatch *pDisp = NULL;
IEnumVARIANT *pEnum = NULL;
IDirectorySearch *pGCSearch = NULL;


if (NULL == pContainer || NULL == pcwszUsername || NULL == pwszLdapPath || 0 == dwcchLdapPathSize || NULL == pdwError)
{
return FALSE;
}

hr = pContainer->get__NewEnum(&pUnk);
if (SUCCEEDED(hr))
{
hr = pUnk->QueryInterface(IID_IEnumVARIANT, (void**) &pEnum);
if (SUCCEEDED(hr))
{
//
// Now Enumerate--there should be only one item.
//
hr = pEnum->Next(1, &var, &lFetch);
if (SUCCEEDED(hr))
{
while (hr == S_OK)
{
if (lFetch == 1)
{
pDisp = V_DISPATCH(&var);
hr = pDisp->QueryInterface(IID_IDirectorySearch, (void**)&pGCSearch);
hrGC = hr;
}

VariantClear(&var);
hr = pEnum->Next(1, &var, &lFetch);
};
}
}

if (pEnum)
{
pEnum->Release();
}
}

if (pUnk)
{
pUnk->Release();
}

if (FAILED(hrGC))
{
if (pGCSearch)
{
pGCSearch->Release();
}

return FALSE;
}

//
// Create search filter.
//
WCHAR rgSearchFilter[1024];
wsprintfW(rgSearchFilter, L"(&(objectCategory=person)(objectClass=user)(sAMAccountName=%s))", pcwszUsername);

//Search entire subtree from root.
ADS_SEARCHPREF_INFO SearchPrefs;
SearchPrefs.dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
SearchPrefs.vValue.dwType = ADSTYPE_INTEGER;
SearchPrefs.vValue.Integer = ADS_SCOPE_SUBTREE;
DWORD dwNumPrefs = 1;

// COL for iterations
ADS_SEARCH_COLUMN col;

// Handle used for searching
ADS_SEARCH_HANDLE hSearch;

// Set the search preference
hr = pGCSearch->SetSearchPreference(&SearchPrefs, dwNumPrefs);
if (FAILED(hr))
{
return FALSE;
}

// Set attributes to return
CONST DWORD dwAttrNameSize = 4;
LPOLESTR pszAttribute[dwAttrNameSize] = {L"cn", L"distinguishedName", L"sAMAccountName", L"ADsPath"};

// Execute the search
hr = pGCSearch->ExecuteSearch(rgSearchFilter, pszAttribute, dwAttrNameSize, &hSearch);
if (SUCCEEDED(hr))
{
if (pGCSearch->GetFirstRow(hSearch) == S_ADS_NOMORE_ROWS)
{
return FALSE;
}
else // The UPN was found
{
do
{
// loop through the array of passed column names, print the data for each column.
for (DWORD x = 0; x < dwAttrNameSize; x++)
{
// Get the data for this column.
hr = pGCSearch->GetColumn(hSearch, pszAttribute[x], &col);
if (SUCCEEDED(hr))
{
// Print the data for the column and free the column.
// Note the attributes we asked for are type CaseIgnoreString.
// wprintf(L"%s: %srn", pszAttribute[x], col.pADsValues->CaseIgnoreString);

if (x == dwAttrNameSize - 1)
{
wcscpy(pwszLdapPath, col.pADsValues->CaseIgnoreString);
}

pGCSearch->FreeColumn(&col);
}
else
{
//wprintf(L"<%s property is not a string>", pszAttribute[x]);
}
}
}
while (pGCSearch->GetNextRow(hSearch) != S_ADS_NOMORE_ROWS);
}

// Close the search handle to clean up.
pGCSearch->CloseSearchHandle(hSearch);
}

if (pGCSearch)
{
pGCSearch->Release();
}
return TRUE;
}

BOOLEAN __stdcall
ValidateDomainUser(
const WCHAR *pcwszDomainName,
WCHAR *pwszUserName,
WCHAR *pwszPassword,
DWORD *pdwError
)
{
HRESULT hr;
BOOLEAN bRet;
DWORD dwError;
WCHAR *pwszDomainStart;
USER_INFO_1 *pUserInfo;
WCHAR wszUser[_MAX_PATH];
IADsContainer *pContainer;
WCHAR wszDomainName[_MAX_PATH];
WCHAR wszDomainNameWithoutLDAP[MAX_CNNAME_LENGTH];

if (NULL == pcwszDomainName || NULL == pwszPassword || NULL == pwszUserName || NULL == pdwError)
{
return FALSE;
}

CoInitialize(NULL);

hr = ADsOpenObject(
pcwszDomainName,
pwszUserName,
pwszPassword,
ADS_SECURE_AUTHENTICATION, // ADS_SERVER_BIND decision pending.
IID_IADsContainer,
(LPVOID*)&pContainer
);
if (FAILED(hr))
{
CoUninitialize();
return FALSE;
}

WCHAR *pwszTemp = NULL;
WCHAR wszAdsPath[_MAX_PATH] = {0};

wcscpy(wszUser, pwszUserName);
pwszTemp = wcschr(wszUser, L@);
if (pwszTemp)
{
*pwszTemp = L;
}

// Get users complete path if the user exists in domain.
bRet = GetUserLdapPath(pContainer, wszUser, wszAdsPath, ARRAY_SIZE(wszAdsPath), pdwError);
if (FALSE == bRet)
{
pContainer->Release();
CoUninitialize();
return FALSE;
}

pContainer->Release();

IADsUser *pUser = NULL;
hr = ADsOpenObject(
wszAdsPath,
pwszUserName,
pwszPassword,
ADS_SECURE_AUTHENTICATION, // ADS_SERVER_BIND decision pending.
IID_IADsUser,
(LPVOID*)&pUser
);
if (FAILED(hr))
{
CoUninitialize();
return FALSE;
}

//
// Check if the user belongs to Doamin Admins group.
// Note: Doamin Admins group name can be renamed by administrator
// where DC is installed. In this case, IsAdminUser will returns
// FALSE. It relies on group name returned by IADsUser interface.
//
bRet = IsAdminUser(pUser);

pUser->Release();
CoUninitialize();

return bRet;
}

BOOLEAN IsAdminUser(IADsUser *pUser)
{
HRESULT hr = S_OK;
IADsMembers *pGroups;

hr = pUser->Groups(&pGroups);
if (FAILED(hr))
{
return FALSE;
}

IUnknown *pUnk;
hr = pGroups->get__NewEnum(&pUnk);
if (FAILED(hr))
{
return FALSE;
}

pGroups->Release();

IEnumVARIANT *pEnum;
hr = pUnk->QueryInterface(IID_IEnumVARIANT,(void**)&pEnum);
if (FAILED(hr))
{
return FALSE;
}

pUnk->Release();

// Enumerate.
BSTR bstr;
VARIANT var;
IADs *pADs;
ULONG lFetch;
IDispatch *pDisp;

VariantInit(&var);
hr = pEnum->Next(1, &var, &lFetch);
while(hr == S_OK)
{
if (lFetch == 1)
{
pDisp = V_DISPATCH(&var);
pDisp->QueryInterface(IID_IADs, (void**)&pADs);
pADs->get_Name(&bstr);

if (0 == wcscmp(L"CN=Domain Admins", bstr))
{
SysFreeString(bstr);
pADs->Release();
VariantClear(&var);
pDisp=NULL;
pEnum->Release();
return TRUE;
}

SysFreeString(bstr);
pADs->Release();
}

VariantClear(&var);
pDisp=NULL;
hr = pEnum->Next(1, &var, &lFetch);
};

hr = pEnum->Release();

return FALSE;
}

int main()
{
DWORD dwRet;
BOOLEAN bRet = ValidateDomainUser(
L"architectsunited.com,
L"administrator@architectsunite",
L"...",
&dwRet
);
if (FALSE == bRet)
{
printf("nValidateDomainUser failed (Err Code -> %u)", dwRet);
}
else
{
printf("nValidateDomainUser success.");
}

return 0;
}
The problem is that GetFirstRow returns S_ADS_NOMORE_ROWS whereas "administrator" user exists on the DC. Can anyone show some light on the issue. I will appreciate that.
Thank you.
-Abhay

View the full article
 
Back
Top