windows-nt/Source/XPSP1/NT/net/rras/ras/ppp/raschap/eapchap.c

5567 lines
161 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/********************************************************************/
/** Copyright(c) 1985-1997 Microsoft Corporation. **/
/********************************************************************/
//***
//
// Filename: eapchap.c
//
// Description: Will do MD5 CHAP for EAP. This module is a EAP wrapper
// around CHAP
//
// History: May 11,1997 NarenG Created original version.
//
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntlsa.h>
#include <ntmsv1_0.h>
#include <ntsamp.h>
#define SECURITY_WIN32
#include <security.h> // For GetUserNameExW
#include <crypt.h>
#include <windows.h>
#include <lmcons.h>
#include <string.h>
#include <stdlib.h>
#include <rasman.h>
#include <pppcp.h>
#include <raserror.h>
#include <rtutils.h>
#include <md5.h>
#include <raseapif.h>
#include <eaptypeid.h>
#include <pppcp.h>
#define INCL_RASAUTHATTRIBUTES
#define INCL_PWUTIL
#define INCL_HOSTWIRE
#include <ppputil.h>
#include <raschap.h>
#include <wincrypt.h>
#include <wintrust.h>
#include <softpub.h>
#include <mscat.h>
#include <ezlogon.h>
#include "resource.h"
#define STRSAFE_NO_DEPRECATE
#include <strsafe.h>
#define EAPTYPE_MD5Challenge 4
//
// We need to move this definition to pppcp.h
//
#define VENDOR_MICROSOFT 311
//
// Various states that EAPMSCHAPv2 can be in.
//
#define EAPMSCHAPv2STATE enum tagEAPMSCHAPv2STATE
EAPMSCHAPv2STATE
{
EMV2_Initial,
EMV2_RequestSend,
EMV2_ResponseSend,
EMV2_CHAPAuthSuccess,
EMV2_CHAPAuthFail,
EMV2_Success,
EMV2_Failure
};
//
// These ids are pulled in from rasdlg. Need them for the
// change password dialog in case of winlogon scenario
//
#define DID_CP_ChangePassword2 109
#define CID_CP_EB_ConfirmPassword_RASDLG 1058
#define CID_CP_EB_OldPassword_RASDLG 1059
#define CID_CP_EB_Password_RASDLG 1060
//
// Reg Key for EAPMSCHAPv2
//
#define EAPMSCHAPv2_KEY "System\\CurrentControlSet\\Services\\Rasman\\PPP\\EAP\\26"
#define EAPMSCHAPv2_VAL_SERVER_CONFIG_DATA "ServerConfigData"
//
//
// Flags for EAPMSChapv2
//
//
/*
** SaveUid and password
*/
#define EAPMSCHAPv2_FLAG_SAVE_UID_PWD 0x00000001
/*
** Use Winlogon Credentials
*/
#define EAPMSCHAPv2_FLAG_USE_WINLOGON_CREDS 0x00000002
/*
** Allow Change password - server side only.
*/
#define EAPMSCHAPv2_FLAG_ALLOW_CHANGEPWD 0x00000004
/*
** MACHINE Auth is happening
*/
#define EAPMSCHAPv2_FLAG_MACHINE_AUTH 0x00000008
#define EAPMSCHAPv2_FLAG_CALLED_WITHIN_WINLOGON 0x00000010
#define EAPMSCHAPv2_FLAG_8021x 0x00000020
typedef struct _EAPMSCHAPv2_USER_PROPERTIES
{
DWORD dwVersion; //Version = 2
DWORD fFlags;
//This is a server config property. Tells the server
//how many retris are allowed
DWORD dwMaxRetries;
CHAR szUserName[UNLEN+1];
CHAR szPassword[PWLEN+1];
CHAR szDomain[DNLEN+1];
DWORD cbEncPassword; //Number of bytes in encrypted password
BYTE bEncPassword[1]; //Encrypted Password if any ...
}EAPMSCHAPv2_USER_PROPERTIES, *PEAPMSCHAPv2_USER_PROPERTIES;
//
// USER properties for EAPMSCHAPv2
//
typedef struct _EAPMSCHAPv2_USER_PROPERTIES_v1
{
DWORD dwVersion;
DWORD fFlags;
//This is a server config property. Tells the server
//how many retris are allowed
DWORD dwMaxRetries;
CHAR szUserName[UNLEN+1];
CHAR szPassword[PWLEN+1];
CHAR szDomain[DNLEN+1];
}EAPMSCHAPv2_USER_PROPERTIES_v1, *PEAPMSCHAPv2_USER_PROPERTIES_v1;
//
// CONNECTION properties for EAPMSCHAPv2
//
typedef struct _EAPMSCHAPv2_CONN_PROPERTIES
{
DWORD dwVersion;
//This is the only field for now. Maybe more will come in later.
DWORD fFlags;
}EAPMSCHAPv2_CONN_PROPERTIES, * PEAPMSCHAPv2_CONN_PROPERTIES;
//
// Interactive UI for EAPMSCHAPv2
//
// Flag for retry password ui
#define EAPMSCHAPv2_INTERACTIVE_UI_FLAG_RETRY 0x00000001
//
// flag indicating show the change password in case
// the old password is provided
#define EAPMSCHAPv2_INTERACTIVE_UI_FLAG_CHANGE_PWD 0x00000002
//
// flag indicating that change password was invoked in
// winlogon context
//
#define EAPMSCHAPv2_INTERACTIVE_UI_FLAG_CHANGE_PWD_WINLOGON 0x00000004
typedef struct _EAPMSCHAPv2_INTERACTIVE_UI
{
DWORD dwVersion;
DWORD fFlags;
EAPMSCHAPv2_USER_PROPERTIES UserProp;
CHAR szNewPassword[PWLEN+1];
}EAPMSCHAPv2_INTERACTIVE_UI, * PEAPMSCHAPv2_INTERACTIVE_UI;
#define EAPMSCHAPv2WB struct tagEAPMSCHAPv2WB
EAPMSCHAPv2WB
{
EAPMSCHAPv2STATE EapState;
DWORD fFlags;
DWORD dwInteractiveUIOperation;
BYTE IdToSend;
BYTE IdToExpect;
PEAPMSCHAPv2_INTERACTIVE_UI pUIContextData;
PEAPMSCHAPv2_USER_PROPERTIES pUserProp;
CHAR szOldPassword[PWLEN+1];
//We need to save this for auth purposes.
WCHAR wszRadiusUserName[UNLEN+DNLEN+1];
PEAPMSCHAPv2_CONN_PROPERTIES pConnProp;
CHAPWB * pwb;
RAS_AUTH_ATTRIBUTE * pUserAttributes;
DWORD dwAuthResultCode;
};
//
// This structure is shared between retry and
// logon dialog
//
typedef struct _EAPMSCHAPv2_LOGON_DIALOG
{
PEAPMSCHAPv2_USER_PROPERTIES pUserProp;
HWND hWndUserName;
HWND hWndPassword;
HWND hWndDomain;
HWND hWndSavePassword;
}EAPMSCHAPv2_LOGON_DIALOG, * PEAPMSCHAPv2_LOGON_DIALOG;
//
// This stuct is used for client config UI.
//
typedef struct _EAPMSCHAPv2_CLIENTCONFIG_DIALOG
{
PEAPMSCHAPv2_CONN_PROPERTIES pConnProp;
}EAPMSCHAPv2_CLIENTCONFIG_DIALOG, * PEAPMSCHAPv2_CLIENTCONFIG_DIALOG;
typedef struct _EAPMSCHAPv2_SERVERCONFIG_DIALOG
{
PEAPMSCHAPv2_USER_PROPERTIES pUserProp;
HWND hWndRetries;
}EAPMSCHAPv2_SERVERCONFIG_DIALOG, *PEAPMSCHAPv2_SERVERCONFIG_DIALOG;
typedef struct _EAPMSCHAPv2_CHANGEPWD_DIALOG
{
PEAPMSCHAPv2_INTERACTIVE_UI pInteractiveUIData;
HWND hWndNewPassword;
HWND hWndConfirmNewPassword;
HWND hWndOldPassword;
}EAPMSCHAPv2_CHANGEPWD_DIALOG, *PEAPMSCHAPv2_CHANGEPWD_DIALOG;
DWORD
AllocateUserDataWithEncPwd ( EAPMSCHAPv2WB * pEapwb, DATA_BLOB * pDBPassword );
DWORD
EapMSCHAPv2Initialize(
IN BOOL fInitialize
);
INT_PTR CALLBACK
LogonDialogProc(
IN HWND hWnd,
IN UINT unMsg,
IN WPARAM wParam,
IN LPARAM lParam
);
INT_PTR CALLBACK
RetryDialogProc(
IN HWND hWnd,
IN UINT unMsg,
IN WPARAM wParam,
IN LPARAM lParam
);
INT_PTR CALLBACK
ClientConfigDialogProc(
IN HWND hWnd,
IN UINT unMsg,
IN WPARAM wParam,
IN LPARAM lParam
);
INT_PTR CALLBACK
ServerConfigDialogProc(
IN HWND hWnd,
IN UINT unMsg,
IN WPARAM wParam,
IN LPARAM lParam
);
INT_PTR CALLBACK
ChangePasswordDialogProc(
IN HWND hWnd,
IN UINT unMsg,
IN WPARAM wParam,
IN LPARAM lParam
);
HINSTANCE
GetHInstance(
VOID
);
HINSTANCE
GetResouceDLLHInstance(
VOID
);
HINSTANCE
GetRasDlgDLLHInstance(
VOID
);
extern DWORD g_dwTraceIdChap;
DWORD
ReadUserData(
IN BYTE* pUserDataIn,
IN DWORD dwSizeOfUserDataIn,
OUT PEAPMSCHAPv2_USER_PROPERTIES* ppUserProp
);
DWORD
ReadConnectionData(
IN BOOL fWirelessConnection,
IN BYTE* pConnectionDataIn,
IN DWORD dwSizeOfConnectionDataIn,
OUT PEAPMSCHAPv2_CONN_PROPERTIES* ppConnProp
);
DWORD
ServerConfigDataIO(
IN BOOL fRead,
IN CHAR* pszMachineName,
IN OUT BYTE** ppData,
IN DWORD dwNumBytes
);
DWORD
EncodePassword(
DWORD cbPassword,
PBYTE pbPassword,
DATA_BLOB * pDataBlobPassword)
{
DWORD dwErr = NO_ERROR;
DATA_BLOB DataBlobIn;
if(NULL == pDataBlobPassword)
{
dwErr = E_INVALIDARG;
goto done;
}
if( (0 == cbPassword)
|| (NULL == pbPassword))
{
//
// nothing to encrypt. just return success
//
goto done;
}
ZeroMemory(pDataBlobPassword, sizeof(DATA_BLOB));
DataBlobIn.cbData = cbPassword;
DataBlobIn.pbData = pbPassword;
if(!CryptProtectData(
&DataBlobIn,
NULL,
NULL,
NULL,
NULL,
CRYPTPROTECT_UI_FORBIDDEN |
CRYPTPROTECT_LOCAL_MACHINE,
pDataBlobPassword))
{
dwErr = GetLastError();
goto done;
}
done:
return dwErr;
}
DWORD
DecodePassword(
DATA_BLOB * pDataBlobPassword,
DWORD * pcbPassword,
PBYTE * ppbPassword)
{
DWORD dwErr = NO_ERROR;
DATA_BLOB DataOut;
if( (NULL == pDataBlobPassword)
|| (NULL == pcbPassword)
|| (NULL == ppbPassword))
{
dwErr = E_INVALIDARG;
goto done;
}
*pcbPassword = 0;
*ppbPassword = NULL;
if( (NULL == pDataBlobPassword->pbData)
|| (0 == pDataBlobPassword->cbData))
{
//
// nothing to decrypt. Just return success.
//
goto done;
}
ZeroMemory(&DataOut, sizeof(DATA_BLOB));
if(!CryptUnprotectData(
pDataBlobPassword,
NULL,
NULL,
NULL,
NULL,
CRYPTPROTECT_UI_FORBIDDEN |
CRYPTPROTECT_LOCAL_MACHINE,
&DataOut))
{
dwErr = GetLastError();
goto done;
}
*pcbPassword = DataOut.cbData;
*ppbPassword = DataOut.pbData;
done:
return dwErr;
}
VOID
FreePassword(DATA_BLOB *pDBPassword)
{
if(NULL == pDBPassword)
{
return;
}
if(NULL != pDBPassword->pbData)
{
RtlSecureZeroMemory(pDBPassword->pbData, pDBPassword->cbData);
LocalFree(pDBPassword->pbData);
}
ZeroMemory(pDBPassword, sizeof(DATA_BLOB));
}
//**
//
// Call: MapEapInputToApInput
//
// Returns: NO_ERROR - Success
// Non-zero returns - Failure
//
// Description:
//
VOID
MapEapInputToApInput(
IN PPP_EAP_INPUT* pPppEapInput,
OUT PPPAP_INPUT * pInput
)
{
pInput->fServer = pPppEapInput->fAuthenticator;
pInput->APDataSize = 1;
pInput->fAuthenticationComplete = pPppEapInput->fAuthenticationComplete;
pInput->dwAuthResultCode = pPppEapInput->dwAuthResultCode;
pInput->dwAuthError = NO_ERROR;
pInput->pUserAttributes = NULL;
pInput->pAttributesFromAuthenticator= pPppEapInput->pUserAttributes;
pInput->fSuccessPacketReceived = pPppEapInput->fSuccessPacketReceived;
pInput->dwInitialPacketId = pPppEapInput->bInitialId;
//
// These are used only for MS-CHAP
//
pInput->pszOldPassword = "";
pInput->dwRetries = 0;
}
//**
//
// Call: MapApInputToEapInput
//
// Returns: NONE
//
//
// Description: $TODO: Put in the correct mapping here
//
VOID
MapApResultToEapOutput(
IN PPPAP_RESULT * pApResult,
OUT PPP_EAP_OUTPUT* pPppEapOutput
)
{
//
//Action is already taken care of. So dont set it here
//
pPppEapOutput->dwAuthResultCode = pApResult->dwError;
pPppEapOutput->pUserAttributes = pApResult->pUserAttributes;
}
//**
//
// Call: EapChapBeginCommon
//
// Returns: NO_ERROR - Success
// Non-zero returns - Failure
//
// Description: Wrapper around ChapBegin
//
DWORD
EapChapBeginCommon(
IN DWORD dwEapType,
IN BOOL fUseWinLogon,
IN DWORD dwRetries,
IN EAPMSCHAPv2WB * pWB,
OUT VOID ** ppWorkBuffer,
IN PPP_EAP_INPUT * pPppEapInput
)
{
PPPAP_INPUT Input;
DWORD dwRetCode;
PPP_EAP_INPUT* pInput = (PPP_EAP_INPUT* )pPppEapInput;
BYTE bMD5 = 0x05;
BYTE bMSChapNew = 0x81;
BYTE bInvalid = 0xFF;
WCHAR * pWchar = NULL;
CHAR szDomain[DNLEN+1];
CHAR szUserName[UNLEN+1];
CHAR szPassword[PWLEN+1];
PPPAP_RESULT ApResult;
TRACE("EapChapBeginCommon");
ZeroMemory( &Input, sizeof( PPPAP_INPUT ) );
ZeroMemory( szDomain, sizeof( szDomain ) );
ZeroMemory( szUserName, sizeof( szUserName ) );
ZeroMemory( szPassword, sizeof( szPassword ) );
ZeroMemory( &ApResult, sizeof(ApResult) );
MapEapInputToApInput( pPppEapInput, &Input );
if ( dwEapType == EAPTYPE_MD5Challenge )
{
Input.pAPData = &bMD5;
}
else if ( dwEapType == PPP_EAP_MSCHAPv2 )
{
Input.pAPData = &bMSChapNew;
}
else
//Set the value to invalid type and let ChapBegin Fail
Input.pAPData = &bInvalid;
//
// If we dont have to use winlogon or we have to do machine auth
//
if ( !fUseWinLogon ||
( pPppEapInput->fFlags & RAS_EAP_FLAG_MACHINE_AUTH )
)
{
if ( NULL != pPppEapInput->pwszIdentity )
{
pWchar = wcschr( pPppEapInput->pwszIdentity, L'\\' );
if ( pWchar == NULL )
{
if ( 0 == WideCharToMultiByte(
CP_ACP,
0,
pPppEapInput->pwszIdentity,
-1,
szUserName,
UNLEN + 1,
NULL,
NULL ) )
{
return( GetLastError() );
}
}
else
{
*pWchar = 0;
if ( 0 == WideCharToMultiByte(
CP_ACP,
0,
pPppEapInput->pwszIdentity,
-1,
szDomain,
DNLEN + 1,
NULL,
NULL ) )
{
return( GetLastError() );
}
*pWchar = L'\\';
if ( 0 == WideCharToMultiByte(
CP_ACP,
0,
pWchar + 1,
-1,
szUserName,
UNLEN + 1,
NULL,
NULL ) )
{
return( GetLastError() );
}
}
}
if ( dwEapType == EAPTYPE_MD5Challenge )
{
if ( NULL != pPppEapInput->pwszPassword )
{
if ( 0 == WideCharToMultiByte(
CP_ACP,
0,
pPppEapInput->pwszPassword,
-1,
szPassword,
PWLEN + 1,
NULL,
NULL ) )
{
return( GetLastError() );
}
}
}
else
{
// if this is not a server then copy the user props
if ( !pPppEapInput->fAuthenticator )
{
strncpy( szPassword, pWB->pUserProp->szPassword, PWLEN );
}
}
}
else
{
if ( !pPppEapInput->fAuthenticator &&
!(pPppEapInput->fFlags & RAS_EAP_FLAG_MACHINE_AUTH )
)
{
//Set up the Luid for the logged on user
TOKEN_STATISTICS TokenStats;
DWORD TokenStatsSize;
if (!GetTokenInformation(pPppEapInput->hTokenImpersonateUser,
TokenStatistics,
&TokenStats,
sizeof(TOKEN_STATISTICS),
&TokenStatsSize))
{
dwRetCode = GetLastError();
return dwRetCode;
}
//
// "This will tell us if there was an API failure
// (means our buffer wasn't big enough)"
//
if (TokenStatsSize > sizeof(TOKEN_STATISTICS))
{
dwRetCode = GetLastError();
return dwRetCode;
}
Input.Luid = TokenStats.AuthenticationId;
}
}
Input.dwRetries = dwRetries;
Input.pszDomain = szDomain;
Input.pszUserName = szUserName;
Input.pszPassword = szPassword;
if ( (pPppEapInput->fFlags & RAS_EAP_FLAG_MACHINE_AUTH) )
Input.fConfigInfo |= PPPCFG_MachineAuthentication;
dwRetCode = ChapBegin( ppWorkBuffer, &Input );
if ( NO_ERROR != dwRetCode )
return dwRetCode;
ZeroMemory( szPassword, sizeof( szPassword ) );
if ( ! (Input.fServer) )
{
//if this is a client then call ChapMakeMessage to
//move the state from Initial to WaitForChallange
dwRetCode = ChapMakeMessage(
*ppWorkBuffer,
NULL,
NULL,
0,
&ApResult,
&Input );
}
return( dwRetCode );
}
DWORD EapMSChapv2Begin (
OUT VOID ** ppWorkBuffer,
IN PPP_EAP_INPUT * pPppEapInput
)
{
DWORD dwRetCode = NO_ERROR;
EAPMSCHAPv2WB * pWB = NULL;
TRACE("EapChapBeginMSChapV2");
//
// Allocate a work buffer here and send it back as our
// work buffer.
//
pWB = (EAPMSCHAPv2WB *)LocalAlloc(LPTR, sizeof(EAPMSCHAPv2WB) );
if ( NULL == pWB )
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
goto done;
}
if ( (pPppEapInput->fFlags & RAS_EAP_FLAG_MACHINE_AUTH) )
{
pWB->fFlags |= EAPMSCHAPv2_FLAG_MACHINE_AUTH;
}
if ( pPppEapInput->fAuthenticator )
{
dwRetCode = ServerConfigDataIO(TRUE /* fRead */, NULL /* pwszMachineName */,
(BYTE**)&(pWB->pUserProp), 0);
}
else
{
dwRetCode = ReadUserData( pPppEapInput->pUserData,
pPppEapInput->dwSizeOfUserData,
&(pWB->pUserProp)
);
}
if ( ERROR_SUCCESS != dwRetCode )
{
goto done;
}
//
// Check to see if we got password field set. If so, we use that password
// It means that the user has chosen to save the password. If not,
// szpassword field should be empty.
if ( !( pPppEapInput->fFlags & RAS_EAP_FLAG_8021X_AUTH ) )
{
if ( pPppEapInput->pwszPassword &&
*(pPppEapInput->pwszPassword) &&
wcscmp (pPppEapInput->pwszPassword, L"****************")
)
{
WideCharToMultiByte( CP_ACP,
0,
pPppEapInput->pwszPassword ,
-1,
pWB->pUserProp->szPassword,
PWLEN+1,
NULL,
NULL );
}
}
dwRetCode = ReadConnectionData ( ( pPppEapInput->fFlags & RAS_EAP_FLAG_8021X_AUTH ),
pPppEapInput->pConnectionData,
pPppEapInput->dwSizeOfConnectionData,
&(pWB->pConnProp )
);
if ( ERROR_SUCCESS != dwRetCode )
{
goto done;
}
dwRetCode = EapChapBeginCommon( PPP_EAP_MSCHAPv2,
(pWB->pConnProp->fFlags & EAPMSCHAPv2_FLAG_USE_WINLOGON_CREDS ),
(pWB->pUserProp->dwMaxRetries ),
pWB,
&pWB->pwb,
pPppEapInput
);
if ( NO_ERROR != dwRetCode )
{
goto done;
}
if ( pPppEapInput->pwszIdentity )
{
wcsncpy ( pWB->wszRadiusUserName, pPppEapInput->pwszIdentity, UNLEN+DNLEN );
}
*ppWorkBuffer = (PVOID)pWB;
done:
if ( NO_ERROR != dwRetCode )
{
if ( pWB )
{
LocalFree(pWB->pUserProp);
LocalFree(pWB->pConnProp);
LocalFree(pWB);
}
}
return dwRetCode;
}
DWORD CheckCallerIdentity ( HANDLE hWVTStateData )
{
DWORD dwRetCode = ERROR_ACCESS_DENIED;
PCRYPT_PROVIDER_DATA pProvData = NULL;
PCCERT_CHAIN_CONTEXT pChainContext = NULL;
PCRYPT_PROVIDER_SGNR pProvSigner = NULL;
CERT_CHAIN_POLICY_PARA chainpolicyparams;
CERT_CHAIN_POLICY_STATUS chainpolicystatus;
if (!(pProvData = WTHelperProvDataFromStateData(hWVTStateData)))
{
goto done;
}
if (!(pProvSigner = WTHelperGetProvSignerFromChain(pProvData, 0, FALSE, 0)))
{
goto done;
}
chainpolicyparams.cbSize = sizeof(CERT_CHAIN_POLICY_PARA);
//
//
// We do want to test for microsoft test root flags. and dont care
// for revocation flags...
//
chainpolicyparams.dwFlags = CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG |
CERT_CHAIN_POLICY_TRUST_TESTROOT_FLAG |
CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS;
pChainContext = pProvSigner->pChainContext;
if (!CertVerifyCertificateChainPolicy (
CERT_CHAIN_POLICY_MICROSOFT_ROOT,
pChainContext,
&chainpolicyparams,
&chainpolicystatus))
{
goto done;
}
else
{
if ( S_OK == chainpolicystatus.dwError )
{
dwRetCode = NO_ERROR;
}
else
{
//
// Check the base policy to see if this
// is a Microsoft test root
//
if (!CertVerifyCertificateChainPolicy (
CERT_CHAIN_POLICY_BASE,
pChainContext,
&chainpolicyparams,
&chainpolicystatus))
{
goto done;
}
else
{
if ( S_OK == chainpolicystatus.dwError )
{
dwRetCode = NO_ERROR;
}
}
}
}
done:
return dwRetCode;
}
DWORD VerifyCallerTrust ( LPWSTR lpszCaller )
{
DWORD dwRetCode = NO_ERROR;
HRESULT hr = S_OK;
WINTRUST_DATA wtData;
WINTRUST_FILE_INFO wtFileInfo;
WINTRUST_CATALOG_INFO wtCatalogInfo;
BOOL fRet = FALSE;
HCATADMIN hCATAdmin = NULL;
GUID guidPublishedSoftware = WINTRUST_ACTION_GENERIC_VERIFY_V2;
//
// Following GUID is Mirosoft's Catalog System Root
//
GUID guidCatSystemRoot = { 0xf750e6c3, 0x38ee, 0x11d1,{ 0x85, 0xe5, 0x0, 0xc0, 0x4f, 0xc2, 0x95, 0xee } };
HCATINFO hCATInfo = NULL;
CATALOG_INFO CatInfo;
HANDLE hFile = INVALID_HANDLE_VALUE;
BYTE bHash[40];
DWORD cbHash = 40;
if ( NULL == lpszCaller )
{
dwRetCode = ERROR_INVALID_PARAMETER;
goto done;
}
//
//
// Try and see if WinVerifyTrust will verify
// the signature as a standalone file
//
//
ZeroMemory ( &wtData, sizeof(wtData) );
ZeroMemory ( &wtFileInfo, sizeof(wtFileInfo) );
wtData.cbStruct = sizeof(wtData);
wtData.dwUIChoice = WTD_UI_NONE;
wtData.fdwRevocationChecks = WTD_REVOKE_NONE;
wtData.dwStateAction = WTD_STATEACTION_VERIFY;
wtData.dwUnionChoice = WTD_CHOICE_FILE;
wtData.pFile = &wtFileInfo;
wtFileInfo.cbStruct = sizeof( wtFileInfo );
wtFileInfo.pcwszFilePath = lpszCaller;
hr = WinVerifyTrust ( NULL,
&guidPublishedSoftware,
&wtData
);
if ( ERROR_SUCCESS == hr )
{
//
// Check to see if this is indeed microsoft
// signed caller
//
dwRetCode = CheckCallerIdentity( wtData.hWVTStateData);
wtData.dwStateAction = WTD_STATEACTION_CLOSE;
WinVerifyTrust(NULL, &guidPublishedSoftware, &wtData);
goto done;
}
wtData.dwStateAction = WTD_STATEACTION_CLOSE;
WinVerifyTrust(NULL, &guidPublishedSoftware, &wtData);
//
// We did not find the file was signed.
// So check the system catalog to see if
// the file is in the catalog and the catalog
// is signed
//
//
// Open the file
//
hFile = CreateFileW ( lpszCaller,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if ( INVALID_HANDLE_VALUE == hFile )
{
dwRetCode = GetLastError();
goto done;
}
fRet = CryptCATAdminAcquireContext( &hCATAdmin,
&guidCatSystemRoot,
0
);
if ( !fRet )
{
dwRetCode = GetLastError();
goto done;
}
//
// Get the hash of the file here
//
fRet = CryptCATAdminCalcHashFromFileHandle ( hFile,
&cbHash,
bHash,
0
);
if ( !fRet )
{
dwRetCode = GetLastError();
goto done;
}
ZeroMemory(&CatInfo, sizeof(CatInfo));
CatInfo.cbStruct = sizeof(CatInfo);
ZeroMemory( &wtCatalogInfo, sizeof(wtCatalogInfo) );
wtData.dwUnionChoice = WTD_CHOICE_CATALOG;
wtData.dwStateAction = WTD_STATEACTION_VERIFY;
wtData.pCatalog = &wtCatalogInfo;
wtCatalogInfo.cbStruct = sizeof(wtCatalogInfo);
wtCatalogInfo.hMemberFile = hFile;
wtCatalogInfo.pbCalculatedFileHash = bHash;
wtCatalogInfo.cbCalculatedFileHash = cbHash;
while ( ( hCATInfo = CryptCATAdminEnumCatalogFromHash ( hCATAdmin,
bHash,
cbHash,
0,
&hCATInfo
)
)
)
{
if (!(CryptCATCatalogInfoFromContext(hCATInfo, &CatInfo, 0)))
{
// should do something (??)
continue;
}
wtCatalogInfo.pcwszCatalogFilePath = CatInfo.wszCatalogFile;
hr = WinVerifyTrust ( NULL,
&guidPublishedSoftware,
&wtData
);
if ( ERROR_SUCCESS == hr )
{
//
// Verify that this file is trusted
//
dwRetCode = CheckCallerIdentity( wtData.hWVTStateData);
wtData.dwStateAction = WTD_STATEACTION_CLOSE;
WinVerifyTrust(NULL, &guidPublishedSoftware, &wtData);
goto done;
}
}
//
// File not found in any of the catalogs
//
dwRetCode = ERROR_ACCESS_DENIED;
done:
if ( hCATInfo )
{
CryptCATAdminReleaseCatalogContext( hCATAdmin, hCATInfo, 0 );
}
if ( hCATAdmin )
{
CryptCATAdminReleaseContext( hCATAdmin, 0 );
}
if ( hFile )
{
CloseHandle(hFile);
}
return dwRetCode;
}
#define PERFORM_CALLER_TRUST 0
DWORD
EapChapBegin(
OUT VOID ** ppWorkBuffer,
IN PPP_EAP_INPUT * pPppEapInput
)
{
void* callersAddress;
DWORD dwRetCode;
MEMORY_BASIC_INFORMATION mbi;
SIZE_T nbyte;
DWORD nchar;
wchar_t callersModule[MAX_PATH + 1];
#ifdef PERFORM_CALLER_TRUST
static BOOL fCallerTrusted = FALSE;
#else
static BOOL fCallerTrusted = TRUE;
#endif
//
//Verify the caller first and then proceed with
//other business
//
//
// This code is causing boot time perf issues
// So this is removed until XPSP2
#if 0
if ( !fCallerTrusted )
{
//
//First Verify the caller and then
//proceed with initialization
//
callersAddress = _ReturnAddress();
nbyte = VirtualQuery(
callersAddress,
&mbi,
sizeof(mbi)
);
if (nbyte < sizeof(mbi))
{
dwRetCode = ERROR_ACCESS_DENIED;
goto done;
}
nchar = GetModuleFileNameW(
(HMODULE)(mbi.AllocationBase),
callersModule,
MAX_PATH
);
if (nchar == 0)
{
dwRetCode = GetLastError();
goto done;
}
dwRetCode = VerifyCallerTrust(callersModule);
if ( NO_ERROR != dwRetCode )
{
goto done;
}
fCallerTrusted = TRUE;
}
#endif
dwRetCode = EapChapBeginCommon( EAPTYPE_MD5Challenge,
FALSE,
0,
NULL,
ppWorkBuffer,
pPppEapInput
);
#if 0
done:
#endif
return dwRetCode;
}
DWORD
EapMSChapv2End ( IN VOID * pWorkBuf )
{
DWORD dwRetCode = NO_ERROR;
EAPMSCHAPv2WB * pWB = (EAPMSCHAPv2WB *)pWorkBuf;
TRACE("EapMSChapv2End");
if ( pWB )
{
dwRetCode = ChapEnd( pWB->pwb );
LocalFree ( pWB->pUIContextData );
LocalFree ( pWB->pUserProp );
LocalFree ( pWB->pConnProp );
if ( pWB->pUserAttributes )
RasAuthAttributeDestroy(pWB->pUserAttributes);
LocalFree( pWB );
}
return dwRetCode;
}
//**
//
// Call: EapChapEnd
//
// Returns: NO_ERROR - Success
// Non-zero returns - Failure
//
// Description: Wrapper around ChapEnd.
//
DWORD
EapChapEnd(
IN VOID* pWorkBuf
)
{
return( ChapEnd( pWorkBuf ) );
}
DWORD
GetIdentityFromUserName (
LPSTR lpszUserName,
LPSTR lpszDomain,
LPWSTR * ppwszIdentity
)
{
DWORD dwRetCode = NO_ERROR;
DWORD dwNumBytes;
//domain+ user + '\' + null
dwNumBytes = (strlen(lpszUserName) + strlen(lpszDomain) + 1 + 1) * sizeof(WCHAR);
*ppwszIdentity = LocalAlloc ( LPTR, dwNumBytes);
if ( NULL == *ppwszIdentity )
{
dwRetCode = ERROR_OUTOFMEMORY;
goto LDone;
}
if ( *lpszDomain )
{
MultiByteToWideChar( CP_ACP,
0,
lpszDomain,
-1,
*ppwszIdentity,
dwNumBytes/sizeof(WCHAR) );
wcscat( *ppwszIdentity, L"\\");
}
MultiByteToWideChar( CP_ACP,
0,
lpszUserName,
-1,
*lpszDomain? *ppwszIdentity + strlen(lpszDomain) + 1:*ppwszIdentity,
dwNumBytes/sizeof(WCHAR) - strlen(lpszDomain) );
LDone:
return dwRetCode;
}
// Convert a number to a hex representation.
BYTE num2Digit(BYTE num)
{
return (num < 10) ? num + '0' : num + ('A' - 10);
}
//
DWORD
ChangePassword ( IN OUT EAPMSCHAPv2WB * pEapwb,
PPP_EAP_OUTPUT* pEapOutput,
PPPAP_INPUT* pApInput)
{
DWORD dwRetCode = NO_ERROR;
RAS_AUTH_ATTRIBUTE * pAttribute = NULL;
WCHAR wszUserName[UNLEN + DNLEN +1] = {0};
LPWSTR lpwszHashUserName = NULL;
CHAR szHashUserName[UNLEN+1] = {0};
WCHAR wszDomainName[DNLEN +1] = {0};
PBYTE pbEncHash = NULL;
BYTE bEncPassword[550] = {0};
HANDLE hAttribute;
int i;
//
// check to see if change password attribute is present in
// User Attributes
//
pAttribute = RasAuthAttributeGetVendorSpecific(
VENDOR_MICROSOFT,
MS_VSA_CHAP2_CPW,
pEapOutput->pUserAttributes );
if ( NULL == pAttribute )
{
TRACE ( "no change password attribute");
goto LDone;
}
//Get encrypted Hash
pbEncHash = (PBYTE)pAttribute->Value + 8;
//
// Get the user name and domain name
//
pAttribute = RasAuthAttributeGet ( raatUserName,
pEapOutput->pUserAttributes
);
if ( NULL == pAttribute )
{
//Need a better way of sending error
TRACE ( "UserName missing");
dwRetCode = ERROR_AUTHENTICATION_FAILURE;
goto LDone;
}
//
// Convert the username to unicode
//
MultiByteToWideChar( CP_ACP,
0,
pAttribute->Value,
pAttribute->dwLength,
wszUserName,
UNLEN + DNLEN + 1 );
//
// Get the hash user name and domain name
//
lpwszHashUserName = wcschr ( wszUserName, '\\' );
if ( lpwszHashUserName )
{
wcsncpy ( wszDomainName, wszUserName, lpwszHashUserName - wszUserName );
lpwszHashUserName ++;
}
else
{
lpwszHashUserName = wszUserName;
}
/*
//Convert hash user name to multibyte
WideCharToMultiByte( CP_ACP,
0,
lpwszHashUserName,
-1,
szHashUserName,
DNLEN+1,
NULL,
NULL );
*/
//
// Get encrypted password
//
pAttribute = RasAuthAttributeGetFirst( raatVendorSpecific,
pEapOutput->pUserAttributes,
&hAttribute );
while ( pAttribute )
{
if ( *((PBYTE)pAttribute->Value + 4) == MS_VSA_CHAP_NT_Enc_PW )
{
//
// check to see the sequence number and copy it
// proper place in our buffer.
//
switch ( WireToHostFormat16 ( (PBYTE) pAttribute->Value + 8 ) )
{
case 1:
CopyMemory( bEncPassword,
(PBYTE)pAttribute->Value + 10,
243
);
break;
case 2:
CopyMemory( bEncPassword+ 243,
(PBYTE)pAttribute->Value + 10,
243
);
break;
case 3:
CopyMemory( bEncPassword+ 486,
(PBYTE)pAttribute->Value + 10,
30
);
break;
default:
TRACE("Invalid enc password attribute");
break;
}
}
//
// Check to see if this is enc password
// and also get the sequence number.
//
pAttribute = RasAuthAttributeGetNext( &hAttribute,
raatVendorSpecific );
}
//
// Call Change password function
//
dwRetCode = IASChangePassword3( lpwszHashUserName,
wszDomainName,
pbEncHash,
bEncPassword
);
LDone:
return dwRetCode;
}
DWORD
AuthenticateUser ( IN OUT EAPMSCHAPv2WB * pEapwb,
IN PPP_EAP_OUTPUT* pEapOutput,
PPPAP_INPUT * pApInput
)
{
DWORD dwRetCode = NO_ERROR;
RAS_AUTH_ATTRIBUTE * pAttribute = NULL;
WCHAR wszUserName[UNLEN + DNLEN +1] = {0};
WCHAR wszHashUserName[UNLEN+DNLEN+1] = {0};
//Hash user name is taken from chapwb
CHAR szHashUserName[UNLEN+1] = {0};
WCHAR* lpszRover = NULL;
WCHAR wszDomainName[DNLEN +1] = {0};
//Format is Type + Length + identity + "S=" + 40 bytes response
UCHAR szAuthSuccessResponse[1+1+1+2+40] ={0};
//Domain Name Type + Length+Domainname
CHAR szDomainName[1+1+1+DNLEN+1] ={0};
//MPPE Keys Type+Length+Salt+KeyLength+NTkey(16)+PAdding(15)
BYTE bMPPEKey[1+1+2+1+16+15]={0};
PBYTE pbChapChallenge = NULL;
DWORD cbChallenge = 0;
PBYTE pbResponse = NULL;
PBYTE pbPeerChallenge = NULL;
IAS_MSCHAP_V2_PROFILE Profile;
HANDLE hToken = INVALID_HANDLE_VALUE;
DWORD dwCurAttr = 0;
DWORD dwCount=0;
DWORD dwChapRetCode = NO_ERROR;
//Type +
CHAR szChapError[64] = {0};
TRACE("Authenticate User");
//
// Authenticate the user by calling the IASLogonUser function here
// This is stolen from IAS.
//
//Extract the attribs from pUserAttributes
//
// We need following attribs
// raatUserName,
// MS_VSA_CHAP_Challenge
// MS_VSA_CHAP2_Response
//
//We dont use the user name got from EAP for auth. We use the one got from
//Radius
#if 0
pAttribute = RasAuthAttributeGet ( raatUserName,
pEapOutput->pUserAttributes
);
if ( NULL == pAttribute )
{
//Need a better way of sending error
TRACE ( "UserName missing");
dwRetCode = ERROR_AUTHENTICATION_FAILURE;
goto done;
}
//
// Convert the username to unicode
//
MultiByteToWideChar( CP_ACP,
0,
pAttribute->Value,
pAttribute->dwLength,
wszUserName,
UNLEN + DNLEN + 1 );
#endif
//Get the chap challenge and chap response
pAttribute = RasAuthAttributeGetVendorSpecific(
VENDOR_MICROSOFT,
MS_VSA_CHAP_Challenge,
pEapOutput->pUserAttributes );
if ( NULL == pAttribute )
{
TRACE ( "Challenge missing");
dwRetCode = ERROR_AUTHENTICATION_FAILURE;
goto done;
}
pbChapChallenge = (PBYTE)pAttribute->Value + 6;
cbChallenge = ((DWORD)(*((PBYTE)pAttribute->Value + 5))) - 2;
pAttribute = RasAuthAttributeGetVendorSpecific(
VENDOR_MICROSOFT,
MS_VSA_CHAP2_Response,
pEapOutput->pUserAttributes );
if ( NULL == pAttribute )
{
//
// Try and see if this is a change password response
//
pAttribute = RasAuthAttributeGetVendorSpecific(
VENDOR_MICROSOFT,
MS_VSA_CHAP2_CPW,
pEapOutput->pUserAttributes );
if ( NULL == pAttribute )
{
TRACE("Response missing");
dwRetCode = ERROR_AUTHENTICATION_FAILURE;
goto done;
}
//
// Setup response and peer challenge here
//
pbPeerChallenge = (PBYTE)pAttribute->Value + 8 + 16;
pbResponse = (PBYTE)pAttribute->Value + 8 + 16 + 24;
}
else
{
//
// Get the peer challenge and response from
// the VSA
//
pbPeerChallenge = (PBYTE)pAttribute->Value + 8;
pbResponse = (PBYTE)pAttribute->Value + 8 + 16 + 8;
}
//
// Get the hash user name and domain name
//
MultiByteToWideChar( CP_ACP,
0,
pEapwb->pwb->szUserName,
-1,
wszHashUserName,
UNLEN+DNLEN );
//
// Get the domain if any
//
lpszRover = wcschr ( wszHashUserName, '\\' );
if ( lpszRover )
{
lpszRover++;
}
else
{
lpszRover = wszHashUserName;
}
//Convert hash user name to multibyte
WideCharToMultiByte( CP_ACP,
0,
lpszRover,
-1,
szHashUserName,
UNLEN+1,
NULL,
NULL );
lpszRover = wcschr ( pEapwb->wszRadiusUserName, '\\');
if ( lpszRover )
{
wcsncpy ( wszDomainName, pEapwb->wszRadiusUserName, lpszRover - pEapwb->wszRadiusUserName );
lpszRover++;
}
else
{
lpszRover = pEapwb->wszRadiusUserName;
}
dwRetCode = IASLogonMSCHAPv2( (PCWSTR)lpszRover,
(PCWSTR)wszDomainName,
szHashUserName,
pbChapChallenge,
cbChallenge,
pbResponse,
pbPeerChallenge,
&Profile,
&hToken
);
//
// Map the return errors to correct errors
// create a set of attributes to be sent back to raschap
//
if ( NO_ERROR == dwRetCode )
{
//
// Setup the authenticator attributes here
// Following attributes will be send back.
// 1. SendKey
// 2. RecvKey
// 3. AuthResponse
// 4. MSCHAPDomain
//
pApInput->dwAuthResultCode = NO_ERROR;
pApInput->fAuthenticationComplete = TRUE;
pAttribute = RasAuthAttributeCreate ( 4 );
if ( NULL == pAttribute )
{
TRACE("RasAuthAttributeCreate failed");
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
goto done;
}
for ( dwCurAttr = 0; dwCurAttr < 4; dwCurAttr ++ )
{
switch ( dwCurAttr )
{
case 0:
{
CHAR * p = szDomainName;
//
// Setup MSCHAP Domain name here
//
*p++ = (BYTE)MS_VSA_CHAP_Domain;
*p++ = (BYTE)wcslen(Profile.LogonDomainName)+1+1;
*p++ = 1;
WideCharToMultiByte( CP_ACP,
0,
Profile.LogonDomainName,
-1,
p,
DNLEN+1,
NULL,
NULL );
dwRetCode = RasAuthAttributeInsertVSA(
dwCurAttr,
pAttribute,
VENDOR_MICROSOFT,
(DWORD)szDomainName[1],
szDomainName );
break;
}
case 1:
case 2:
{
//SEtup MPPE SEnd Key attributes here
PBYTE p = bMPPEKey;
ZeroMemory(bMPPEKey, sizeof(bMPPEKey) );
if ( dwCurAttr == 1 )
*p++ = (BYTE)MS_VSA_MPPE_Send_Key; //Type
else
*p++ = (BYTE)MS_VSA_MPPE_Recv_Key; //Type
*p++ = (BYTE)36; //Length
p++;p++; //Salt is 0
*p++ = 16; //Key Length
if ( dwCurAttr == 1 )
CopyMemory(p, Profile.SendSessionKey, 16 );
else
CopyMemory(p, Profile.RecvSessionKey, 16 );
dwRetCode = RasAuthAttributeInsertVSA(
dwCurAttr,
pAttribute,
VENDOR_MICROSOFT,
36,
bMPPEKey );
break;
}
case 3:
{
UCHAR * p = szAuthSuccessResponse;
*p++ = (BYTE)MS_VSA_CHAP2_Success; //Type of attr
*p++ = (BYTE)45; //Length of the VSA
*p++ = (BYTE)1; //ID ignored by out implementation of MSCHAPv2
*p++ = 'S';
*p++ = '=';
for ( dwCount = 0; dwCount < 20; dwCount++ )
{
*p++ = num2Digit(Profile.AuthResponse[dwCount] >> 4);
*p++ = num2Digit(Profile.AuthResponse[dwCount] & 0xF);
}
//
// Setup the value field here
//
dwRetCode = RasAuthAttributeInsertVSA(
dwCurAttr,
pAttribute,
VENDOR_MICROSOFT,
45,
szAuthSuccessResponse );
break;
}
default:
break;
}
if ( NO_ERROR != dwRetCode )
{
TRACE("RasAuthAttributeInsetVSA failed");
goto done;
}
}
pApInput->pAttributesFromAuthenticator = pAttribute;
//
// Also save the attributes in the WB to send across later.
//
pEapwb->pUserAttributes = pAttribute;
pEapwb->dwAuthResultCode = NO_ERROR;
pApInput->fAuthenticationComplete = TRUE;
pApInput->dwAuthResultCode = pApInput->dwAuthError = NO_ERROR;
}
else
{
//
// Handle the failure by sending
//
switch ( dwRetCode )
{
case ERROR_INVALID_LOGON_HOURS:
dwChapRetCode = ERROR_RESTRICTED_LOGON_HOURS;
break;
case ERROR_ACCOUNT_DISABLED:
dwChapRetCode = ERROR_ACCT_DISABLED;
break;
case ERROR_PASSWORD_EXPIRED:
case ERROR_PASSWORD_MUST_CHANGE:
dwChapRetCode = ERROR_PASSWD_EXPIRED;
break;
case ERROR_ILL_FORMED_PASSWORD:
case ERROR_PASSWORD_RESTRICTION:
dwChapRetCode = ERROR_CHANGING_PASSWORD;
break;
default:
dwChapRetCode = ERROR_AUTHENTICATION_FAILURE;
}
pAttribute = RasAuthAttributeCreate ( 1 );
if ( NULL == pAttribute )
{
TRACE("RasAuthAttributeCreate failed");
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
goto done;
}
//Make a VSA out of this and send it back
wsprintf ( &szChapError[3], "E=%lu R=0 V=3", dwChapRetCode );
szChapError[0] = MS_VSA_CHAP_Error;
szChapError[1] = 3 + strlen(&szChapError[3]);
szChapError[2] = pEapwb->IdToExpect;
dwRetCode = RasAuthAttributeInsertVSA(
0,
pAttribute,
VENDOR_MICROSOFT,
szChapError[1],
szChapError );
pApInput->fAuthenticationComplete = TRUE;
pApInput->pAttributesFromAuthenticator = pAttribute;
pApInput->dwAuthError = NO_ERROR;
pApInput->dwAuthResultCode = dwChapRetCode;
}
done:
if ( INVALID_HANDLE_VALUE != hToken )
CloseHandle(hToken);
if ( NO_ERROR != dwRetCode )
{
RasAuthAttributeDestroy(pAttribute);
pApInput->pAttributesFromAuthenticator = NULL;
}
return dwRetCode;
}
DWORD
CallMakeMessageAndSetEAPState(
IN PVOID pWorkBuf,
IN PPP_CONFIG* pReceiveBuf,
IN OUT PPP_CONFIG* pSendBuf,
IN DWORD cbSendBuf,
PPPAP_RESULT * pApResult,
PPPAP_INPUT * pApInput,
OUT PPP_EAP_OUTPUT* pEapOutput
)
{
DWORD dwRetCode = NO_ERROR;
CHAPWB * pwb = (CHAPWB *)pWorkBuf;
dwRetCode = ChapMakeMessage(
pWorkBuf,
pReceiveBuf,
pSendBuf,
cbSendBuf,
pApResult,
pApInput );
if ( dwRetCode != NO_ERROR )
{
goto done;
}
switch( pApResult->Action )
{
case APA_NoAction:
pEapOutput->Action = EAPACTION_NoAction;
break;
case APA_Done:
pEapOutput->Action = EAPACTION_Done;
break;
case APA_SendAndDone:
case APA_Send:
pEapOutput->Action = EAPACTION_Send;
break;
case APA_SendWithTimeout:
pEapOutput->Action = ( pwb->fServer )
? EAPACTION_SendWithTimeout
: EAPACTION_Send;
break;
case APA_SendWithTimeout2:
pEapOutput->Action = ( pwb->fServer )
? EAPACTION_SendWithTimeoutInteractive
: EAPACTION_Send;
break;
case APA_Authenticate:
pEapOutput->pUserAttributes = pApResult->pUserAttributes;
pEapOutput->Action = EAPACTION_Authenticate;
break;
default:
RTASSERT(FALSE);
break;
}
done:
return dwRetCode;
}
DWORD
EapMSChapv2SMakeMessage(
IN VOID* pWorkBuf,
IN PPP_EAP_PACKET* pReceivePacket,
OUT PPP_EAP_PACKET* pSendPacket,
IN DWORD cbSendPacket,
OUT PPP_EAP_OUTPUT* pEapOutput,
IN PPP_EAP_INPUT* pEapInput
)
{
DWORD dwRetCode = NO_ERROR;
PPP_CONFIG * pReceiveBuf = NULL;
PPP_CONFIG * pSendBuf = NULL;
DWORD cbSendBuf = 1500;
PPPAP_INPUT ApInput;
PPPAP_RESULT ApResult;
WORD cbPacket = 0;
EAPMSCHAPv2WB * pEapwb = (EAPMSCHAPv2WB * ) pWorkBuf;
TRACE("EapMSChapv2SMakeMessage");
//
//Do default processing here.
//
ZeroMemory( &ApResult, sizeof(ApResult) );
if ( ( pSendBuf = LocalAlloc( LPTR, cbSendBuf ) ) == NULL )
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
goto done;
}
if ( pEapInput != NULL )
{
MapEapInputToApInput( pEapInput, &ApInput );
}
switch ( pEapwb->EapState )
{
case EMV2_Initial:
TRACE("EMV2_Initial");
//
// This is the first time this has been invoked.
// So we make a MACHAPv2 chap challenge and send
// back a response
//
dwRetCode = CallMakeMessageAndSetEAPState(
pEapwb->pwb,
pReceiveBuf,
pSendBuf,
cbSendBuf,
&ApResult,
( pEapInput ? &ApInput : NULL ),
pEapOutput
);
//
// We got the CHAP Challenge now. If all's fine
// package the result back and send it to the client
//
//
// Translate MSCHAPv2 packet to EAP packet
//
if ( NO_ERROR == dwRetCode && pSendBuf )
{
pSendPacket->Code = EAPCODE_Request;
pEapwb->IdToExpect = pEapwb->IdToSend =
pSendPacket->Id = pEapwb->pwb->bIdToSend;
//
// Length = sizeof Header + sizeof MSCHAP packet to send
// This includes the first byte of
cbPacket = WireToHostFormat16( pSendBuf->Length );
CopyMemory ( pSendPacket->Data+1, pSendBuf, cbPacket);
cbPacket += sizeof(PPP_EAP_PACKET);
HostToWireFormat16( cbPacket, pSendPacket->Length );
pSendPacket->Data[0] = (BYTE)PPP_EAP_MSCHAPv2;
pEapwb->EapState = EMV2_RequestSend;
}
break;
case EMV2_RequestSend:
TRACE("EMV2_RequestSend");
//
// We should only get a response here.
// If not discard this packet.
//
if ( NULL != pReceivePacket )
{
if ( pReceivePacket->Code != EAPCODE_Response )
{
TRACE("Got unexpected packet. Does not have response");
dwRetCode = ERROR_PPP_INVALID_PACKET;
break;
}
if ( pReceivePacket->Id != pEapwb->IdToExpect )
{
TRACE("received packet id does not match");
dwRetCode = ERROR_PPP_INVALID_PACKET;
break;
}
//
// Translate the packet received to
// MSCHAP v2 format
//
cbPacket = WireToHostFormat16(pReceivePacket->Length);
if ( cbPacket > sizeof( PPP_EAP_PACKET ) )
{
pReceiveBuf = (PPP_CONFIG *)( pReceivePacket->Data + 1);
dwRetCode = CallMakeMessageAndSetEAPState(
pEapwb->pwb,
pReceiveBuf,
pSendBuf,
cbSendBuf,
&ApResult,
( pEapInput ? &ApInput : NULL ),
pEapOutput
);
if ( NO_ERROR == dwRetCode )
{
//Check to see if we are asked to authenticate
if ( pEapOutput->Action == EAPACTION_Authenticate )
{
//
// If we have come this far pEapInput cannot be NULL
// Or else it is a bug in the client.
//
//
// Check to see if this is a change password request
// If so first change tha password and then authenticate.
//
dwRetCode = ChangePassword (pEapwb, pEapOutput, &ApInput);
if ( NO_ERROR == dwRetCode )
{
//
// Now authenticate user
//
dwRetCode = AuthenticateUser (pEapwb, pEapOutput, &ApInput );
}
//
// We will get a set of auth attributes back
// that we need to send back to the mschap
// protocol.
//
dwRetCode = CallMakeMessageAndSetEAPState
(
pEapwb->pwb,
pReceiveBuf,
pSendBuf,
cbSendBuf,
&ApResult,
&ApInput,
pEapOutput
);
}
//
// Check to see if auth was success or fail.
// If Auth was success then set state to EMV2_CHAPAuthSuccess
//
if ( NO_ERROR == dwRetCode && pSendBuf )
{
pSendPacket->Code = EAPCODE_Request;
pEapwb->IdToSend ++;
pEapwb->IdToExpect = pSendPacket->Id = pEapwb->IdToSend;
//
// Length = sizeof Header + sizeof MSCHAP packet to send
// This includes the first byte of
cbPacket = WireToHostFormat16( pSendBuf->Length );
CopyMemory ( pSendPacket->Data+1, pSendBuf, cbPacket);
cbPacket += sizeof(PPP_EAP_PACKET);
HostToWireFormat16( cbPacket, pSendPacket->Length );
pSendPacket->Data[0] = (BYTE)PPP_EAP_MSCHAPv2;
if ( pEapwb->pwb->result.dwError == NO_ERROR )
{
//
// We succeeded in auth
//
pEapwb->EapState = EMV2_CHAPAuthSuccess;
pEapOutput->Action = EAPACTION_SendWithTimeout;
}
else
{
//
// Could be a retryable failure. So we need to send
// with interactive timeout.
//
if ( pEapwb->pwb->result.fRetry )
{
pEapwb->EapState = EMV2_RequestSend;
pEapOutput->Action = EAPACTION_SendWithTimeoutInteractive;
}
else if ( pEapwb->pwb->result.dwError == ERROR_PASSWD_EXPIRED )
{
if ( pEapwb->pUserProp->fFlags & EAPMSCHAPv2_FLAG_ALLOW_CHANGEPWD )
{
//
// Check to see if this is allowed
//
pEapwb->EapState = EMV2_RequestSend;
pEapOutput->Action = EAPACTION_SendWithTimeoutInteractive;
}
else
{
pSendPacket->Code = EAPCODE_Failure;
HostToWireFormat16 ( (WORD)4, pSendPacket->Length );
pEapwb->EapState = EMV2_Failure;
pEapOutput->dwAuthResultCode = pEapwb->pwb->result.dwError;
pEapOutput->Action = EAPACTION_SendAndDone;
}
}
else
{
pSendPacket->Code = EAPCODE_Failure;
HostToWireFormat16 ( (WORD)4, pSendPacket->Length );
pEapwb->EapState = EMV2_Failure;
pEapOutput->dwAuthResultCode = pEapwb->pwb->result.dwError;
pEapOutput->Action = EAPACTION_SendAndDone;
}
}
}
}
}
else
{
//
// We should never get an empty response in
//
dwRetCode = ERROR_PPP_INVALID_PACKET;
}
}
else
{
dwRetCode = ERROR_PPP_INVALID_PACKET;
}
break;
case EMV2_CHAPAuthSuccess:
TRACE("EMV2_CHAPAuthSuccess");
//
// We should only get an response here indicating
// if the client could validate the server successfully.
// Then we can send back a EAP_SUCCESS or EAP_FAIL.
//
if ( NULL != pReceivePacket )
{
if ( pReceivePacket->Code != EAPCODE_Response )
{
dwRetCode = ERROR_PPP_INVALID_PACKET;
break;
}
if ( pReceivePacket->Id != pEapwb->IdToExpect )
{
//Invalid packet id
dwRetCode = ERROR_PPP_INVALID_PACKET;
break;
}
//
// Translate the packet received to
// MSCHAP v2 format
//
cbPacket = WireToHostFormat16(pReceivePacket->Length);
if ( cbPacket == sizeof( PPP_EAP_PACKET ) + 1 )
{
//
// Check to see if the data is CHAPCODE_Success
// or CHAPCode Fail and send appropriate packet
//
if ( *(pReceivePacket->Data+1) == CHAPCODE_Success )
{
//
//peer could auth successfully
//
pSendPacket->Code = EAPCODE_Success;
}
else
{
pSendPacket->Code = EAPCODE_Failure;
}
pEapwb->IdToSend++;
pEapwb->IdToExpect =
pSendPacket->Id = pEapwb->IdToSend;
HostToWireFormat16( (WORD)4, pSendPacket->Length );
pEapwb->EapState = EMV2_Success;
//Set the Out attributes here
pEapOutput->pUserAttributes = pEapwb->pUserAttributes;
pEapOutput->dwAuthResultCode = pEapwb->dwAuthResultCode;
pEapOutput->Action = EAPACTION_SendAndDone;
}
else
{
dwRetCode = ERROR_PPP_INVALID_PACKET;
}
}
break;
case EMV2_CHAPAuthFail:
TRACE("EMV2_CHAPAuthFail");
//
// We could get a retry or a change password packet here
// Again we should get only a EAPCODE_Response here...
//
//Got a response. So send it to MSCHAP and see what happens
//
break;
case EMV2_Success:
TRACE("EMV2_Success");
//
// See the CS_Done state in raschap for this state to be here.
//
break;
case EMV2_Failure:
TRACE("EMV2_Failure");
break;
case EMV2_ResponseSend:
default:
TRACE1("Why is this EAPMschapv2 in this state? %d",pEapwb->EapState );
break;
}
done:
if ( pSendBuf )
{
LocalFree(pSendBuf);
}
return dwRetCode;
}
DWORD
GetClientMPPEKeys ( EAPMSCHAPv2WB *pEapwb, PPPAP_RESULT * pApResult )
{
DWORD dwRetCode = NO_ERROR;
BYTE bRecvKey[16] = {0};
BYTE bSendKey[16] = {0};
RAS_AUTH_ATTRIBUTE * pAttribute;
RAS_AUTH_ATTRIBUTE * pSendRecvKeyAttr = NULL;
//MPPE Keys Type+Length+Salt+KeyLength+NTkey(16)+PAdding(15)
BYTE bMPPEKey[1+1+2+1+16+15]={0};
TRACE("GetClientMPPEKeys");
pEapwb->pUserAttributes = NULL;
pAttribute = RasAuthAttributeGetVendorSpecific(
311, MS_VSA_CHAP_MPPE_Keys,
pApResult->pUserAttributes);
if ( NULL == pAttribute )
{
TRACE("No User Session Key");
dwRetCode = ERROR_NOT_FOUND;
goto done;
}
dwRetCode = IASGetSendRecvSessionKeys( ((PBYTE)(pAttribute->Value))+6+8,
16,
pApResult->abResponse,
24,
bSendKey,
bRecvKey
);
if ( NO_ERROR != dwRetCode )
{
TRACE("Failed to generate send/recv keys");
goto done;
}
pSendRecvKeyAttr = RasAuthAttributeCreate ( 2 );
if ( NULL == pSendRecvKeyAttr )
{
TRACE("RasAuthAttributeCreate failed");
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
goto done;
}
bMPPEKey[0] = MS_VSA_MPPE_Send_Key;
bMPPEKey[1] = 36;
bMPPEKey[4] = 16;
CopyMemory(&bMPPEKey[5], bSendKey, 16 );
dwRetCode = RasAuthAttributeInsertVSA(
0,
pSendRecvKeyAttr,
VENDOR_MICROSOFT,
36,
bMPPEKey );
if ( NO_ERROR != dwRetCode )
{
TRACE("Failed to insert send key");
goto done;
}
bMPPEKey[0] = MS_VSA_MPPE_Recv_Key;
CopyMemory(&bMPPEKey[5], bRecvKey, 16 );
dwRetCode = RasAuthAttributeInsertVSA(
1,
pSendRecvKeyAttr,
VENDOR_MICROSOFT,
36,
bMPPEKey );
if ( NO_ERROR != dwRetCode )
{
TRACE("Failed to insert recv key");
goto done;
}
pEapwb->pUserAttributes = pSendRecvKeyAttr;
done:
if ( NO_ERROR != dwRetCode )
{
if ( pSendRecvKeyAttr )
RasAuthAttributeDestroy(pSendRecvKeyAttr);
}
return dwRetCode;
}
DWORD
EapMSChapv2CMakeMessage(
IN VOID* pWorkBuf,
IN PPP_EAP_PACKET* pReceivePacket,
OUT PPP_EAP_PACKET* pSendPacket,
IN DWORD cbSendPacket,
OUT PPP_EAP_OUTPUT* pEapOutput,
IN PPP_EAP_INPUT* pEapInput
)
{
DWORD dwRetCode = NO_ERROR;
PPP_CONFIG* pReceiveBuf = NULL;
PPP_CONFIG* pSendBuf = NULL;
DWORD cbSendBuf = 1500;
PPPAP_INPUT ApInput;
PPPAP_RESULT ApResult;
WORD cbPacket = 0;
EAPMSCHAPv2WB * pEapwb = (EAPMSCHAPv2WB * ) pWorkBuf;
TRACE("EapMSChapv2CMakeMessage");
//
//Do default processing here.
//
ZeroMemory( &ApResult, sizeof(ApResult) );
if ( ( pSendBuf = LocalAlloc( LPTR, cbSendBuf ) ) == NULL )
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
goto done;
}
if ( pEapInput != NULL )
{
MapEapInputToApInput( pEapInput, &ApInput );
}
switch ( pEapwb->EapState )
{
case EMV2_Initial:
TRACE("EMV2_Initial");
//
// We can oly get a request here...
//
if ( NULL != pReceivePacket )
{
if ( pReceivePacket->Code != EAPCODE_Request )
{
dwRetCode = ERROR_PPP_INVALID_PACKET;
break;
}
//
// Translate the packet received to
// MSCHAP v2 format
//
cbPacket = WireToHostFormat16(pReceivePacket->Length);
if ( cbPacket > sizeof( PPP_EAP_PACKET ) )
{
pReceiveBuf = (PPP_CONFIG *) (pReceivePacket->Data + 1);
dwRetCode = CallMakeMessageAndSetEAPState(
pEapwb->pwb,
pReceiveBuf,
pSendBuf,
cbSendBuf,
&ApResult,
( pEapInput ? &ApInput : NULL ),
pEapOutput
);
// Translate MSCHAPv2 packet to EAP packet
//
if ( NO_ERROR == dwRetCode && pSendBuf )
{
pSendPacket->Code = EAPCODE_Response;
pEapwb->IdToExpect = pEapwb->IdToSend =
pSendPacket->Id = pEapwb->pwb->bIdToSend;
//
// Length = sizeof Header + sizeof MSCHAP packet to send
// This includes the first byte of
cbPacket = WireToHostFormat16( pSendBuf->Length );
CopyMemory ( pSendPacket->Data+1, pSendBuf, cbPacket);
cbPacket += sizeof(PPP_EAP_PACKET);
HostToWireFormat16( cbPacket, pSendPacket->Length );
pSendPacket->Data[0] = (BYTE)PPP_EAP_MSCHAPv2;
pEapwb->EapState = EMV2_ResponseSend;
}
}
}
break;
case EMV2_ResponseSend:
TRACE("EMV2_ResponseSend");
//
// We should get either a CHAP auth success or CHAP Auth fail here
// for the initial challenge send out.
//
if ( NULL != pReceivePacket )
{
if ( pReceivePacket->Code != EAPCODE_Request &&
pReceivePacket->Code != EAPCODE_Failure
)
{
dwRetCode = ERROR_PPP_INVALID_PACKET;
break;
}
if ( pReceivePacket->Code == EAPCODE_Failure )
{
TRACE("Got a Code Failure when expecting Response. Failing Auth");
pEapwb->EapState = EMV2_Failure;
pEapOutput->Action = EAPACTION_Done;
pEapOutput->fSaveUserData = FALSE;
ZeroMemory ( pEapwb->pUserProp->szPassword, sizeof( pEapwb->pUserProp->szPassword ) );
pEapOutput->dwAuthResultCode = ERROR_AUTHENTICATION_FAILURE;
break;
}
//
// Translate the packet received to
// MSCHAP v2 format
//
cbPacket = WireToHostFormat16(pReceivePacket->Length);
if ( cbPacket > sizeof( PPP_EAP_PACKET ) )
{
pReceiveBuf = (PPP_CONFIG *) (pReceivePacket->Data + 1);
dwRetCode = CallMakeMessageAndSetEAPState(
pEapwb->pwb,
pReceiveBuf,
pSendBuf,
cbSendBuf,
&ApResult,
( pEapInput ? &ApInput : NULL ),
pEapOutput
);
//
// Translate MSCHAPv2 packet to EAP packet
//
if ( NO_ERROR == dwRetCode && pSendBuf )
{
if ( ApResult.dwError == NO_ERROR )
{
if ( ApResult.Action == APA_NoAction )
{
pEapOutput->Action = EAPACTION_NoAction;
pEapOutput->dwAuthResultCode = NO_ERROR;
break;
}
//
// We need to change MSCHAP keys to MPPE send recv keys
// This is needed because there is no way to pass the
// MSCHAP challenge response back
//
dwRetCode = GetClientMPPEKeys ( pEapwb, &ApResult );
if ( NO_ERROR != dwRetCode )
{
break;
}
//
//Client could successfully validate the server
//
pSendPacket->Code = EAPCODE_Response;
pEapwb->IdToSend ++;
//send the same id as received packet back
pEapwb->IdToExpect = pSendPacket->Id = pReceivePacket->Id;
//
// Length = sizeof Header + sizeof MSCHAP packet to send
// This includes the first byte of
* (pSendPacket->Data+1) = CHAPCODE_Success;
cbPacket = sizeof(PPP_EAP_PACKET) + 1;
HostToWireFormat16( cbPacket, pSendPacket->Length );
pSendPacket->Data[0] = (BYTE)PPP_EAP_MSCHAPv2;
pEapwb->EapState = EMV2_CHAPAuthSuccess;
//
// Set the out attributes and the response
//
pEapOutput->Action = EAPACTION_Send;
pEapwb->dwAuthResultCode = ApResult.dwError;
}
else
{
//
// Based on what MSCHAPV2 has send back
// we need to Invoke appropriate interactive UI
// Retry password or change password here.
// If both retry and change pwd are not
// applicable then just send a fail message.
// and wait for EAP_Failure message from server.
// And Auth state goes to CHAPAuthFailed
//
// If this is a failure with rety then show
// interactive UI.
if ( pEapwb->fFlags & EAPMSCHAPv2_FLAG_MACHINE_AUTH )
{
//
// This is a machine auth. So we dont to show any
// retry or any of that stuff even though the server
// might have send such things back.
//
pEapOutput->dwAuthResultCode = ERROR_AUTHENTICATION_FAILURE;
pEapOutput->Action = EAPACTION_Done;
pEapwb->EapState = EMV2_Failure;
}
else
{
if ( ApResult.fRetry )
{
pEapOutput->fInvokeInteractiveUI = TRUE;
//
// Setup the UI Context data
//
pEapwb->pUIContextData =
(PEAPMSCHAPv2_INTERACTIVE_UI) LocalAlloc ( LPTR,
sizeof(EAPMSCHAPv2_INTERACTIVE_UI) );
if ( NULL == pEapwb->pUIContextData )
{
TRACE ("Error allocating memory for UI context data");
dwRetCode = ERROR_OUTOFMEMORY;
goto done;
}
pEapwb->pUIContextData->dwVersion = 1;
pEapwb->pUIContextData->fFlags |= EAPMSCHAPv2_INTERACTIVE_UI_FLAG_RETRY;
pEapwb->dwInteractiveUIOperation |= EAPMSCHAPv2_INTERACTIVE_UI_FLAG_RETRY;
if ( pEapwb->pUserProp )
{
CopyMemory( &(pEapwb->pUIContextData->UserProp),
pEapwb->pUserProp,
sizeof(EAPMSCHAPv2_USER_PROPERTIES)
);
}
if ( pEapwb->pConnProp->fFlags & EAPMSCHAPv2_FLAG_USE_WINLOGON_CREDS )
{
//We are using winlogon creds
// and this is a retryable failure
// so copy over the username and domain
// from chap wb to eapchap wb
WCHAR * pWchar = NULL;
pWchar = wcschr( pEapwb->wszRadiusUserName, L'\\' );
if ( pWchar == NULL )
{
WideCharToMultiByte(
CP_ACP,
0,
pEapwb->wszRadiusUserName,
-1,
pEapwb->pUIContextData->UserProp.szUserName,
UNLEN + 1,
NULL,
NULL );
}
else
{
*pWchar = 0;
WideCharToMultiByte(
CP_ACP,
0,
pEapwb->wszRadiusUserName,
-1,
pEapwb->pUIContextData->UserProp.szDomain,
DNLEN + 1,
NULL,
NULL );
*pWchar = L'\\';
WideCharToMultiByte(
CP_ACP,
0,
pWchar + 1,
-1,
pEapwb->pUIContextData->UserProp.szUserName,
UNLEN + 1,
NULL,
NULL );
}
}
pEapOutput->Action = EAPACTION_NoAction;
pEapOutput->pUIContextData = (PBYTE)pEapwb->pUIContextData;
pEapOutput->dwSizeOfUIContextData = sizeof(EAPMSCHAPv2_INTERACTIVE_UI);
pEapwb->EapState = EMV2_CHAPAuthFail;
}
else if ( ApResult.dwError == ERROR_PASSWD_EXPIRED )
{
//
// show the change password GUI.
//
pEapOutput->fInvokeInteractiveUI = TRUE;
//
// Setup the UI Context data
//
pEapwb->pUIContextData =
(PEAPMSCHAPv2_INTERACTIVE_UI) LocalAlloc ( LPTR,
sizeof(EAPMSCHAPv2_INTERACTIVE_UI) );
if ( NULL == pEapwb->pUIContextData )
{
TRACE ("Error allocating memory for UI context data");
dwRetCode = ERROR_OUTOFMEMORY;
goto done;
}
pEapwb->pUIContextData->dwVersion = 1;
if ( pEapwb->pConnProp->fFlags & EAPMSCHAPv2_FLAG_USE_WINLOGON_CREDS )
{
//
// Show the dialog with old pwd, new pwd and conf pwd
//
pEapwb->pUIContextData->fFlags |= EAPMSCHAPv2_INTERACTIVE_UI_FLAG_CHANGE_PWD_WINLOGON;
pEapwb->dwInteractiveUIOperation |= EAPMSCHAPv2_INTERACTIVE_UI_FLAG_CHANGE_PWD_WINLOGON;
}
else
{
//
// We have the old password. So show the dialog with new pwd and conf pwd.
//
pEapwb->pUIContextData->fFlags |= EAPMSCHAPv2_INTERACTIVE_UI_FLAG_CHANGE_PWD;
pEapwb->dwInteractiveUIOperation |= EAPMSCHAPv2_INTERACTIVE_UI_FLAG_CHANGE_PWD;
}
if ( pEapwb->pUserProp )
{
CopyMemory( &(pEapwb->pUIContextData->UserProp),
pEapwb->pUserProp,
sizeof(EAPMSCHAPv2_USER_PROPERTIES)
);
}
pEapOutput->Action = EAPACTION_NoAction;
pEapOutput->pUIContextData = (PBYTE)pEapwb->pUIContextData;
pEapOutput->dwSizeOfUIContextData = sizeof(EAPMSCHAPv2_INTERACTIVE_UI);
pEapwb->EapState = EMV2_CHAPAuthFail;
}
else
{
//
// this is not a retryable failure
// So we are done with Auth and failed.
//
pEapOutput->dwAuthResultCode = ApResult.dwError;
pEapOutput->Action = EAPACTION_Done;
pEapwb->EapState = EMV2_Failure;
}
}
}
}
else
{
// Something went wrong here.
TRACE1("Error returned by MSCHAPv2 protocol 0x%x", dwRetCode);
}
}
else
{
dwRetCode = ERROR_PPP_INVALID_PACKET;
}
}
else
{
dwRetCode = ERROR_PPP_INVALID_PACKET;
}
break;
case EMV2_CHAPAuthFail:
TRACE("EMV2_CHAPAuthFail");
//
// We come here in case of a retryable
// failure from chap and after we have popped
// interactive UI.
//
//
// Check to see if we have got data from user
//
if ( pEapInput->fDataReceivedFromInteractiveUI )
{
//
// Copy the new uid/pwd and then call chap make message again.
// adjust our state
LocalFree(pEapwb->pUIContextData);
pEapwb->pUIContextData = NULL;
LocalFree(pEapwb->pUserProp);
pEapwb->pUserProp = (PEAPMSCHAPv2_USER_PROPERTIES)LocalAlloc(LPTR,
sizeof(EAPMSCHAPv2_USER_PROPERTIES) );
if (NULL == pEapwb->pUserProp )
{
TRACE("Failed to allocate memory for user props.");
dwRetCode = ERROR_OUTOFMEMORY;
break;
}
CopyMemory( pEapwb->pUserProp,
&(((PEAPMSCHAPv2_INTERACTIVE_UI)(pEapInput->pDataFromInteractiveUI))->UserProp),
sizeof(EAPMSCHAPv2_USER_PROPERTIES)
);
//
// Call into mschap here
//
ApInput.pszDomain = pEapwb->pUserProp->szDomain;
if ( ((PEAPMSCHAPv2_INTERACTIVE_UI)(pEapInput->pDataFromInteractiveUI))->fFlags &
EAPMSCHAPv2_INTERACTIVE_UI_FLAG_RETRY
)
{
ApInput.pszUserName = pEapwb->pUserProp->szUserName;
ApInput.pszPassword = pEapwb->pUserProp->szPassword;
}
else
{
if ( pEapwb->pConnProp->fFlags & EAPMSCHAPv2_FLAG_USE_WINLOGON_CREDS )
{
CopyMemory ( pEapwb->pUserProp->szPassword,
((PEAPMSCHAPv2_INTERACTIVE_UI)(pEapInput->pDataFromInteractiveUI))->UserProp.szPassword,
PWLEN
);
}
CopyMemory ( pEapwb->szOldPassword,
pEapwb->pUserProp->szPassword,
PWLEN
);
CopyMemory ( pEapwb->pUserProp->szPassword,
((PEAPMSCHAPv2_INTERACTIVE_UI)(pEapInput->pDataFromInteractiveUI))->szNewPassword,
PWLEN
);
ApInput.pszUserName = pEapwb->pUserProp->szUserName;
ApInput.pszPassword = pEapwb->pUserProp->szPassword;
ApInput.pszOldPassword = pEapwb->szOldPassword;
}
dwRetCode = CallMakeMessageAndSetEAPState(
pEapwb->pwb,
pReceiveBuf,
pSendBuf,
cbSendBuf,
&ApResult,
( pEapInput ? &ApInput : NULL ),
pEapOutput
);
if ( NO_ERROR == dwRetCode && pSendBuf )
{
pSendPacket->Code = EAPCODE_Response;
pSendPacket->Id = pEapwb->pwb->bIdToSend;
//
// Length = sizeof Header + sizeof MSCHAP packet to send
// This includes the first byte of
cbPacket = WireToHostFormat16( pSendBuf->Length );
CopyMemory ( pSendPacket->Data+1, pSendBuf, cbPacket);
cbPacket += sizeof(PPP_EAP_PACKET);
HostToWireFormat16( cbPacket, pSendPacket->Length );
pSendPacket->Data[0] = (BYTE)PPP_EAP_MSCHAPv2;
pEapwb->EapState = EMV2_ResponseSend;
pEapOutput->dwAuthResultCode = ApResult.dwError;
pEapOutput->Action = EAPACTION_Send;
}
}
else
{
TRACE("No Data received from interactive UI when expecting some");
//Work around for PPP misbehavior. We have invoked
//interactive UI and ppp is sending stuff to us all the time...
if ( !pEapwb->pUIContextData )
{
pEapOutput->dwAuthResultCode = ApResult.dwError;
pEapOutput->Action = EAPACTION_Done;
pEapwb->EapState = EMV2_Failure;
}
}
break;
case EMV2_CHAPAuthSuccess:
TRACE("EMV2_CHAPAuthSuccess");
//We should get an EAPSUCCESS here
if ( NULL != pReceivePacket )
{
if ( pReceivePacket->Code != EAPCODE_Success )
{
dwRetCode = ERROR_PPP_INVALID_PACKET;
pEapwb->EapState = EMV2_Failure;
break;
}
if ( ( pEapwb->dwInteractiveUIOperation &
EAPMSCHAPv2_INTERACTIVE_UI_FLAG_CHANGE_PWD_WINLOGON
) ||
( ( pEapwb->dwInteractiveUIOperation &
EAPMSCHAPv2_INTERACTIVE_UI_FLAG_RETRY ) &&
( pEapwb->pConnProp->fFlags &
EAPMSCHAPv2_FLAG_USE_WINLOGON_CREDS
)
)
)
{
//
// We need to plumb creds in winlogon.
//
dwRetCode = RasSetCachedCredentials ( pEapwb->pUserProp->szUserName,
pEapwb->pUserProp->szDomain,
pEapwb->pUserProp->szPassword
);
if ( NO_ERROR != dwRetCode )
{
TRACE1("RasSetCachedCredentials failed with error 0x%x", dwRetCode);
TRACE("Change password operation could not apply changes to winlogon.");
dwRetCode = NO_ERROR;
}
//since we entered this mode in winlogon mode
//wipe out the uid pwd if set
//
ZeroMemory ( pEapwb->pUserProp->szUserName, sizeof(pEapwb->pUserProp->szUserName) );
ZeroMemory ( pEapwb->pUserProp->szDomain, sizeof(pEapwb->pUserProp->szDomain) );
}
pEapwb->EapState = EMV2_Success;
pEapOutput->Action = EAPACTION_Done;
pEapOutput->fSaveUserData = TRUE;
if ( pEapwb->pUserProp->szPassword[0] )
{
DATA_BLOB DBPassword;
//Encode the password to send back.
dwRetCode = EncodePassword( strlen(pEapwb->pUserProp->szPassword) + 1,
pEapwb->pUserProp->szPassword,
&(DBPassword)
);
if ( NO_ERROR == dwRetCode )
{
AllocateUserDataWithEncPwd ( pEapwb, &DBPassword );
FreePassword ( &DBPassword );
}
else
{
TRACE1("EncodePassword failed with errror 0x%x.", dwRetCode);
dwRetCode = NO_ERROR;
}
}
RtlSecureZeroMemory ( pEapwb->pUserProp->szPassword, sizeof( pEapwb->pUserProp->szPassword ) );
LocalFree ( pEapOutput->pUserData );
pEapOutput->pUserData = (PBYTE)pEapwb->pUserProp;
pEapOutput->dwSizeOfUserData =
sizeof( EAPMSCHAPv2_USER_PROPERTIES) + pEapwb->pUserProp->cbEncPassword -1 ;
pEapOutput->pUserAttributes = pEapwb->pUserAttributes;
pEapOutput->dwAuthResultCode = pEapwb->dwAuthResultCode;
}
else
{
dwRetCode = ERROR_PPP_INVALID_PACKET;
}
break;
case EMV2_Success:
TRACE("EMV2_Success");
break;
case EMV2_Failure:
TRACE("EMV2_Failure");
break;
case EMV2_RequestSend:
default:
TRACE1("Why is this EAPMschapv2 in this state? %d", pEapwb->EapState);
break;
}
done:
if ( pSendBuf )
{
LocalFree(pSendBuf);
}
return dwRetCode;
}
//**
//
// Call: EapMSChapv2MakeMessage
//
// Returns: NO_ERROR - Success
// Non-zero returns - Failure
//
// Description:
//
DWORD
EapMSChapv2MakeMessage(
IN VOID* pWorkBuf,
IN PPP_EAP_PACKET* pReceivePacket,
OUT PPP_EAP_PACKET* pSendPacket,
IN DWORD cbSendPacket,
OUT PPP_EAP_OUTPUT* pEapOutput,
IN PPP_EAP_INPUT* pEapInput
)
{
DWORD dwRetCode = NO_ERROR;
EAPMSCHAPv2WB * pwb = (EAPMSCHAPv2WB *)pWorkBuf;
TRACE("EapMSChapv2MakeMessage");
//
// There may not be a real pressing need to split
// this function but it is just cleaner.
if ( pwb->pwb->fServer )
{
dwRetCode = EapMSChapv2SMakeMessage ( pWorkBuf,
pReceivePacket,
pSendPacket,
cbSendPacket,
pEapOutput,
pEapInput
);
}
else
{
dwRetCode = EapMSChapv2CMakeMessage ( pWorkBuf,
pReceivePacket,
pSendPacket,
cbSendPacket,
pEapOutput,
pEapInput
);
}
return dwRetCode;
}
//**
//
// Call: EapChapMakeMessage
//
// Returns: NO_ERROR - Success
// Non-zero returns - Failure
//
// Description:
//
DWORD
EapChapMakeMessage(
IN VOID* pWorkBuf,
IN PPP_EAP_PACKET* pReceivePacket,
OUT PPP_EAP_PACKET* pSendPacket,
IN DWORD cbSendPacket,
OUT PPP_EAP_OUTPUT* pEapOutput,
IN PPP_EAP_INPUT* pEapInput
)
{
DWORD dwRetCode;
PPP_CONFIG* pReceiveBuf = NULL;
PPP_CONFIG* pSendBuf = NULL;
DWORD cbSendBuf = 1500;
PPPAP_INPUT ApInput;
PPPAP_RESULT ApResult;
CHAPWB * pwb = (CHAPWB *)pWorkBuf;
ZeroMemory( &ApResult, sizeof(ApResult) );
if ( ( pSendBuf = LocalAlloc( LPTR, cbSendBuf ) ) == NULL )
{
return( ERROR_NOT_ENOUGH_MEMORY );
}
//
// Convert EAP to CHAP packet.
//
if ( pReceivePacket != NULL )
{
WORD cbPacket = WireToHostFormat16( pReceivePacket->Length );
if ( ( pReceiveBuf = LocalAlloc( LPTR, cbPacket ) ) == NULL )
{
LocalFree( pSendBuf );
return( ERROR_NOT_ENOUGH_MEMORY );
}
switch( pReceivePacket->Code )
{
case EAPCODE_Request:
//
// CHAP challenge code
//
pReceiveBuf->Code = 1;
//
// Length is EAP length - 1 for type
//
cbPacket--;
break;
case EAPCODE_Response:
//
// CHAP response code
//
pReceiveBuf->Code = 2;
//
// Length is EAP length - 1 for type
//
cbPacket--;
break;
case EAPCODE_Success:
//
// CHAP success code
//
pReceiveBuf->Code = 3;
break;
case EAPCODE_Failure:
//
// CHAP failure code
//
pReceiveBuf->Code = 4;
break;
default:
//
// Unknown code
//
LocalFree( pSendBuf );
LocalFree( pReceiveBuf );
return( ERROR_PPP_INVALID_PACKET );
}
//
// Set the Id
//
pReceiveBuf->Id = pReceivePacket->Id;
//
// Set the length
//
HostToWireFormat16( (WORD)cbPacket, pReceiveBuf->Length );
if ( cbPacket > PPP_EAP_PACKET_HDR_LEN )
{
if ( ( pReceivePacket->Code == EAPCODE_Request ) ||
( pReceivePacket->Code == EAPCODE_Response ) )
{
//
// Do not copy EAP type
//
CopyMemory( pReceiveBuf->Data,
pReceivePacket->Data+1,
cbPacket - PPP_EAP_PACKET_HDR_LEN );
}
else
{
//
// As per the EAP spec, there shouldn't be any data but
// copy it anyway if there is.
//
CopyMemory( pReceiveBuf->Data,
pReceivePacket->Data,
cbPacket - PPP_EAP_PACKET_HDR_LEN );
}
}
}
if ( pEapInput != NULL )
{
MapEapInputToApInput( pEapInput, &ApInput );
//
// On the client side, if we received an indication that a success
// packet was received, then simply create a success packet and
// pass it in
//
if ( pEapInput->fSuccessPacketReceived )
{
if ( ( pReceiveBuf = LocalAlloc( LPTR, 4 ) ) == NULL )
{
LocalFree( pSendBuf );
return( ERROR_NOT_ENOUGH_MEMORY );
}
pReceiveBuf->Code = 3; // CHAP success code
pReceiveBuf->Id = pwb->bIdExpected;
HostToWireFormat16( (WORD)4, pReceiveBuf->Length );
}
}
dwRetCode = ChapMakeMessage(
pWorkBuf,
pReceiveBuf,
pSendBuf,
cbSendBuf,
&ApResult,
( pEapInput == NULL ) ? NULL : &ApInput );
if ( dwRetCode != NO_ERROR )
{
LocalFree( pSendBuf );
LocalFree( pReceiveBuf );
return( dwRetCode );
}
//
// Convert ApResult to pEapOutput
//
switch( ApResult.Action )
{
case APA_NoAction:
pEapOutput->Action = EAPACTION_NoAction;
break;
case APA_Done:
pEapOutput->Action = EAPACTION_Done;
break;
case APA_SendAndDone:
pEapOutput->Action = EAPACTION_SendAndDone;
break;
case APA_Send:
pEapOutput->Action = EAPACTION_Send;
break;
case APA_SendWithTimeout:
pEapOutput->Action = ( pwb->fServer )
? EAPACTION_SendWithTimeout
: EAPACTION_Send;
break;
case APA_SendWithTimeout2:
pEapOutput->Action = ( pwb->fServer )
? EAPACTION_SendWithTimeoutInteractive
: EAPACTION_Send;
break;
case APA_Authenticate:
pEapOutput->pUserAttributes = ApResult.pUserAttributes;
pEapOutput->Action = EAPACTION_Authenticate;
break;
default:
RTASSERT(FALSE);
break;
}
switch( pEapOutput->Action )
{
case EAPACTION_SendAndDone:
case EAPACTION_Send:
case EAPACTION_SendWithTimeout:
case EAPACTION_SendWithTimeoutInteractive:
{
//
// Convert CHAP to EAP packet
// Length is CHAP length + 1 for EAP type
//
WORD cbPacket = WireToHostFormat16( pSendBuf->Length );
switch( pSendBuf->Code )
{
case 1: // CHAPCODE_Challenge
pSendPacket->Code = EAPCODE_Request;
cbPacket++; // Add one octect for EAP type
break;
case 2: // CHAPCODE_Response
pSendPacket->Code = EAPCODE_Response;
cbPacket++; // Add one octect for EAP type
break;
case 3: // CHAPCODE_Success
pSendPacket->Code = EAPCODE_Success;
break;
case 4: // CHAPCODE_Failure
pSendPacket->Code = EAPCODE_Failure;
break;
default:
RTASSERT( FALSE );
break;
}
pSendPacket->Id = pSendBuf->Id;
//
// Need to copy the payload and the EAP type in the data field
//
if ( ( pSendPacket->Code == EAPCODE_Request ) ||
( pSendPacket->Code == EAPCODE_Response ) )
{
HostToWireFormat16( (WORD)cbPacket, pSendPacket->Length );
*pSendPacket->Data = EAPTYPE_MD5Challenge; // EAPTYPE_MD5Challenge;
//
// If there is a payload, copy it
//
if ( ( cbPacket - 1 ) > PPP_CONFIG_HDR_LEN )
{
CopyMemory( pSendPacket->Data+1,
pSendBuf->Data,
cbPacket - 1 - PPP_CONFIG_HDR_LEN );
}
}
else
{
//
// Success or failure should not have any data bytes.
//
HostToWireFormat16( (WORD)4, pSendPacket->Length );
}
//
// Fall thru...
//
}
default:
pEapOutput->dwAuthResultCode = ApResult.dwError;
break;
}
LocalFree( pSendBuf );
if ( pReceiveBuf != NULL )
{
LocalFree( pReceiveBuf );
}
return( dwRetCode );
}
//**
//
// Call: EapChapInitialize
//
// Returns: NO_ERROR - Success
// Non-zero returns - Failure
//
// Description:
//
DWORD
EapChapInitialize(
IN BOOL fInitialize
)
{
return ChapInit( fInitialize );
}
//**
//
// Call: RasEapGetInfo
//
// Returns: NO_ERROR - Success
// Non-zero returns - Failure
//
// Description:
//
DWORD
RasEapGetInfo(
IN DWORD dwEapTypeId,
OUT PPP_EAP_INFO* pEapInfo
)
{
if ( dwEapTypeId != PPP_EAP_MSCHAPv2 &&
dwEapTypeId != EAPTYPE_MD5Challenge
)
{
//
// We support 4 (MD5) eap type
//
//
// and now we support MSCHAP V2 also
//
//
return( ERROR_NOT_SUPPORTED );
}
ZeroMemory( pEapInfo, sizeof( PPP_EAP_INFO ) );
//
// Fill in the required information
//
pEapInfo->dwEapTypeId = dwEapTypeId;
if ( dwEapTypeId == EAPTYPE_MD5Challenge ) //MD5 CHAP
{
pEapInfo->RasEapInitialize = EapChapInitialize;
pEapInfo->RasEapBegin = EapChapBegin;
pEapInfo->RasEapEnd = EapChapEnd;
pEapInfo->RasEapMakeMessage = EapChapMakeMessage;
}
else
{
pEapInfo->RasEapInitialize = EapMSCHAPv2Initialize;
pEapInfo->RasEapBegin = EapMSChapv2Begin;
pEapInfo->RasEapEnd = EapMSChapv2End;
pEapInfo->RasEapMakeMessage = EapMSChapv2MakeMessage;
}
return( NO_ERROR );
}
DWORD
RasEapGetCredentials(
DWORD dwTypeId,
VOID * pWorkBuf,
VOID ** ppCredentials)
{
RASMAN_CREDENTIALS *pCreds = NULL;
DWORD dwRetCode = NO_ERROR;
EAPMSCHAPv2WB *pWB = (EAPMSCHAPv2WB *)pWorkBuf;
if(PPP_EAP_MSCHAPv2 != dwTypeId)
{
dwRetCode = E_NOTIMPL;
goto done;
}
if(NULL == pWorkBuf)
{
dwRetCode = E_INVALIDARG;
goto done;
}
//
// Retrieve the password and return. Its important that
// the allocation below is made from process heap.
//
pCreds = LocalAlloc(LPTR, sizeof(RASMAN_CREDENTIALS));
if(NULL == pCreds)
{
dwRetCode = GetLastError();
goto done;
}
(VOID) StringCchCopyA(pCreds->szUserName, UNLEN, pWB->pwb->szUserName);
(VOID) StringCchCopyA(pCreds->szDomain, DNLEN, pWB->pwb->szDomain);
DecodePw( pWB->pwb->chSeed, pWB->pwb->szPassword );
//
// Convert the password to unicode
//
if(!MultiByteToWideChar(CP_ACP,
0,
pWB->pwb->szPassword,
-1,
pCreds->wszPassword,
PWLEN))
{
TRACE("RasEapGetCredentials: multibytetowidechar failed");
}
EncodePw(pWB->pwb->chSeed, pWB->pwb->szPassword);
done:
*ppCredentials = (VOID *) pCreds;
return dwRetCode;
}
DWORD
ReadConnectionData(
IN BOOL fWireless,
IN BYTE* pConnectionDataIn,
IN DWORD dwSizeOfConnectionDataIn,
OUT PEAPMSCHAPv2_CONN_PROPERTIES* ppConnProp
)
{
DWORD dwErr = NO_ERROR;
PEAPMSCHAPv2_CONN_PROPERTIES pConnProp = NULL;
TRACE("ReadConnectionData");
RTASSERT(NULL != ppConnProp);
if ( dwSizeOfConnectionDataIn < sizeof(EAPMSCHAPv2_CONN_PROPERTIES) )
{
pConnProp = LocalAlloc(LPTR, sizeof(EAPMSCHAPv2_CONN_PROPERTIES));
if (NULL == pConnProp)
{
dwErr = GetLastError();
TRACE1("LocalAlloc failed and returned %d", dwErr);
goto LDone;
}
//This is a new structure
pConnProp->dwVersion = 1;
if ( fWireless )
{
//Set the use winlogon default flag
pConnProp->fFlags = EAPMSCHAPv2_FLAG_USE_WINLOGON_CREDS;
}
}
else
{
RTASSERT(NULL != pConnectionDataIn);
//
//Check to see if this is a version 0 structure
//If it is a version 0 structure then we migrate it to version1
//
pConnProp = LocalAlloc(LPTR, dwSizeOfConnectionDataIn);
if (NULL == pConnProp)
{
dwErr = GetLastError();
TRACE1("LocalAlloc failed and returned %d", dwErr);
goto LDone;
}
// If the user has mucked with the phonebook, we mustn't be affected.
// The size must be correct.
CopyMemory(pConnProp, pConnectionDataIn, dwSizeOfConnectionDataIn);
}
*ppConnProp = pConnProp;
pConnProp = NULL;
LDone:
LocalFree(pConnProp);
return(dwErr);
}
DWORD
AllocateUserDataWithEncPwd ( EAPMSCHAPv2WB * pEapwb, DATA_BLOB * pDBPassword )
{
DWORD dwRetCode = NO_ERROR;
PEAPMSCHAPv2_USER_PROPERTIES pUserProp = NULL;
TRACE("AllocateUserDataWithEncPwd");
pUserProp = LocalAlloc ( LPTR, sizeof( EAPMSCHAPv2_USER_PROPERTIES) + pDBPassword->cbData - 1 );
if ( NULL == pUserProp )
{
TRACE("LocalAlloc failed");
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
goto LDone;
}
//
// Set the fields here
//
pUserProp->dwVersion = pEapwb->pUserProp->dwVersion;
pUserProp->fFlags = pEapwb->pUserProp->fFlags;
pUserProp->dwMaxRetries = pEapwb->pUserProp->dwMaxRetries;
strncpy ( pUserProp->szUserName, pEapwb->pUserProp->szUserName, UNLEN );
strncpy ( pUserProp->szPassword, pEapwb->pUserProp->szPassword, PWLEN );
strncpy ( pUserProp->szDomain, pEapwb->pUserProp->szDomain, DNLEN );
pUserProp->cbEncPassword = pDBPassword->cbData;
CopyMemory (pUserProp->bEncPassword,
pDBPassword->pbData,
pDBPassword->cbData
);
LocalFree ( pEapwb->pUserProp );
pEapwb->pUserProp = pUserProp;
LDone:
return dwRetCode;
}
DWORD
ReadUserData(
IN BYTE* pUserDataIn,
IN DWORD dwSizeOfUserDataIn,
OUT PEAPMSCHAPv2_USER_PROPERTIES* ppUserProp
)
{
DWORD dwRetCode = NO_ERROR;
PEAPMSCHAPv2_USER_PROPERTIES pUserProp = NULL;
DATA_BLOB DBPassword;
DWORD cbPassword = 0;
PBYTE pbPassword = NULL;
TRACE("ReadUserData");
RTASSERT(NULL != ppUserProp);
if (dwSizeOfUserDataIn < sizeof(EAPMSCHAPv2_USER_PROPERTIES_v1))
{
pUserProp = LocalAlloc(LPTR, sizeof(EAPMSCHAPv2_USER_PROPERTIES));
if (NULL == pUserProp)
{
dwRetCode = GetLastError();
TRACE1("LocalAlloc failed and returned %d", dwRetCode);
goto LDone;
}
pUserProp->dwVersion = 1;
}
else
{
DWORD dwSizeToAllocate = dwSizeOfUserDataIn;
RTASSERT(NULL != pUserDataIn);
if ( dwSizeOfUserDataIn == sizeof( EAPMSCHAPv2_USER_PROPERTIES_v1 ) )
{
//This is the old struct so allocation new number of bytes.
dwSizeToAllocate = sizeof( EAPMSCHAPv2_USER_PROPERTIES );
}
pUserProp = LocalAlloc(LPTR, dwSizeToAllocate);
if (NULL == pUserProp)
{
dwRetCode = GetLastError();
TRACE1("LocalAlloc failed and returned %d", dwRetCode);
goto LDone;
}
CopyMemory(pUserProp, pUserDataIn, dwSizeOfUserDataIn);
pUserProp->dwVersion = 2;
if ( pUserProp->cbEncPassword )
{
// We have the encrypted password.
DBPassword.cbData = pUserProp->cbEncPassword;
DBPassword.pbData = pUserProp->bEncPassword;
DecodePassword( &(DBPassword),
&cbPassword,
&pbPassword
);
if ( cbPassword )
{
CopyMemory ( pUserProp->szPassword,
pbPassword,
cbPassword
);
}
}
}
*ppUserProp = pUserProp;
pUserProp = NULL;
LDone:
LocalFree(pUserProp);
return dwRetCode;
}
DWORD
OpenEapEAPMschapv2RegistryKey(
IN LPSTR pszMachineName,
IN REGSAM samDesired,
OUT HKEY* phKeyEapMschapv2
)
{
HKEY hKeyLocalMachine = NULL;
BOOL fHKeyLocalMachineOpened = FALSE;
BOOL fHKeyEapMschapv2Opened = FALSE;
LONG lRet;
DWORD dwErr = NO_ERROR;
RTASSERT(NULL != phKeyEapMschapv2);
lRet = RegConnectRegistry(pszMachineName, HKEY_LOCAL_MACHINE,
&hKeyLocalMachine);
if (ERROR_SUCCESS != lRet)
{
dwErr = lRet;
TRACE2("RegConnectRegistry(%s) failed and returned %d",
pszMachineName ? pszMachineName : "NULL", dwErr);
goto LDone;
}
fHKeyLocalMachineOpened = TRUE;
lRet = RegOpenKeyEx(hKeyLocalMachine, EAPMSCHAPv2_KEY, 0, samDesired,
phKeyEapMschapv2);
if (ERROR_SUCCESS != lRet)
{
dwErr = lRet;
TRACE2("RegOpenKeyEx(%s) failed and returned %d",
EAPMSCHAPv2_KEY, dwErr);
goto LDone;
}
fHKeyEapMschapv2Opened = TRUE;
LDone:
if ( fHKeyEapMschapv2Opened
&& (ERROR_SUCCESS != dwErr))
{
RegCloseKey(*phKeyEapMschapv2);
}
if (fHKeyLocalMachineOpened)
{
RegCloseKey(hKeyLocalMachine);
}
return(dwErr);
}
DWORD
ServerConfigDataIO(
IN BOOL fRead,
IN CHAR* pszMachineName,
IN OUT BYTE** ppData,
IN DWORD dwNumBytes
)
{
HKEY hKeyEapMschapv2;
PEAPMSCHAPv2_USER_PROPERTIES pUserProp;
BOOL fHKeyEapMsChapv2Opened = FALSE;
BYTE* pData = NULL;
DWORD dwSize = 0;
LONG lRet;
DWORD dwType;
DWORD dwErr = NO_ERROR;
RTASSERT(NULL != ppData);
dwErr = OpenEapEAPMschapv2RegistryKey(pszMachineName,
fRead ? KEY_READ : KEY_WRITE, &hKeyEapMschapv2);
if (ERROR_SUCCESS != dwErr)
{
goto LDone;
}
fHKeyEapMsChapv2Opened = TRUE;
if (fRead)
{
lRet = RegQueryValueEx(hKeyEapMschapv2, EAPMSCHAPv2_VAL_SERVER_CONFIG_DATA, NULL,
&dwType, NULL, &dwSize);
if ( (ERROR_SUCCESS != lRet)
|| (REG_BINARY != dwType)
|| (sizeof(EAPMSCHAPv2_USER_PROPERTIES) != dwSize))
{
pData = LocalAlloc(LPTR, sizeof(EAPMSCHAPv2_USER_PROPERTIES));
if (NULL == pData)
{
dwErr = GetLastError();
TRACE1("LocalAlloc failed and returned %d", dwErr);
goto LDone;
}
pUserProp = (EAPMSCHAPv2_USER_PROPERTIES*)pData;
pUserProp->dwVersion = 1;
}
else
{
pData = LocalAlloc(LPTR, dwSize);
if (NULL == pData)
{
dwErr = GetLastError();
TRACE1("LocalAlloc failed and returned %d", dwErr);
goto LDone;
}
lRet = RegQueryValueEx(hKeyEapMschapv2, EAPMSCHAPv2_VAL_SERVER_CONFIG_DATA,
NULL, &dwType, pData, &dwSize);
if (ERROR_SUCCESS != lRet)
{
dwErr = lRet;
TRACE2("RegQueryValueEx(%s) failed and returned %d",
EAPMSCHAPv2_VAL_SERVER_CONFIG_DATA, dwErr);
goto LDone;
}
}
pUserProp = (EAPMSCHAPv2_USER_PROPERTIES*)pData;
*ppData = pData;
pData = NULL;
}
else
{
lRet = RegSetValueEx(hKeyEapMschapv2, EAPMSCHAPv2_VAL_SERVER_CONFIG_DATA, 0,
REG_BINARY, *ppData, dwNumBytes);
if (ERROR_SUCCESS != lRet)
{
dwErr = lRet;
TRACE2("RegSetValueEx(%s) failed and returned %d",
EAPMSCHAPv2_VAL_SERVER_CONFIG_DATA, dwErr);
goto LDone;
}
}
LDone:
if (fHKeyEapMsChapv2Opened)
{
RegCloseKey(hKeyEapMschapv2);
}
LocalFree(pData);
return(dwErr);
}
DWORD
InvokeServerConfigUI (
HWND hWnd,
LPSTR pszMachineName
)
{
return ERROR_CALL_NOT_IMPLEMENTED;
#if 0
DWORD dwRetCode = NO_ERROR;
INT_PTR nRet = 0;
EAPMSCHAPv2_SERVERCONFIG_DIALOG EapServerConfig;
BOOL fLocal = FALSE;
if (0 == *pszMachineName)
{
fLocal = TRUE;
}
//Read the information from registry here
dwRetCode = ServerConfigDataIO(TRUE /* fRead */, fLocal ? NULL : pszMachineName,
(BYTE**)&(EapServerConfig.pUserProp), 0);
if (NO_ERROR != dwRetCode)
{
goto LDone;
}
//Show the server config UI here
nRet = DialogBoxParam(
GetResouceDLLHInstance(),
MAKEINTRESOURCE(IDD_DIALOG_SERVER_CONFIG),
hWnd,
ServerConfigDialogProc,
(LPARAM)&EapServerConfig);
if (-1 == nRet)
{
dwRetCode = GetLastError();
goto LDone;
}
else if (IDOK != nRet)
{
dwRetCode = ERROR_CANCELLED;
goto LDone;
}
//Read the information from registry here
dwRetCode = ServerConfigDataIO(FALSE/* fRead */, fLocal ? NULL : pszMachineName,
(BYTE**)&(EapServerConfig.pUserProp), sizeof(EAPMSCHAPv2_USER_PROPERTIES));
LDone:
return dwRetCode;
#endif
}
BOOL FFormatMachineIdentity1 ( LPWSTR lpszMachineNameRaw, LPWSTR * lppszMachineNameFormatted )
{
BOOL fRetVal = FALSE;
LPWSTR lpwszPrefix = L"host/";
RTASSERT(NULL != lpszMachineNameRaw );
RTASSERT(NULL != lppszMachineNameFormatted );
//
// Prepend host/ to the UPN name
//
*lppszMachineNameFormatted =
(LPWSTR)LocalAlloc ( LPTR, ( wcslen ( lpszMachineNameRaw ) + wcslen ( lpwszPrefix ) + 2 ) * sizeof(WCHAR) );
if ( NULL == *lppszMachineNameFormatted )
{
goto done;
}
wcscpy( *lppszMachineNameFormatted, lpwszPrefix );
wcscat ( *lppszMachineNameFormatted, lpszMachineNameRaw );
fRetVal = TRUE;
done:
return fRetVal;
}
BOOL FFormatMachineIdentity ( LPWSTR lpszMachineNameRaw, LPWSTR * lppszMachineNameFormatted )
{
BOOL fRetVal = TRUE;
LPWSTR s1 = lpszMachineNameRaw;
LPWSTR s2 = NULL;
RTASSERT(NULL != lpszMachineNameRaw );
RTASSERT(NULL != lppszMachineNameFormatted );
//Need to add 2 more chars. One for NULL and other for $ sign
*lppszMachineNameFormatted = (LPWSTR )LocalAlloc ( LPTR, (wcslen(lpszMachineNameRaw) + 2)* sizeof(WCHAR) );
if ( NULL == *lppszMachineNameFormatted )
{
return FALSE;
}
//find the first "." and that is the identity of the machine.
//the second "." is the domain.
//check to see if there at least 2 dots. If not the raw string is
//the output string
while ( *s1 )
{
if ( *s1 == '.' )
{
if ( !s2 ) //First dot
s2 = s1;
else //second dot
break;
}
s1++;
}
//can perform several additional checks here
if ( *s1 != '.' ) //there are no 2 dots so raw = formatted
{
wcscpy ( *lppszMachineNameFormatted, lpszMachineNameRaw );
goto done;
}
if ( s1-s2 < 2 )
{
wcscpy ( *lppszMachineNameFormatted, lpszMachineNameRaw );
goto done;
}
memcpy ( *lppszMachineNameFormatted, s2+1, ( s1-s2-1) * sizeof(WCHAR));
memcpy ( (*lppszMachineNameFormatted) + (s1-s2-1) , L"\\", sizeof(WCHAR));
wcsncpy ( (*lppszMachineNameFormatted) + (s1-s2), lpszMachineNameRaw, s2-lpszMachineNameRaw );
done:
//Append the $ sign no matter what...
wcscat ( *lppszMachineNameFormatted, L"$" );
//upper case the identity
_wcsupr ( *lppszMachineNameFormatted );
return fRetVal;
}
DWORD
GetLocalMachineName (
OUT WCHAR ** ppLocalMachineName
)
{
DWORD dwRetCode = NO_ERROR;
WCHAR * pLocalMachineName = NULL;
DWORD dwLocalMachineNameLen = 0;
if ( !GetComputerNameExW ( ComputerNameDnsFullyQualified,
pLocalMachineName,
&dwLocalMachineNameLen
)
)
{
dwRetCode = GetLastError();
if ( ERROR_MORE_DATA != dwRetCode )
goto LDone;
dwRetCode = NO_ERROR;
}
pLocalMachineName = (WCHAR *)LocalAlloc( LPTR, (dwLocalMachineNameLen * sizeof(WCHAR)) + sizeof(WCHAR) );
if ( NULL == pLocalMachineName )
{
dwRetCode = GetLastError();
goto LDone;
}
if ( !GetComputerNameExW ( ComputerNameDnsFullyQualified,
pLocalMachineName,
&dwLocalMachineNameLen
)
)
{
dwRetCode = GetLastError();
goto LDone;
}
*ppLocalMachineName = pLocalMachineName;
pLocalMachineName = NULL;
LDone:
LocalFree(pLocalMachineName);
return dwRetCode;
}
DWORD
RasEapGetIdentity(
IN DWORD dwEapTypeId,
IN HWND hwndParent,
IN DWORD dwFlags,
IN const WCHAR* pwszPhonebook,
IN const WCHAR* pwszEntry,
IN BYTE* pConnectionDataIn,
IN DWORD dwSizeOfConnectionDataIn,
IN BYTE* pUserDataIn,
IN DWORD dwSizeOfUserDataIn,
OUT BYTE** ppUserDataOut,
OUT DWORD* pdwSizeOfUserDataOut,
OUT WCHAR** ppwszIdentityOut
)
{
DWORD dwRetCode = NO_ERROR;
PEAPMSCHAPv2_USER_PROPERTIES pUserProp = NULL;
PEAPMSCHAPv2_CONN_PROPERTIES pConnProp = NULL;
EAPMSCHAPv2_LOGON_DIALOG EapMsChapv2LogonDialog;
INT_PTR nRet = 0;
LPWSTR lpwszLocalMachineName = NULL;
RASCREDENTIALSW RasCredentials;
CHAR szOldPwd[PWLEN+1]= {0};
BOOL fShowUI = TRUE;
TRACE("RasEapGetIdentity");
RTASSERT(NULL != ppUserDataOut);
RTASSERT(NULL != pdwSizeOfUserDataOut);
*ppUserDataOut = NULL;
ZeroMemory( &EapMsChapv2LogonDialog,
sizeof(EapMsChapv2LogonDialog) );
//
// Read User data first
//
dwRetCode = ReadUserData ( pUserDataIn,
dwSizeOfUserDataIn,
&pUserProp
);
if ( NO_ERROR != dwRetCode )
{
goto LDone;
}
//
// ReadConnectionData and see if we have been setup to use winlogon
// credentials. If so, just call to get user id and send back
// information.
//
dwRetCode = ReadConnectionData ( ( dwFlags & RAS_EAP_FLAG_8021X_AUTH ),
pConnectionDataIn,
dwSizeOfConnectionDataIn,
&pConnProp
);
if ( NO_ERROR != dwRetCode )
{
TRACE("Error reading connection properties");
goto LDone;
}
//MAchine Auth
if ( (dwFlags & RAS_EAP_FLAG_MACHINE_AUTH) )
{
//Send the identity back as domain\machine$
dwRetCode = GetLocalMachineName(&lpwszLocalMachineName );
if ( NO_ERROR != dwRetCode )
{
TRACE("Failed to get computer name");
goto LDone;
}
if ( ! FFormatMachineIdentity1 ( lpwszLocalMachineName,
ppwszIdentityOut )
)
{
TRACE("Failed to format machine identity");
}
*ppUserDataOut = (PBYTE)pUserProp;
*pdwSizeOfUserDataOut = sizeof(EAPMSCHAPv2_USER_PROPERTIES);
pUserProp = NULL;
goto LDone;
}
if ( !(pConnProp->fFlags & EAPMSCHAPv2_FLAG_USE_WINLOGON_CREDS) &&
dwFlags & RAS_EAP_FLAG_NON_INTERACTIVE
)
{
if ( (dwFlags & RAS_EAP_FLAG_8021X_AUTH ) )
{
// Wireless case - If there is no username or password cached
// we need to show the interactive UI
if( !pUserProp->szUserName[0] ||
!pUserProp->cbEncPassword
)
{
TRACE("Passed non interactive mode when interactive mode expected.");
dwRetCode = ERROR_INTERACTIVE_MODE;
goto LDone;
}
}
else
{
//VPN case
dwRetCode = ERROR_INTERACTIVE_MODE;
goto LDone;
}
}
//User Auth
if ( pConnProp->fFlags & EAPMSCHAPv2_FLAG_USE_WINLOGON_CREDS )
{
WCHAR wszUserName[UNLEN + DNLEN + 2];
DWORD dwNumChars = UNLEN + DNLEN;
if ( dwFlags & RAS_EAP_FLAG_LOGON)
{
//
// This is not allowed.
//
dwRetCode = ERROR_INVALID_MSCHAPV2_CONFIG;
goto LDone;
}
//Get currently logged on user name for identity
if (!GetUserNameExW(NameSamCompatible, wszUserName, &dwNumChars))
{
dwRetCode = GetLastError();
TRACE1("GetUserNameExW failed and returned %d", dwRetCode );
goto LDone;
}
*ppwszIdentityOut = (WCHAR *)LocalAlloc(LPTR,
dwNumChars * sizeof(WCHAR) + sizeof(WCHAR) );
if ( NULL == *ppwszIdentityOut )
{
TRACE("Failed to allocate memory for identity");
dwRetCode = ERROR_OUTOFMEMORY;
goto LDone;
}
CopyMemory(*ppwszIdentityOut, wszUserName, dwNumChars * sizeof(WCHAR) );
//All other fields in user prop remains blank
}
else
{
EapMsChapv2LogonDialog.pUserProp = pUserProp;
//
// Show the logon dialog for credentials
//
// if Machine Auth flag is passed in, we dont show
// the logon dialog. If Get Credentials from winlogon
// is passed in dont show logon dialog. else show
// logon dialog.
//
// Check to see if we have the password saved in LSA
// It should not matter if it is not.
if ( !(dwFlags & RAS_EAP_FLAG_LOGON ) )
{
#if 0
ZeroMemory(&RasCredentials, sizeof(RasCredentials));
RasCredentials.dwSize = sizeof(RasCredentials);
RasCredentials.dwMask = RASCM_Password;
dwRetCode = RasGetCredentialsW(pwszPhonebook, pwszEntry,
&RasCredentials);
if ( (dwRetCode == NO_ERROR)
&& (RasCredentials.dwMask & RASCM_Password))
{
//Set the password
WideCharToMultiByte(
CP_ACP,
0,
RasCredentials.szPassword,
-1,
pUserProp->szPassword,
PWLEN + 1,
NULL,
NULL );
strncpy (szOldPwd, pUserProp->szPassword, PWLEN );
}
dwRetCode = NO_ERROR;
#endif
}
else
{
EapMsChapv2LogonDialog.pUserProp->fFlags |= EAPMSCHAPv2_FLAG_CALLED_WITHIN_WINLOGON;
if ( pUserProp->fFlags & EAPMSCHAPv2_FLAG_SAVE_UID_PWD )
pUserProp->fFlags &= ~EAPMSCHAPv2_FLAG_SAVE_UID_PWD;
}
if ( dwFlags & RAS_EAP_FLAG_8021X_AUTH )
{
EapMsChapv2LogonDialog.pUserProp->fFlags |= EAPMSCHAPv2_FLAG_8021x;
}
//We have a username and password. So no need to show
//the UI in case of 8021x
if ( (dwFlags & RAS_EAP_FLAG_8021X_AUTH ) &&
pUserProp->szUserName[0] &&
pUserProp->cbEncPassword
)
{
fShowUI = FALSE;
}
if ( fShowUI )
{
nRet = DialogBoxParam(
GetResouceDLLHInstance(),
MAKEINTRESOURCE(IDD_DIALOG_LOGON),
hwndParent,
LogonDialogProc,
(LPARAM)&EapMsChapv2LogonDialog);
if (-1 == nRet)
{
dwRetCode = GetLastError();
goto LDone;
}
else if (IDOK != nRet)
{
dwRetCode = ERROR_CANCELLED;
goto LDone;
}
}
if ( !(dwFlags & RAS_EAP_FLAG_ROUTER ) )
{
//
// Setup the identity parameter here
//
dwRetCode = GetIdentityFromUserName ( pUserProp->szUserName,
pUserProp->szDomain,
ppwszIdentityOut
);
if ( NO_ERROR != dwRetCode )
{
goto LDone;
}
}
}
#if 0
if ( !(dwFlags & RAS_EAP_FLAG_LOGON ) )
{
ZeroMemory(&RasCredentials, sizeof(RasCredentials));
RasCredentials.dwSize = sizeof(RasCredentials);
RasCredentials.dwMask = RASCM_Password;
if ( pUserProp->fFlags & EAPMSCHAPv2_FLAG_SAVE_UID_PWD )
{
//
// Check to see if the new password is different from the old one
//
if ( strcmp ( szOldPwd, pUserProp->szPassword ) )
{
//
// There is a new password for us to save.
//
MultiByteToWideChar( CP_ACP,
0,
pUserProp->szPassword,
-1,
RasCredentials.szPassword,
sizeof(RasCredentials.szPassword)/sizeof(WCHAR) );
RasSetCredentialsW(pwszPhonebook, pwszEntry, &RasCredentials,
FALSE /* fClearCredentials */);
}
}
else
{
RasSetCredentialsW(pwszPhonebook, pwszEntry, &RasCredentials,
TRUE /* fClearCredentials */);
}
}
#endif
*ppUserDataOut = (PBYTE)pUserProp;
*pdwSizeOfUserDataOut = sizeof(EAPMSCHAPv2_USER_PROPERTIES);
pUserProp = NULL;
LDone:
if ( lpwszLocalMachineName )
LocalFree(lpwszLocalMachineName);
LocalFree(pUserProp);
return dwRetCode;
}
DWORD
RasEapInvokeConfigUI(
IN DWORD dwEapTypeId,
IN HWND hwndParent,
IN DWORD dwFlags,
IN BYTE* pConnectionDataIn,
IN DWORD dwSizeOfConnectionDataIn,
OUT BYTE** ppConnectionDataOut,
OUT DWORD* pdwSizeOfConnectionDataOut
)
{
DWORD dwRetCode = NO_ERROR;
EAPMSCHAPv2_CLIENTCONFIG_DIALOG ClientConfigDialog;
INT_PTR nRet;
TRACE("RasEapInvokeConfigUI");
*ppConnectionDataOut = NULL;
*pdwSizeOfConnectionDataOut = 0;
//
// In case of Router there is nothing to configure
//
if ( dwFlags & RAS_EAP_FLAG_ROUTER )
{
CHAR szMessage[512] = {0};
CHAR szHeader[64] = {0};
//
// Load resource from res file
//
LoadString( GetResouceDLLHInstance(),
IDS_NO_ROUTER_CONFIG,
szMessage,
sizeof(szMessage)-1
);
LoadString( GetResouceDLLHInstance(),
IDS_MESSAGE_HEADER,
szHeader,
sizeof(szHeader)-1
);
MessageBox (hwndParent,
szMessage,
szHeader,
MB_OK
);
goto LDone;
}
//
// If we are a client, read connection data and call
// the dialog to do the config.
//
dwRetCode = ReadConnectionData ( ( dwFlags & RAS_EAP_FLAG_8021X_AUTH ),
pConnectionDataIn,
dwSizeOfConnectionDataIn,
&(ClientConfigDialog.pConnProp)
);
if ( NO_ERROR != dwRetCode )
{
TRACE("Error reading conn prop");
goto LDone;
}
//
// Call in the dialog to show connection props
//
nRet = DialogBoxParam(
GetResouceDLLHInstance(),
MAKEINTRESOURCE(IDD_DIALOG_CLIENT_CONFIG),
hwndParent,
ClientConfigDialogProc,
(LPARAM)&ClientConfigDialog);
if (-1 == nRet)
{
dwRetCode = GetLastError();
goto LDone;
}
else if (IDOK != nRet)
{
dwRetCode = ERROR_CANCELLED;
goto LDone;
}
//
// Setup the out parameters in the ppDataFromInteractiveUI
// so that we can send the new uid/pwd back
//
* ppConnectionDataOut = LocalAlloc( LPTR, sizeof(EAPMSCHAPv2_CONN_PROPERTIES) );
if ( NULL == * ppConnectionDataOut )
{
TRACE("Error allocating memory for pConnectionDataOut");
dwRetCode = ERROR_OUTOFMEMORY;
goto LDone;
}
CopyMemory( *ppConnectionDataOut,
ClientConfigDialog.pConnProp,
sizeof(EAPMSCHAPv2_CONN_PROPERTIES)
);
* pdwSizeOfConnectionDataOut = sizeof(EAPMSCHAPv2_CONN_PROPERTIES);
LDone:
LocalFree(ClientConfigDialog.pConnProp);
return dwRetCode;
}
DWORD
RasEapFreeMemory(
IN BYTE* pMemory
)
{
LocalFree(pMemory);
return(NO_ERROR);
}
DWORD
RasEapInvokeInteractiveUI(
IN DWORD dwEapTypeId,
IN HWND hWndParent,
IN BYTE* pUIContextData,
IN DWORD dwSizeofUIContextData,
OUT BYTE** ppDataFromInteractiveUI,
OUT DWORD* pdwSizeOfDataFromInteractiveUI
)
{
DWORD dwRetCode = NO_ERROR;
PEAPMSCHAPv2_USER_PROPERTIES pUserProp = NULL;
PEAPMSCHAPv2_INTERACTIVE_UI pEapMschapv2InteractiveUI = NULL;
EAPMSCHAPv2_CHANGEPWD_DIALOG EapMsChapv2ChangePwdDialog;
EAPMSCHAPv2_LOGON_DIALOG EapMsChapv2LogonDialog;
INT_PTR nRet = 0;
TRACE("RasEapInvokeInteractiveUI");
RTASSERT(NULL != pUIContextData);
RTASSERT(dwSizeofUIContextData == sizeof(EAPMSCHAPv2_INTERACTIVE_UI));
* ppDataFromInteractiveUI = NULL;
* pdwSizeOfDataFromInteractiveUI = 0;
pEapMschapv2InteractiveUI = (PEAPMSCHAPv2_INTERACTIVE_UI)pUIContextData;
if ( pEapMschapv2InteractiveUI->fFlags & EAPMSCHAPv2_INTERACTIVE_UI_FLAG_RETRY )
{
ZeroMemory( &EapMsChapv2LogonDialog,
sizeof(EapMsChapv2LogonDialog) );
EapMsChapv2LogonDialog.pUserProp =
&(pEapMschapv2InteractiveUI->UserProp);
//
// Show the retry dialog for credentials
//
nRet = DialogBoxParam(
GetResouceDLLHInstance(),
MAKEINTRESOURCE(IDD_DIALOG_RETRY_LOGON),
hWndParent,
RetryDialogProc,
(LPARAM)&EapMsChapv2LogonDialog);
if (-1 == nRet)
{
dwRetCode = GetLastError();
goto LDone;
}
else if (IDOK != nRet)
{
dwRetCode = ERROR_CANCELLED;
goto LDone;
}
//
// Setup the out parameters in the ppDataFromInteractiveUI
// so that we can send the new uid/pwd back
//
* ppDataFromInteractiveUI = LocalAlloc( LPTR, sizeof(EAPMSCHAPv2_INTERACTIVE_UI) );
if ( NULL == * ppDataFromInteractiveUI )
{
TRACE("Error allocating memory for pDataFromInteractiveUI");
dwRetCode = ERROR_OUTOFMEMORY;
goto LDone;
}
CopyMemory ( *ppDataFromInteractiveUI,
pEapMschapv2InteractiveUI,
sizeof( EAPMSCHAPv2_INTERACTIVE_UI )
);
pEapMschapv2InteractiveUI = (PEAPMSCHAPv2_INTERACTIVE_UI)*ppDataFromInteractiveUI;
CopyMemory( &(pEapMschapv2InteractiveUI->UserProp),
EapMsChapv2LogonDialog.pUserProp,
sizeof(EAPMSCHAPv2_USER_PROPERTIES)
);
* pdwSizeOfDataFromInteractiveUI = sizeof(EAPMSCHAPv2_INTERACTIVE_UI);
}
else if ( ( pEapMschapv2InteractiveUI->fFlags & EAPMSCHAPv2_INTERACTIVE_UI_FLAG_CHANGE_PWD )||
( pEapMschapv2InteractiveUI->fFlags & EAPMSCHAPv2_INTERACTIVE_UI_FLAG_CHANGE_PWD_WINLOGON )
)
{
//
// Change password
//
ZeroMemory( &EapMsChapv2ChangePwdDialog,
sizeof(EapMsChapv2ChangePwdDialog)
);
EapMsChapv2ChangePwdDialog.pInteractiveUIData = (PEAPMSCHAPv2_INTERACTIVE_UI)pUIContextData;
//
// Show the retry dialog for credentials
//
if ( pEapMschapv2InteractiveUI->fFlags & EAPMSCHAPv2_INTERACTIVE_UI_FLAG_CHANGE_PWD )
{
nRet = DialogBoxParam(
GetResouceDLLHInstance(),
MAKEINTRESOURCE(IDD_DIALOG_CHANGE_PASSWORD),
hWndParent,
ChangePasswordDialogProc,
(LPARAM)&EapMsChapv2ChangePwdDialog);
}
else
{
//
// We need to get this dialog from rasdlg because
// in XPSP1 no more resources can be added.
//
nRet = DialogBoxParam(
GetRasDlgDLLHInstance(),
MAKEINTRESOURCE(DID_CP_ChangePassword2),
hWndParent,
ChangePasswordDialogProc,
(LPARAM)&EapMsChapv2ChangePwdDialog);
}
if (-1 == nRet)
{
dwRetCode = GetLastError();
goto LDone;
}
else if (IDOK != nRet)
{
dwRetCode = ERROR_CANCELLED;
goto LDone;
}
//
// Setup the out parameters in the ppDataFromInteractiveUI
// so that we can send the new uid/pwd back
//
* ppDataFromInteractiveUI = LocalAlloc( LPTR, sizeof(EAPMSCHAPv2_INTERACTIVE_UI) );
if ( NULL == * ppDataFromInteractiveUI )
{
TRACE("Error allocating memory for pDataFromInteractiveUI");
dwRetCode = ERROR_OUTOFMEMORY;
goto LDone;
}
CopyMemory( *ppDataFromInteractiveUI,
EapMsChapv2ChangePwdDialog.pInteractiveUIData,
sizeof(EAPMSCHAPv2_INTERACTIVE_UI)
);
* pdwSizeOfDataFromInteractiveUI = sizeof(EAPMSCHAPv2_INTERACTIVE_UI);
}
LDone:
return dwRetCode;
}
DWORD
EapMSCHAPv2Initialize(
IN BOOL fInitialize
)
{
static DWORD dwRefCount = 0;
DWORD dwRetCode = NO_ERROR;
if ( fInitialize )
{
//Initialize
if (0 == dwRefCount)
{
dwRetCode = IASLogonInitialize();
}
dwRefCount ++;
}
else
{
dwRefCount --;
if (0 == dwRefCount)
{
IASLogonShutdown();
}
}
dwRetCode = ChapInit( fInitialize );
return dwRetCode;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////
// All the dialogs required for EAPMSCHAPv2 go here. Move into it's own file later.
////////////////////////////////////////////////////////////////////////////////////////////////////////
static const DWORD g_adwHelp[] =
{
0, 0
};
VOID
ContextHelp(
IN const DWORD* padwMap,
IN HWND hWndDlg,
IN UINT unMsg,
IN WPARAM wParam,
IN LPARAM lParam
)
{
return;
}
BOOL
LogonInitDialog(
IN HWND hWnd,
IN LPARAM lParam
)
{
PEAPMSCHAPv2_LOGON_DIALOG pMSCHAPv2LogonDialog;
PEAPMSCHAPv2_USER_PROPERTIES pUserProp;
SetWindowLongPtr(hWnd, DWLP_USER, lParam);
pMSCHAPv2LogonDialog = (PEAPMSCHAPv2_LOGON_DIALOG)lParam;
pUserProp = pMSCHAPv2LogonDialog->pUserProp;
pMSCHAPv2LogonDialog->hWndUserName =
GetDlgItem(hWnd, IDC_EDIT_USERNAME);
pMSCHAPv2LogonDialog->hWndPassword =
GetDlgItem(hWnd, IDC_EDIT_PASSWORD);
pMSCHAPv2LogonDialog->hWndDomain =
GetDlgItem(hWnd, IDC_EDIT_DOMAIN);
pMSCHAPv2LogonDialog->hWndSavePassword =
GetDlgItem(hWnd, IDC_CHECK_SAVE_UID_PWD);
//Setup upper limit on text boxes
SendMessage(pMSCHAPv2LogonDialog->hWndUserName,
EM_LIMITTEXT,
UNLEN,
0L
);
SendMessage(pMSCHAPv2LogonDialog->hWndPassword,
EM_LIMITTEXT,
PWLEN,
0L
);
SendMessage(pMSCHAPv2LogonDialog->hWndDomain,
EM_LIMITTEXT,
DNLEN,
0L
);
if ( pUserProp->fFlags & EAPMSCHAPv2_FLAG_CALLED_WITHIN_WINLOGON )
{
EnableWindow ( pMSCHAPv2LogonDialog->hWndSavePassword, FALSE );
}
else if ( pUserProp->fFlags & EAPMSCHAPv2_FLAG_8021x )
{
ShowWindow ( pMSCHAPv2LogonDialog->hWndSavePassword, SW_HIDE );
}
else
{
if ( pUserProp->fFlags & EAPMSCHAPv2_FLAG_SAVE_UID_PWD )
{
CheckDlgButton(hWnd, IDC_CHECK_SAVE_UID_PWD, BST_CHECKED);
}
}
if ( pUserProp->szUserName[0] )
{
SetWindowText( pMSCHAPv2LogonDialog->hWndUserName,
pUserProp->szUserName
);
}
if ( pUserProp->szPassword[0] )
{
SetWindowText( pMSCHAPv2LogonDialog->hWndPassword,
pUserProp->szPassword
);
}
if ( pUserProp->szDomain[0] )
{
SetWindowText( pMSCHAPv2LogonDialog->hWndDomain,
pUserProp->szDomain
);
}
if ( !pUserProp->szUserName[0] )
{
SetFocus(pMSCHAPv2LogonDialog->hWndUserName);
}
else
{
SetFocus(pMSCHAPv2LogonDialog->hWndPassword);
}
return FALSE;
}
BOOL
LogonCommand(
IN PEAPMSCHAPv2_LOGON_DIALOG pMSCHAPv2LogonDialog,
IN WORD wNotifyCode,
IN WORD wId,
IN HWND hWndDlg,
IN HWND hWndCtrl
)
{
BOOL fRetVal = FALSE;
PEAPMSCHAPv2_USER_PROPERTIES pUserProp = pMSCHAPv2LogonDialog->pUserProp;
switch(wId)
{
case IDC_CHECK_SAVE_UID_PWD:
if ( pUserProp->fFlags & EAPMSCHAPv2_FLAG_SAVE_UID_PWD )
{
//
// We got the creds from rasman. So toggle the display
//
if ( BST_CHECKED ==
IsDlgButtonChecked ( hWndDlg, IDC_CHECK_SAVE_UID_PWD )
)
{
SetWindowText( pMSCHAPv2LogonDialog->hWndPassword,
pUserProp->szPassword
);
}
else
{
SetWindowText( pMSCHAPv2LogonDialog->hWndPassword,
""
);
}
}
break;
case IDOK:
//
//grab info from the fields and set it in
//the logon dialog structure
//
GetWindowText( pMSCHAPv2LogonDialog->hWndUserName,
pUserProp->szUserName,
UNLEN+1
);
GetWindowText( pMSCHAPv2LogonDialog->hWndPassword,
pUserProp->szPassword,
PWLEN+1
);
GetWindowText ( pMSCHAPv2LogonDialog->hWndDomain,
pUserProp->szDomain,
DNLEN+1
);
if ( !(pUserProp->fFlags & EAPMSCHAPv2_FLAG_CALLED_WITHIN_WINLOGON )
&& !(pUserProp->fFlags & EAPMSCHAPv2_FLAG_8021x) )
{
if ( BST_CHECKED ==
IsDlgButtonChecked ( hWndDlg, IDC_CHECK_SAVE_UID_PWD )
)
{
pUserProp->fFlags |= EAPMSCHAPv2_FLAG_SAVE_UID_PWD;
}
else
{
pUserProp->fFlags &= ~EAPMSCHAPv2_FLAG_SAVE_UID_PWD;
}
}
else if ( pUserProp->fFlags & EAPMSCHAPv2_FLAG_8021x )
{
pUserProp->fFlags |= EAPMSCHAPv2_FLAG_SAVE_UID_PWD;
}
case IDCANCEL:
EndDialog(hWndDlg, wId);
fRetVal = TRUE;
break;
default:
break;
}
return fRetVal;
}
INT_PTR CALLBACK
LogonDialogProc(
IN HWND hWnd,
IN UINT unMsg,
IN WPARAM wParam,
IN LPARAM lParam
)
{
PEAPMSCHAPv2_LOGON_DIALOG pMSCHAPv2LogonDialog;
switch (unMsg)
{
case WM_INITDIALOG:
return(LogonInitDialog(hWnd, lParam));
case WM_HELP:
case WM_CONTEXTMENU:
{
ContextHelp(g_adwHelp, hWnd, unMsg, wParam, lParam);
break;
}
case WM_COMMAND:
pMSCHAPv2LogonDialog = (PEAPMSCHAPv2_LOGON_DIALOG)GetWindowLongPtr(hWnd, DWLP_USER);
return(LogonCommand(pMSCHAPv2LogonDialog,
HIWORD(wParam),
LOWORD(wParam),
hWnd,
(HWND)lParam)
);
}
return(FALSE);
}
BOOL
RetryInitDialog(
IN HWND hWnd,
IN LPARAM lParam
)
{
PEAPMSCHAPv2_LOGON_DIALOG pMSCHAPv2LogonDialog;
PEAPMSCHAPv2_USER_PROPERTIES pUserProp;
SetWindowLongPtr(hWnd, DWLP_USER, lParam);
pMSCHAPv2LogonDialog = (PEAPMSCHAPv2_LOGON_DIALOG)lParam;
pUserProp = pMSCHAPv2LogonDialog->pUserProp;
pMSCHAPv2LogonDialog->hWndUserName =
GetDlgItem(hWnd, IDC_RETRY_USERNAME);
pMSCHAPv2LogonDialog->hWndPassword =
GetDlgItem(hWnd, IDC_RETRY_PASSWORD);
pMSCHAPv2LogonDialog->hWndDomain =
GetDlgItem(hWnd, IDC_RETRY_DOMAIN);
//Setup upper limit on text boxes
SendMessage(pMSCHAPv2LogonDialog->hWndUserName,
EM_LIMITTEXT,
UNLEN,
0L
);
SendMessage(pMSCHAPv2LogonDialog->hWndPassword,
EM_LIMITTEXT,
PWLEN,
0L
);
SendMessage(pMSCHAPv2LogonDialog->hWndDomain,
EM_LIMITTEXT,
DNLEN,
0L
);
if ( pUserProp->fFlags & EAPMSCHAPv2_FLAG_SAVE_UID_PWD )
{
CheckDlgButton(hWnd, IDC_CHECK_SAVE_UID_PWD, BST_CHECKED);
}
if ( pUserProp->szUserName[0] )
{
SetWindowText( pMSCHAPv2LogonDialog->hWndUserName,
pUserProp->szUserName
);
}
if ( pUserProp->szPassword[0] )
{
SetWindowText( pMSCHAPv2LogonDialog->hWndPassword,
pUserProp->szPassword
);
}
if ( pUserProp->szDomain[0] )
{
SetWindowText( pMSCHAPv2LogonDialog->hWndDomain,
pUserProp->szDomain
);
}
SetFocus(pMSCHAPv2LogonDialog->hWndUserName);
return FALSE;
}
BOOL
RetryCommand(
IN PEAPMSCHAPv2_LOGON_DIALOG pMSCHAPv2LogonDialog,
IN WORD wNotifyCode,
IN WORD wId,
IN HWND hWndDlg,
IN HWND hWndCtrl
)
{
BOOL fRetVal = FALSE;
PEAPMSCHAPv2_USER_PROPERTIES pUserProp = pMSCHAPv2LogonDialog->pUserProp;
switch(wId)
{
case IDC_CHECK_SAVE_UID_PWD:
if ( BST_CHECKED ==
IsDlgButtonChecked ( hWndDlg, IDC_CHECK_SAVE_UID_PWD )
)
{
pUserProp->fFlags |= EAPMSCHAPv2_FLAG_SAVE_UID_PWD;
}
else
{
pUserProp->fFlags &= ~EAPMSCHAPv2_FLAG_SAVE_UID_PWD;
}
break;
case IDOK:
//
//grab new password from the dialog and set it in
//the logon dialog structure
//
GetWindowText( pMSCHAPv2LogonDialog->hWndPassword,
pUserProp->szPassword,
PWLEN+1
);
case IDCANCEL:
EndDialog(hWndDlg, wId);
fRetVal = TRUE;
break;
default:
break;
}
return fRetVal;
}
INT_PTR CALLBACK
RetryDialogProc(
IN HWND hWnd,
IN UINT unMsg,
IN WPARAM wParam,
IN LPARAM lParam
)
{
PEAPMSCHAPv2_LOGON_DIALOG pMSCHAPv2LogonDialog;
switch (unMsg)
{
case WM_INITDIALOG:
return(RetryInitDialog(hWnd, lParam));
case WM_HELP:
case WM_CONTEXTMENU:
{
ContextHelp(g_adwHelp, hWnd, unMsg, wParam, lParam);
break;
}
case WM_COMMAND:
pMSCHAPv2LogonDialog = (PEAPMSCHAPv2_LOGON_DIALOG)GetWindowLongPtr(hWnd, DWLP_USER);
return(RetryCommand(pMSCHAPv2LogonDialog,
HIWORD(wParam),
LOWORD(wParam),
hWnd,
(HWND)lParam)
);
}
return(FALSE);
}
///
/// Client configuration dialog
///
BOOL
ClientConfigInitDialog(
IN HWND hWnd,
IN LPARAM lParam
)
{
PEAPMSCHAPv2_CLIENTCONFIG_DIALOG pClientConfigDialog;
PEAPMSCHAPv2_CONN_PROPERTIES pConnProp;
SetWindowLongPtr(hWnd, DWLP_USER, lParam);
pClientConfigDialog = (PEAPMSCHAPv2_CLIENTCONFIG_DIALOG)lParam;
pConnProp = pClientConfigDialog->pConnProp;
if ( pConnProp ->fFlags & EAPMSCHAPv2_FLAG_USE_WINLOGON_CREDS )
{
CheckDlgButton(hWnd, IDC_CHK_USE_WINLOGON, BST_CHECKED);
}
return FALSE;
}
BOOL
ClientConfigCommand(
IN PEAPMSCHAPv2_CLIENTCONFIG_DIALOG pClientConfigDialog,
IN WORD wNotifyCode,
IN WORD wId,
IN HWND hWndDlg,
IN HWND hWndCtrl
)
{
BOOL fRetVal = FALSE;
PEAPMSCHAPv2_CONN_PROPERTIES pConnProp = pClientConfigDialog->pConnProp;
switch(wId)
{
case IDC_CHK_USE_WINLOGON:
if ( BST_CHECKED ==
IsDlgButtonChecked ( hWndDlg, IDC_CHK_USE_WINLOGON )
)
{
pConnProp->fFlags |= EAPMSCHAPv2_FLAG_USE_WINLOGON_CREDS;
}
else
{
pConnProp->fFlags &= ~EAPMSCHAPv2_FLAG_USE_WINLOGON_CREDS;
}
break;
case IDOK:
case IDCANCEL:
EndDialog(hWndDlg, wId);
fRetVal = TRUE;
break;
default:
break;
}
return fRetVal;
}
INT_PTR CALLBACK
ClientConfigDialogProc(
IN HWND hWnd,
IN UINT unMsg,
IN WPARAM wParam,
IN LPARAM lParam
)
{
PEAPMSCHAPv2_CLIENTCONFIG_DIALOG pClientConfigDialog;
switch (unMsg)
{
case WM_INITDIALOG:
return(ClientConfigInitDialog(hWnd, lParam));
case WM_HELP:
case WM_CONTEXTMENU:
{
ContextHelp(g_adwHelp, hWnd, unMsg, wParam, lParam);
break;
}
case WM_COMMAND:
pClientConfigDialog = (PEAPMSCHAPv2_CLIENTCONFIG_DIALOG)GetWindowLongPtr(hWnd, DWLP_USER);
return(ClientConfigCommand(pClientConfigDialog,
HIWORD(wParam),
LOWORD(wParam),
hWnd,
(HWND)lParam)
);
}
return(FALSE);
}
//// Server Configuration
//
BOOL
ServerConfigInitDialog(
IN HWND hWnd,
IN LPARAM lParam
)
{
PEAPMSCHAPv2_SERVERCONFIG_DIALOG pServerConfigDialog;
PEAPMSCHAPv2_USER_PROPERTIES pUserProp;
CHAR szRetries[10] = {0};
SetWindowLongPtr(hWnd, DWLP_USER, lParam);
pServerConfigDialog = (PEAPMSCHAPv2_SERVERCONFIG_DIALOG)lParam;
pUserProp = pServerConfigDialog->pUserProp;
pServerConfigDialog->hWndRetries =
GetDlgItem(hWnd, IDC_EDIT_RETRIES);
SendMessage(pServerConfigDialog->hWndRetries ,
EM_LIMITTEXT,
2,
0L
);
if ( pUserProp->fFlags & EAPMSCHAPv2_FLAG_ALLOW_CHANGEPWD )
{
CheckDlgButton(hWnd, IDC_CHECK_ALLOW_CHANGEPWD, BST_CHECKED);
}
SetWindowText( pServerConfigDialog->hWndRetries,
_ltoa(pUserProp->dwMaxRetries, szRetries, 10)
);
return FALSE;
}
BOOL
ServerConfigCommand(
IN PEAPMSCHAPv2_SERVERCONFIG_DIALOG pServerConfigDialog,
IN WORD wNotifyCode,
IN WORD wId,
IN HWND hWndDlg,
IN HWND hWndCtrl
)
{
BOOL fRetVal = FALSE;
PEAPMSCHAPv2_USER_PROPERTIES pUserProp = pServerConfigDialog->pUserProp;
switch(wId)
{
case IDC_CHECK_ALLOW_CHANGEPWD:
if ( BST_CHECKED ==
IsDlgButtonChecked ( hWndDlg, IDC_CHECK_ALLOW_CHANGEPWD )
)
{
pUserProp->fFlags |= EAPMSCHAPv2_FLAG_ALLOW_CHANGEPWD;
}
else
{
pUserProp->fFlags &= ~EAPMSCHAPv2_FLAG_ALLOW_CHANGEPWD;
}
fRetVal = TRUE;
break;
case IDOK:
{
CHAR szRetries[10] = {0};
//
// Get the new value for retries
//
GetWindowText ( pServerConfigDialog->hWndRetries,
szRetries,
9
);
pUserProp->dwMaxRetries = atol(szRetries);
}
case IDCANCEL:
EndDialog(hWndDlg, wId);
fRetVal = TRUE;
break;
default:
break;
}
return fRetVal;
}
INT_PTR CALLBACK
ServerConfigDialogProc(
IN HWND hWnd,
IN UINT unMsg,
IN WPARAM wParam,
IN LPARAM lParam
)
{
PEAPMSCHAPv2_SERVERCONFIG_DIALOG pServerConfigDialog;
switch (unMsg)
{
case WM_INITDIALOG:
return(ServerConfigInitDialog(hWnd, lParam));
case WM_HELP:
case WM_CONTEXTMENU:
{
ContextHelp(g_adwHelp, hWnd, unMsg, wParam, lParam);
break;
}
case WM_COMMAND:
pServerConfigDialog = (PEAPMSCHAPv2_SERVERCONFIG_DIALOG)GetWindowLongPtr(hWnd, DWLP_USER);
return(ServerConfigCommand(pServerConfigDialog,
HIWORD(wParam),
LOWORD(wParam),
hWnd,
(HWND)lParam)
);
}
return(FALSE);
}
//// Change Password Dialog
//
BOOL
ChangePasswordInitDialog(
IN HWND hWnd,
IN LPARAM lParam
)
{
PEAPMSCHAPv2_CHANGEPWD_DIALOG pChangePwdDialog;
SetWindowLongPtr(hWnd, DWLP_USER, lParam);
pChangePwdDialog = (PEAPMSCHAPv2_CHANGEPWD_DIALOG)lParam;
if ( pChangePwdDialog->pInteractiveUIData->fFlags & EAPMSCHAPv2_INTERACTIVE_UI_FLAG_CHANGE_PWD )
{
pChangePwdDialog->hWndNewPassword =
GetDlgItem(hWnd, IDC_NEW_PASSWORD);
pChangePwdDialog->hWndConfirmNewPassword =
GetDlgItem(hWnd, IDC_CONFIRM_NEW_PASSWORD);
SetWindowText( pChangePwdDialog->hWndNewPassword,
""
);
}
else
{
pChangePwdDialog->hWndNewPassword =
GetDlgItem(hWnd, CID_CP_EB_Password_RASDLG);
pChangePwdDialog->hWndConfirmNewPassword =
GetDlgItem(hWnd, CID_CP_EB_ConfirmPassword_RASDLG);
pChangePwdDialog->hWndOldPassword =
GetDlgItem(hWnd,CID_CP_EB_OldPassword_RASDLG);
SetWindowText ( pChangePwdDialog->hWndOldPassword,
""
);
SetFocus( pChangePwdDialog->hWndOldPassword );
}
SendMessage ( pChangePwdDialog->hWndNewPassword,
EM_LIMITTEXT,
PWLEN-1,
0L
);
SendMessage ( pChangePwdDialog->hWndConfirmNewPassword,
EM_LIMITTEXT,
PWLEN-1,
0L
);
SetWindowText( pChangePwdDialog->hWndNewPassword,
""
);
SetWindowText( pChangePwdDialog->hWndConfirmNewPassword,
""
);
return FALSE;
}
BOOL
ChangePasswordCommand(
IN PEAPMSCHAPv2_CHANGEPWD_DIALOG pChangePwdDialog,
IN WORD wNotifyCode,
IN WORD wId,
IN HWND hWndDlg,
IN HWND hWndCtrl
)
{
BOOL fRetVal = FALSE;
switch(wId)
{
case IDOK:
{
CHAR szOldPassword[PWLEN+1] = {0};
CHAR szNewPassword[PWLEN+1] = {0};
CHAR szConfirmNewPassword[PWLEN+1] = {0};
CHAR szMessage[512] = {0};
CHAR szHeader[64] = {0};
LoadString( GetResouceDLLHInstance(),
IDS_MESSAGE_HEADER,
szHeader,
sizeof(szHeader)-1
);
if ( pChangePwdDialog->pInteractiveUIData->fFlags &
EAPMSCHAPv2_INTERACTIVE_UI_FLAG_CHANGE_PWD_WINLOGON
)
{
GetWindowText ( pChangePwdDialog->hWndOldPassword,
szOldPassword,
PWLEN
);
}
//
// Get the new value for retries
//
GetWindowText ( pChangePwdDialog->hWndNewPassword,
szNewPassword,
PWLEN
);
GetWindowText ( pChangePwdDialog->hWndConfirmNewPassword,
szConfirmNewPassword,
PWLEN
);
if ( szNewPassword[0] == 0 )
{
//
// Load resource from res file
//
LoadString( GetResouceDLLHInstance(),
IDS_PASSWORD_REQUIRED,
szMessage,
sizeof(szMessage)-1
);
MessageBox (hWndDlg,
szMessage,
szHeader,
MB_OK
);
break;
}
if ( pChangePwdDialog->pInteractiveUIData->fFlags &
EAPMSCHAPv2_INTERACTIVE_UI_FLAG_CHANGE_PWD_WINLOGON
)
{
if ( szOldPassword[0] == 0 )
{
LoadString( GetResouceDLLHInstance(),
IDS_PASSWORD_REQUIRED,
szMessage,
sizeof(szMessage)-1
);
MessageBox (hWndDlg,
szMessage,
szHeader,
MB_OK
);
break;
}
}
if ( strncmp ( szNewPassword, szConfirmNewPassword, PWLEN ) )
{
LoadString( GetResouceDLLHInstance(),
IDS_PASSWORD_MISMATCH,
szMessage,
sizeof(szMessage)-1
);
MessageBox (hWndDlg,
szMessage,
szHeader,
MB_OK
);
break;
}
if ( pChangePwdDialog->pInteractiveUIData->fFlags &
EAPMSCHAPv2_INTERACTIVE_UI_FLAG_CHANGE_PWD_WINLOGON
)
{
//Save the old paswword.
CopyMemory ( pChangePwdDialog->pInteractiveUIData->UserProp.szPassword,
szOldPassword,
PWLEN
);
}
CopyMemory ( pChangePwdDialog->pInteractiveUIData->szNewPassword,
szNewPassword,
PWLEN
);
//fall thru
}
case IDCANCEL:
EndDialog(hWndDlg, wId);
fRetVal = TRUE;
break;
default:
break;
}
return fRetVal;
}
INT_PTR CALLBACK
ChangePasswordDialogProc(
IN HWND hWnd,
IN UINT unMsg,
IN WPARAM wParam,
IN LPARAM lParam
)
{
PEAPMSCHAPv2_CHANGEPWD_DIALOG pChangePwdDialog;
switch (unMsg)
{
case WM_INITDIALOG:
return(ChangePasswordInitDialog(hWnd, lParam));
case WM_HELP:
case WM_CONTEXTMENU:
{
ContextHelp(g_adwHelp, hWnd, unMsg, wParam, lParam);
break;
}
case WM_COMMAND:
pChangePwdDialog = (PEAPMSCHAPv2_CHANGEPWD_DIALOG)GetWindowLongPtr(hWnd, DWLP_USER);
return(ChangePasswordCommand(pChangePwdDialog,
HIWORD(wParam),
LOWORD(wParam),
hWnd,
(HWND)lParam)
);
}
return(FALSE);
}