/********************************************************************/ /** 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 #include #include #include #include #include #define SECURITY_WIN32 #include // For GetUserNameExW #include #include #include #include #include #include #include #include #include #include #include #include #include #define INCL_RASAUTHATTRIBUTES #define INCL_PWUTIL #define INCL_HOSTWIRE #include #include #include #include #include #include #include #include "resource.h" #define STRSAFE_NO_DEPRECATE #include #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; DWORD dwLSARetCode; //Return value from LSA }; // // 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 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 ); //** // // 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; RtlSecureZeroMemory( 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 ) { #if 0 dwRetCode = ServerConfigDataIO( TRUE /* fRead */, NULL /* pwszMachineName */, (BYTE**)&(pWB->pUserProp), 0); #endif // // pConnectionData should have the config data which // was supplied in InvokeConfigUI2 routine. // if( (NULL == pPppEapInput->pConnectionData) || (pPppEapInput->dwSizeOfConnectionData < sizeof(EAPMSCHAPv2_USER_PROPERTIES))) { pWB->pUserProp = LocalAlloc(LPTR, sizeof(EAPMSCHAPv2_USER_PROPERTIES)); if(NULL == pWB->pUserProp) { dwRetCode = E_OUTOFMEMORY; goto done; } pWB->pUserProp->dwVersion = 1; //Set Defaults here pWB->pUserProp->dwMaxRetries = 2; pWB->pUserProp->fFlags |= EAPMSCHAPv2_FLAG_ALLOW_CHANGEPWD; } else { pWB->pUserProp = (EAPMSCHAPv2_USER_PROPERTIES *) LocalAlloc(LPTR, pPppEapInput->dwSizeOfConnectionData); if(NULL == pWB->pUserProp) { dwRetCode = E_OUTOFMEMORY; goto done; } CopyMemory(pWB->pUserProp, pPppEapInput->pConnectionData, pPppEapInput->dwSizeOfConnectionData); } } 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 TEST_VIVEKK_PRIVATE 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 TEST_VIVEKK_PRIVATE static BOOL fCallerTrusted = TRUE; #else static BOOL fCallerTrusted = FALSE; #endif // //Verify the caller first and then proceed with //other business // 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; } dwRetCode = EapChapBeginCommon( EAPTYPE_MD5Challenge, FALSE, 0, NULL, ppWorkBuffer, pPppEapInput ); done: 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 ); pEapwb->dwLSARetCode = dwRetCode; 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; pEapwb->dwLSARetCode = NO_ERROR; pApInput->fAuthenticationComplete = TRUE; pApInput->dwAuthResultCode = pApInput->dwAuthError = NO_ERROR; } else { pEapwb->dwLSARetCode = dwRetCode; // // 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 ); } else { // // Change password operation failed. // pSendPacket->Code = EAPCODE_Failure; HostToWireFormat16 ( (WORD)4, pSendPacket->Length ); pEapwb->EapState = EMV2_Failure; //pEapOutput->dwAuthResultCode = pEapwb->pwb->result.dwError; pEapOutput->dwAuthResultCode = pEapwb->dwLSARetCode; pEapOutput->Action = EAPACTION_SendAndDone; dwRetCode = NO_ERROR; break; } // // 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->dwAuthResultCode = pEapwb->dwLSARetCode; 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->dwAuthResultCode = pEapwb->dwLSARetCode; 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; DWORD cbPassword; PBYTE pbPassword = NULL; 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 ); dwRetCode = DecodePassword(&pWB->pwb->DBPassword, &cbPassword, &pbPassword); if(NO_ERROR != dwRetCode) { goto done; } // // 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); RtlSecureZeroMemory(pbPassword, cbPassword); LocalFree(pbPassword); 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 = 2; //Set Defaults here pUserProp->dwMaxRetries = 2; pUserProp->fFlags |= EAPMSCHAPv2_FLAG_ALLOW_CHANGEPWD; } 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 ); RtlSecureZeroMemory(pbPassword, cbPassword); LocalFree(pbPassword); } } } *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, BOOL fConfigDataInRegistry, const BYTE* pConfigDataIn, DWORD dwSizeofConfigDataIn, BYTE** ppConfigDataOut, DWORD* pdwSizeofConfigDataOut ) { DWORD dwRetCode = NO_ERROR; INT_PTR nRet = 0; EAPMSCHAPv2_SERVERCONFIG_DIALOG EapServerConfig; BOOL fLocal = FALSE; if (0 == *pszMachineName) { fLocal = TRUE; } if(fConfigDataInRegistry) { //Read the information from registry here dwRetCode = ServerConfigDataIO( TRUE /* fRead */, fLocal ? NULL : pszMachineName, (BYTE**)&(EapServerConfig.pUserProp), 0); if (NO_ERROR != dwRetCode) { goto LDone; } } else { if(dwSizeofConfigDataIn < sizeof(EAPMSCHAPv2_USER_PROPERTIES)) { dwRetCode = ReadUserData(NULL,0, &EapServerConfig.pUserProp); } else { EapServerConfig.pUserProp = LocalAlloc(LPTR, dwSizeofConfigDataIn); if(NULL == EapServerConfig.pUserProp) { dwRetCode = E_OUTOFMEMORY; goto LDone; } CopyMemory(EapServerConfig.pUserProp, pConfigDataIn, dwSizeofConfigDataIn); } if(NO_ERROR != dwRetCode) { goto LDone; } } //Show the server config UI here nRet = DialogBoxParam( GetHInstance(), 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; } if(fConfigDataInRegistry) { //Read the information from registry here dwRetCode = ServerConfigDataIO( FALSE/* fRead */, fLocal ? NULL : pszMachineName, (BYTE**)&(EapServerConfig.pUserProp), sizeof(EAPMSCHAPv2_USER_PROPERTIES)); LocalFree(EapServerConfig.pUserProp); } else { *ppConfigDataOut = (BYTE *) EapServerConfig.pUserProp; *pdwSizeofConfigDataOut = sizeof(EAPMSCHAPv2_USER_PROPERTIES); } LDone: return dwRetCode; } 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; } // Check to see if our existing user props are cached? If so, // there is no need to show the dialog if ( (dwFlags & RAS_EAP_FLAG_8021X_AUTH ) && pUserProp->szUserName[0] && pUserProp->cbEncPassword ) { fShowUI = FALSE; } if ( fShowUI ) { //Either we have an empty user name //or password nRet = DialogBoxParam( GetHInstance(), 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( GetHInstance(), IDS_NO_ROUTER_CONFIG, szMessage, sizeof(szMessage)-1 ); LoadString( GetHInstance(), 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( GetHInstance(), MAKEINTRESOURCE(IDD_DIALOG_CLEINT_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( GetHInstance(), 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( GetHInstance(), 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( GetHInstance(), 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( GetHInstance(), 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( GetHInstance(), IDS_PASSWORD_REQUIRED, szMessage, sizeof(szMessage)-1 ); MessageBox (hWndDlg, szMessage, szHeader, MB_OK ); break; } } if ( strncmp ( szNewPassword, szConfirmNewPassword, PWLEN ) ) { LoadString( GetHInstance(), 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; } DWORD DwGetGlobalConfig( IN DWORD dwEapTypeId, OUT PBYTE* ppConfigDataOut, OUT DWORD* pdwSizeOfConfigDataOut ) { DWORD dwErr = NO_ERROR; PBYTE pbData = NULL; dwErr = ServerConfigDataIO( TRUE, NULL, ppConfigDataOut, 0); if(NO_ERROR != dwErr) { goto done; } *pdwSizeOfConfigDataOut = sizeof(EAPMSCHAPv2_USER_PROPERTIES); done: return HRESULT_FROM_WIN32(dwErr); } 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); }