370 lines
9.9 KiB
C++
370 lines
9.9 KiB
C++
/*
|
|
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
* PARTICULAR PURPOSE.
|
|
*
|
|
* Copyright (c) Microsoft Corporation. All Rights Reserved.
|
|
*/
|
|
|
|
// bindtoparent.cpp : Defines the entry point for the console application.
|
|
//
|
|
#include <stdio.h>
|
|
#include <wchar.h>
|
|
#include <objbase.h>
|
|
#include <activeds.h>
|
|
|
|
#define INPUT_BUFF_SIZE MAX_PATH
|
|
#define SEARCH_FILTER_SIZE INPUT_BUFF_SIZE + 64
|
|
|
|
HRESULT GetParentObject(IADs *pObject, //Pointer the object whose parent to bind to.
|
|
IADs **ppParent //Return a pointer to the parent object.
|
|
);
|
|
|
|
HRESULT FindUserByName(IDirectorySearch *pSearchBase, //Container to search
|
|
LPOLESTR szFindUser, //Name of user to find.
|
|
IADs **ppUser); //Return a pointer to the user
|
|
|
|
int __cdecl wmain( int argc, wchar_t *argv[])
|
|
{
|
|
int inputsize = 0;
|
|
|
|
//Handle the command line arguments.
|
|
OLECHAR szBuffer[INPUT_BUFF_SIZE] = {0};
|
|
if (NULL == argv[1])
|
|
{
|
|
wprintf(L"This program finds a user in the current Window 2000 domain\n");
|
|
wprintf(L"and displays its parent container's ADsPath and binds to that container.\n");
|
|
wprintf(L"Enter Common Name of the user to find:");
|
|
fgetws(szBuffer, ARRAYSIZE(szBuffer), stdin);
|
|
|
|
// Note that fgetws retains final newline - strip this
|
|
inputsize = wcsnlen(szBuffer, ARRAYSIZE(szBuffer));
|
|
if (0 < inputsize && '\n' == szBuffer[inputsize-1])
|
|
szBuffer[inputsize-1] = '\0';
|
|
}
|
|
else
|
|
wcscpy_s(szBuffer, ARRAYSIZE(szBuffer), argv[1]);
|
|
|
|
//if empty string, exit.
|
|
if (0 == wcscmp(L"", szBuffer))
|
|
{
|
|
wprintf(L"Empty user name.\n");
|
|
return 1;
|
|
}
|
|
|
|
wprintf(L"\nFinding user: %s...\n",szBuffer);
|
|
|
|
//Intialize COM
|
|
HRESULT hr = S_OK;
|
|
hr = CoInitialize(NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"CoInitialize failed. hr=0x%x\n", hr);
|
|
return 1;
|
|
}
|
|
|
|
//Get rootDSE and the domain container's DN.
|
|
IADs *pObject = NULL;
|
|
IADs *pParent = NULL;
|
|
IDirectorySearch *pDS = NULL;
|
|
OLECHAR szPath[MAX_PATH];
|
|
VARIANT var;
|
|
BSTR bstr = NULL;
|
|
BSTR bstrC = NULL;
|
|
|
|
VariantInit(&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. hr=0x%x\n", hr);
|
|
goto CleanUp;
|
|
}
|
|
|
|
BSTR bNamingContext = NULL;
|
|
bNamingContext = SysAllocString(L"defaultNamingContext");
|
|
if (NULL == bNamingContext)
|
|
{
|
|
wprintf(L"SysAllocString for defaultNamingContext failed.\n");
|
|
goto CleanUp;
|
|
}
|
|
|
|
hr = pObject->Get(bNamingContext,&var);
|
|
SysFreeString(bNamingContext);
|
|
bNamingContext = NULL;
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"Get for %s failed. hr=0x%x\n", bNamingContext, hr);
|
|
goto CleanUp;
|
|
}
|
|
|
|
wcscpy_s(szPath, ARRAYSIZE(szPath), L"LDAP://"); // If you're running on NT 4.0 or Win9.x machine, you need to
|
|
// add the server name e.g L"LDAP://myServer"
|
|
wcscat_s(szPath, ARRAYSIZE(szPath), var.bstrVal);
|
|
|
|
//Bind to the root of the current domain.
|
|
hr = ADsOpenObject(szPath,
|
|
NULL,
|
|
NULL,
|
|
ADS_SECURE_AUTHENTICATION, //Use Secure Authentication
|
|
IID_IDirectorySearch,
|
|
(void**)&pDS);
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf (L"ADsOpenObject failed for path %s. hr=0x%x\n", szPath, hr);
|
|
goto CleanUp;
|
|
}
|
|
|
|
if (pObject)
|
|
{
|
|
pObject->Release();
|
|
pObject = NULL;
|
|
}
|
|
hr = FindUserByName(pDS, //Container to search
|
|
szBuffer, //Name of user to find.
|
|
&pObject); //Return a pointer to the user
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"User \"%s\" not Found.\n",szBuffer);
|
|
wprintf (L"FindUserByName failed with the following HR: 0x%x\n", hr);
|
|
goto CleanUp;
|
|
}
|
|
|
|
hr = GetParentObject(pObject, //Pointer the object whose parent to bind to.
|
|
&pParent //Return a pointer to the parent object.
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"GetParentObject failed with hr: %x\n",hr);
|
|
goto CleanUp;
|
|
}
|
|
wprintf(L"Successfully bound to parent container\n");
|
|
|
|
//Get ADsPath
|
|
hr = pParent->get_ADsPath(&bstr);
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"get_ADsPath failed. hr = 0x%x\n", hr);
|
|
goto CleanUp;
|
|
}
|
|
|
|
//Get the distinguishedName property
|
|
BSTR bDName = SysAllocString(L"distinguishedName");
|
|
if (NULL == bDName)
|
|
{
|
|
wprintf(L"SysAllocString for distinguishedName failed.\n");
|
|
goto CleanUp;
|
|
}
|
|
|
|
VariantClear(&var);
|
|
hr = pParent->Get(bDName, &var);
|
|
SysFreeString(bDName);
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"Get failed for %s. hr = 0x%x\n", bDName, hr);
|
|
goto CleanUp;
|
|
}
|
|
|
|
//Get class
|
|
hr = pParent->get_Class(&bstrC);
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"get_Class failed with hr: 0x%x\n",hr);
|
|
goto CleanUp;
|
|
}
|
|
|
|
wprintf(L"ADsPath: %s\n",bstr);
|
|
wprintf(L"DN: %s\n",var.bstrVal);
|
|
wprintf(L"Class: %s\n",bstrC);
|
|
|
|
|
|
CleanUp:
|
|
|
|
if (bstr)
|
|
{
|
|
FreeADsStr(bstr);
|
|
bstr = NULL;
|
|
}
|
|
if (bstrC)
|
|
{
|
|
FreeADsStr(bstrC);
|
|
bstrC = NULL;
|
|
}
|
|
VariantClear(&var);
|
|
|
|
if (pObject)
|
|
{
|
|
pObject->Release();
|
|
pObject = NULL;
|
|
}
|
|
if (pDS)
|
|
{
|
|
pDS->Release();
|
|
pDS = NULL;
|
|
}
|
|
if (pParent)
|
|
{
|
|
pParent->Release();
|
|
pParent = NULL;
|
|
}
|
|
|
|
//Uninitalize COM
|
|
CoUninitialize();
|
|
|
|
return FAILED(hr)?1:0;
|
|
}
|
|
|
|
HRESULT GetParentObject(IADs *pObject, //Pointer the object whose parent to bind to.
|
|
IADs **ppParent //Return a pointer to the parent object.
|
|
)
|
|
{
|
|
if ((!pObject)||(!ppParent))
|
|
return E_INVALIDARG;
|
|
|
|
HRESULT hr = E_FAIL;
|
|
BSTR bstr = NULL;
|
|
hr = pObject->get_Parent(&bstr);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//Bind to the parent container.
|
|
*ppParent = NULL;
|
|
hr = ADsOpenObject(bstr,
|
|
NULL,
|
|
NULL,
|
|
ADS_SECURE_AUTHENTICATION, //Use Secure Authentication
|
|
IID_IADs,
|
|
(void**)ppParent);
|
|
if(FAILED(hr))
|
|
{
|
|
if ((*ppParent))
|
|
{
|
|
(*ppParent)->Release();
|
|
(*ppParent) = NULL;
|
|
}
|
|
}
|
|
}
|
|
if (bstr)
|
|
{
|
|
FreeADsStr(bstr);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT FindUserByName(IDirectorySearch *pSearchBase, //Container to search
|
|
LPOLESTR szFindUser, //Name of user to find.
|
|
IADs **ppUser) //Return a pointer to the user
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if ((!pSearchBase)||(!szFindUser))
|
|
return E_INVALIDARG;
|
|
|
|
//Create search filter
|
|
OLECHAR szSearchFilter[SEARCH_FILTER_SIZE] = {0};
|
|
OLECHAR szADsPath[MAX_PATH] = {0};
|
|
wcscpy_s(szSearchFilter, ARRAYSIZE(szSearchFilter), L"(&(objectCategory=person)(objectClass=user)(cn=");
|
|
wcscat_s(szSearchFilter, ARRAYSIZE(szSearchFilter), szFindUser);
|
|
wcscat_s(szSearchFilter, ARRAYSIZE(szSearchFilter), L"))");
|
|
|
|
//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 = {0};
|
|
// Handle used for searching
|
|
ADS_SEARCH_HANDLE hSearch = NULL;
|
|
// Set the search preference
|
|
|
|
hr = pSearchBase->SetSearchPreference( &SearchPrefs, dwNumPrefs);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// Set attributes to return
|
|
LPOLESTR pszAttribute[1] = {L"ADsPath"};
|
|
|
|
// Execute the search
|
|
hr = pSearchBase->ExecuteSearch(szSearchFilter,
|
|
pszAttribute,
|
|
1,
|
|
&hSearch
|
|
);
|
|
|
|
DWORD noUsersFound = 0;
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
|
|
// Call IDirectorySearch::GetNextRow() to retrieve the next row
|
|
//of data
|
|
while( pSearchBase->GetNextRow( hSearch) != S_ADS_NOMORE_ROWS )
|
|
{
|
|
|
|
if(noUsersFound>0 && ((*ppUser) != NULL))(*ppUser)->Release();
|
|
wprintf(L"Found User %s.\n",szFindUser);
|
|
// Get the data for this column
|
|
hr = pSearchBase->GetColumn( hSearch, pszAttribute[0], &col );
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
// Print the data for the column and free the column
|
|
// Note the attribute we asked for is type CaseIgnoreString.
|
|
wcscpy_s(szADsPath, ARRAYSIZE(szADsPath), col.pADsValues->CaseIgnoreString);
|
|
wprintf(L"%s: %s\r\n",pszAttribute[0],col.pADsValues->CaseIgnoreString);
|
|
hr = ADsOpenObject(szADsPath,
|
|
NULL,
|
|
NULL,
|
|
ADS_SECURE_AUTHENTICATION, //Use Secure Authentication
|
|
IID_IADs,
|
|
(void**)ppUser);
|
|
if(SUCCEEDED(hr)) noUsersFound ++;
|
|
|
|
pSearchBase->FreeColumn( &col );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// Close the search handle to clean up
|
|
if (hSearch)
|
|
{
|
|
pSearchBase->CloseSearchHandle(hSearch);
|
|
hSearch = NULL;
|
|
}
|
|
|
|
if (noUsersFound>1)
|
|
{
|
|
VARIANT var;
|
|
wprintf(L"---------------------------------------------------\n");
|
|
wprintf(L"More than one user with CN %s was found.\n",szFindUser);
|
|
|
|
BSTR bDName = SysAllocString(L"distinguishedName");
|
|
if (NULL == bDName)
|
|
return E_FAIL;
|
|
|
|
(*ppUser)->Get(bDName, &var);
|
|
SysFreeString(bDName);
|
|
|
|
wprintf(L"Returning pointer to User (DN): %s\n",var.bstrVal);
|
|
wprintf(L"---------------------------------------------------\n");
|
|
VariantClear(&var);
|
|
}
|
|
|
|
if(0 == noUsersFound)
|
|
hr = E_FAIL;
|
|
|
|
return hr;
|
|
}
|