Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1781 lines
50 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
MPRINIT.CXX
Abstract:
Contains the DLL initialization routine for the Mutiple-Provider
Router. The following are names of functions in this file:
MprDllInit
MprCheckProviders
MprLevel1Init
MprLevel2Init
MprProcessDetach
GetProviderCapabilities
MprFreeGlobalProviderInfo
MprMakeServiceKeyName
MprGetOrderedList
MprGetNumProviders
MprExtractProviderInfo
The router distinguishes between Providers and ActiveProviders. It
maintains global information about GlobalNumProviders and
GlobalNumActiveProviders. The two counts can be distinguished in the
following ways:
GlobalNumProviders - This determines the size of the provider database
that mpr maintains. This count reflects the number of providers for
which we were able to obtain registry information. A provider is
added to the list if we are able to obtain its name and the
name of its dll routine.
GlobalNumActiveProviders - A provider becomes active when we are able
to successfully load the dll, and obtain at least one entry point
for it.
Author:
Dan Lafferty (danl) 6-Oct-1991
Environment:
User Mode - Win32
Notes:
Revision History:
05-May-1999 jschwart
Make provider addition/removal dynamic
09-Aug-1996 AnirudhS
Disabled thread library calls, since they cause extra paging and
are 100% useless. Fixed memory leak of error records on DLL unload.
02-Mar-1995 AnirudhS
Add test for WNNC_ENUM_CONTEXT capability.
09-Aug-1994 Danl
Only do PROCESS_DETACH cleanup work if the PROCESS_DETACH occurs
because of a FreeLibrary.
01-Mar-1994 Danl
Created a seperate location for the Credential Managers GetCaps()
function. This way if a provider has both a credential manager
dll and a network dll, we will be able to direct calls to the
correct GetCaps() function.
08-Apr-1993 Danl
MprLevel1Init: Created a tempOrderedString which will be used
for incrementing through the buffer. This way we can Free
orderedString because it still points to the beginning of the buffer.
24-Nov-1992 Danl
Modified many things to allow for initialization to occur on
first call rather than at DLL initialization time. Also coded
for the future possibility of Authentication Providers.
02-Nov-1992 Danl
Allow MPR to continue operation even if there are no providers, or
if the network is not installed and provider info is not available
in the registry. Removed MprHack.
31-Aug-1992 Danl
Removed use of the list of active providers. Now all providers
in the Provider Order list are loaded at init time.
06-Oct-1991 Danl
Created
--*/
//
// Includes
//
#include "precomp.hxx"
#include <debugfmt.h> // FORMAT_LPTSTR
#include "mprres.h" // IDS_NETROOT
#include "connify.h" // MprConnectNotifyInit()
//
// Local Function Prototypes
//
BOOL
MprProcessAttach(
HANDLE DllHandle
);
BOOL
MprProcessDetach(
DWORD dwInitLevel
);
BOOL
GetProviderCapabilities(
LPPROVIDER Provider
);
VOID
MprFreeGlobalProviderInfo(VOID);
BOOL
MprGetOrderedList(
HKEY ControlRootKey,
LPTSTR *OrderString
);
DWORD
MprMakeServiceKeyName(
IN OUT LPTSTR *OrderedNamePtr,
OUT LPTSTR *NameBufferPtr,
OUT LPTSTR *NamePtr
);
DWORD
MprGetNumProviders(
LPTSTR OrderedString
);
BOOL
MprExtractProviderInfo(
HKEY ProviderInfoKey,
LPPROVIDER Provider
);
BOOL
MprInitializeProviderGlobals(
VOID
);
BOOL
MprGetLUIDDeviceMapsEnabled(
PBOOL pResult
);
//
// Constants
//
#define TEMP_SIZE 256
//
// Some registry path names
//
#define PROVIDER_KEY_NAME TEXT("control\\NetworkProvider\\active")
#define PROVIDER_ORDER_KEY TEXT("control\\NetworkProvider\\HwOrder")
#define SERVICES_KEY_NAME TEXT("services\\")
#define SYSTEM_CONTROL_ROOT TEXT("system\\CurrentControlSet")
#define PROVIDER_PATH TEXT("\\NetworkProvider")
#define VALUE_PATHNAME TEXT("ProviderPath")
#define AUTHENT_PATHNAME TEXT("AuthentProviderPath")
#define VALUE_CLASS TEXT("Class")
//
// Defines for the DLL's init state
//
#define MPR_PROVIDERLOCK_CREATED 0x00000001
#define MPR_INITCRITSEC_CREATED 0x00000002
#define MPR_ERRORCRITSEC_CREATED 0x00000004
#define MPR_CACHE_CONSTRUCTED 0x00000008
//
// Global Data Structures
//
LPPROVIDER GlobalProviderInfo=NULL; // A pointer to array of PROVIDER Structures
DWORD GlobalNumProviders=0;
DWORD GlobalNumActiveProviders=0;
CRITICAL_SECTION MprInitCritSec;
HMODULE hDLL;
HANDLE g_hProvidersChanged; // Event set on provider addition/deletion
HKEY g_hProviderKey; // Registry key of the provider list
WCHAR g_wszEntireNetwork[40]; // "Entire Network" string for top-level enum
BOOL g_LUIDDeviceMapsEnabled=FALSE; // LUID device map enabled/disabled
//
// GlobalInitLevel is a set of bit flags used to indicate how much
// initialization work has been done.
//
volatile DWORD GlobalInitLevel = 0;
DWORD MprDebugLevel;
extern "C"
BOOL
MprDllInit(
IN HINSTANCE DllHandle,
IN DWORD Reason,
IN PCONTEXT pContext OPTIONAL
)
/*++
Routine Description:
This routine reads the registry to determine what network providers are
available. It then loads and initializes the Network Providers. After
this, a call is made to each of the providers to get a list of
Capabilities (via WNetGetCaps).
Arguments:
DllHandle - A handle for the DLL?
Reason - The reason for which this routine is being called. This might
be one of the following:
DLL_PROCESS_ATTACH
DLL_THREAD_ATTACH
DLL_THREAD_DETACH
DLL_PROCESS_DETACH
pContext - Pointer to a context structure
Return Value:
Note:
--*/
{
//
// We need to keep track of how far initialization went since
// we may get called with DLL_PROCESS_DETACH if init fails and
// don't want to clean up uninitialized data
//
static DWORD s_dwInitLevel;
NTSTATUS Status;
if (Reason == DLL_PROCESS_ATTACH) {
#if DBG == 1
//
// Read the debug message level from the registry
//
HKEY MprKey;
if (MprOpenKey(HKEY_LOCAL_MACHINE,
L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Mpr",
&MprKey,
0))
{
MprDebugLevel = (DWORD) MprGetKeyNumberValue(MprKey, L"DebugLevel", 0);
RegCloseKey(MprKey);
}
#endif
//
// create semaphore used to protect global data (DLL handles and
// function pointers.
//
if ((MprLoadLibSemaphore = CreateSemaphore( NULL,1,1,NULL )) == NULL)
{
MPR_LOG1(ERROR,
"MprDllInit: CreateSemaphore FAILED %d\n",
GetLastError());
return FALSE ;
}
if (!MprInitializeProviderGlobals())
{
return FALSE;
}
s_dwInitLevel |= MPR_PROVIDERLOCK_CREATED;
MPR_LOG2(PS,"Process %#lx (%ws) attached to the DLL\n",
GetCurrentProcessId(), GetCommandLineW());
//
// Save the DLL handle, to be used in LoadString
//
hDLL = DllHandle;
//
// Create the critical section to synchronize access to global
// data when doing init on first call.
//
Status = RtlInitializeCriticalSection(&MprInitCritSec);
if (!NT_SUCCESS(Status))
{
return FALSE;
}
s_dwInitLevel |= MPR_INITCRITSEC_CREATED;
//
// Initialize critical section that protects the Linked list of
// Error Records.
//
//
Status = RtlInitializeCriticalSection(&MprErrorRecCritSec);
if (!NT_SUCCESS(Status))
{
return FALSE;
}
s_dwInitLevel |= MPR_ERRORCRITSEC_CREATED;
CRoutedOperation::ConstructCache();
s_dwInitLevel |= MPR_CACHE_CONSTRUCTED;
DisableThreadLibraryCalls(DllHandle);
}
else if (Reason == DLL_PROCESS_DETACH) {
//
// Only do cleanup if detach was due to a FreeLibrary() call.
// In this case pContext will be NULL. Otherwise, this gets called
// because the process is terminating. We will let the process
// cleanup code clean up everything.
//
if (pContext == NULL) {
//
// close handle for semaphore
//
CloseHandle(MprLoadLibSemaphore) ;
MprLoadLibSemaphore = NULL ;
MPR_LOG(PS,"Process %#lx detached from the DLL\n",GetCurrentProcessId());
MPR_LOG(TRACE,"******************* CLEAN-UP ********************\n",0);
MprProcessDetach(s_dwInitLevel);
if (s_dwInitLevel & MPR_CACHE_CONSTRUCTED)
{
CRoutedOperation::DestroyCache();
}
MPR_LOG(TRACE,"***************** CLEAN_UP END ******************\n",0);
}
}
else if (Reason == DLL_THREAD_ATTACH) {
// This should never happen
MPR_LOG2(PS,"Thread %#lx.%#lx attached to the DLL\n",
GetCurrentProcessId(), GetCurrentThreadId());
}
else if (Reason == DLL_THREAD_DETACH) {
// This should never happen
MPR_LOG2(PS,"Thread %#lx.%#lx detached from the DLL\n",
GetCurrentProcessId(), GetCurrentThreadId());
}
return(TRUE);
}
BOOL
MprInitializeProviderGlobals(
VOID
)
{
g_hProvidersChanged = CreateEvent(NULL, // Default security
TRUE, // Manual reset
FALSE, // Starts out unsignaled
NULL); // No name
if (g_hProvidersChanged == NULL)
{
MPR_LOG1(ERROR,
"MprInitializeProviderGlobals: CreateEvent FAILED %d\n",
GetLastError());
return FALSE;
}
//
// NOTE: Key handle must be global since RegNotifyChangeKeyValue
// fires when the handle is closed (done in MprProcessDetach)
//
if (!MprOpenKey(HKEY_LOCAL_MACHINE,
SYSTEM_CONTROL_ROOT L"\\" PROVIDER_ORDER_KEY,
&g_hProviderKey,
0))
{
MPR_LOG1(ERROR,
"MprInitializeProviderGlobals: MprOpenKey FAILED %d\n",
GetLastError());
CloseHandle(g_hProvidersChanged);
return FALSE;
}
if (RegNotifyChangeKeyValue(g_hProviderKey, // Key
FALSE, // Don't watch subtree
REG_NOTIFY_CHANGE_LAST_SET, // Watch for value changes
g_hProvidersChanged, // Event to signal
TRUE) // Asynchronous
!= ERROR_SUCCESS)
{
//
// If this call fails, we won't notice provider additions/deletions
//
MPR_LOG1(ERROR,
"MprInitializeProviderGlobals: RegNotifyChangeKeyValue FAILED %d\n",
GetLastError());
}
//
// Check if LUID device maps are Enabled
//
MprGetLUIDDeviceMapsEnabled( &g_LUIDDeviceMapsEnabled );
//
// Create the lock that restricts access to the provider array
//
if (!MPRProviderLock.Initialize("P", "Provider"))
{
MPR_LOG0(ERROR,
"MprInitializeProviderGlobals: MPRProviderLock.Initialize FAILED\n");
RegCloseKey(g_hProviderKey);
CloseHandle(g_hProvidersChanged);
return FALSE;
}
return TRUE;
}
VOID
MprCheckProviders(
VOID
)
{
ASSERT(!MPRProviderLock.Have());
if (WaitForSingleObject(g_hProvidersChanged, 0) == WAIT_OBJECT_0)
{
//
// The providers have changed -- grab the exclusive lock and
// check again to avoid a race condition. Note that there
// is no need to acquire the MprInitCritsec since an API must
// always acquire the critsec (via INIT_IF_NECESSARY) AFTER it
// acquires the shared provider lock.
//
CProviderExclusiveLock PLock;
if (WaitForSingleObject(g_hProvidersChanged, 0) == WAIT_OBJECT_0)
{
//
// Still set -- this is the first thread here. Free up the provider
// info and reset the init level so the next INIT_IF_NECESSARY call
// will reinitialize the providers as necessary.
//
MPR_LOG0(TRACE,
"MprCheckProviders: Provider list changed -- reinitializing\n");
MprDeleteIndexArray();
MprFreeGlobalProviderInfo();
GlobalInitLevel = 0;
//
// Flush the provider cache
//
CRoutedOperation::DestroyCache();
CRoutedOperation::ConstructCache();
ResetEvent(g_hProvidersChanged);
if (RegNotifyChangeKeyValue(g_hProviderKey, // Key
FALSE, // Don't watch subtree
REG_NOTIFY_CHANGE_LAST_SET, // Watch for value changes
g_hProvidersChanged, // Event to signal
TRUE) // Asynchronous
!= ERROR_SUCCESS)
{
//
// If this call fails we won't notice provider additions/deletions
//
MPR_LOG1(ERROR,
"MprCheckProviders: RegNotifyChangeKeyValue FAILED %d\n",
GetLastError());
}
}
}
}
DWORD
MprLevel1Init(
VOID
)
/*++
Routine Description:
This function looks into the registry to find the names of the providers
and their associated DLLs. A Global table of provider information is
then allocated (GlobalProviderInfo). This table is an array of provider
information structures. The number of elements in the array is stored
in GlobalNumProviders.
If the provider is in the registry ORDERED list, then it is assumed that
complete provider information is stored in the "services" section of
the registry for that provider. This provider information includes such
things as the pathname for the provider dll, and the provider type.
The information is stored in the provider structure for use by the
MprLevel2Init routine.
Arguments:
Return Value:
Note:
--*/
{
DWORD status;
LPPROVIDER provider;
DWORD i;
HKEY controlRootKey;
HKEY providerInfoKey;
LPTSTR orderedString = NULL;
LPTSTR tempOrderedString;
LPTSTR nameBuffer = NULL; // system\LanmanRedirector\NetworkProvider
LPTSTR providerIdString = NULL; // points to provider id in nameBuffer
BOOL oneInitialized = FALSE;
EnterCriticalSection(&MprInitCritSec);
MPR_LOG(TRACE,"******************* LEVEL 1 INIT ********************\n",0);
//
// If this level of initialization is already complete, then return.
//
if (GlobalInitLevel & FIRST_LEVEL) {
LeaveCriticalSection(&MprInitCritSec);
return(WN_SUCCESS);
}
//
// This function had better be called first and only once
//
ASSERT(GlobalInitLevel == 0);
//
// Get a handle to the "current" services part of the registry
//
if(!MprOpenKey(
HKEY_LOCAL_MACHINE, // hKey
SYSTEM_CONTROL_ROOT, // lpSubKey
&controlRootKey, // Newly Opened Key Handle
DA_READ)) { // Desired Access
MPR_LOG(ERROR,"MprLevel1Init: MprOpenKey (System) Error\n",0);
LeaveCriticalSection(&MprInitCritSec);
return(WN_NO_NETWORK);
}
MPR_LOG2(TRACE,"OpenKey %ws,0x%lx\n ",SYSTEM_CONTROL_ROOT,controlRootKey);
//
// Obtain the ordered list information.
// (the orderedString buffer is allocated here)
//
// If this fails, we assume that there are no providers.
//
if (!MprGetOrderedList(controlRootKey, &orderedString)) {
MPR_LOG(ERROR,"Could not get the ordered list of providers\n",0);
RegCloseKey(controlRootKey);
LeaveCriticalSection(&MprInitCritSec);
return(WN_NO_NETWORK);
}
MPR_LOG1(TRACE,"ProviderOrderString = %ws\n",orderedString);
GlobalNumProviders = MprGetNumProviders(orderedString);
//
// Allocate the database in which to store Provider Information.
// This is to be an array of PROVIDER structures. Memory is set
// to zero so that all the provider entry points will be initialized to
// zero.
//
GlobalProviderInfo = (LPPROVIDER) LocalAlloc(
LPTR,
sizeof(PROVIDER) * GlobalNumProviders);
if (GlobalProviderInfo == NULL) {
status = GetLastError();
MPR_LOG(ERROR,"MprLevel1Init: provider array LocalAlloc Failed %d\n",
status);
LocalFree(orderedString);
GlobalNumProviders = 0;
RegCloseKey(controlRootKey);
LeaveCriticalSection(&MprInitCritSec);
return(status);
}
provider = GlobalProviderInfo;
tempOrderedString = orderedString;
for(i=0; i<GlobalNumProviders; i++,provider++) {
//
// Build the Service key name for the next Service/Driver.
// NOTE: This function allocates a nameBuffer.
//
status = MprMakeServiceKeyName(
&tempOrderedString,
&nameBuffer,
&providerIdString );
if (status != WN_SUCCESS) {
goto SkipProvider;
}
//
// Create the path name to the provider information in the
// service's tree.
//
wcscat(nameBuffer, PROVIDER_PATH);
//
// Open the provider portion of that service/driver's
// node in the service tree.
//
if (!MprOpenKey( controlRootKey, nameBuffer, &providerInfoKey, DA_READ)){
LocalFree(nameBuffer);
goto SkipProvider;
}
MPR_LOG1(TRACE,"\n\t----%ws----\n",providerIdString);
MPR_LOG3(TRACE,"\tOpenKey %ws,\n\t%ws\n,\t0x%lx\n",
SYSTEM_CONTROL_ROOT,
nameBuffer,
providerInfoKey);
//
// Free the memory that was allocated for the name buffer.
//
LocalFree (nameBuffer);
//
// Get the data for the provider from the registry at the
// location referenced by providerInfoKey.
//
if (!MprExtractProviderInfo(providerInfoKey, provider)) {
MPR_LOG(TRACE,"CloseKey 0x%lx\n", providerInfoKey);
RegCloseKey(providerInfoKey);
goto SkipProvider;
}
//
// Close the ProviderInfoKey.
//
MPR_LOG(TRACE,"CloseKey 0x%lx\n", providerInfoKey);
RegCloseKey(providerInfoKey);
//
// We have information for at least one provider.
//
oneInitialized = TRUE;
SkipProvider:
; // The complier needs to find something to go to.
} // End For NumProviders
MPR_LOG(TRACE,"CloseKey 0x%lx\n", controlRootKey);
RegCloseKey(controlRootKey);
if (orderedString != NULL) {
LocalFree(orderedString);
}
GlobalInitLevel = FIRST_LEVEL;
LeaveCriticalSection(&MprInitCritSec);
if (oneInitialized == FALSE) {
return(WN_NO_NETWORK);
}
return(WN_SUCCESS);
}
DWORD
MprLevel2Init(
DWORD InitLevel
)
/*++
Routine Description:
This routine initializes all providers of the class described by
the InitLevel parameter. We loop though all providers that meet
this description, and load the dll and find the dll's function entry
points. If we were successful in getting this information for the
provider, it will be added to our "active" list by having its provider
index placed in the GlobalIndexArray (via MprInitIndexArray).
NOTE:
This routine can potentially be called once for each type of
initialization that is supported. For instance, it may be called for
authentication initialization, and then called later for network
initialization.
Each time this routine is called, a new indexArray is created.
After this array is filled in, it is merged with any existing
indexArray left over from previous calls. The merge is performed
by MprInitIndexArray. Locks on this array must be held in order to
update it.
Arguments:
InitLevel - This indicates the level of initialization. This can be
a NETWORK_LEVEL or CREDENTIAL_LEVEL initialization, or both.
Return Value:
WN_SUCCESS - This is returned if we are able to obtain some entry point
information for at least one provider.
Otherwise, an appropriate error is returned.
--*/
{
DWORD status = WN_SUCCESS;
LPPROVIDER provider;
DWORD i;
LPDWORD indexArray = NULL;
DWORD numActive = 0;
DWORD InitClass = 0;
//
// Before we can do a level2 initialization, we must first check to
// see if level 1 has been completed.
//
if (!(GlobalInitLevel & FIRST_LEVEL)) {
status = MprLevel1Init();
if (status != WN_SUCCESS) {
return(status);
}
}
EnterCriticalSection(&MprInitCritSec);
MPR_LOG(TRACE,"******************* LEVEL 2 INIT ********************\n",0);
//
// If this level of initialization is already complete, then return.
//
if (GlobalInitLevel & InitLevel) {
LeaveCriticalSection(&MprInitCritSec);
return(WN_SUCCESS);
}
//
// Translate InitLevel into an InitClass so it can be compared with the
// provider class.
//
if (InitLevel & NETWORK_LEVEL)
{
InitClass |= NETWORK_TYPE;
//
// Load the "Entire Network" string (used by WNetEnumResource
// for RESOURCE_CONNECTED). Note that WNetEnumResource requires
// only NETWORK_LEVEL initialization, so it's OK to load it
// here and only here.
//
if (g_wszEntireNetwork[0] == L'\0')
{
int cch = LoadString(hDLL,
IDS_NETROOT,
g_wszEntireNetwork,
LENGTH(g_wszEntireNetwork));
ASSERT(cch > 0 && cch < LENGTH(g_wszEntireNetwork));
}
}
if (InitLevel & CREDENTIAL_LEVEL)
{
InitClass |= CREDENTIAL_TYPE;
}
if (InitLevel & NOTIFIEE_LEVEL)
{
status = MprConnectNotifyInit();
GlobalInitLevel |= InitLevel;
LeaveCriticalSection(&MprInitCritSec);
return(status);
}
provider = GlobalProviderInfo;
//
// Allocate storage for the ordered list of indices. This storage is
// freed by MprInitIndexArray.
//
indexArray = (LPDWORD) LocalAlloc(LPTR, sizeof(DWORD) * GlobalNumProviders);
if (indexArray == NULL) {
MPR_LOG(ERROR,"MprProcessAttach: indexArray LocalAlloc Failed %d\n",
GetLastError());
LeaveCriticalSection(&MprInitCritSec);
return(GetLastError());
}
for(i=0; i<GlobalNumProviders; i++,provider++) {
//
// If this provider matches the init type for which we are
// initializing, then load the library and get the entry points.
// Then add the provider array index to the index array.
//
if (provider->InitClass & InitClass) {
//
// Load the DLL and free the memory for its name.
//
if (provider->AuthentDllName != NULL) {
MPR_LOG1(TRACE,"MprLevel2Init: Loading %ws\n",provider->AuthentDllName);
provider->AuthentHandle = LoadLibraryEx(
provider->AuthentDllName,
NULL,
LOAD_WITH_ALTERED_SEARCH_PATH);
if (provider->AuthentHandle == NULL) {
MPR_LOG(ERROR,"MprLevel2Init: LoadLibraryEx Failed %d\n",
GetLastError());
}
LocalFree(provider->AuthentDllName);
provider->AuthentDllName = NULL;
}
if (provider->DllName != NULL) {
MPR_LOG1(TRACE,"MprLevel2Init: Loading %ws\n",provider->DllName);
provider->Handle = LoadLibraryEx(
provider->DllName,
NULL,
LOAD_WITH_ALTERED_SEARCH_PATH);
if (provider->Handle == NULL) {
MPR_LOG(ERROR,"MprLevel2Init: LoadLibraryEx Failed %d\n",
GetLastError());
}
//
// Keep around the DLL name since we need to do another
// LoadLibraryEx to refcount the DLL in WNetOpenEnum
//
}
if ((provider->Handle != NULL) || (provider->AuthentHandle != NULL)) {
MPR_LOG0(TRACE,"MprLevel2Init: LoadLibraryEx success\n");
//
// Obtain the various entry points for the library.
// This is done based on the capabilities that are listed for the
// provider.
//
if (GetProviderCapabilities(provider)) {
//
// Only providers for which we are able to successfully
// get the entry points are added to the active array.
//
// Since this provider information is now initialized, the
// provider is considered ACTIVE. Put the index to the
// provider in the index array.
//
MPR_LOG1(TRACE,"MprLevel2Init: Successfully got "
"capabilities for %ws\n",provider->Resource.lpProvider);
indexArray[numActive] = i;
numActive++;
}
}
} // End If InitLevel match
} // End For NumProviders
//
// Store the information in this indexArray in the GlobalIndexArray.
//
MprInitIndexArray(indexArray, numActive);
GlobalInitLevel |= InitLevel;
LeaveCriticalSection(&MprInitCritSec);
MPR_LOG(TRACE,"******************* END LEVEL 2 INIT ********************\n",0);
return(WN_SUCCESS);
}
BOOL
MprProcessDetach(
DWORD dwInitLevel
)
/*++
Routine Description:
This function cleans up resources for a process when it detaches
from the dll.
Arguments:
none
Return Value:
none
Note:
--*/
{
MprDeleteIndexArray();
MprFreeGlobalProviderInfo();
GlobalNumProviders = 0;
GlobalProviderInfo = NULL;
if (dwInitLevel & MPR_INITCRITSEC_CREATED)
{
DeleteCriticalSection(&MprInitCritSec);
}
if (dwInitLevel & MPR_PROVIDERLOCK_CREATED)
{
RegCloseKey(g_hProviderKey);
CloseHandle(g_hProvidersChanged);
MPRProviderLock.Delete();
}
if (dwInitLevel & MPR_ERRORCRITSEC_CREATED)
{
MprFreeAllErrorRecords();
DeleteCriticalSection(&MprErrorRecCritSec);
}
return(TRUE);
}
BOOL
GetProviderCapabilities(
LPPROVIDER Provider
)
/*++
Routine Description:
This function obtains the provider's capabilities and then gets the
procedure entry point for all supported API.
Arguments:
Provider - A pointer to a PROVIDER structure which will contain all
information that must be maintained for a given provider.
Return Value:
TRUE - If at least one capability is found for this provider.
FALSE - If no capabilities are found for the provider.
History:
Johnl 17-Jan-1992 Added Property dialog support
--*/
//
// The following macro is designed to work within the function
// GetProviderCapabilities().
//
#define GET_ADDRESS(apiName) Provider-> ## apiName = (PF_NP ## apiName) GetProcAddress( \
Provider->Handle, \
"NP"#apiName); \
if (Provider-> ## apiName == NULL) { \
MPR_LOG(ERROR, \
"GetProviderCapabilities: Can't get NP"#apiName " Address %d\n",\
GetLastError()); \
} \
else { \
status = TRUE; \
}
#define GET_AUTH_ADDRESS(apiName) Provider-> ## apiName = (PF_NP ## apiName) GetProcAddress( \
Provider->AuthentHandle, \
"NP"#apiName); \
if (Provider-> ## apiName == NULL) { \
MPR_LOG(ERROR, \
"GetProviderCapabilities: Can't get NP"#apiName " Address %d\n",\
GetLastError()); \
} \
else { \
status = TRUE; \
}
{
DWORD bitMask;
BOOLEAN status=FALSE;
GET_ADDRESS(GetCaps);
if (status) {
//
// Get the Network Type
//
// CODEWORK: Read the type from the registry when possible -- this
// will allow us to avoid doing a Level 2 init in all the cases where
// only the provider type is needed (e.g., MprFindProviderByType).
//
Provider->Type = Provider->GetCaps(WNNC_NET_TYPE);
//
// Reject providers that don't supply their type
//
if (Provider->Type == 0)
{
MPR_LOG(ERROR, "%ws provider reported a net type of 0\n",
Provider->Resource.lpProvider);
ASSERT(!"Network provider didn't report its network type");
return FALSE;
}
//
// Does it support WNetGetUser?
//
bitMask = Provider->GetCaps(WNNC_USER);
if (bitMask & WNNC_USR_GETUSER) {
GET_ADDRESS(GetUser);
}
//
// Connection Api Supported
//
bitMask = Provider->GetCaps(WNNC_CONNECTION);
Provider->ConnectCaps = bitMask;
if (bitMask & WNNC_CON_ADDCONNECTION) {
GET_ADDRESS(AddConnection);
}
if (bitMask & WNNC_CON_ADDCONNECTION3) {
DWORD bitMask2;
GET_ADDRESS(AddConnection3);
GET_ADDRESS(GetReconnectFlags); // optional entry point
//
// Connection Api flags Supported
//
bitMask2 = Provider->GetCaps(WNNC_CONNECTION_FLAGS);
if (bitMask2 == 0) {
bitMask2 = WNNC_CF_DEFAULT;
}
bitMask2 &= WNNC_CF_MAXIMUM;
Provider->ConnectFlagCaps = bitMask2;
}
if (bitMask & WNNC_CON_CANCELCONNECTION) {
GET_ADDRESS(CancelConnection);
}
if (bitMask & WNNC_CON_GETCONNECTIONS) {
GET_ADDRESS(GetConnection);
GET_ADDRESS(GetConnection3);
GET_ADDRESS(GetUniversalName);
}
if (bitMask & WNNC_CON_GETPERFORMANCE) {
GET_ADDRESS(GetConnectionPerformance);
}
//
// Enumeration Api Supported
//
bitMask = Provider->GetCaps(WNNC_ENUMERATION);
if ((bitMask & WNNC_ENUM_GLOBAL) ||
(bitMask & WNNC_ENUM_LOCAL) ||
(bitMask & WNNC_ENUM_CONTEXT)) {
GET_ADDRESS(OpenEnum);
GET_ADDRESS(EnumResource);
GET_ADDRESS(CloseEnum);
}
//
// Admin Api Supported
//
bitMask = Provider->GetCaps(WNNC_ADMIN);
if (bitMask & WNNC_ADM_GETDIRECTORYTYPE) {
GET_ADDRESS(GetDirectoryType);
}
if (bitMask & WNNC_ADM_DIRECTORYNOTIFY) {
GET_ADDRESS(DirectoryNotify);
}
//
// Dialog API Support
//
bitMask = Provider->GetCaps(WNNC_DIALOG);
if (bitMask & WNNC_DLG_PROPERTYDIALOG) {
GET_ADDRESS(GetPropertyText);
GET_ADDRESS(PropertyDialog);
}
if (bitMask & WNNC_DLG_SEARCHDIALOG) {
GET_ADDRESS(SearchDialog);
}
if (bitMask & WNNC_DLG_FORMATNETWORKNAME) {
GET_ADDRESS(FormatNetworkName);
}
if (bitMask & WNNC_DLG_PERMISSIONEDITOR) {
GET_ADDRESS(FMXGetPermCaps);
GET_ADDRESS(FMXEditPerm);
GET_ADDRESS(FMXGetPermHelp);
}
if (bitMask & WNNC_DLG_GETRESOURCEPARENT) {
GET_ADDRESS(GetResourceParent);
}
if (bitMask & WNNC_DLG_GETRESOURCEINFORMATION) {
GET_ADDRESS(GetResourceInformation);
}
}
else {
if (Provider->GetAuthentCaps == NULL) {
Provider->GetAuthentCaps = (PF_NPGetCaps)GetProcAddress(
Provider->AuthentHandle,
"NPGetCaps");
if (Provider->GetAuthentCaps == NULL) {
MPR_LOG(ERROR,
"GetProviderCapabilities: Can't get NPGetCaps %d\n",
GetLastError());
}
else {
status = TRUE;
}
}
//
// If we couldn't get an address for GetCaps from either the
// network provider dll or the authentication provider dll, then
// we should return an error. The rule is, this must be supported
// by one of the providers.
//
if (status == FALSE) {
return(FALSE);
}
}
//
// Get Authentication Provider entry points
//
if (Provider->InitClass & CREDENTIAL_TYPE) {
if (Provider->AuthentHandle == NULL) {
MPR_LOG0(TRACE,"GetProvCaps: CM provider in same DLL\n");
GET_ADDRESS(LogonNotify);
GET_ADDRESS(PasswordChangeNotify);
}
else {
MPR_LOG0(TRACE,"GetProvCaps: CM provider in seperate DLL\n");
GET_AUTH_ADDRESS(LogonNotify);
GET_AUTH_ADDRESS(PasswordChangeNotify);
if (Provider->GetAuthentCaps == NULL) {
Provider->GetAuthentCaps = (PF_NPGetCaps)GetProcAddress(
Provider->AuthentHandle,
"NPGetCaps");
if (Provider->GetAuthentCaps == NULL) {
MPR_LOG(ERROR,
"GetProviderCapabilities: Can't get NPGetCaps %d\n",
GetLastError());
}
else {
status = TRUE;
}
}
}
}
return(status);
}
VOID
MprFreeGlobalProviderInfo(
VOID
)
/*++
Routine Description:
This function walks through the array of provider structures, and
frees up all the valid pointers to the provider name. Then if frees
the GlobalProviderInfo array.
Arguments:
none.
Return Value:
none.
--*/
{
LPPROVIDER provider;
DWORD i;
if (GlobalProviderInfo == NULL)
{
return;
}
provider = GlobalProviderInfo;
//
// Free all the valid pointers to the provider's name.
//
for(i = 0; i < GlobalNumProviders; i++, provider++)
{
MPR_LOG(TRACE, "Freeing Name for provider %d\n",i);
if (provider->Handle != NULL)
{
MPR_LOG1(TRACE,
"Freeing Library for "FORMAT_LPTSTR" \n",
provider->Resource.lpProvider);
FreeLibrary(provider->Handle);
}
LocalFree(provider->DllName);
if (provider->AuthentHandle != NULL)
{
MPR_LOG1(TRACE,
"Freeing authentication library for "FORMAT_LPTSTR" \n",
provider->Resource.lpProvider);
FreeLibrary(provider->AuthentHandle);
}
//
// Should have been freed when the DLL was loaded
//
ASSERT(provider->AuthentDllName == NULL);
LocalFree(provider->Resource.lpRemoteName);
}
//
// Free the top level data structure and reinit the globals
//
MPR_LOG(TRACE, "Freeing GlobalProviderInfo\n",0);
LocalFree(GlobalProviderInfo);
GlobalProviderInfo = NULL;
GlobalNumProviders = 0;
GlobalNumActiveProviders = 0;
}
DWORD
MprMakeServiceKeyName(
IN OUT LPTSTR *OrderedNamePtr,
OUT LPTSTR *NameBufferPtr,
OUT LPTSTR *NamePtr
)
/*++
Routine Description:
This function gets the name of the provider device driver key within
the registry tree. A buffer is allocated that is large enough for
that name as well as the name of the key where the provider information
is stored.
For example, the following buffer is allocated and filled with
only the path prefix followed by the LanmanRedirector name.
NameBuffer = [services\LanmanRedirector ]
The buffer is sized so that it can be filled in later with the
following information.
NameBuffer = [services\LanmanRedirector\NetworkProvider]
The Driver name is needed for comparison with the ordered list names.
Arguments:
OrderedNamePtr - On entry this points to a location where there is a
pointer to the the next name in the ordered list of providers.
These names are seperated by commas. The last entry is followed by
a trailing NUL.
On exit a pointer to the next name in the list is stored here. If
it is the last name, the pointer is NULL.
NameBufferPtr - This is a pointer to a location where the pointer to the
name buffer is to be placed.
NamePtr - This is a a location where the pointer to the provider
name is placed. In the above example, this pointer would point
to the beginnning of the LanmanRedirector portion of the string.
Return Value:
TRUE - We successfully obtained the driver name.
FALSE - We were unsuccessful in obtaining the driver name.
Note:
--*/
{
LPTSTR pNext;
DWORD bufferSize; // number of BYTES in buffer
DWORD nameLength; // number of CHARACTERS in string
//
// The OrderedNamePtr should always be valid. If not there is a software
// error in this code.
//
if (*OrderedNamePtr == NULL) {
MPR_LOG(ERROR,"GetDriverName: The ordered Name Ptr was NULL.\n",0);
return(WN_NO_NETWORK);
}
pNext = *OrderedNamePtr;
//
// Find the next NULL or COMMA.
//
while ( (*pNext != TEXT('\0')) &&
(*pNext != TEXT(',')) ){
pNext++;
}
//
// Allocate a buffer for the name to be stored in
//
bufferSize = (DWORD)((LPBYTE)pNext - (LPBYTE)(*OrderedNamePtr));
nameLength = bufferSize / sizeof(TCHAR);
bufferSize = bufferSize + sizeof(PROVIDER_PATH) + sizeof(SERVICES_KEY_NAME);
*NameBufferPtr = (LPTSTR) LocalAlloc(LPTR, bufferSize);
if (*NameBufferPtr == NULL) {
MPR_LOG(ERROR,"MprMakeServiceKeyName:LocalAllocFailed %d\n",GetLastError());
return(GetLastError());
}
//
// Copy the path prefix "services\\" followed by the name
// into the buffer and terminate with a NULL character.
//
wcscpy(*NameBufferPtr, SERVICES_KEY_NAME);
*NamePtr = (LPTSTR)(*NameBufferPtr + (wcslen(*NameBufferPtr)));
wcsncat(*NameBufferPtr, *OrderedNamePtr, nameLength);
*((*NamePtr) + nameLength) = TEXT('\0');
if (*pNext == TEXT('\0')) {
*OrderedNamePtr = NULL;
}
else {
*OrderedNamePtr = pNext + 1;
}
return (WN_SUCCESS);
}
BOOL
MprGetOrderedList(
HKEY ControlRootKey,
LPTSTR *OrderString
)
/*++
Routine Description:
This function returns a pointer to a string that contains the
ordered list of providers. This ordered list is to be used when
we go through the list of providers with a trial-and-error method
when servicing a WINNET API call.
ALLOCATES STORAGE: This function allocates the buffer for the
OrderString.
Arguments:
OrderString - This is a pointer to a location where the pointer to
the order string is to be placed.
Return Value:
TRUE - The ordered list was found, and the string was returned.
FALSE - A failure occured when attempting to find the ordered list.
--*/
{
HKEY orderKey;
*OrderString = NULL;
//
// Get a handle to the key for the ordered provider information.
//
if(!MprOpenKey(
ControlRootKey, // hKey
PROVIDER_ORDER_KEY, // lpSubKey
&orderKey, // Newly Opened Key Handle
DA_READ)) { // Desired Access
MPR_LOG(ERROR,"MprGetOrderedList: MprOpenKey (ActiveProviders) Error\n",0);
return(FALSE);
}
//
// Get the provider order string from the registry.
//
if (!MprGetKeyValue(orderKey, TEXT("ProviderOrder"), OrderString)) {
MPR_LOG(ERROR,"MprGetOrderedList: MprGetKeyValue Error.\n", 0);
RegCloseKey(orderKey);
return(FALSE);
}
RegCloseKey(orderKey);
return(TRUE);
}
DWORD
MprGetNumProviders(
LPTSTR OrderedString
)
/*++
Routine Description:
This routine finds the number of provider names in the string of
ordered provider names.
Arguments:
OrderedString - This is a pointer to a NUL terminated string of
ordered provider names. Names are seperated by commas.
Return Value:
--*/
{
DWORD count = 0;
LPTSTR pBegin;
pBegin = OrderedString;
while (*OrderedString != TEXT('\0')) {
//
// If a seperator has been found, and if there are characters
// between it and the last seperator (or the beginning), then
// increment the count.
//
if (*OrderedString == TEXT(',')) {
if((OrderedString - pBegin) > 0) {
count++;
}
pBegin = OrderedString + 1;
}
OrderedString++;
}
//
// The last name is expected to be followed by a NUL rather than a
// comma.
//
if ((OrderedString - pBegin) > 0) {
count++;
}
return(count);
}
BOOL
MprExtractProviderInfo(
HKEY ProviderInfoKey,
LPPROVIDER Provider
)
/*++
Routine Description:
This function extracts information from the ProviderInfoKey location
in the registry and stores it in the Provider data structure.
Arguments:
ProviderInfoKey - This is a registry key handle for the location in
the registry where we expect to obtain all the necessary
information about a provider.
Provider - This is a pointer to a provider structure that is to be
filled in with the information from the registry.
Return Value:
TRUE - The operation was completely successful.
FALSE - The operation failed.
Note:
--*/
{
LPTSTR providerName = NULL;
LPTSTR fileName = NULL;
DWORD ValueType;
DWORD Class;
DWORD classSize = sizeof(DWORD);
DWORD status;
MPR_LOG(TRACE,"In MprExtractProviderInfo....\n",0);
//
// Get Provider Name
//
if(!MprGetKeyValue(ProviderInfoKey, TEXT("name"), &providerName) ||
providerName[0] == L'\0') {
MPR_LOG0(ERROR,"MprExtractProviderInfo: Couldn't get provider name\n");
return(FALSE);
}
//
// Initialize all the fields in the resource structure.
// NOTE: The reserved field in dwUsage is set to indicate this is
// a top level structure.
//
Provider->Resource.lpProvider = providerName;
Provider->Resource.lpRemoteName = providerName;
Provider->Resource.dwScope = RESOURCE_GLOBALNET;
Provider->Resource.dwType = 0;
Provider->Resource.dwDisplayType= RESOURCEDISPLAYTYPE_NETWORK;
Provider->Resource.dwUsage = RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_RESERVED;
Provider->Resource.lpComment = NULL;
//
// Get the Provider Class. If there isn't a Class value in the
// registry, assume it is a NetworkClass only.
//
status = RegQueryValueEx(
ProviderInfoKey, // hKey
VALUE_CLASS, // lpValueName
NULL, // lpTitleIndex
&ValueType, // lpType
(LPBYTE)&Class, // lpData
&classSize); // lpcbData
if (status != NO_ERROR) {
//
// If we get an error we assume it is because there is no key - thus
// indicating that this provider is a network provider only.
//
MPR_LOG0(TRACE,"Couldn't find Authenticator Class value "
"- assume it is Network-type only\n");
Class = WN_NETWORK_CLASS;
}
Provider->InitClass = Class;
MPR_LOG1(TRACE,"MprExtractProviderInfo: Provider InitClass = %d\n",Class);
//
// Get the name of the provider's DLL routine
//
if(!MprGetKeyValue(ProviderInfoKey,VALUE_PATHNAME,&fileName)){
MPR_LOG(ERROR,
"MprExtractProviderInfo: Failed to get the Dll path from registry\n",0);
//
// If this is a network class provider, it MUST have a provider
// dll. Otherwise, we return a failure.
//
if (Class & WN_NETWORK_CLASS) {
return(FALSE);
}
else {
fileName = NULL;
}
}
Provider->DllName = fileName;
//
// If this is a CREDENTIAL_CLASS or PRIMARY_AUTHENT_CLASS provider
// then try to get the dll name for the authentication provider.
//
if (Class & (WN_CREDENTIAL_CLASS | WN_PRIMARY_AUTHENT_CLASS)) {
//
// Get the name of the provider's Credential Management DLL routine
//
if(!MprGetKeyValue(ProviderInfoKey,AUTHENT_PATHNAME,&fileName)){
//
// If we can't get a name for the Authentication Provider's DLL,
// then we will assume the network provider dll exports the
// Credential Management functions.
//
MPR_LOG0(ERROR,
"MprExtractProviderInfo: Failed to get the Authenticator "
"Dll path from registry\n");
//
// If we don't have a provider dll name, or an authent provider
// dll name, then this is an error condition.
//
if (Provider->DllName == NULL) {
return(FALSE);
}
}
else {
Provider->AuthentDllName = fileName;
}
}
return(TRUE);
}
BOOL
MprGetLUIDDeviceMapsEnabled(
PBOOL pResult
)
/*++
Routine Description:
This function calls NtQueryInformationProcess() to determine if
LUID device maps are enabled
Arguments:
pResult - returns the result of "Is LUID device maps are enabled?"
TRUE - LUID device maps are enabled
FALSE - LUID device maps are disabled
Return Value:
TRUE - This is returned if we are able to determine if LUID device
maps are enabled/disabled.
FALSE - Encountered an error
--*/
{
NTSTATUS Status;
ULONG LUIDDeviceMapsEnabled;
BOOL Result;
if( pResult == NULL ) {
return (FALSE);
}
Status = NtQueryInformationProcess( NtCurrentProcess(),
ProcessLUIDDeviceMapsEnabled,
&LUIDDeviceMapsEnabled,
sizeof(LUIDDeviceMapsEnabled),
NULL
);
if( !NT_SUCCESS(Status) ) {
MPR_LOG(ERROR,"MprGetLUIDDeviceMapsEnabled: NtQueryInformationProcess (g_LUIDDeviceMapsEnabled) Error\n",0);
return( FALSE );
}
else{
Result = (LUIDDeviceMapsEnabled != 0);
}
*pResult = Result;
return( TRUE );
}
extern "C" int __cdecl
_purecall(
VOID
)
{
// Make it build... (the compiler will initialize all pure virtual
// function pointers to point to this... If we hit this function,
// there's a really big problem.)
RtlRaiseStatus(STATUS_NOT_IMPLEMENTED);
return 0;
}