How To Enumerate Properties Associated with an Extended Right Using Visual C++ and ATL (302250)



The information in this article applies to:

  • Microsoft Windows 2000 Server
  • Microsoft Windows 2000 Advanced Server
  • Microsoft Visual C++, 32-bit Editions 6.0
  • Microsoft Visual Studio, Enterprise Edition 6.0
  • Microsoft Active Directory Services Interface, System Component
  • Microsoft Active Directory Client Extension
  • Microsoft Active Directory Service Interfaces 2.5

This article was previously published under Q302250

SUMMARY

The article shows how to perform a Lightweight Directory Access Protocol (LDAP) search to locate all of the properties in the schema that are part of a given extended right.

The code contained in this article illustrates the following:
  1. How to use Active Template Library (ATL) to access Active Directory (AD) objects.
  2. How to set up a simple LDAP query against a given container.
  3. How to properly encode a binary value for use in an LDAP query string.
  4. How to display the IDirectorySearch results.
  5. How to properly manage Active Directory Services Interface (ADSI) objects and interfaces.
  6. How to use the RootDSE object to obtain information about the directory.

MORE INFORMATION

How to Use the Code Contained in this Article

  1. Create an empty Windows 32 console application in Visual Studio.
  2. Click the FileView tab.
  3. From the File menu, click New, and then click C++ Source File.
  4. In the File name edit control, type main.cpp, and then click OK.
  5. Copy the code from the "Main.cpp File Contents" section of this article and paste it into the Main.cpp file in the Visual C++ project.
  6. From the File menu, click New, and then click C++ Source File.
  7. In the File name edit control, type util.cpp, and then click OK.
  8. Copy the code from the "Util.cpp File Contents" section of this article and paste it into the Util.cpp file in the Visual C++ project.
  9. From the File menu, click New, and then click C/C++ Header File.
  10. In the File name edit control, type util.h, and then click OK.
  11. Copy the code from the "Util.h File Contents" section of this article and paste it into the Util.h file in the Visual C++ project.
  12. From the Project menu, click Settings, and then click the Link tab.
  13. Add Adsiid.lib and Activeds.lib to the Object/library modules.
  14. Click the Debug tab.
  15. In the Program Arguments edit control, type cn=general-information, and then click OK.
  16. Press CTRL+F5 to build and execute the project.

Visual C++ Code

Main.cpp File Contents

// 
// The following code segment illustrates how to enumerate all of the AttributeSchema objects
// whose attributeSecurityGUID matches the RightsGUID of the given extended rights object
// 
#define _WIN32_WINNT 0x0500
#define UNICODE

#include <windows.h>
#include <stdio.h>
#include <wchar.h>
#include <stdio.h>
#include <atlbase.h>
#include <objbase.h>
#include <activeds.h>
#include <winnt.h>
#include <sddl.h>
#include "util.h"


int wmain( int argc, wchar_t *argv[ ], wchar_t *envp[ ] )

{
   // 
   // NO error checking is performed.  If a call fails, the code
   // will end ungracefully.  Do not use this code as an example of how
   // to properly handle COM errors.
   // 
   // The program expects 1 argument, the LDAP ADsPath of a user object.
   // if this path is missing, the code will terminate very ungracefully.
   // a sample command line would like:
   // 
   //  code_executable "cn=ControlAccessRight_Object_Common_Name"
   // 
   // Assuming of course, that this code was compiled into an executable called 
   // code_executable.exe
   // 
   // Be sure to include:
   // ActiveDS.lib
   // Adsiid.lib
   // on the Link tab of the project.
   // 
   HRESULT hr = E_FAIL;
   // 
   // Very Important for ADSI interfaces to work proper, must initialize COM
   // 
   CoInitialize(NULL);
   // 
   // Check for the correct number of arguments
   // 
   if( argc < 2 )
   {
      PrintUsage();
      return E_FAIL;
   }
   // 
   // Need to bind to the RootDSE to locate the Schema and Configuration Containers
   // 
   CComPtr<IADs> oRootDSE;
   VARIANT vData;
   VariantInit(&vData);
   CComBSTR bConfigurationNamingContext;
   CComBSTR bSchemaNamingContext;
   CComBSTR bDefaultNamingContext;
   hr = ADsGetObject(  L"LDAP://RootDSE", IID_IADs, (LPVOID *)&oRootDSE );
   if( FAILED( hr ) )
   {
      printf("Error %d occured opening RootDSE object\nTerminating Program\n");
      return E_FAIL;
   }
   hr = oRootDSE->Get(L"defaultNamingContext", &vData);
   bDefaultNamingContext.AppendBSTR( vData.bstrVal );
   VariantClear(&vData);
   hr = oRootDSE->Get(L"SchemaNamingContext", &vData);
   bSchemaNamingContext.AppendBSTR( vData.bstrVal);
   VariantClear(&vData);
   hr = oRootDSE->Get(L"ConfigurationNamingContext", &vData);
   bConfigurationNamingContext.AppendBSTR(vData.bstrVal);
   VariantClear(&vData );
   oRootDSE.Release();
   // 
   // Build the  ControlAccessRight object path from the given Extended Right 
   // passed as the first argument of the tooll
   // 
   CComBSTR bArg = argv[1];
   CComBSTR bControlAccessRightPath = L"LDAP://";
   bControlAccessRightPath.AppendBSTR( bArg );
   bControlAccessRightPath.Append(L",CN=Extended-Rights,");
   bControlAccessRightPath.AppendBSTR( bConfigurationNamingContext);
   CComPtr <IADs> oControlAccessRight;
   hr = ADsGetObject( bControlAccessRightPath.m_str, IID_IADs, (LPVOID *) &oControlAccessRight);
   if( FAILED(hr) )
   {
      printf("Unable to open ControlAccessRight object :\n%S\nReceived error %d\nTerminating Program\n",
         bControlAccessRightPath.m_str, hr);
      // 
      // CleanUp and exit
      // 
      oRootDSE.Release();
      CoUninitialize();
      return hr;
   }
   // 
   // Retrieve the RightsGUID from the ControlAccessRight.
   // Put it into the form of "{GUID STRING}"...
   // 
   oControlAccessRight->Get(L"RightsGUID", &vData );
   CComBSTR bRightsGUID = L"{";
   bRightsGUID.AppendBSTR( vData.bstrVal );
   bRightsGUID.Append(L"}");
   VariantClear(&vData);
   // 
   // Convert it into its binary equivalent and then Binary Encode it to be used later in 
   // the LDAP search....
   // 
   // NOTE: The pointer returned by ADsEncodeBinaryData is allocated by the API and must be 
   // freed when we are done with it using the FreeADsMem API.
   // 
   // We are done with the ControlAccessRight object so we can release the IADs interface
   // associated with it.
   // 
   CLSID binaryRightsGUID;
   LPWSTR pszEncodedRightsGUID;
   CLSIDFromString( bRightsGUID.m_str, &binaryRightsGUID );
   ADsEncodeBinaryData( (PBYTE)&binaryRightsGUID, sizeof(CLSID), &pszEncodedRightsGUID);
   oControlAccessRight.Release();
   // 
   //  Now, bind to the Schema Container and retrieve an IDirectorySearch
   //  interface to prepare for the LDAP search....
   // 
   CComBSTR bSchemaBindString = L"LDAP://";
   bSchemaBindString.AppendBSTR( bSchemaNamingContext);
   CComPtr <IADs> oIADsSchema;
   hr = ADsGetObject( bSchemaBindString.m_str, IID_IADs, (LPVOID *)&oIADsSchema);
   CComQIPtr <IDirectorySearch, &IID_IDirectorySearch> oSearch( oIADsSchema );
   oIADsSchema.Release();
   // 
   // Build the LDAP query string that will look someting like:
   // LDAP Server : bDefaltNamingContext
   // LDAP Query String: (&(objectclass=attributeSchema)(attributeSecurityGUID=BINARY_ENCODED_RIGHTS_GUID))
   // LDAP Properties to return: CN
   // Search Properties: Paged Search
   // Search Scope: Sub Tree ( from the schema container and beyond)
   // 
   // 
   // 
   // Build the query string...
   // 
   CComBSTR bLDAPQueryStr;
   bLDAPQueryStr = L"(&(objectclass=attributeSchema)(attributeSecurityGUID=";
   bLDAPQueryStr.Append( pszEncodedRightsGUID );
   bLDAPQueryStr.Append(L"))");
   // 
   // Setup the Attributes and search preferences
   // 
   // Perform a subtree search
   // 
   ADS_SEARCHPREF_INFO prefInfo[2];
   prefInfo[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
   prefInfo[0].vValue.dwType = ADSTYPE_INTEGER;
   prefInfo[0].vValue.Integer = ADS_SCOPE_SUBTREE;
   // 
   // Set the maximum records returned to 1000 ( maximum for AD )
   // 
   prefInfo [1].dwSearchPref = ADS_SEARCHPREF_PAGESIZE ;
   prefInfo [1].vValue.dwType = ADSTYPE_INTEGER;
   prefInfo [1].vValue.Integer = 1000;
   // 
   // Set bind the search preferences with the IDirectorySearch object...
   // 
   hr = oSearch->SetSearchPreference( prefInfo, 2);
   // 
   // Prepare a list of attributes to return in the query...
   // in our case, we want the Common Name only...
   // 
   LPWSTR pszAttr[] = { L"cn"};
   ADS_SEARCH_HANDLE hSearch;
   DWORD dwCount= sizeof(pszAttr)/sizeof(LPWSTR);
   // 
   // Execute the LDAP Query....
   // 
   hr=oSearch->ExecuteSearch(bLDAPQueryStr.m_str, pszAttr, dwCount, &hSearch );
   if (!SUCCEEDED(hr))
   {
      printf("LDAP Search failed with error %d\nTerminating program\n", hr );
      // 
      // Clean up
      // 
      oSearch.Release();
      FreeADsMem( (LPVOID)pszEncodedRightsGUID);
      return hr;
   }
   // 
   // Now enumerate the result
   // 
   ADS_SEARCH_COLUMN col;
   //     "0---------1---------2---------3----5"
   BOOL bFirstTime = TRUE;
   while( oSearch->GetNextRow(hSearch) != S_ADS_NOMORE_ROWS )
   {
      // Get attributes
      // 
      // CN
      // 
      hr = oSearch->GetColumn( hSearch, pszAttr[0], &col );
      if ( SUCCEEDED(hr) )
      {
         if( bFirstTime )
         {
            printf("Properties Associated with ControlAccessRight: %S\n", argv[1]);
            bFirstTime = FALSE;
         }
         printf("%S\n",(LPWSTR)col.pADsValues->CaseIgnoreString);
         oSearch->FreeColumn( &col );
      }
   }
   oSearch->CloseSearchHandle( hSearch );
   oSearch.Release();
   // 
   // Free the binary encoded string received from ADsEncodeBinaryData...
   // 
   FreeADsMem( (LPVOID)pszEncodedRightsGUID);
   
   CoUninitialize();
   
   return 0;
}
				

Util.cpp File Contents

#include <stdio.h>
// 
// UTIL.CPP
// 
// Implementation of some global helper functions
// 
void PrintUsage( void )
{
    printf("Usage:\nexecutable_name ExtRightCN\nWhere:\n\tExtRightCN-> Common Name for an Extended Right\n");
    printf("\nie: executable_name \"cn=General-Information\" \n\n");
    printf("This utility will perform an LDAP search using the IDirectorySearch\n");
    printf("interface against the Schema container to retrieve all of the \n");
    printf("attributeSchema objects whose attributeSecurityGUID match the \n");
    printf("RightsGUID of the specified Extended Right.\n\n");
}
				

Util.h File Contents

// 
// This header file contains helper functions definitions for
// used by the main ADSI program
// 

#ifndef _UTIL_H
#define _UTIL_H
   // 
   // Function Stubs
   // 
   void PrintUsage( void );


#endif  // end of definition for _UTIL_H header
				

REFERENCES

For additional information, click the article numbers below to view the articles in the Microsoft Knowledge Base:

302515 How To Find All Extended Rights that Apply to a Schema Class Object Using Visual C++

301920 How To Search for a RightsGUID or a SchemaIDGuid


Modification Type:MinorLast Reviewed:8/15/2005
Keywords:kbDSWADSI2003Swept kbhowto KB302250 kbAudDeveloper