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.
1347 lines
43 KiB
1347 lines
43 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
credman.cxx
|
|
|
|
Abstract:
|
|
|
|
WNet Credential Management API functions
|
|
|
|
Author:
|
|
|
|
Dan Lafferty (danl) 07-Dec-1992
|
|
|
|
Environment:
|
|
|
|
User Mode - Win32
|
|
|
|
|
|
Revision History:
|
|
|
|
05-May-1999 jschwart
|
|
Make provider addition/removal dynamic
|
|
|
|
19-Apr-1994 danl
|
|
Fix timeout logic where we would ignore the
|
|
provider-supplied timeout if the timeout was smaller than the default.
|
|
Now, if all the providers know their timeouts, the larger of those
|
|
timeouts is used. Even if smaller than the default.
|
|
|
|
09-Jun-1993 danl
|
|
Fixed MaxWait in MprCheckTimeout() so that now it is passed in.
|
|
Until now, it was left uninitialized.
|
|
|
|
07-Apr-1993 danl
|
|
Initialize the pointer to the logon script to NULL prior to passing
|
|
it to the provider to fill in. We are expecting it to be NULL if
|
|
they don't have a logon script.
|
|
|
|
18-Jan-1993 danl
|
|
WNetLogonNotify: If the provider returns an error that mpr
|
|
doesn't understand, it should discontinue calling that provider.
|
|
This is accomplished by setting the ContinueFlag for that provider
|
|
to FALSE.
|
|
|
|
07-Dec-1992 danl
|
|
Created
|
|
|
|
--*/
|
|
|
|
//
|
|
// INCLUDES
|
|
//
|
|
#include "precomp.hxx"
|
|
#include <tstr.h> // WCSSIZE
|
|
|
|
//
|
|
// DEFINES
|
|
//
|
|
|
|
typedef struct _RETRY_INFO {
|
|
DWORD ProviderIndex;
|
|
DWORD Status;
|
|
DWORD ProviderWait;
|
|
BOOL ContinueFlag;
|
|
LPWSTR LogonScript;
|
|
} RETRY_INFO, *LPRETRY_INFO;
|
|
|
|
//
|
|
// LOCAL FUNCTIONS
|
|
//
|
|
DWORD
|
|
MprMakeRetryArray(
|
|
LPCWSTR lpPrimaryAuthenticator,
|
|
LPDWORD lpNumProviders,
|
|
LPRETRY_INFO *lpRetryArray,
|
|
LPDWORD lpRegMaxWait
|
|
);
|
|
|
|
VOID
|
|
MprUpdateTimeout(
|
|
LPRETRY_INFO RetryArray,
|
|
LPPROVIDER Provider,
|
|
DWORD RegMaxWait,
|
|
LPDWORD pMaxWait,
|
|
DWORD StartTime,
|
|
DWORD CallStatus
|
|
);
|
|
|
|
VOID
|
|
MprCheckTimeout(
|
|
BOOL *ContinueFlag,
|
|
DWORD StartTime,
|
|
DWORD MaxWait,
|
|
LPDWORD lpStatus
|
|
);
|
|
|
|
|
|
DWORD APIENTRY
|
|
WNetLogonNotify(
|
|
LPCWSTR lpPrimaryAuthenticator,
|
|
PLUID lpLogonId,
|
|
LPCWSTR lpAuthentInfoType,
|
|
LPVOID lpAuthentInfo,
|
|
LPCWSTR lpPreviousAuthentInfoType, // may be NULL
|
|
LPVOID lpPreviousAuthentInfo, // may be NULL
|
|
LPWSTR lpStationName,
|
|
LPVOID StationHandle,
|
|
LPWSTR *lpLogonScripts
|
|
)
|
|
|
|
/*++
|
|
|
|
Description:
|
|
|
|
This function provides notification to provider dll's that must handle
|
|
log-on events.
|
|
|
|
Each Credential Manager Provider is allowed to return
|
|
a single command line string which will execute a logon script.
|
|
WNetLogonNotify gathers these strings into a MULTI_SZ string buffer.
|
|
(Meaning each string is NULL terminated, and the set of strings is
|
|
NULL terminated - thus making the last string doubly NULL terminated).
|
|
|
|
!! IMPORTANT !!
|
|
The caller of this function is responsible for freeing the
|
|
buffer pointed to by *lpLogonScripts. The windows API function
|
|
LocalFree() should be used to do this.
|
|
|
|
Arguments:
|
|
|
|
lpPrimaryAuthenticator - This is a pointer to a string that identifies
|
|
the primary authenticator. The router uses this information to
|
|
skip the credential manager identified by this string. Since it
|
|
is the primary, it has already handled the logon. This string is
|
|
obtained from the "\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\
|
|
Services\*(keyname)\NetworkProvider\Name" registry value.
|
|
|
|
lpLogonId - The logon ID of the session currently being logged on.
|
|
|
|
lpAuthentInfoType - This points to a string that identifies the
|
|
AuthentInfo structure type.
|
|
|
|
When Microsoft is the primary authenticator, the values that may
|
|
be expected here are the ones described for the lpAuthentInfoType
|
|
parameter to NPLogonNotify().
|
|
|
|
lpAuthentInfo - This points to a structure that contains the
|
|
credentials used to successfully log the user on via the
|
|
primary authenticator. The structures that may be specified when
|
|
using Micosoft's primary authenticator are:
|
|
|
|
When Microsoft is the primary authenticator, the structures that
|
|
may be expected here are the ones described for the lpAuthentInfo
|
|
parameter to NPLogonNotify().
|
|
|
|
lpPreviousAuthentInfoType - This is pointer to a string that identifies
|
|
the PreviousAuthentInfo structure. If this pointer is NULL, then
|
|
no PreviousAuthentInfo is available.
|
|
|
|
The values that may be expected here are the same as the values that
|
|
may be expected for the lpAuthentInfoType parameter.
|
|
|
|
lpPreviousAuthentInfo - If the user was forced to change the password
|
|
prioir to logging on, this points to a AuthentInfo structure that
|
|
will contain the credential information used prior to the password
|
|
change. If the user was not forced to change the password prior
|
|
to logging on, then this pointer is NULL.
|
|
|
|
The structures that may be expected here are the same as the
|
|
structures that may be expected for the lpAuthentInfo parameter.
|
|
|
|
lpStationName - This parameter contains the name of the station the
|
|
user has logged onto. This may be used to determine whether or
|
|
not interaction with the user to obtain additional (provider-specific)
|
|
credentials is possible. This information will also have a bearing
|
|
on the meaning and use of the StationHandle parameter.
|
|
|
|
When Microsoft is the primary authenticator, the values that
|
|
may be expected here are the ones described for the lpStationName
|
|
parameter to NPLogonNotify().
|
|
|
|
StationHandle - Is a 32-bit value whose meaning is dependent upon the
|
|
name (and consequently, the type) of station being logged onto.
|
|
|
|
When Microsoft is the primary authenticator, the values that
|
|
may be expected here are the ones described for the lpStationHandle
|
|
parameter to NPLogonNotify().
|
|
|
|
lpLogonScripts - This is a pointer to a location where a pointer to
|
|
a MULTI_SZ string may be returned. Each null terminated
|
|
string in the MULTI_SZ string is assumed to contain the name
|
|
of a program to execute and parameters to pass to the program.
|
|
The memory allocated to hold the returned string must be
|
|
deallocatable by the calling routine. The caller of this
|
|
routine is responsible for freeing the memory used to house
|
|
this string when it is no longer needed.
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
DWORD status = WN_SUCCESS;
|
|
DWORD numProviders;
|
|
LPPROVIDER provider;
|
|
BOOL fcnSupported = FALSE; // Is fcn supported by a provider?
|
|
DWORD i;
|
|
BOOL ContinueFlag;
|
|
LPRETRY_INFO RetryArray;
|
|
DWORD RegMaxWait=0;
|
|
DWORD MaxWait=0;
|
|
DWORD StartTime;
|
|
DWORD scriptSize=0;
|
|
LPWSTR pScript;
|
|
|
|
MprCheckProviders();
|
|
|
|
CProviderSharedLock PLock;
|
|
|
|
INIT_IF_NECESSARY(CREDENTIAL_LEVEL,status);
|
|
|
|
MPR_LOG0(TRACE,"Entered WNetLogonNotify\n");
|
|
//
|
|
// Now create an array of information about the providers so that we
|
|
// can retry until timeout, or all providers are functional.
|
|
// Note: The Status field in each retry array element is initialized
|
|
// WN_NO_NETWORK.
|
|
//
|
|
__try {
|
|
*lpLogonScripts = NULL;
|
|
|
|
status = MprMakeRetryArray(
|
|
lpPrimaryAuthenticator,
|
|
&numProviders,
|
|
&RetryArray,
|
|
&RegMaxWait);
|
|
}
|
|
__except(MPR_EXCEPTION_FILTER) {
|
|
status = GetExceptionCode();
|
|
if (status != EXCEPTION_ACCESS_VIOLATION) {
|
|
MPR_LOG(ERROR,"WNetLogonNotify:Unexpected Exception 0x%lx\n",status);
|
|
}
|
|
status = WN_BAD_POINTER;
|
|
}
|
|
|
|
if ((status != WN_SUCCESS) || (numProviders == 0)) {
|
|
MPR_LOG2(TRACE,"WNetLogonNotify: Error - status=%d, numProviders=%d\n",
|
|
status,numProviders);
|
|
return(status);
|
|
}
|
|
|
|
//
|
|
// Initialize the timer.
|
|
//
|
|
if (RegMaxWait != 0) {
|
|
MaxWait = RegMaxWait;
|
|
}
|
|
StartTime = GetTickCount();
|
|
|
|
//
|
|
// Loop through the list of providers notifying each one in turn.
|
|
// If the underlying service or driver is not available for the
|
|
// provider such that it cannot complete this call, then we will
|
|
// wait for it to become available.
|
|
//
|
|
|
|
do {
|
|
|
|
ContinueFlag = FALSE;
|
|
|
|
for (i=0; i<numProviders; i++) {
|
|
|
|
//
|
|
// Call the appropriate provider's API entry point
|
|
//
|
|
provider = GlobalProviderInfo + RetryArray[i].ProviderIndex;
|
|
|
|
if ((RetryArray[i].ContinueFlag) &&
|
|
(provider->LogonNotify != NULL)) {
|
|
|
|
fcnSupported = TRUE;
|
|
|
|
RetryArray[i].LogonScript = NULL;
|
|
|
|
__try {
|
|
MPR_LOG(TRACE,"Calling (%ws) LogonNotify function\n",
|
|
provider->Resource.lpProvider);
|
|
status = provider->LogonNotify(
|
|
lpLogonId,
|
|
lpAuthentInfoType,
|
|
lpAuthentInfo,
|
|
lpPreviousAuthentInfoType,
|
|
lpPreviousAuthentInfo,
|
|
lpStationName,
|
|
StationHandle,
|
|
(LPWSTR *)&(RetryArray[i].LogonScript));
|
|
}
|
|
__except(MPR_EXCEPTION_FILTER) {
|
|
status = GetExceptionCode();
|
|
if (status != EXCEPTION_ACCESS_VIOLATION) {
|
|
MPR_LOG(ERROR,"WNetLogonNotify:Unexpected Exception "
|
|
"0x%lx\n",status);
|
|
}
|
|
status = WN_BAD_POINTER;
|
|
}
|
|
|
|
switch (status) {
|
|
case WN_SUCCESS:
|
|
//
|
|
// Because this provider may have put up dialogs, and
|
|
// taken a long time to complete, we want to skip the
|
|
// timeout check and try all the providers once more.
|
|
// We force the index to 0 in order to assure that all
|
|
// providers will be tried again prior to checking for
|
|
// a timeout.
|
|
//
|
|
RetryArray[i].Status = WN_SUCCESS;
|
|
RetryArray[i].ContinueFlag = FALSE;
|
|
|
|
if (RetryArray[i].LogonScript != NULL)
|
|
{
|
|
//
|
|
// If the provider returns an empty logon script,
|
|
// don't add the empty string to the list as that
|
|
// shows up as the end of the list to the caller.
|
|
//
|
|
|
|
DWORD dwSize = WCSSIZE(RetryArray[i].LogonScript);
|
|
|
|
if (dwSize > sizeof(WCHAR))
|
|
{
|
|
scriptSize += dwSize;
|
|
}
|
|
}
|
|
|
|
ContinueFlag = FALSE;
|
|
i=0;
|
|
break;
|
|
|
|
case WN_NO_NETWORK:
|
|
case WN_FUNCTION_BUSY:
|
|
//
|
|
// The provider is not ready to be notified (its underlying
|
|
// driver or service is not running yet). Attempt to
|
|
// find out how long to wait, or if it will ever start.
|
|
// This function will update MaxWait if the provider can
|
|
// give us a wait hint.
|
|
//
|
|
MprUpdateTimeout(
|
|
&(RetryArray[i]),
|
|
provider,
|
|
RegMaxWait,
|
|
&MaxWait,
|
|
StartTime,
|
|
status);
|
|
break;
|
|
|
|
default:
|
|
RetryArray[i].Status = status;
|
|
RetryArray[i].ContinueFlag = FALSE;
|
|
break;
|
|
|
|
} // End Switch (Get providers timeouts).
|
|
|
|
ContinueFlag |= RetryArray[i].ContinueFlag;
|
|
|
|
} // end check to see if function is supported.
|
|
|
|
} // end for i<numProviders.
|
|
|
|
//
|
|
// Check to see if the timeout has expired.
|
|
//
|
|
MprCheckTimeout(&ContinueFlag, StartTime, MaxWait, &status);
|
|
|
|
} while (ContinueFlag);
|
|
|
|
if (fcnSupported == FALSE) {
|
|
//
|
|
// No providers in the list support the API function. Therefore,
|
|
// we assume that no networks are installed.
|
|
//
|
|
MPR_LOG0(TRACE,"WNetLogonNotify: Function Not Supported\n");
|
|
status = WN_NOT_SUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Handle normal errors passed back from the provider
|
|
//
|
|
if (status == WN_SUCCESS)
|
|
{
|
|
if (scriptSize != 0)
|
|
{
|
|
//
|
|
// There must be some logon scripts. Allocate memory for them.
|
|
//
|
|
*lpLogonScripts = (LPWSTR)LocalAlloc(
|
|
LMEM_FIXED,
|
|
scriptSize+sizeof(WCHAR));
|
|
|
|
if (*lpLogonScripts != NULL)
|
|
{
|
|
//
|
|
// Copy the logon scripts into the new buffer.
|
|
//
|
|
pScript = *lpLogonScripts;
|
|
|
|
for (i = 0; i < numProviders; i++)
|
|
{
|
|
if ((RetryArray[i].Status == WN_SUCCESS) &&
|
|
(RetryArray[i].LogonScript != NULL))
|
|
{
|
|
//
|
|
// If the provider returns an empty logon script,
|
|
// don't add the empty string to the list as that
|
|
// shows up as the end of the list to the caller.
|
|
//
|
|
|
|
DWORD dwSize = WCSSIZE(RetryArray[i].LogonScript);
|
|
|
|
if (dwSize > sizeof(WCHAR))
|
|
{
|
|
wcscpy(pScript, RetryArray[i].LogonScript);
|
|
|
|
//
|
|
// Update the pointer to point beyond the last null
|
|
// terminator.
|
|
//
|
|
|
|
pScript += (dwSize / sizeof(WCHAR));
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add the double NULL terminator.
|
|
//
|
|
*pScript = L'\0';
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The allocation failed. (ERROR LOG?)
|
|
//
|
|
MPR_LOG0(ERROR,"Logon scripts will be lost - could not "
|
|
"allocate memory\n");
|
|
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
SetLastError(status);
|
|
}
|
|
|
|
if (RetryArray != NULL) {
|
|
LocalFree(RetryArray);
|
|
}
|
|
MPR_LOG1(TRACE,"Leaving WNetLogonNotify status = %d\n",status);
|
|
return(status);
|
|
}
|
|
|
|
DWORD APIENTRY
|
|
WNetPasswordChangeNotify(
|
|
LPCWSTR lpPrimaryAuthenticator,
|
|
LPCWSTR lpAuthentInfoType,
|
|
LPVOID lpAuthentInfo,
|
|
LPCWSTR lpPreviousAuthentInfoType,
|
|
LPVOID lpPreviousAuthentInfo,
|
|
LPWSTR lpStationName,
|
|
LPVOID StationHandle,
|
|
DWORD dwChangeInfo
|
|
)
|
|
|
|
|
|
/*++
|
|
|
|
Description:
|
|
|
|
This function is used to notify credential managers of a password
|
|
change for an account.
|
|
|
|
Arguments:
|
|
|
|
lpPrimaryAuthenticator - This is a pointer to a string that identifies
|
|
the primary authenticator. Credential Manager does not need the
|
|
password notification since it already handled the change.
|
|
This string is obtained from the "\HKEY_LOCAL_MACHINE\SYSTEM\
|
|
CurrentControlSet\Services\*(keyname)\NetworkProvider\Name" registry
|
|
value.
|
|
|
|
lpAuthentInfoType - This points to a string that identifies the
|
|
AuthentInfo structure type.
|
|
|
|
When Microsoft is the primary authenticator, the values that
|
|
may be expected here are the ones described for the
|
|
lpAuthentInfoType parameter to NPLogonNotify().
|
|
|
|
lpAuthentInfo - This points to a structure that contains the
|
|
new credentials.
|
|
|
|
When Microsoft is the primary authenticator, the structures that
|
|
may be expected here are the ones described for the lpAuthentInfo
|
|
parameter to NPLogonNotify().
|
|
|
|
lpPreviousAuthentInfoType - This points to the string that identifies
|
|
the PreviousAuthentInfo structure type.
|
|
|
|
The values that may be expected here are the same as the values that
|
|
may be expected for the lpAuthentInfoType parameter.
|
|
|
|
lpPreviousAuthentInfo - This points to an AuthentInfo structure that
|
|
contains the previous credential information. (old password and such).
|
|
|
|
The structures that may be expected here are the same as the
|
|
structures that may be expected for the lpAuthentInfo parameter.
|
|
|
|
lpStationName - This parameter contains the name of the station the
|
|
user performed the authentication information change from.
|
|
This may be used to determine whether or not interaction with the
|
|
user to obtain additional (provider-specific) information is possible.
|
|
This information will also have a bearing on the meaning and use of
|
|
the StationHandle parameter.
|
|
|
|
When Microsoft is the primary authenticator, the values that
|
|
may be expected here are the ones described for the lpStationName
|
|
parameter to NPLogonNotify().
|
|
|
|
StationHandle - Is a 32-bit value whose meaning is dependent upon the
|
|
name (and consequently, the type) of station being logged onto.
|
|
|
|
When Microsoft is the primary authenticator, the values that
|
|
may be expected here are the ones described for the lpStationHandle
|
|
parameter to NPLogonNotify().
|
|
|
|
dwChangeInfo - This is a set of flags that provide information about the
|
|
change. Currently the following possible values are defined:
|
|
|
|
WN_VALID_LOGON_ACCOUNT - If this flag is set, then the
|
|
password (or, more accurately, the authentication
|
|
information) that was changed will affect future
|
|
logons. Some authentication information changes
|
|
will only affect connections made in untrusted
|
|
domains. These are accounts that the user cannot
|
|
use to logon to this machine anyway. In these
|
|
cases, this flag will not be set.
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
Note:
|
|
|
|
|
|
--*/
|
|
{
|
|
DWORD status = WN_SUCCESS;
|
|
LPDWORD indexArray;
|
|
DWORD localArray[DEFAULT_MAX_PROVIDERS];
|
|
DWORD numProviders;
|
|
LPPROVIDER provider;
|
|
BOOL fcnSupported = FALSE; // Is fcn supported by a provider?
|
|
DWORD i,j;
|
|
DWORD primaryIndex;
|
|
BOOL oneSuccess=FALSE;
|
|
|
|
MprCheckProviders();
|
|
|
|
CProviderSharedLock PLock;
|
|
|
|
INIT_IF_NECESSARY(CREDENTIAL_LEVEL,status);
|
|
|
|
//
|
|
// Find the list of providers to call for this request.
|
|
//
|
|
indexArray = localArray;
|
|
|
|
//
|
|
// If there are no active providers, MprFindCallOrder returns
|
|
// WN_NO_NETWORK.
|
|
//
|
|
status = MprFindCallOrder(
|
|
NULL,
|
|
&indexArray,
|
|
&numProviders,
|
|
CREDENTIAL_TYPE);
|
|
|
|
if (status != WN_SUCCESS) {
|
|
return(status);
|
|
}
|
|
|
|
__try {
|
|
//
|
|
// Remove the primary authenticator from the list.
|
|
//
|
|
if (MprGetProviderIndex((LPTSTR)lpPrimaryAuthenticator,&primaryIndex)) {
|
|
|
|
for (i=0; i<numProviders ;i++ ) {
|
|
if (indexArray[i] == primaryIndex) {
|
|
numProviders--;
|
|
j=i;
|
|
i++;
|
|
for (; j<numProviders; i++,j++) {
|
|
indexArray[j] = indexArray[i];
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
__except(MPR_EXCEPTION_FILTER) {
|
|
status = GetExceptionCode();
|
|
if (status != EXCEPTION_ACCESS_VIOLATION) {
|
|
MPR_LOG(ERROR,"WNetChangePassword:Unexpected Exception 0x%lx\n",status);
|
|
}
|
|
status = WN_BAD_POINTER;
|
|
}
|
|
|
|
//
|
|
// If there are no credential managers aside from the primary, the
|
|
// return with success.
|
|
//
|
|
if (numProviders == 0) {
|
|
if (indexArray != localArray) {
|
|
LocalFree(indexArray);
|
|
}
|
|
return(WN_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// Loop through the list of providers notifying each one.
|
|
//
|
|
|
|
for (i=0; i<numProviders; i++) {
|
|
|
|
//
|
|
// Call the appropriate provider's API entry point
|
|
//
|
|
provider = GlobalProviderInfo + indexArray[i];
|
|
|
|
if (provider->PasswordChangeNotify != NULL) {
|
|
|
|
fcnSupported = TRUE;
|
|
|
|
__try {
|
|
MPR_LOG(TRACE,"Calling (%ws) ChangePasswordNotify function\n",
|
|
provider->Resource.lpProvider);
|
|
|
|
status = provider->PasswordChangeNotify(
|
|
lpAuthentInfoType,
|
|
lpAuthentInfo,
|
|
lpPreviousAuthentInfoType,
|
|
lpPreviousAuthentInfo,
|
|
lpStationName,
|
|
StationHandle,
|
|
dwChangeInfo);
|
|
}
|
|
__except(MPR_EXCEPTION_FILTER) {
|
|
status = GetExceptionCode();
|
|
if (status != EXCEPTION_ACCESS_VIOLATION) {
|
|
MPR_LOG(ERROR,"WNetChangePassword:Unexpected Exception 0x%lx\n",status);
|
|
}
|
|
status = WN_BAD_POINTER;
|
|
}
|
|
if (status == WN_SUCCESS) {
|
|
//
|
|
// If the call was successful, then we indicate that at least
|
|
// one of the calls was successful.
|
|
//
|
|
oneSuccess = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fcnSupported == FALSE) {
|
|
//
|
|
// No providers in the list support the API function. Therefore,
|
|
// we assume that no networks are installed.
|
|
//
|
|
status = WN_NOT_SUPPORTED;
|
|
}
|
|
|
|
//
|
|
// If memory was allocated by MprFindCallOrder, free it.
|
|
//
|
|
if (indexArray != localArray) {
|
|
LocalFree(indexArray);
|
|
}
|
|
|
|
//
|
|
// Handle normal errors passed back from the provider
|
|
//
|
|
if (oneSuccess == TRUE) {
|
|
status = WN_SUCCESS;
|
|
}
|
|
else {
|
|
SetLastError(status);
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
#ifdef REMOVE
|
|
|
|
DWORD APIENTRY
|
|
WNetLogoffNotify(
|
|
HWND hwndOwner,
|
|
LPCWSTR lpPrimaryAuthenticator,
|
|
PLUID lpLogonId,
|
|
WN_OPERATION_TYPE OperationType
|
|
)
|
|
|
|
/*++
|
|
|
|
Description:
|
|
|
|
This function provides log-off notification to credential managers.
|
|
|
|
Arguments:
|
|
|
|
hwndOwner - Identifies the owner window.
|
|
|
|
lpPrimaryAuthenticator - This is a pointer to a string that identifies
|
|
the primary authenticator. Credential Manager does not need the
|
|
password notification since it already handled the change.
|
|
|
|
lpLogonId - The logon ID of the session currently being logged on.
|
|
|
|
OperationType - The type of operation. This indicates whether the
|
|
function call is from an interactive program (winlogon), or a
|
|
background program (service controller). User dialogs should not
|
|
be displayed if the call was from a background process.
|
|
|
|
|
|
Return Value:
|
|
|
|
WN_SUCCESS - This is returned if we are able to successfully notify at
|
|
least one of the providers which has registered an entry point for
|
|
the Logoff event.
|
|
|
|
WN_NO_NETWORK - This is returned if there are no providers, or if
|
|
there is only one provider, but its supporting service/driver is
|
|
not available.
|
|
|
|
WN_BAD_POINTER - This is returned if one of the pointer parameters
|
|
is bad and causes an exception.
|
|
|
|
WN_NOT_SUPPORTED - This is returned if none of the active providers
|
|
support this function.
|
|
|
|
system errors such as ERROR_OUT_OF_MEMORY are also reported.
|
|
|
|
|
|
Note:
|
|
|
|
|
|
--*/
|
|
{
|
|
DWORD status = WN_SUCCESS;
|
|
LPDWORD indexArray;
|
|
DWORD localArray[DEFAULT_MAX_PROVIDERS];
|
|
DWORD numProviders;
|
|
LPPROVIDER provider;
|
|
BOOL fcnSupported = FALSE; // Is fcn supported by a provider?
|
|
DWORD i,j;
|
|
DWORD primaryIndex;
|
|
BOOL oneSuccess=FALSE;
|
|
|
|
MprCheckProviders();
|
|
|
|
CProviderSharedLock PLock;
|
|
|
|
INIT_IF_NECESSARY(CREDENTIAL_LEVEL,status);
|
|
|
|
//
|
|
// Find the list of providers to call for this request.
|
|
//
|
|
indexArray = localArray;
|
|
|
|
//
|
|
// If there are no active providers, MprFindCallOrder returns
|
|
// WN_NO_NETWORK.
|
|
//
|
|
status = MprFindCallOrder(
|
|
NULL,
|
|
&indexArray,
|
|
&numProviders,
|
|
CREDENTIAL_TYPE);
|
|
|
|
if (status != WN_SUCCESS) {
|
|
return(status);
|
|
}
|
|
|
|
try {
|
|
//
|
|
// Remove the primary authenticator from the list.
|
|
//
|
|
if (MprGetProviderIndex((LPTSTR)lpPrimaryAuthenticator,&primaryIndex)) {
|
|
|
|
for (i=0; i<numProviders ;i++ ) {
|
|
if (indexArray[i] == primaryIndex) {
|
|
numProviders--;
|
|
j=i;
|
|
i++;
|
|
for (; j<numProviders; i++,j++) {
|
|
indexArray[j] = indexArray[i];
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
except(MPR_EXCEPTION_FILTER) {
|
|
status = GetExceptionCode();
|
|
if (status != EXCEPTION_ACCESS_VIOLATION) {
|
|
MPR_LOG(ERROR,"WNetChangePassword:Unexpected Exception 0x%lx\n",status);
|
|
}
|
|
status = WN_BAD_POINTER;
|
|
}
|
|
|
|
//
|
|
// If there are no credential managers aside from the primary, the
|
|
// return with success.
|
|
//
|
|
if (numProviders == 0) {
|
|
if (indexArray != localArray) {
|
|
LocalFree(indexArray);
|
|
}
|
|
return(WN_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// Loop through the list of providers notifying each one.
|
|
//
|
|
|
|
for (i=0; i<numProviders; i++) {
|
|
|
|
//
|
|
// Call the appropriate provider's API entry point
|
|
//
|
|
provider = GlobalProviderInfo + indexArray[i];
|
|
|
|
if ((provider->InitClass & CREDENTIAL_TYPE) &&
|
|
(provider->LogoffNotify != NULL)) {
|
|
|
|
fcnSupported = TRUE;
|
|
|
|
try {
|
|
status = provider->LogoffNotify(
|
|
hwndOwner,
|
|
lpLogonId,
|
|
OperationType);
|
|
}
|
|
except(MPR_EXCEPTION_FILTER) {
|
|
status = GetExceptionCode();
|
|
if (status != EXCEPTION_ACCESS_VIOLATION) {
|
|
MPR_LOG(ERROR,"WNetLogoffNotify:Unexpected Exception 0x%lx\n",status);
|
|
}
|
|
status = WN_BAD_POINTER;
|
|
}
|
|
if (status == WN_SUCCESS) {
|
|
//
|
|
// If the call was successful, then we indicate that at least
|
|
// one of the calls was successful.
|
|
//
|
|
oneSuccess = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fcnSupported == FALSE) {
|
|
//
|
|
// No providers in the list support the API function. Therefore,
|
|
// we assume that no networks are installed.
|
|
//
|
|
status = WN_NOT_SUPPORTED;
|
|
}
|
|
|
|
//
|
|
// If memory was allocated by MprFindCallOrder, free it.
|
|
//
|
|
if (indexArray != localArray) {
|
|
LocalFree(indexArray);
|
|
}
|
|
|
|
//
|
|
// Handle normal errors passed back from the provider
|
|
//
|
|
if (oneSuccess == TRUE) {
|
|
status = WN_SUCCESS;
|
|
}
|
|
else {
|
|
SetLastError(status);
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
#endif // REMOVE
|
|
|
|
DWORD
|
|
MprMakeRetryArray(
|
|
LPCWSTR lpPrimaryAuthenticator,
|
|
LPDWORD lpNumProviders,
|
|
LPRETRY_INFO *lpRetryArray,
|
|
LPDWORD lpRegMaxWait
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns with an array of RETRY_INFO structures. There is
|
|
one array element for each credential manager provider that is NOT
|
|
the current primary authenticator. The structures contain such information
|
|
as the provider index in the global array of provider information, a
|
|
location for the provider's timeout value, status and continue flag.
|
|
|
|
This function will also attempt to obtain the WaitTimeout from the
|
|
registry if it exists.
|
|
|
|
IMPORTANT!
|
|
This function allocates memory for lpRetryArray. The caller is
|
|
expected to free this memory with LocalFree(). If an error is
|
|
returned, or if the data at lpNumProviders is 0, then memory is
|
|
not allocated.
|
|
|
|
Arguments:
|
|
|
|
lpPrimaryAuthenticator - This is a pointer to a string that identifies
|
|
the primary authenticator. The router uses this information to
|
|
skip the credential manager identified by this string. Since it
|
|
is the primary, it has already handled the logon.
|
|
|
|
lpNumProviders - This is a pointer to a location where the number of
|
|
providers in the lpRetryArray are stored.
|
|
|
|
lpRetryArray - This is an array of RETRY_INFO structures. There is one
|
|
element in the array for each Credential Manager provider that is
|
|
not the current PrimaryAuthenticator. The status in the array is
|
|
initialized to WN_NO_NETWORK.
|
|
|
|
lpRegMaxWait - This is a pointer to the location to where the Maximum
|
|
Wait Timeout from the registry is to be placed. If there is no
|
|
MaxWait value in the registry, zero is returned.
|
|
|
|
|
|
Return Value:
|
|
|
|
WN_SUCCESS is returned if we successfully created an array of
|
|
RetryInfo structures, or if there are no credential manager providers.
|
|
If we are unable to allocate memory for the RetryInfo structures,
|
|
then the failure from LocalAlloc is returned.
|
|
|
|
--*/
|
|
{
|
|
DWORD status;
|
|
DWORD i,j;
|
|
HKEY providerKeyHandle;
|
|
DWORD primaryIndex;
|
|
DWORD ValueType;
|
|
DWORD Temp;
|
|
DWORD numProviders;
|
|
LPDWORD indexArray;
|
|
DWORD localArray[DEFAULT_MAX_PROVIDERS];
|
|
|
|
ASSERT(MPRProviderLock.Have());
|
|
|
|
//
|
|
// Find the list of providers to call for this request.
|
|
//
|
|
indexArray = localArray;
|
|
|
|
//
|
|
// If there are no active providers, or none of the active providers are
|
|
// in this InitClass MprFindCallOrder returns WN_NO_NETWORK.
|
|
//
|
|
status = MprFindCallOrder(
|
|
NULL,
|
|
&indexArray,
|
|
&numProviders,
|
|
CREDENTIAL_TYPE);
|
|
|
|
if ((status != WN_SUCCESS) || (numProviders == 0)) {
|
|
//
|
|
// If there aren't any credential managers, then just return.
|
|
//
|
|
MPR_LOG0(TRACE,"MprMakeRetryArray: There aren't any Credential Managers\n");
|
|
*lpNumProviders = 0;
|
|
return(WN_SUCCESS);
|
|
}
|
|
|
|
*lpNumProviders = numProviders;
|
|
|
|
//
|
|
// Remove the primary authenticator from the list.
|
|
//
|
|
if (MprGetProviderIndex((LPTSTR)lpPrimaryAuthenticator,&primaryIndex)) {
|
|
|
|
for (i=0; i<numProviders ;i++ ) {
|
|
if (indexArray[i] == primaryIndex) {
|
|
numProviders--;
|
|
j=i;
|
|
i++;
|
|
for (; j<numProviders; i++,j++) {
|
|
indexArray[j] = indexArray[i];
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
//
|
|
// If there are no credential managers aside from the primary, the
|
|
// return with success.
|
|
//
|
|
*lpNumProviders = numProviders;
|
|
if (numProviders == 0) {
|
|
if (indexArray != localArray) {
|
|
LocalFree(indexArray);
|
|
}
|
|
MPR_LOG0(TRACE,"MprMakeRetryArray: There aren't any "
|
|
"Credential Managers aside from the Primary\n");
|
|
return(WN_SUCCESS);
|
|
}
|
|
}
|
|
|
|
//
|
|
// At this point the indexArray only contains indices for Credential
|
|
// Manager providers that are not the primary authenticator.
|
|
//
|
|
//
|
|
// Now create an array of information about the providers so that we
|
|
// can retry until timeout, or all providers are functional. This
|
|
// memory is expected to be initialized to zero when allocated.
|
|
//
|
|
|
|
*lpRetryArray = (LPRETRY_INFO)LocalAlloc(LPTR, sizeof(RETRY_INFO) * numProviders);
|
|
if (*lpRetryArray == NULL) {
|
|
return(GetLastError());
|
|
}
|
|
for (i=0; i<numProviders; i++) {
|
|
(*lpRetryArray)[i].Status = WN_NO_NETWORK;
|
|
(*lpRetryArray)[i].ProviderIndex = indexArray[i];
|
|
(*lpRetryArray)[i].ContinueFlag = TRUE;
|
|
}
|
|
|
|
if (indexArray != localArray) {
|
|
LocalFree(indexArray);
|
|
}
|
|
|
|
//
|
|
// Read the MaxWait value that is stored in the registry.
|
|
// If it is not there or if the value is less than our default
|
|
// maximum value, then use the default instead.
|
|
//
|
|
|
|
if(!MprOpenKey(
|
|
HKEY_LOCAL_MACHINE, // hKey
|
|
NET_PROVIDER_KEY, // lpSubKey
|
|
&providerKeyHandle, // Newly Opened Key Handle
|
|
DA_READ)) { // Desired Access
|
|
|
|
MPR_LOG(ERROR,"MprCreateConnectionArray: MprOpenKey (%ws) Error\n",
|
|
NET_PROVIDER_KEY);
|
|
|
|
*lpRegMaxWait = 0;
|
|
return(WN_SUCCESS);
|
|
}
|
|
MPR_LOG(TRACE,"OpenKey %ws\n",NET_PROVIDER_KEY);
|
|
|
|
Temp = sizeof(*lpRegMaxWait);
|
|
|
|
status = RegQueryValueEx(
|
|
providerKeyHandle,
|
|
RESTORE_WAIT_VALUE,
|
|
NULL,
|
|
&ValueType,
|
|
(LPBYTE)lpRegMaxWait,
|
|
&Temp);
|
|
|
|
if (status != NO_ERROR) {
|
|
*lpRegMaxWait = 0;
|
|
}
|
|
|
|
RegCloseKey(providerKeyHandle);
|
|
|
|
return(WN_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
MprUpdateTimeout(
|
|
LPRETRY_INFO RetryInfo,
|
|
LPPROVIDER Provider,
|
|
DWORD RegMaxWait,
|
|
LPDWORD pMaxWait,
|
|
DWORD StartTime,
|
|
DWORD CallStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function attempts to get timeout information from the provider.
|
|
If the provider will never start, the ContinueFlag in the RetryInfo is
|
|
set to FALSE. If the provider tells us how long we should wait, then
|
|
MaxWait is updated if that time is longer than the current MaxWait.
|
|
|
|
Arguments:
|
|
|
|
RetryInfo - This is a pointer to a structure that contains retry
|
|
information for a particular provider.
|
|
|
|
Provider - This is a pointer to a structure that contains dll
|
|
entry points for a particular provider.
|
|
|
|
RegMaxWait - This is the default timeout. It is either the hard-coded
|
|
timeout, or the timeout in the registry.
|
|
|
|
pMaxWait - This is a pointer to a value that is the maximum amount of
|
|
time that the router will wait for the provider to be ready to receive
|
|
the function call.
|
|
|
|
StartTime - This is the clock tick time that we started the operation with.
|
|
|
|
CallStatus - This is the status from the most recent function call to the
|
|
provider.
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
DWORD ElapsedTime;
|
|
DWORD CurrentTime;
|
|
DWORD providerStatus;
|
|
PF_NPGetCaps pGetCaps;
|
|
|
|
MPR_LOG0(TRACE,"Entering MprUpdateTimeout\n");
|
|
|
|
ASSERT(MPRProviderLock.Have());
|
|
|
|
//
|
|
// First try the credential manager's GetCaps function.
|
|
// if it doesn't exist, then use the network provider's
|
|
// function.
|
|
//
|
|
pGetCaps = Provider->GetAuthentCaps;
|
|
if (pGetCaps == NULL) {
|
|
pGetCaps = Provider->GetCaps;
|
|
}
|
|
|
|
//
|
|
// If this is the first pass through, we don't have the
|
|
// wait times figured out for each provider. Do that
|
|
// now.
|
|
//
|
|
if (RetryInfo->ProviderWait == 0) {
|
|
|
|
MPR_LOG1(TRACE,"Call GetCaps to get (%ws)provider start timeout\n",
|
|
Provider->Resource.lpProvider);
|
|
|
|
if (pGetCaps != NULL) {
|
|
|
|
providerStatus = pGetCaps(WNNC_START);
|
|
|
|
switch (providerStatus) {
|
|
case PROVIDER_WILL_NOT_START:
|
|
MPR_LOG0(TRACE,"Provider will not start\n");
|
|
RetryInfo->ContinueFlag = FALSE;
|
|
RetryInfo->Status = CallStatus;
|
|
break;
|
|
case NO_TIME_ESTIMATE:
|
|
MPR_LOG0(TRACE,"No Time estimate for Provider start\n");
|
|
if (RegMaxWait != 0) {
|
|
RetryInfo->ProviderWait = RegMaxWait;
|
|
}
|
|
else {
|
|
RetryInfo->ProviderWait = DEFAULT_WAIT_TIME;
|
|
}
|
|
if (*pMaxWait < RetryInfo->ProviderWait) {
|
|
*pMaxWait = RetryInfo->ProviderWait;
|
|
}
|
|
break;
|
|
default:
|
|
|
|
MPR_LOG1(TRACE,"Time estimate for Provider start = %d\n",
|
|
providerStatus);
|
|
//
|
|
// In this case, the providerStatus is actually
|
|
// the amount of time we should wait for this
|
|
// provider. We set MaxWait to the longest of
|
|
// the times specified by the providers.
|
|
//
|
|
if ((providerStatus <= MAX_ALLOWED_WAIT_TIME) &&
|
|
(providerStatus > *pMaxWait)) {
|
|
*pMaxWait = providerStatus;
|
|
}
|
|
RetryInfo->ProviderWait = *pMaxWait;
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
MPR_LOG0(TRACE,"There is no GetCaps function. So we cannot "
|
|
"obtain the provider start timeout\n");
|
|
RetryInfo->ContinueFlag = FALSE;
|
|
RetryInfo->Status = CallStatus;
|
|
}
|
|
}
|
|
//
|
|
// If the status for this provider has just changed to
|
|
// WN_FUNCTION_BUSY from some other status, then calculate
|
|
// a timeout time by getting the provider's new timeout
|
|
// and adding that to the elapsed time since start. This
|
|
// gives a total elapsed time until timeout - which can
|
|
// be compared with the current MaxWait.
|
|
//
|
|
if ((CallStatus == WN_FUNCTION_BUSY) &&
|
|
(RetryInfo->Status == WN_NO_NETWORK)) {
|
|
|
|
MPR_LOG1(TRACE,"Provider status just changed to FUNCTION_BUSY "
|
|
"from some other status - Call GetCaps to get (%ws)provider "
|
|
" start timeout\n",
|
|
Provider->Resource.lpProvider);
|
|
|
|
if (pGetCaps != NULL) {
|
|
providerStatus = pGetCaps(WNNC_START);
|
|
switch (providerStatus) {
|
|
case PROVIDER_WILL_NOT_START:
|
|
MPR_LOG0(TRACE,"Provider will not start - bizzare case\n");
|
|
//
|
|
// This is bizzare to find the status = BUSY,
|
|
// and then have the Provider not starting.
|
|
//
|
|
RetryInfo->ContinueFlag = FALSE;
|
|
break;
|
|
case NO_TIME_ESTIMATE:
|
|
MPR_LOG0(TRACE,"No Time estimate for Provider start\n");
|
|
//
|
|
// No need to alter the timeout for this one.
|
|
//
|
|
break;
|
|
default:
|
|
MPR_LOG1(TRACE,"Time estimate for Provider start = %d\n",
|
|
providerStatus);
|
|
//
|
|
// Make sure this new timeout information will take
|
|
// less than the maximum allowed time for
|
|
// providers.
|
|
//
|
|
if (providerStatus <= MAX_ALLOWED_WAIT_TIME) {
|
|
CurrentTime = GetTickCount();
|
|
//
|
|
// Determine how much time has elapsed since
|
|
// we started.
|
|
//
|
|
ElapsedTime = CurrentTime - StartTime;
|
|
|
|
//
|
|
// Add the Elapsed time to the new timeout
|
|
// we just received from the provider to come
|
|
// up with a timeout value that can be
|
|
// compared with MaxWait.
|
|
//
|
|
providerStatus += ElapsedTime;
|
|
|
|
//
|
|
// If the new timeout is larger than MaxWait,
|
|
// then use the new timeout.
|
|
//
|
|
if (providerStatus > *pMaxWait) {
|
|
*pMaxWait = providerStatus;
|
|
}
|
|
} // EndIf (Make sure time out is < max allowed).
|
|
break;
|
|
|
|
} // End Switch (changed status).
|
|
}
|
|
|
|
} // End If (change state from NO_NET to BUSY)
|
|
|
|
//
|
|
// Store the status (either NO_NET or BUSY) with the
|
|
// retry info.
|
|
//
|
|
RetryInfo->Status = CallStatus;
|
|
|
|
MPR_LOG0(TRACE,"Leaving MprUpdateTimeout\n");
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
MprCheckTimeout(
|
|
BOOL *ContinueFlag,
|
|
DWORD StartTime,
|
|
DWORD MaxWait,
|
|
LPDWORD lpStatus
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function checks to see if a timeout occured.
|
|
|
|
Arguments:
|
|
|
|
ContinueFlag - This is a pointer to the location of the continue flag.
|
|
This is set to FALSE if a timeout occured.
|
|
|
|
StartTime - This is the tick count at the beginning of the operation.
|
|
|
|
lpStatus - This is a pointer to the current status for the operation.
|
|
This is updated only if a timeout occurs.
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
DWORD CurrentTime;
|
|
DWORD ElapsedTime;
|
|
|
|
MPR_LOG0(TRACE,"Entering MprCheckTimeout\n");
|
|
if (*ContinueFlag) {
|
|
//
|
|
// Determine what the elapsed time from the start is.
|
|
//
|
|
CurrentTime = GetTickCount();
|
|
ElapsedTime = CurrentTime - StartTime;
|
|
|
|
//
|
|
// If a timeout occured, then don't continue. Otherwise, sleep
|
|
// for a bit and loop again through all providers.
|
|
//
|
|
if (ElapsedTime > MaxWait) {
|
|
MPR_LOG0(TRACE,"WNetLogonNotify:Timed out while waiting "
|
|
"for Credential Managers\n");
|
|
*ContinueFlag = FALSE;
|
|
*lpStatus = ERROR_SERVICE_REQUEST_TIMEOUT;
|
|
}
|
|
else {
|
|
Sleep(2000);
|
|
}
|
|
}
|
|
MPR_LOG0(TRACE,"Leaving MprCheckTimeout\n");
|
|
}
|