| Platform SDK: Active Directory, ADSI, and Directory Services |
The following code fragment contains a function that checks for absolute membership of an object by recursively checking whether an object is a member of a group or any groups nested within that group:
////////////////////////////////////////////////////////////////////////////////////////////////////
/* RecursiveIsMember() - Recursively scans the members of passed IADsGroup ptr
and any groups belonging to the passed ptr- for membership
of Passed group
Will return a TRUE if the member is found in the passed group,
Or if the passed member is a member of any group which is a member
of the passed group
Parameters
IADsGroup * pADsGroup - Group from which to check members
LPWSTR pwszMember - LDAP path for object to check membership
BOOL bVerbose - IF TRUE, will output verbose information on the scanning
OPTIONAL Parameters
LPOLESTR pwszUser - User Name and Password, if the parameters are NOT passed,
LPOLESTER pwszPassword - Binding will use ADsGetObject, if the parameters
- Are specified, will use ADsOpenObject, passing user name and password
*/
BOOL RecursiveIsMember(IADsGroup * pADsGroup,LPWSTR pwszMemberGUID,LPWSTR pwszMemberPath,
BOOL bVerbose, LPOLESTR pwszUser, LPOLESTR pwszPassword)
{
HRESULT hr = S_OK; // COM Result Code
IADsMembers * pADsMembers = NULL; // Ptr to Members of the IADsGroup
BOOL fContinue = TRUE; // Looping Variable
IEnumVARIANT * pEnumVariant = NULL; // Ptr to the Enum variant
IUnknown * pUnknown = NULL; // IUnknown for getting the ENUM initially
VARIANT VariantArray[FETCH_NUM]; // Variant array for temp holding returned data
ULONG ulElementsFetched = NULL; // Number of elements fetched
BSTR bsGroupPath = NULL;
BOOL bRet = FALSE;
// Get the path of the object passed in
hr = pADsGroup->get_ADsPath(&bsGroupPath);
if (!SUCCEEDED(hr))
return hr;
if (bVerbose)
{
WCHAR pwszOutput[2048];
wsprintf(pwszOutput,L"Checking the Group:\n\n%s\n\n for the member:\n\n%s\n\n",bsGroupPath,pwszMemberPath);
PrintBanner(pwszOutput);
}
// Get an interface pointer to the IADsCollection of members
hr = pADsGroup->Members(&pADsMembers);
if (SUCCEEDED(hr))
{
// Ask the IADsCollection of members for a new ENUM Interface
// Note the enum comes back as an IUnknown *
hr = pADsMembers->get__NewEnum(&pUnknown);
if (SUCCEEDED(hr))
{
// QI the IUnknown * for an IEnumVARIANT interface
hr = pUnknown->QueryInterface(IID_IEnumVARIANT, (void **)&pEnumVariant);
if (SUCCEEDED(hr))
{
// While have not hit errors or end of data....
while (fContinue)
{
ulElementsFetched = 0;
// Get a "batch" number of group members- number of rows specified by FETCH_NUM
hr = ADsEnumerateNext(pEnumVariant, FETCH_NUM, VariantArray, &ulElementsFetched);
if (ulElementsFetched )
{
// Loop through the current batch- printing the path
// for each member
for (ULONG i = 0; i < ulElementsFetched; i++ )
{
IDispatch * pDispatch = NULL; // ptr for holding dispath of element
BSTR bstrCurrentPath = NULL; // Holds path of object
BSTR bstrGuidCurrent = NULL; // Holds path of object
IDirectoryObject * pIDOCurrent = NULL;// Holds the current object
// Get the dispatch ptr for the variant
pDispatch = VariantArray[i].pdispVal;
assert(HAS_BIT_STYLE(VariantArray[i].vt,VT_DISPATCH));
// Get the IADs interface for the "member" of this group
hr = pDispatch->QueryInterface(IID_IDirectoryObject,
(VOID **) &pIDOCurrent ) ;
if (SUCCEEDED(hr))
{
// Retrieve the GUID for the current object
hr = GetObjectGuid(pIDOCurrent,bstrGuidCurrent);
if (FAILED(hr))
return hr;
IADs * pIADsCurrent = NULL;
// Retrieve the IADs Interface for the current object
hr = pIDOCurrent->QueryInterface(IID_IADs,(void**)&pIADsCurrent);
if (FAILED(hr))
return hr;
// Get the ADsPath property for this member
hr = pIADsCurrent->get_ADsPath(&bstrCurrentPath);
if (SUCCEEDED(hr))
{
if (bVerbose)
wprintf(L"Comparing:\n\n%s\nWITH:\n%s\n\n",bstrGuidCurrent,pwszMemberGUID);
// Is the "member of this group Equal to passed?
if (_wcsicmp(bstrGuidCurrent,pwszMemberGUID)==0)
{
if (bVerbose)
wprintf(L"!!!!!Object:\n\n%s\n\nIs a member of\n\n%s\n\n",pwszMemberPath,bstrGuidCurrent);
bRet = TRUE;
break;
}
else // Otherwise, we should bind to this and see if it is a group
{ // If is it a group then the QI to IADsGroup will succeed
IADsGroup * pIADsGroupAsMember = NULL;
if (pwszUser)
hr = ADsOpenObject( bstrCurrentPath,
pwszUser,
pwszPassword,
ADS_SECURE_AUTHENTICATION,
IID_IADsGroup,
(void**) &pIADsGroupAsMember);
else
hr = ADsGetObject( bstrCurrentPath, IID_IADsGroup,(void **)&pIADsGroupAsMember);
// If we DID bind, then this IS a group
if (SUCCEEDED(hr))
{
// Recursively call ourselves to check THIS group
BOOL bRetRecurse;
bRetRecurse = RecursiveIsMember(pIADsGroupAsMember,pwszMemberGUID,pwszMemberPath,bVerbose,pwszUser ,pwszPassword );
if (bRetRecurse)
{
bRet = TRUE;
break;
}
pIADsGroupAsMember->Release();
pIADsGroupAsMember = NULL;
}
}
SysFreeString(bstrCurrentPath);
bstrCurrentPath = NULL;
SysFreeString(bstrGuidCurrent);
bstrGuidCurrent = NULL;
}
// Release
pIDOCurrent->Release();
pIDOCurrent = NULL;
if (pIADsCurrent)
{
pIADsCurrent->Release();
pIADsCurrent = NULL;
}
}
}
// Clear the variant array
memset(VariantArray, 0, sizeof(VARIANT)*FETCH_NUM);
}
else
fContinue = FALSE;
}
pEnumVariant->Release();
pEnumVariant = NULL;
}
pUnknown->Release();
pUnknown = NULL;
}
pADsMembers ->Release();
pADsMembers = NULL;
}
// Free the group path if it was retrieved.
if (bsGroupPath)
{
SysFreeString(bsGroupPath);
bsGroupPath = NULL;
}
return bRet;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* GetObjectGuid() - Retrieves the GUID in String form from the passed Directory Object
Returns S_OK on success
Parameters
IDirectoryObject * pDO - Directory Object from where GUID will be retrieved.
BSTR & bsGuid - Returned GUID
*/
HRESULT GetObjectGuid(IDirectoryObject * pDO,BSTR &bsGuid)
{
GUID *pObjectGUID = NULL;
PADS_ATTR_INFO pAttributeEntries;
LPWSTR pAttributeName = L"objectGUID"; //Get the GUID for the object
DWORD dwAttributesReturned = 0;
HRESULT hr;
hr = pDO->GetObjectAttributes( &pAttributeName, //objectGUID
1, //Only objectGUID
&pAttributeEntries, // Returned attributes
&dwAttributesReturned //Number of attributes returned
);
if (SUCCEEDED(hr) && dwAttributesReturned>0)
{
//Make sure that we got the right type--objectGUID is ADSTYPE_OCTET_STRING
if (pAttributeEntries->dwADsType == ADSTYPE_OCTET_STRING)
{
//Get COM converted string version of the GUID
//lpvalue should be LPBYTE. Should be able to cast it to ptr to GUID.
pObjectGUID = (GUID*)(pAttributeEntries->pADsValues[0].OctetString.lpValue);
//OLE str to fit a GUID
LPOLESTR szGUID = new WCHAR [64];
szGUID[0]=NULL;
//Convert GUID to string.
::StringFromGUID2(*pObjectGUID, szGUID, 39);
bsGuid = SysAllocString(szGUID);
delete [] szGUID;
}
}
return hr;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/* PrintBanner() - Prints a banner on the screen
Parameters
LPOLESTR pwszBanner - String to print
*/
void PrintBanner(LPOLESTR pwszBanner)
{
_putws(L"");
_putws(L"////////////////////////////////////////////////////");
wprintf(L"\t");
_putws(pwszBanner);
_putws(L"////////////////////////////////////////////////////\n");
}