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.
730 lines
17 KiB
730 lines
17 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1993.
|
|
//
|
|
// File: libmain.cxx
|
|
//
|
|
// Contents: LibMain for ADs.dll
|
|
//
|
|
// Functions: LibMain, DllGetClassObject
|
|
//
|
|
// History: 25-Oct-94 KrishnaG Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "ldap.hxx"
|
|
#pragma hdrstop
|
|
|
|
|
|
LPCWSTR lpszTopLevel = L"SOFTWARE\\Microsoft\\ADs\\Providers\\LDAP";
|
|
LPCWSTR lpszExtensions = L"Extensions";
|
|
|
|
PCLASS_ENTRY gpClassHead = NULL;
|
|
|
|
|
|
PCLASS_ENTRY
|
|
BuildClassesList()
|
|
{
|
|
HKEY hTopLevelKey = NULL;
|
|
HKEY hExtensionKey = NULL;
|
|
HKEY hExtensionRootKey = NULL;
|
|
|
|
HKEY hClassKey = NULL;
|
|
|
|
DWORD dwIndex = 0;
|
|
WCHAR lpszClassName[MAX_PATH];
|
|
DWORD dwchClassName = 0;
|
|
PCLASS_ENTRY pClassHead = NULL;
|
|
PCLASS_ENTRY pClassEntry = NULL;
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
lpszTopLevel,
|
|
0,
|
|
KEY_READ,
|
|
&hTopLevelKey
|
|
) != ERROR_SUCCESS)
|
|
{
|
|
goto CleanupAndExit;
|
|
}
|
|
|
|
if (RegOpenKeyEx(hTopLevelKey,
|
|
lpszExtensions,
|
|
0,
|
|
KEY_READ,
|
|
&hExtensionRootKey
|
|
) != ERROR_SUCCESS)
|
|
|
|
{
|
|
goto CleanupAndExit;
|
|
|
|
}
|
|
|
|
memset(lpszClassName, 0, sizeof(lpszClassName));
|
|
dwchClassName = sizeof(lpszClassName)/sizeof(WCHAR);
|
|
|
|
while(RegEnumKeyEx(hExtensionRootKey,
|
|
dwIndex,
|
|
lpszClassName,
|
|
&dwchClassName,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
) == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Read namespace
|
|
//
|
|
|
|
if (RegOpenKeyEx(hExtensionRootKey,
|
|
lpszClassName,
|
|
0,
|
|
KEY_READ,
|
|
&hClassKey
|
|
) != ERROR_SUCCESS){
|
|
goto CleanupAndExit;
|
|
}
|
|
|
|
pClassEntry = BuildClassEntry(
|
|
lpszClassName,
|
|
hClassKey
|
|
);
|
|
|
|
if (pClassEntry) {
|
|
|
|
pClassEntry->pNext = pClassHead;
|
|
pClassHead = pClassEntry;
|
|
}
|
|
|
|
if (hClassKey) {
|
|
CloseHandle(hClassKey);
|
|
}
|
|
|
|
memset(lpszClassName, 0, sizeof(lpszClassName));
|
|
dwchClassName = sizeof(lpszClassName)/sizeof(WCHAR);
|
|
dwIndex++;
|
|
}
|
|
|
|
CleanupAndExit:
|
|
|
|
if (hExtensionRootKey) {
|
|
RegCloseKey(hExtensionRootKey);
|
|
}
|
|
|
|
if (hTopLevelKey) {
|
|
RegCloseKey(hTopLevelKey);
|
|
}
|
|
|
|
return(pClassHead);
|
|
}
|
|
|
|
|
|
VOID
|
|
FreeClassesList(
|
|
PCLASS_ENTRY pClassHead
|
|
)
|
|
{
|
|
PCLASS_ENTRY pDelete;
|
|
|
|
while (pClassHead) {
|
|
|
|
pDelete = pClassHead;
|
|
pClassHead = pClassHead->pNext;
|
|
|
|
FreeClassEntry(pDelete);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
PCLASS_ENTRY
|
|
BuildClassEntry(
|
|
LPWSTR lpszClassName,
|
|
HKEY hClassKey
|
|
)
|
|
{
|
|
HKEY hTopLevelKey = NULL;
|
|
HKEY hExtensionKey = NULL;
|
|
|
|
DWORD dwIndex = 0;
|
|
DWORD dwchExtensionCLSID = 0;
|
|
WCHAR lpszExtensionCLSID[MAX_PATH];
|
|
PCLASS_ENTRY pClassEntry = NULL;
|
|
PEXTENSION_ENTRY pExtensionHead = NULL;
|
|
PEXTENSION_ENTRY pExtensionEntry = NULL;
|
|
|
|
pClassEntry = (PCLASS_ENTRY)AllocADsMem(sizeof(CLASS_ENTRY));
|
|
|
|
if (!pClassEntry) {
|
|
|
|
goto CleanupAndExit;
|
|
}
|
|
|
|
wcscpy(pClassEntry->szClassName, lpszClassName);
|
|
|
|
memset(lpszExtensionCLSID, 0, sizeof(lpszExtensionCLSID));
|
|
dwchExtensionCLSID = sizeof(lpszExtensionCLSID)/sizeof(WCHAR);
|
|
|
|
while(RegEnumKeyEx(hClassKey,
|
|
dwIndex,
|
|
lpszExtensionCLSID,
|
|
&dwchExtensionCLSID,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
) == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Read namespace
|
|
//
|
|
|
|
if (RegOpenKeyEx(hClassKey,
|
|
lpszExtensionCLSID,
|
|
0,
|
|
KEY_READ,
|
|
&hExtensionKey
|
|
) != ERROR_SUCCESS){
|
|
goto CleanupAndExit;
|
|
}
|
|
|
|
//
|
|
// Read the Interfaces that this Extension supports
|
|
//
|
|
|
|
pExtensionEntry = BuildExtensionEntry(
|
|
lpszExtensionCLSID,
|
|
hExtensionKey
|
|
);
|
|
|
|
if (pExtensionEntry) {
|
|
|
|
wcscpy(pExtensionEntry->szExtensionCLSID, lpszExtensionCLSID);
|
|
|
|
pExtensionEntry->pNext = pExtensionHead;
|
|
pExtensionHead = pExtensionEntry;
|
|
}
|
|
|
|
|
|
if (hExtensionKey) {
|
|
|
|
CloseHandle(hExtensionKey);
|
|
}
|
|
|
|
memset(lpszExtensionCLSID, 0, sizeof(lpszExtensionCLSID));
|
|
dwchExtensionCLSID = sizeof(lpszExtensionCLSID)/sizeof(WCHAR);
|
|
dwIndex++;
|
|
|
|
}
|
|
|
|
CleanupAndExit:
|
|
|
|
if (pExtensionHead)
|
|
{
|
|
pClassEntry->pExtensionHead = pExtensionHead;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// There are no values under the key
|
|
//
|
|
if(pClassEntry)
|
|
{
|
|
FreeADsMem(pClassEntry);
|
|
pClassEntry = NULL;
|
|
}
|
|
}
|
|
|
|
return(pClassEntry);
|
|
}
|
|
|
|
|
|
PEXTENSION_ENTRY
|
|
BuildExtensionEntry(
|
|
LPWSTR lpszExtensionCLSID,
|
|
HKEY hExtensionKey
|
|
)
|
|
{
|
|
PEXTENSION_ENTRY pExtensionEntry = NULL;
|
|
PINTERFACE_ENTRY pInterfaceEntry = NULL;
|
|
PINTERFACE_ENTRY pInterfaceHead = NULL;
|
|
WCHAR lpszInterfaces[MAX_PATH];
|
|
DWORD dwchInterfaces = 0;
|
|
LPWSTR psz = NULL;
|
|
WCHAR Interface[MAX_PATH];
|
|
HRESULT hr = S_OK;
|
|
DWORD dwStatus = NO_ERROR;
|
|
|
|
|
|
pExtensionEntry = (PEXTENSION_ENTRY)AllocADsMem(sizeof(EXTENSION_ENTRY));
|
|
|
|
if (!pExtensionEntry) {
|
|
|
|
goto CleanupAndExit;
|
|
}
|
|
|
|
memset(lpszInterfaces, 0, sizeof(lpszInterfaces));
|
|
dwchInterfaces = sizeof(lpszInterfaces);
|
|
|
|
dwStatus = RegQueryValueEx(
|
|
hExtensionKey,
|
|
L"Interfaces",
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE) lpszInterfaces,
|
|
&dwchInterfaces
|
|
);
|
|
|
|
if(dwStatus)
|
|
{
|
|
// we should bail here
|
|
goto CleanupAndExit;
|
|
}
|
|
|
|
psz = lpszInterfaces;
|
|
|
|
while (psz && *psz) {
|
|
|
|
wcscpy(Interface, psz);
|
|
|
|
// skip (length) + 1
|
|
// lstrlen returns length sans '\0'
|
|
|
|
|
|
pInterfaceEntry = (PINTERFACE_ENTRY)AllocADsMem(sizeof(INTERFACE_ENTRY));
|
|
|
|
if (pInterfaceEntry) {
|
|
|
|
wcscpy(pInterfaceEntry->szInterfaceIID, Interface);
|
|
hr = IIDFromString(Interface, &(pInterfaceEntry->iid));
|
|
|
|
pInterfaceEntry->pNext = pInterfaceHead;
|
|
pInterfaceHead = pInterfaceEntry;
|
|
|
|
}
|
|
|
|
psz = psz + lstrlen(psz) + 1;
|
|
|
|
}
|
|
|
|
wcscpy(pExtensionEntry->szExtensionCLSID, lpszExtensionCLSID);
|
|
hr = CLSIDFromString(lpszExtensionCLSID, &(pExtensionEntry->ExtCLSID));
|
|
if(FAILED(hr))
|
|
{
|
|
// we should bail out since ExtCLSID is the one we use to cocreate the extensions
|
|
goto CleanupAndExit;
|
|
}
|
|
|
|
pExtensionEntry->pIID = pInterfaceHead;
|
|
|
|
return pExtensionEntry;
|
|
|
|
CleanupAndExit:
|
|
|
|
pInterfaceEntry = pInterfaceHead;
|
|
|
|
while(pInterfaceEntry)
|
|
{
|
|
pInterfaceHead = pInterfaceHead->pNext;
|
|
FreeADsMem(pInterfaceEntry);
|
|
|
|
pInterfaceEntry = pInterfaceHead;
|
|
|
|
}
|
|
|
|
if(pExtensionEntry)
|
|
{
|
|
FreeADsMem(pExtensionEntry);
|
|
pExtensionEntry = NULL;
|
|
}
|
|
|
|
return(pExtensionEntry);
|
|
}
|
|
|
|
|
|
void
|
|
FreeInterfaceEntry(
|
|
PINTERFACE_ENTRY pInterfaceEntry
|
|
)
|
|
{
|
|
if (pInterfaceEntry) {
|
|
|
|
FreeADsMem(pInterfaceEntry);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
FreeExtensionEntry(
|
|
PEXTENSION_ENTRY pExtensionEntry
|
|
)
|
|
{
|
|
PINTERFACE_ENTRY pInterfaceEntry = NULL;
|
|
PINTERFACE_ENTRY pTemp = NULL;
|
|
|
|
if (pExtensionEntry) {
|
|
|
|
pInterfaceEntry = pExtensionEntry->pIID;
|
|
|
|
while (pInterfaceEntry) {
|
|
|
|
pTemp = pInterfaceEntry->pNext;
|
|
|
|
if (pInterfaceEntry) {
|
|
|
|
FreeInterfaceEntry(pInterfaceEntry);
|
|
}
|
|
|
|
pInterfaceEntry = pTemp;
|
|
|
|
}
|
|
|
|
//
|
|
// Now unload the Extension Object
|
|
//
|
|
|
|
if (pExtensionEntry->pUnknown) {
|
|
|
|
//
|
|
// Call non-delegating Release to release ref. count on innner
|
|
// object to inner object -> inner object self destroyed.
|
|
//
|
|
(pExtensionEntry->pUnknown)->Release();
|
|
|
|
}
|
|
|
|
|
|
FreeADsMem(pExtensionEntry);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
FreeClassEntry(
|
|
PCLASS_ENTRY pClassEntry
|
|
)
|
|
{
|
|
|
|
PEXTENSION_ENTRY pExtensionEntry = NULL;
|
|
PEXTENSION_ENTRY pTemp = NULL;
|
|
|
|
if (pClassEntry) {
|
|
|
|
pExtensionEntry = pClassEntry->pExtensionHead;
|
|
|
|
while (pExtensionEntry) {
|
|
|
|
pTemp = pExtensionEntry->pNext;
|
|
|
|
if (pExtensionEntry) {
|
|
|
|
FreeExtensionEntry(pExtensionEntry);
|
|
}
|
|
|
|
pExtensionEntry = pTemp;
|
|
|
|
}
|
|
|
|
FreeADsMem(pClassEntry);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
PINTERFACE_ENTRY
|
|
MakeCopyofInterfaceEntry(
|
|
PINTERFACE_ENTRY pInterfaceEntry
|
|
)
|
|
{
|
|
PINTERFACE_ENTRY pNewInterfaceEntry = NULL;
|
|
|
|
pNewInterfaceEntry = (PINTERFACE_ENTRY)AllocADsMem(sizeof(INTERFACE_ENTRY));
|
|
|
|
if (pNewInterfaceEntry) {
|
|
|
|
wcscpy(pNewInterfaceEntry->szInterfaceIID, pInterfaceEntry->szInterfaceIID);
|
|
memcpy(&(pNewInterfaceEntry->iid), &(pInterfaceEntry->iid), sizeof(GUID));
|
|
}
|
|
|
|
return(pNewInterfaceEntry);
|
|
}
|
|
|
|
|
|
|
|
PEXTENSION_ENTRY
|
|
MakeCopyofExtensionEntry(
|
|
PEXTENSION_ENTRY pExtensionEntry
|
|
)
|
|
{
|
|
PEXTENSION_ENTRY pNewExtensionEntry = NULL;
|
|
|
|
PINTERFACE_ENTRY pInterfaceEntry = NULL;
|
|
|
|
PINTERFACE_ENTRY pNewInterfaceEntry = NULL;
|
|
|
|
PINTERFACE_ENTRY pNewInterfaceHead = NULL;
|
|
|
|
|
|
pInterfaceEntry = pExtensionEntry->pIID;
|
|
|
|
while (pInterfaceEntry) {
|
|
|
|
pNewInterfaceEntry = MakeCopyofInterfaceEntry(pInterfaceEntry);
|
|
|
|
if (pNewInterfaceEntry) {
|
|
|
|
pNewInterfaceEntry->pNext = pNewInterfaceHead;
|
|
pNewInterfaceHead = pNewInterfaceEntry;
|
|
}
|
|
|
|
pInterfaceEntry = pInterfaceEntry->pNext;
|
|
|
|
}
|
|
|
|
pNewExtensionEntry = (PEXTENSION_ENTRY)AllocADsMem(sizeof(EXTENSION_ENTRY));
|
|
|
|
if (pNewExtensionEntry) {
|
|
|
|
wcscpy(
|
|
pNewExtensionEntry->szExtensionCLSID,
|
|
pExtensionEntry->szExtensionCLSID
|
|
);
|
|
|
|
memcpy(
|
|
&(pNewExtensionEntry->ExtCLSID),
|
|
&(pExtensionEntry->ExtCLSID),
|
|
sizeof(GUID)
|
|
);
|
|
|
|
pNewExtensionEntry->pIID = pNewInterfaceHead;
|
|
|
|
|
|
//
|
|
// Initialize fields we won't know the values of until an instacne of
|
|
// the extension is created and aggregated (loaded).
|
|
//
|
|
|
|
pNewExtensionEntry->pUnknown=NULL;
|
|
pNewExtensionEntry->pPrivDisp=NULL;
|
|
pNewExtensionEntry->pADsExt=NULL;
|
|
pNewExtensionEntry->fDisp=FALSE;
|
|
pNewExtensionEntry->dwExtensionID = (DWORD) -1; //invalid dwExtensionID
|
|
|
|
//
|
|
// let class entry handle pNext
|
|
//
|
|
}
|
|
else
|
|
{
|
|
// clear out the memory of interface entries
|
|
pInterfaceEntry = pNewInterfaceHead;
|
|
|
|
while (pInterfaceEntry) {
|
|
|
|
pNewInterfaceHead = pNewInterfaceHead->pNext;
|
|
|
|
FreeADsMem(pInterfaceEntry);
|
|
|
|
pInterfaceEntry = pNewInterfaceHead;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return(pNewExtensionEntry);
|
|
}
|
|
|
|
|
|
PCLASS_ENTRY
|
|
MakeCopyofClassEntry(
|
|
PCLASS_ENTRY pClassEntry
|
|
)
|
|
{
|
|
PCLASS_ENTRY pNewClassEntry = NULL;
|
|
|
|
PEXTENSION_ENTRY pExtensionEntry = NULL;
|
|
|
|
PEXTENSION_ENTRY pNewExtensionEntry = NULL;
|
|
|
|
PEXTENSION_ENTRY pNewExtensionHead = NULL;
|
|
|
|
|
|
pExtensionEntry = pClassEntry->pExtensionHead;
|
|
|
|
while (pExtensionEntry) {
|
|
|
|
pNewExtensionEntry = MakeCopyofExtensionEntry(pExtensionEntry);
|
|
|
|
if (pNewExtensionEntry) {
|
|
|
|
pNewExtensionEntry->pNext = pNewExtensionHead;
|
|
pNewExtensionHead = pNewExtensionEntry;
|
|
}
|
|
|
|
pExtensionEntry = pExtensionEntry->pNext;
|
|
|
|
}
|
|
|
|
pNewClassEntry = (PCLASS_ENTRY)AllocADsMem(sizeof(CLASS_ENTRY));
|
|
|
|
if (pNewClassEntry) {
|
|
|
|
wcscpy(pNewClassEntry->szClassName, pClassEntry->szClassName);
|
|
|
|
pNewClassEntry->pExtensionHead = pNewExtensionHead;
|
|
|
|
}
|
|
else
|
|
{
|
|
// clear the memory of extension entries
|
|
pExtensionEntry = pNewExtensionHead;
|
|
|
|
while(pExtensionEntry)
|
|
{
|
|
pNewExtensionHead = pNewExtensionHead->pNext;
|
|
FreeExtensionEntry(pExtensionEntry);
|
|
|
|
pExtensionEntry = pNewExtensionHead;
|
|
}
|
|
}
|
|
|
|
return(pNewClassEntry);
|
|
}
|
|
|
|
|
|
CRITICAL_SECTION g_ExtCritSect;
|
|
|
|
#define ENTER_EXTENSION_CRITSECT() EnterCriticalSection(&g_ExtCritSect)
|
|
#define LEAVE_EXTENSION_CRITSECT() LeaveCriticalSection(&g_ExtCritSect)
|
|
|
|
HRESULT
|
|
ADSIGetExtensionList(
|
|
LPWSTR pszClassName,
|
|
PCLASS_ENTRY * ppClassEntry
|
|
)
|
|
{
|
|
|
|
PCLASS_ENTRY pTempClassEntry = NULL;
|
|
PCLASS_ENTRY pClassEntry = NULL;
|
|
ENTER_EXTENSION_CRITSECT();
|
|
|
|
//
|
|
// Initialize global extensions list if not already
|
|
// initialized. Note that this takes place inside the
|
|
// g_ExtCritSect to protect against multiple threads trying
|
|
// to simultaneously initialize it.
|
|
//
|
|
if (!gpClassHead) {
|
|
gpClassHead = BuildClassesList();
|
|
}
|
|
|
|
pTempClassEntry = gpClassHead;
|
|
|
|
while (pTempClassEntry) {
|
|
|
|
|
|
if (!_wcsicmp(pTempClassEntry->szClassName, pszClassName)) {
|
|
|
|
//
|
|
// Make a copy of this entire extension and
|
|
// hand it over to the calling entity.
|
|
//
|
|
|
|
pClassEntry = MakeCopyofClassEntry(pTempClassEntry);
|
|
|
|
*ppClassEntry = pClassEntry;
|
|
|
|
LEAVE_EXTENSION_CRITSECT();
|
|
|
|
RRETURN(S_OK);
|
|
|
|
}
|
|
|
|
pTempClassEntry = pTempClassEntry->pNext;
|
|
|
|
}
|
|
|
|
|
|
*ppClassEntry = NULL;
|
|
|
|
LEAVE_EXTENSION_CRITSECT();
|
|
|
|
RRETURN(S_OK);
|
|
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: ADSIAppendToExntesionList
|
|
//
|
|
// Synopsis: Adds to the end of the current class entry,
|
|
// the extensions of the class pszClassName. This is
|
|
// used in scenarios as follows - suppose fooUser
|
|
// is derived from User, then we want to load the extensions
|
|
// defined for User too apart from the extensions available
|
|
// directly on fooUser.
|
|
//
|
|
// The first cut is not going to see if the class is already
|
|
// there in the list. This optimization can be done later if
|
|
// needed.
|
|
//
|
|
// Arguments: [pszClassName] -- name of class.
|
|
// [ppClassEntry] -- class entry returned
|
|
//
|
|
// The class entry will be modified only if there were no
|
|
// entries, if not we will append the new entry at the end.
|
|
// AjayR 11-17-98 (added)
|
|
//-------------------------------------------------------------------------
|
|
HRESULT
|
|
ADSIAppendToExtensionList(
|
|
LPWSTR pszClassName,
|
|
PCLASS_ENTRY * ppClassEntry
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PEXTENSION_ENTRY pLocalExtEntry = NULL;
|
|
PCLASS_ENTRY pLocClassEntry = NULL;
|
|
|
|
|
|
//
|
|
// Check if there are no extensions on the list
|
|
//
|
|
if (!*ppClassEntry) {
|
|
RRETURN(ADSIGetExtensionList(pszClassName, ppClassEntry));
|
|
}
|
|
|
|
pLocalExtEntry = (*ppClassEntry)->pExtensionHead;
|
|
while(pLocalExtEntry->pNext) {
|
|
pLocalExtEntry = pLocalExtEntry->pNext;
|
|
}
|
|
|
|
//
|
|
// Now get the extension list for the current class
|
|
//
|
|
hr = ADSIGetExtensionList(pszClassName, &pLocClassEntry);
|
|
|
|
if (FAILED(hr)) {
|
|
//
|
|
// not a critical failure
|
|
//
|
|
hr = S_OK;
|
|
}
|
|
else {
|
|
//
|
|
// Add to the end of the current list.
|
|
//
|
|
if (pLocClassEntry) {
|
|
|
|
pLocalExtEntry->pNext = pLocClassEntry->pExtensionHead;
|
|
|
|
FreeADsMem((void*)pLocClassEntry);
|
|
}
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|