|
|
/********************************************************************/ /** 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); }
|