Directory Services

Example Code for Checking for Membership in a Group

The following code example contains a function that verifies 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 that belong 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 verify members.
		LPWSTR		pwszMember	- LDAP path for object to verify membership.
		BOOL			bVerbose		- IF TRUE, will output verbose information for the scan.
 
	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, ADsOpenObject is used, 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 retrieved
	BSTR			bsGroupPath	 = NULL;
	BOOL			bRet			= FALSE;

	if(!IADsGroup || !pwszMemberGUID || !pwszMemberPath)
	{
		return 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))
	{
		// Query the IADsCollection of members for a new ENUM Interface
		// Be aware that 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))
							{
								// Get 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);
								
									// Verify that the member of this group is 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, bind to this and see if it is a group.
									{ // If is it a group then the QI to IADsGroup succeeds
									
										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 bind was completed, then this is a group.
										if (SUCCEEDED(hr))
										{
											// Recursively call this group to verify 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 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 is 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;

	if(!pDO)
	{
		return E_FAIL;
}

	hr = pDO->GetObjectAttributes(  &pAttributeName, // objectGUID
									1, //Only objectGUID
									&pAttributeEntries, // Returned attributes
									&dwAttributesReturned // Number of attributes returned
									);
 
	if (SUCCEEDED(hr) && dwAttributesReturned>0)
	{
		// Be sure the right type was retrieved--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 to the screen
 
	Parameters
 
				LPOLESTR pwszBanner   - String to print
*/
void PrintBanner(LPOLESTR pwszBanner)
{
	_putws(L"");
	_putws(L"////////////////////////////////////////////////////");
	wprintf(L"\t");
	_putws(pwszBanner);
	_putws(L"////////////////////////////////////////////////////\n");
}