Platform SDK: Active Directory, ADSI, and Directory Services |
The following program creates two objects: a container object and a sub-container object within it. A value for the sub-container object is added to the otherWellKnownObjects property of the container object. The program binds to the sub-container object using the WKGUID binding and displays its ADsPath. It then renames the sub-container object and binds again using the same WKGUID binding.
#include <wchar.h> #include <objbase.h> #include <activeds.h> //Make sure you define UNICODE //Need to define version 5 for Windows 2000 #define _WIN32_WINNT 0x0500 //FOR LDAP API...Required for Beta 3 only. #include <winldap.h> //Need to link against the following LIBs: //wldap32.lib static GUID MyWKOTestObjectGUID = { /* df447b5e-aa5b-11d2-8d53-00c04f79ab81 */ 0xdf447b5e, 0xaa5b, 0x11d2, {0x8d, 0x53, 0x00, 0xc0, 0x4f, 0x79, 0xab, 0x81} }; HRESULT GUIDtoBindableString (LPGUID pGUID, LPOLESTR *ppGUIDString); HRESULT AddValueToOtherWKOProperty(LPOLESTR szContainerDN, //DN for container whose otherWellKnownObjects property to modify LPGUID pWKOGUID, //WKO GUID for the well-known object. LPOLESTR szWKOObjectDN //DN of the well-known object. ); void wmain( int argc, wchar_t *argv[ ]) { LPOLESTR pszBuffer = new OLECHAR[MAX_PATH*2]; wprintf(L"This program does the following:\n"); wprintf(L"1. Creates a container (MyWKOTestContainer) in the current Window 2000 domain.\n"); wprintf(L"2. Creates a container object (MyWKOTestObject) within the container.\n"); wprintf(L"3. Adds a value for the container object on the otherWellKnownObject property of the container.\n"); wprintf(L"4. Binds to the container object using WKGUID binding string.\n"); wprintf(L"5. Renames the container object using WKGUID binding string.\n"); wprintf(L"6. Binds to the container object using WKGUID binding string.\n"); wprintf(L"7. Optionally, cleans up by removing the container and container object.\n\n"); //Intialize COM CoInitialize(NULL); HRESULT hr = S_OK; IADs *pObject = NULL; IADsContainer *pDomain = NULL; IDispatch *pDisp = NULL; IDispatch *pDispNewObject = NULL; IADsContainer *pNewContainer = NULL; IADs *pIADsObject = NULL; IADs *pNewObject = NULL; IADs *pTestWKO1 = NULL; IADs *pTestWKO2 = NULL; VARIANT vartest; BSTR bstr; LPOLESTR szNewContainerDN = new OLECHAR[MAX_PATH]; LPOLESTR szPath = new OLECHAR[MAX_PATH]; LPOLESTR szRelPath = new OLECHAR[MAX_PATH]; LPOLESTR szGUIDString = NULL; //Names of the container and child object. LPOLESTR szContainer = L"MyWKOTestContainer"; LPOLESTR szNewObject = L"MyWKOTestObject"; LPOLESTR szNewObjectRenameRDN = L"cn=ObjectwithNEWNAME"; //Get rootDSE and the domain container's DN. VARIANT var; hr = ADsOpenObject(L"LDAP://rootDSE", NULL, NULL, ADS_SECURE_AUTHENTICATION, //Use Secure Authentication IID_IADs, (void**)&pObject); if (FAILED(hr)) { wprintf(L"Not Found. Could not bind to the domain.\n"); if (pObject) pObject->Release(); return; } hr = pObject->Get(L"defaultNamingContext",&var); if (SUCCEEDED(hr)) { //Build the ADsPath to the domain wcscpy(szPath,L"LDAP://"); wcscat(szPath,var.bstrVal); VariantClear(&var); //Bind to the current domain. hr = ADsOpenObject(szPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, //Use Secure Authentication IID_IADsContainer, (void**)&pDomain); if (SUCCEEDED(hr)) { //Create the container. wcscpy(szRelPath,L"cn="); wcscat(szRelPath,szContainer); hr = pDomain->Create(L"container", //ldapDisplayName of the class of the object to create. szRelPath, //relative path in RDN=value format &pDisp); //return an IDispatch pointer to the new object. if (SUCCEEDED(hr)) { //QI for an IADs interface. hr = pDisp->QueryInterface(IID_IADs, (void **)&pIADsObject); //Commit the new object to the directory. hr = pIADsObject->SetInfo(); //QI for an IADsContainer interface. hr = pDisp->QueryInterface(IID_IADsContainer, (void **)&pNewContainer); if (SUCCEEDED(hr)) { //Create the new container object in the container. wcscpy(szRelPath,L"cn="); wcscat(szRelPath,szNewObject); hr = pNewContainer->Create(L"container", //ldapDisplayName of the class of the object to create. szRelPath, //relative path in RDN=value format &pDispNewObject); //return an IDispatch pointer to the new object. if (SUCCEEDED(hr)) { //Get the DN of the new container object hr = pIADsObject->Get(L"distinguishedName", &var); if (SUCCEEDED(hr)) { wcscpy(szNewContainerDN, var.bstrVal); VariantClear(&var); wprintf(L"Created new container with DN: %s\n",szNewContainerDN); hr = pDispNewObject->QueryInterface(IID_IADs, (void **)&pNewObject); if (SUCCEEDED(hr)) { //Commit the new object to the directory. hr = pNewObject->SetInfo(); //Get the DN for the new object hr = pNewObject->Get(L"distinguishedName", &var); if (SUCCEEDED(hr)) { wprintf(L"Created new child object with DN: %s\n",var.bstrVal); //FOR BETA 3 only. Need to use LDAP API to set the otherWellKnownObjects property. wprintf(L"Call AddValueToOtherWKOProperty with:\n"); wprintf(L"szContainer DN: %s\n",szNewContainerDN); GUIDtoBindableString (&MyWKOTestObjectGUID, &szGUIDString); wprintf(L"pWKOGUID (bindable string format): %s\n",szGUIDString); wprintf(L"szWKOObjectDN: %s\n",var.bstrVal); hr = AddValueToOtherWKOProperty(szNewContainerDN, //DN for container whose otherWellKnownObjects property to modify &MyWKOTestObjectGUID, //WKO GUID for the well-known object. var.bstrVal //DN of the well-known object. ); wprintf(L"AddValueToOtherWKOProperty returned: %x\n",hr); if (SUCCEEDED(hr)) { //Now bind using WKGUID binding //Build the ADsPath to the well-known object wcscpy(szPath,L"LDAP://<WKGUID="); wcscat(szPath,szGUIDString); wcscat(szPath,L","); wcscat(szPath,szNewContainerDN); wcscat(szPath,L">"); wprintf(L"Bind with the following WKGUID binding string: %s\n",szPath); hr = ADsOpenObject(szPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, //Use Secure Authentication IID_IADs, (void**)&pTestWKO1); if (SUCCEEDED(hr)) { hr = pTestWKO1->Get(L"distinguishedName",&vartest); if (SUCCEEDED(hr)) { wprintf(L"Successfully bound to object. DN: %s\n",vartest.bstrVal); VariantClear(&vartest); } } else wprintf(L"Binding failed with hr: %x\n",hr); if (pTestWKO1) pTestWKO1->Release(); //Bind again using the DN to get a regular ADsPath. wcscpy(szPath,L"LDAP://"); wcscat(szPath,var.bstrVal); hr = ADsOpenObject(szPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, //Use Secure Authentication IID_IADs, (void**)&pTestWKO1); hr = pTestWKO1->get_ADsPath(&bstr); //Rename the WKO object hr = pNewContainer->MoveHere(bstr,szNewObjectRenameRDN,NULL); FreeADsStr(bstr); if (pTestWKO1) pTestWKO1->Release(); //Now AGAIN bind using WKGUID binding //Build the ADsPath to the well-known object wcscpy(szPath,L"LDAP://<WKGUID="); wcscat(szPath,szGUIDString); wcscat(szPath,L","); wcscat(szPath,szNewContainerDN); wcscat(szPath,L">"); wprintf(L"Bind AGAIN with the following WKGUID binding string: %s\n",szPath); hr = ADsOpenObject(szPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, //Use Secure Authentication IID_IADs, (void**)&pTestWKO2); if (SUCCEEDED(hr)) { hr = pTestWKO2->Get(L"distinguishedName",&vartest); if (SUCCEEDED(hr)) { wprintf(L"Successfully bound to object (Note the DN reflects the rename). DN: %s\n",vartest.bstrVal); VariantClear(&vartest); } } else wprintf(L"Binding failed with hr: %x\n",hr); } CoTaskMemFree(szGUIDString); } } if (pNewObject) pNewObject->Release(); } VariantClear(&var); } if (pIADsObject) pIADsObject->Release(); if (pDispNewObject) pDispNewObject->Release(); } //Ask user if they want us to delete the test containers. wprintf(L"Do you want to delete the test container and object (Y/N):"); _getws(pszBuffer); if (0==wcsnicmp(L"Y", pszBuffer,1)) { //Delete the object //Delete the container hr = pNewContainer->Delete(L"container",szNewObjectRenameRDN); if (SUCCEEDED(hr)) { wprintf(L"Successfully deleted test object.\n"); wcscpy(szRelPath,L"cn="); wcscat(szRelPath,szContainer); //Delete the container hr = pDomain->Delete(L"container",szRelPath); if (SUCCEEDED(hr)) wprintf(L"Successfully deleted test container and its contents.\n"); else wprintf(L"Failed to delete test container and its contents. hr: %x\n",hr); } else wprintf(L"Failed to delete test container and its contents. hr: %x\n",hr); } if (pNewContainer) pNewContainer->Release(); } if (pDisp) pDisp->Release(); } if (pDomain) pDomain->Release(); } if (pObject) pObject->Release(); //Uninitialize COM CoUninitialize(); return; } HRESULT AddValueToOtherWKOProperty(LPOLESTR szContainerDN, //DN for container whose otherWellKnownObjects property to modify LPGUID pWKOGUID, //WKO GUID for the well-known object. LPOLESTR szWKOObjectDN //DN of the well-known object. ) { HRESULT hr = E_FAIL; LPOLESTR szGUIDString = new OLECHAR[MAX_PATH]; LPOLESTR szDNwithOctetString = new OLECHAR[MAX_PATH*2]; DWORD dwReturn; //Connection handle LDAP *hConnect = NULL; //Specify NULL to bind to a DC in the current computer's domain. //LDAP_PORT is the default port, 389 hConnect = ldap_open(NULL, LDAP_PORT); //Bind using the preferred authentication method on Windows 2000 //and the caller's security context. dwReturn = ldap_bind_s( hConnect, NULL, NULL, LDAP_AUTH_NEGOTIATE ); if (dwReturn==LDAP_SUCCESS) { //Create the WKO value to add. GUIDtoBindableString (pWKOGUID, &szGUIDString); DWORD dwGUIDSize = (wcslen(szGUIDString)); //Build the DNwithoctetstring swprintf(szDNwithOctetString, L"B:%d:%s:%s", dwGUIDSize, szGUIDString,szWKOObjectDN); // ULONG ulBerSize = (wcslen(szDNwithOctetString)); //Build the BerVal // PCHAR pByteVal = (PCHAR)szDNwithOctetString; // berval berWKO; // berWKO.bv_len = ulBerSize; // berWKO.bv_val = pByteVal; //Build the mod structure to add the value. LDAPMod ldWKO; //mod_values takes a NULL terminated array of WCHARs. //We're adding a single value. WCHAR *StrValues[] = {szDNwithOctetString , NULL }; //Operation ldWKO.mod_op = LDAP_MOD_ADD; //Attribute ldWKO.mod_type = L"otherWellKnownObjects"; //Value to set. ldWKO.mod_vals.modv_strvals = StrValues; //mods is a NULL terminated array of LDAPMod structures. //We're adding a single value. LDAPMod *pMod[] = {&ldWKO,NULL}; //Modify the object specified by szContainerDN. dwReturn = ldap_modify_s( hConnect, szContainerDN, pMod); CoTaskMemFree(szGUIDString); if (dwReturn==LDAP_SUCCESS) hr = S_OK; } return hr; } HRESULT GUIDtoBindableString (LPGUID pGUID, LPOLESTR *ppGUIDString) { HRESULT hr = E_FAIL; if (!pGUID) return E_INVALIDARG; //Build bindable GUID string LPOLESTR szDSGUID = new WCHAR [128]; DWORD dwLen = sizeof(*pGUID); LPBYTE lpByte = (LPBYTE) pGUID; //Copy a blank string to make it a zero length string. wcscpy( szDSGUID, L"" ); //Loop through to add each byte to the string. for( DWORD dwItem = 0L; dwItem < dwLen ; dwItem++ ) { //Append to szDSGUID, double-byte, byte at dwItem index. swprintf(szDSGUID + wcslen(szDSGUID), L"%02x", lpByte[dwItem]); if( wcslen( szDSGUID ) > 128 ) break; } //Allocate memory for string *ppGUIDString = (OLECHAR *)CoTaskMemAlloc (sizeof(OLECHAR)*(wcslen(szDSGUID)+1)); if (*ppGUIDString) wcscpy(*ppGUIDString, szDSGUID); else hr=E_FAIL; //Caller must free ppGUIDString using CoTaskMemFree. return hr; } // This function gets the specified well-known object for the current user's domain. HRESULT GetWKOObject(LPOLESTR szBindableWKGUID, //IN. Bindable string GUID of well-known object. IADs **ppObject //OUT. Return a pointer to the specified well-known object. ) { HRESULT hr = E_FAIL; //Get rootDSE and the domain container's DN. IADs *pObject = NULL; LPOLESTR szPath = new OLECHAR[MAX_PATH]; VARIANT var; hr = ADsOpenObject(L"LDAP://rootDSE", NULL, NULL, ADS_SECURE_AUTHENTICATION, //Use Secure Authentication IID_IADs, (void**)&pObject); //Get current domain DN. if (SUCCEEDED(hr)) { hr = pObject->Get(L"defaultNamingContext",&var); if (SUCCEEDED(hr)) { //Build the WKGUID binding string. wcscpy(szPath,L"LDAP://"); wcscat(szPath,L"<WKGUID="); wcscat(szPath,szBindableWKGUID); wcscat(szPath,L","); wcscat(szPath,var.bstrVal); wcscat(szPath,L">"); //Print the binding string. //wprintf(L"WKGUID binding string: %s\n",szPath); VariantClear(&var); //Bind to the well-known object. hr = ADsOpenObject(szPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, //Use Secure Authentication IID_IADs, (void**)ppObject); if (FAILED(hr)) { if (*ppObject) { (*ppObject)->Release(); (*ppObject) = NULL; } } } } if (pObject) pObject->Release(); return hr; }