You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
959 lines
26 KiB
959 lines
26 KiB
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Microsoft Windows, Copyright (C) Microsoft Corporation, 2000
|
|
|
|
File: ADHelpers.cpp
|
|
|
|
Content: Implementation of helper routines for accessing Active Directory.
|
|
Functions in this module require DSClient installed for down level
|
|
clients.
|
|
|
|
History: 11-15-99 dsie created
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
#include "StdAfx.h"
|
|
#include "CAPICOM.h"
|
|
#include "AdHelpers.h"
|
|
#include "Settings.h"
|
|
|
|
////////////////////
|
|
//
|
|
// Local typedefs
|
|
//
|
|
|
|
typedef HRESULT (WINAPI * PADSOPENOBJECT)(LPWSTR lpszPathName,
|
|
LPWSTR lpszUserName,
|
|
LPWSTR lpszPassword,
|
|
DWORD dwReserved,
|
|
REFIID riid,
|
|
VOID FAR * FAR *ppObject);
|
|
|
|
typedef HRESULT (WINAPI * PADSBUILDENUMERATOR)(IADsContainer * pADsContainer,
|
|
IEnumVARIANT ** ppEnumVariant);
|
|
|
|
typedef HRESULT (WINAPI * PADSENUMERATENEXT)(IEnumVARIANT * pEnumVariant,
|
|
ULONG cElements,
|
|
VARIANT FAR * pvar,
|
|
ULONG FAR * pcElementsFetched);
|
|
|
|
typedef HRESULT (WINAPI * PADSFREEENUMERATOR)(IEnumVARIANT * pEnumVariant);
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Local functions.
|
|
//
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : IsUserCertificateInGC
|
|
|
|
Synopsis : Determine if the userCertificate attribute is replicated in the GC.
|
|
|
|
Parameter: HMODULE hDLL - ActiveDS.DLL handle.
|
|
|
|
BOOL * pbResult - Pointer to BOOL to receive result.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static HRESULT IsUserCertificateInGC (HMODULE hDLL,
|
|
BOOL * pbResult)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IADs * pIADs = NULL;
|
|
IDirectorySearch * pISchema = NULL;
|
|
LPOLESTR pszList[] = {L"lDAPDisplayName", L"isMemberOfPartialAttributeSet"};
|
|
LPOLESTR pszFilter = L"(&(objectCategory=attributeSchema)(lDAPDisplayName=userCertificate))";
|
|
ADS_SEARCH_HANDLE hSearch = NULL;
|
|
DWORD dwNumPrefs = 1;
|
|
CComBSTR bstrPath;
|
|
CComBSTR bstrSchema;
|
|
ADS_SEARCHPREF_INFO SearchPrefs;
|
|
CComVariant var;
|
|
PADSOPENOBJECT pADsOpenObject;
|
|
|
|
static BOOL bResult = FALSE;
|
|
static BOOL bChecked = FALSE;
|
|
|
|
DebugTrace("Entering IsUserCertificateInGC().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(hDLL);
|
|
ATLASSERT(pbResult);
|
|
|
|
//
|
|
// If we had already checked once, use the cached result.
|
|
//
|
|
if (bChecked)
|
|
{
|
|
*pbResult = bResult;
|
|
goto CommonExit;
|
|
}
|
|
|
|
//
|
|
// Initialize.
|
|
//
|
|
if (!(bstrPath = L"LDAP://") || !(bstrSchema = L"schemaNamingContext"))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: bstrPath = L\"LDAP://\") || (bstrSchema = L\"schemaNamingContext\" failed.", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get ADsOpenObject address pointer.
|
|
//
|
|
if (!(pADsOpenObject = (PADSOPENOBJECT) ::GetProcAddress(hDLL, "ADsOpenObject")))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: GetProcAddress() failed to load ADsOpenObject().\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Bind to rootDSE to get the schemaNamingContext property.
|
|
//
|
|
if (FAILED(hr = pADsOpenObject(L"LDAP://rootDSE",
|
|
NULL,
|
|
NULL,
|
|
ADS_SECURE_AUTHENTICATION,
|
|
IID_IADs,
|
|
(void **) &pIADs)))
|
|
{
|
|
DebugTrace("Error [%#x]: ADsOpenObject() failed for IID_IADs.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get schema container path.
|
|
//
|
|
if (FAILED(hr = pIADs->Get(bstrSchema, &var)))
|
|
{
|
|
DebugTrace("Error [%#x]: pIADs->Get() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
//
|
|
// Build path to the schema container.
|
|
//
|
|
if (FAILED(hr = bstrPath.AppendBSTR(var.bstrVal)))
|
|
{
|
|
DebugTrace("Error [%#x]: bstrPath.AppendBSTR() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Bind to the actual schema container.
|
|
//
|
|
if (FAILED(hr = pADsOpenObject(bstrPath,
|
|
NULL,
|
|
NULL,
|
|
ADS_SECURE_AUTHENTICATION,
|
|
IID_IDirectorySearch,
|
|
(void **) &pISchema)))
|
|
{
|
|
DebugTrace("Error [%#x]: ADsOpenObject() failed for IID_IDirectorySearch.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Attributes are one-level deep in the Schema container so only
|
|
// need to search one level.
|
|
//
|
|
SearchPrefs.dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
|
|
SearchPrefs.vValue.dwType = ADSTYPE_INTEGER;
|
|
SearchPrefs.vValue.Integer = ADS_SCOPE_ONELEVEL;
|
|
|
|
//
|
|
// Set the search preference.
|
|
//
|
|
if (FAILED(hr = pISchema->SetSearchPreference(&SearchPrefs, dwNumPrefs)))
|
|
{
|
|
DebugTrace("Error [%#x]: pISchema->SetSearchPreference() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Execute search.
|
|
//
|
|
if (FAILED(hr = pISchema->ExecuteSearch(pszFilter,
|
|
pszList,
|
|
sizeof(pszList) / sizeof(LPOLESTR),
|
|
&hSearch)))
|
|
{
|
|
DebugTrace("Error [%#x]: pISchema->ExecuteSearch() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Retrieve first row of data.
|
|
//
|
|
if (FAILED(hr = pISchema->GetFirstRow(hSearch)))
|
|
{
|
|
DebugTrace("Error [%#x]: pISchema->GetFirstRow() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Loop until no more row.
|
|
//
|
|
while (S_ADS_NOMORE_ROWS != hr)
|
|
{
|
|
ADS_SEARCH_COLUMN Column;
|
|
|
|
//
|
|
// Get the lDAPDisplayName column.
|
|
//
|
|
if (FAILED(hr = pISchema->GetColumn(hSearch,
|
|
L"lDAPDisplayName",
|
|
&Column)))
|
|
{
|
|
|
|
DebugTrace("Error [%#x]: pISchema->GetColumn() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
DebugTrace("Info: %ls = %ls\n", Column.pszAttrName, Column.pADsValues->CaseIgnoreString);
|
|
|
|
//
|
|
// Is this attributeSchema for userCertificate?
|
|
//
|
|
if (0 == ::wcscmp(L"userCertificate", Column.pADsValues->CaseIgnoreString))
|
|
{
|
|
pISchema->FreeColumn(&Column);
|
|
|
|
//
|
|
// Get the isMemberOfPartialAttributeSet column.
|
|
//
|
|
if (FAILED(hr = pISchema->GetColumn(hSearch,
|
|
L"isMemberOfPartialAttributeSet",
|
|
&Column)))
|
|
{
|
|
|
|
DebugTrace("Error [%#x]: pISchema->GetColumn() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
bResult = Column.pADsValues->Boolean;
|
|
|
|
//
|
|
// Should only have one row, so we don't really have to
|
|
// break here, but is a little more effiecit to break,
|
|
// since we don't need to ask for the next row to terminate
|
|
// the loop.
|
|
//
|
|
pISchema->FreeColumn(&Column);
|
|
|
|
break;
|
|
}
|
|
|
|
pISchema->FreeColumn(&Column);
|
|
|
|
//
|
|
// Get next row.
|
|
//
|
|
hr = pISchema->GetNextRow(hSearch);
|
|
}
|
|
|
|
//
|
|
// Reset hr.
|
|
//
|
|
hr = S_OK;
|
|
|
|
//
|
|
// Return result to caller.
|
|
//
|
|
*pbResult = bResult;
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (hSearch)
|
|
{
|
|
pISchema->CloseSearchHandle(hSearch);
|
|
}
|
|
|
|
if (pISchema)
|
|
{
|
|
pISchema->Release();
|
|
}
|
|
if (pIADs)
|
|
{
|
|
pIADs->Release();
|
|
}
|
|
|
|
DebugTrace("Leaving IsUserCertificateInGC().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : BuildRootDSESearch
|
|
|
|
Synopsis : Build a search container of the rootDSE.
|
|
|
|
Parameter: HMODULE hDLL - ActiveDS.DLL handle.
|
|
|
|
IDirectorySearch ** ppISearch - To receive container to search.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static HRESULT BuildRootDSESearch (HMODULE hDLL,
|
|
IDirectorySearch ** ppISearch)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IADs * pIADs = NULL;
|
|
CComBSTR bstrPath;
|
|
CComBSTR bstrDefault;
|
|
PADSOPENOBJECT pADsOpenObject;
|
|
CComVariant var;
|
|
|
|
DebugTrace("Entering BuildRootDSESearch().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(hDLL);
|
|
ATLASSERT(ppISearch);
|
|
|
|
//
|
|
// Initialize.
|
|
//
|
|
if (!(bstrPath = L"LDAP://") || !(bstrDefault = L"defaultNamingContext"))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: bstrPath = L\"LDAP://\" || bstrDefault = L\"defaultNamingContext\" failed.", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get ADsOpenObject address pointer.
|
|
//
|
|
if (!(pADsOpenObject = (PADSOPENOBJECT) ::GetProcAddress(hDLL, "ADsOpenObject")))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: GetProcAddress() failed to load ADsOpenObject().\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get rootDSE.
|
|
//
|
|
if (FAILED(hr = pADsOpenObject(L"LDAP://rootDSE",
|
|
NULL,
|
|
NULL,
|
|
ADS_SECURE_AUTHENTICATION,
|
|
IID_IADs,
|
|
(void **) &pIADs)))
|
|
{
|
|
DebugTrace("Error [%#x]: ADsOpenObject() failed for IID_IADs.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get current user's domain container DN.
|
|
//
|
|
if (FAILED(hr = pIADs->Get(bstrDefault, &var)))
|
|
{
|
|
DebugTrace("Error [%#x]: pIADs->Get() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Build path to the domain container.
|
|
//
|
|
if (FAILED(hr = bstrPath.AppendBSTR(var.bstrVal)))
|
|
{
|
|
DebugTrace("Error [%#x]: bstrPath.AppendBSTR(var.bstrVal) failed.", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Get IDerictorySearch interface pointer.
|
|
//
|
|
if (FAILED(hr = pADsOpenObject(bstrPath,
|
|
NULL,
|
|
NULL,
|
|
ADS_SECURE_AUTHENTICATION,
|
|
IID_IDirectorySearch,
|
|
(void **) ppISearch)))
|
|
{
|
|
DebugTrace("Error [%#x]: ADsOpenObject() failed for IID_IDirectorySearch.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (pIADs)
|
|
{
|
|
pIADs->Release();
|
|
}
|
|
|
|
DebugTrace("Leaving BuildRootDSESearch().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : BuildGlobalCatalogSearch
|
|
|
|
Synopsis : Build a search container of the GC.
|
|
|
|
Parameter: HMODULE hDLL - ActiveDS.DLL handle.
|
|
|
|
IDirectorySearch ** ppISearch - To receive container to search.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static HRESULT BuildGlobalCatalogSearch (HMODULE hDLL,
|
|
IDirectorySearch ** ppISearch)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IEnumVARIANT * pIEnum = NULL;
|
|
IADsContainer * pIContainer = NULL;
|
|
IDispatch * pIDispatch = NULL;
|
|
ULONG lFetched = 0;
|
|
|
|
PADSOPENOBJECT pADsOpenObject = NULL;
|
|
PADSBUILDENUMERATOR pADsBuildEnumerator = NULL;
|
|
PADSENUMERATENEXT pADsEnumerateNext = NULL;
|
|
PADSFREEENUMERATOR pADsFreeEnumerator = NULL;
|
|
CComVariant var;
|
|
|
|
DebugTrace("Entering BuildGlobalCatalogSearch().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(hDLL);
|
|
ATLASSERT(ppISearch);
|
|
|
|
//
|
|
// Initialize.
|
|
//
|
|
*ppISearch = NULL;
|
|
|
|
//
|
|
// Get ADs function address pointers.
|
|
//
|
|
if (!(pADsOpenObject = (PADSOPENOBJECT) ::GetProcAddress(hDLL, "ADsOpenObject")))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: GetProcAddress() failed to load ADsOpenObject().\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
if (!(pADsBuildEnumerator = (PADSBUILDENUMERATOR) ::GetProcAddress(hDLL, "ADsBuildEnumerator")))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: GetProcAddress() failed to load ADsBuildEnumerator().\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
if (!(pADsEnumerateNext = (PADSENUMERATENEXT) ::GetProcAddress(hDLL, "ADsEnumerateNext")))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: GetProcAddress() failed to load ADsEnumerateNext().\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
if (!(pADsFreeEnumerator = (PADSFREEENUMERATOR) ::GetProcAddress(hDLL, "ADsFreeEnumerator")))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
DebugTrace("Error [%#x]: GetProcAddress() failed to load ADsFreeEnumerator().\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// First, bind to the GC: namespace container object. The "real" GC DN
|
|
// is a single immediate child of the GC: namespace, which must be
|
|
// obtained using enumeration.
|
|
//
|
|
if (FAILED(hr = pADsOpenObject(L"GC:",
|
|
NULL,
|
|
NULL,
|
|
ADS_SECURE_AUTHENTICATION,
|
|
IID_IADsContainer,
|
|
(void **) &pIContainer)))
|
|
{
|
|
DebugTrace("Error [%#x]: ADsOpenObject() failed for IID_IADsContainer.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Fetch an enumeration interface for the GC container.
|
|
//
|
|
if (FAILED(hr = pADsBuildEnumerator(pIContainer, &pIEnum)))
|
|
{
|
|
DebugTrace("Error [%#x]: ADsBuildEnumerator() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Now enumerate.
|
|
//
|
|
if (FAILED(hr = pADsEnumerateNext(pIEnum, 1, &var, &lFetched)))
|
|
{
|
|
DebugTrace("Error [%#x]: ADsEnumerateNext() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// There should only be one child in the GC object.
|
|
//
|
|
if (1 != lFetched)
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
|
|
DebugTrace("Error [%#x]: ADsEnumerateNext() returns lFetched = %d, which is not 1.\n", hr, lFetched);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Obtain the IDispatch pointer.
|
|
//
|
|
pIDispatch = V_DISPATCH(&var);
|
|
|
|
//
|
|
// Return IDirectorySearch interface pointer to caller.
|
|
//
|
|
if (FAILED(hr = pIDispatch->QueryInterface(IID_IDirectorySearch,
|
|
(void **) ppISearch)))
|
|
{
|
|
DebugTrace("Error [%#x]: pIDispatch->QueryInterface() failed for IID_IDirectorySearch.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (pIEnum)
|
|
{
|
|
pADsFreeEnumerator(pIEnum);
|
|
}
|
|
if (pIContainer)
|
|
{
|
|
pIContainer->Release();
|
|
}
|
|
|
|
DebugTrace("Leaving BuildGlobalCatalogSearch().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : BuildADSearch
|
|
|
|
Synopsis : Build a search container. We will first check to see if the
|
|
userCertificate attribute is replicated in the global catalog.
|
|
If so, we will bind the search to the GC, otherwise, will bind
|
|
to default domain.
|
|
|
|
Parameter: IDirectorySearch ** ppISearch - To receive container to search.
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static HRESULT BuildADSearch (IDirectorySearch ** ppISearch)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL bResult = FALSE;
|
|
HMODULE hDLL = NULL;
|
|
CAPICOM_ACTIVE_DIRECTORY_SEARCH_LOCATION SearchLocation = ActiveDirectorySearchLocation();
|
|
|
|
DebugTrace("Entering BuildADSearch().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(ppISearch);
|
|
|
|
//
|
|
// Initialize.
|
|
//
|
|
*ppISearch = NULL;
|
|
|
|
//
|
|
// Load ActiveDS.DLL.
|
|
//
|
|
if (!(hDLL = ::LoadLibrary("ActiveDS.DLL")))
|
|
{
|
|
hr = CAPICOM_E_NOT_SUPPORTED;
|
|
|
|
DebugTrace("Error: DSClient not installed.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Did user specify a search location?
|
|
//
|
|
if (CAPICOM_SEARCH_ANY == SearchLocation)
|
|
{
|
|
//
|
|
// No, so determine if userCerticate is replicated in the GC.
|
|
//
|
|
if (FAILED(hr = ::IsUserCertificateInGC(hDLL, &bResult)))
|
|
{
|
|
DebugTrace("Error [%#x]: IsUserCertificateInGC() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Search GC or default domain.
|
|
//
|
|
SearchLocation = bResult ? CAPICOM_SEARCH_GLOBAL_CATALOG : CAPICOM_SEARCH_DEFAULT_DOMAIN;
|
|
}
|
|
|
|
//
|
|
// Check to see where to search.
|
|
//
|
|
if (CAPICOM_SEARCH_GLOBAL_CATALOG == SearchLocation)
|
|
{
|
|
//
|
|
// GC.
|
|
//
|
|
hr = ::BuildGlobalCatalogSearch(hDLL, ppISearch);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// rootDSE (default domain).
|
|
//
|
|
hr = ::BuildRootDSESearch(hDLL, ppISearch);
|
|
}
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (hDLL)
|
|
{
|
|
::FreeLibrary(hDLL);
|
|
}
|
|
|
|
DebugTrace("Leaving BuildADSearch().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : LoadUserCertificates
|
|
|
|
Synopsis : Load all certificates from the userCertificate attribute of the
|
|
specified search container for users specified through the filter.
|
|
|
|
Parameter: HCERTSTORE hCertStore - Certificate store handle of store to
|
|
receive all the certificates.
|
|
|
|
IDirectorySearch * pIContainer - Container to search.
|
|
|
|
BSTR bstrFilter - Filter (See Store::Open() for more info).
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static HRESULT LoadUserCertificates (HCERTSTORE hCertStore,
|
|
IDirectorySearch * pIContainer,
|
|
LPOLESTR pszFilter)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ADS_SEARCH_HANDLE hSearch = NULL;
|
|
LPOLESTR pszSearchList[] = {L"userCertificate"};
|
|
CComBSTR bstrSearchFilter;
|
|
ADS_SEARCHPREF_INFO SearchPrefs;
|
|
|
|
DebugTrace("Entering LoadUserCertificates().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(hCertStore);
|
|
ATLASSERT(pIContainer);
|
|
ATLASSERT(pszFilter);
|
|
|
|
try
|
|
{
|
|
//
|
|
// Initialize.
|
|
//
|
|
if (!(bstrSearchFilter = L"(&(objectClass=user)(objectCategory=person)"))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: bstrSearchFilter = L\"(&(objectClass=user)(objectCategory=person)\" failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
if (!(bstrSearchFilter += pszFilter))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: bstrSearchFilter += pszFilter failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
if (!(bstrSearchFilter += L")"))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
DebugTrace("Error [%#x]: bstrSearchFilter += L\")\" failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Specify subtree search.
|
|
//
|
|
SearchPrefs.dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
|
|
SearchPrefs.vValue.dwType = ADSTYPE_INTEGER;
|
|
SearchPrefs.vValue.Integer = ADS_SCOPE_SUBTREE;
|
|
|
|
//
|
|
// Set the search preference.
|
|
//
|
|
if (FAILED(hr = pIContainer->SetSearchPreference(&SearchPrefs, 1)))
|
|
{
|
|
DebugTrace("Error [%#x]: pIContainer->SetSearchPreference() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Execute the search.
|
|
//
|
|
if (FAILED(hr = pIContainer->ExecuteSearch(bstrSearchFilter,
|
|
pszSearchList,
|
|
sizeof(pszSearchList)/sizeof(LPOLESTR),
|
|
&hSearch)))
|
|
{
|
|
DebugTrace("Error [%#x]: pIContainer->ExecuteSearch() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Retrieve first row of data.
|
|
//
|
|
if (FAILED(hr = pIContainer->GetFirstRow(hSearch)))
|
|
{
|
|
DebugTrace("Error [%#x]: pIContainer->GetFirstRow() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Loop until no more row.
|
|
//
|
|
while (S_ADS_NOMORE_ROWS != hr)
|
|
{
|
|
DWORD dwValue;
|
|
ADS_SEARCH_COLUMN Column;
|
|
|
|
//
|
|
// Try to get the userCertificate attribute.
|
|
//
|
|
if (FAILED(hr = pIContainer->GetColumn(hSearch, L"userCertificate", &Column)))
|
|
{
|
|
if (E_ADS_COLUMN_NOT_SET == hr)
|
|
{
|
|
//
|
|
// Get next row.
|
|
//
|
|
hr = pIContainer->GetNextRow(hSearch);
|
|
continue;
|
|
}
|
|
|
|
DebugTrace("Error [%#x]: pIContainer->GetColumn() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Import all the certificate values.
|
|
//
|
|
for (dwValue = 0; dwValue < Column.dwNumValues; dwValue++)
|
|
{
|
|
if (!::CertAddEncodedCertificateToStore(hCertStore,
|
|
CAPICOM_ASN_ENCODING,
|
|
(const PBYTE) Column.pADsValues[dwValue].OctetString.lpValue,
|
|
Column.pADsValues[dwValue].OctetString.dwLength,
|
|
CERT_STORE_ADD_USE_EXISTING,
|
|
NULL))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
|
|
pIContainer->FreeColumn(&Column);
|
|
|
|
DebugTrace("Error [%#x]: CertAddEncodedCertificateToStore() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
pIContainer->FreeColumn(&Column);
|
|
|
|
//
|
|
// Get next row.
|
|
//
|
|
hr = pIContainer->GetNextRow(hSearch);
|
|
}
|
|
|
|
//
|
|
// Reset return code.
|
|
//
|
|
hr = S_OK;
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
DebugTrace("Exception: invalid parameter.\n");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (hSearch)
|
|
{
|
|
pIContainer->CloseSearchHandle(hSearch);
|
|
}
|
|
|
|
DebugTrace("Leaving LoadUserCertificates().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Exported functions.
|
|
//
|
|
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Function : LoadFromDirectory
|
|
|
|
Synopsis : Load all certificates from the userCertificate attribute of users
|
|
specified through the filter.
|
|
|
|
Parameter: HCERTSTORE hCertStore - Certificate store handle of store to
|
|
receive all the certificates.
|
|
|
|
BSTR bstrFilter - Filter (See Store::Open() for more info).
|
|
|
|
Remark :
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
HRESULT LoadFromDirectory (HCERTSTORE hCertStore,
|
|
BSTR bstrFilter)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IDirectorySearch * pIContainerToSearch = NULL;
|
|
|
|
DebugTrace("Entering LoadFromDirectory().\n");
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(bstrFilter);
|
|
ATLASSERT(hCertStore);
|
|
|
|
//
|
|
// Build the AD search container.
|
|
//
|
|
if (FAILED(hr = ::BuildADSearch(&pIContainerToSearch)))
|
|
{
|
|
DebugTrace("Error [%#x]: BuildADSearch() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Load all userCertificate of the specified filter.
|
|
//
|
|
if (FAILED(hr = ::LoadUserCertificates(hCertStore,
|
|
pIContainerToSearch,
|
|
bstrFilter)))
|
|
{
|
|
DebugTrace("Error [%#x]: LoadUserCertificates() failed.\n", hr);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
CommonExit:
|
|
//
|
|
// Free resource.
|
|
//
|
|
if (pIContainerToSearch)
|
|
{
|
|
pIContainerToSearch->Release();
|
|
}
|
|
|
|
DebugTrace("Leaving LoadFromDirectory().\n");
|
|
|
|
return hr;
|
|
|
|
ErrorExit:
|
|
//
|
|
// Sanity check.
|
|
//
|
|
ATLASSERT(FAILED(hr));
|
|
|
|
goto CommonExit;
|
|
}
|